From f602a393a59865261e17c84f57b96ad7dff7fa65 Mon Sep 17 00:00:00 2001 From: nobody Date: Fri, 3 Dec 2021 10:02:31 +1100 Subject: [PATCH] psr12 updates --- ServiceWorker.js | 2 +- Zotlabs/Access/AccessControl.php | 283 +- Zotlabs/Access/PermissionLimits.php | 139 +- Zotlabs/Access/PermissionRoles.php | 326 +- Zotlabs/Access/Permissions.php | 444 +- Zotlabs/Daemon/Addon.php | 2 +- Zotlabs/Daemon/CacheThumb.php | 2 +- Zotlabs/Daemon/Cache_embeds.php | 2 +- Zotlabs/Daemon/Cache_image.php | 2 +- Zotlabs/Daemon/Channel_purge.php | 2 +- Zotlabs/Daemon/Checksites.php | 2 +- Zotlabs/Daemon/Content_importer.php | 2 +- Zotlabs/Daemon/Convo.php | 2 +- Zotlabs/Daemon/Cron.php | 2 +- Zotlabs/Daemon/Cron_daily.php | 2 +- Zotlabs/Daemon/Cron_weekly.php | 2 +- Zotlabs/Daemon/Cronhooks.php | 2 +- Zotlabs/Daemon/CurlAuth.php | 2 +- Zotlabs/Daemon/Deliver.php | 2 +- Zotlabs/Daemon/Deliver_hooks.php | 2 +- Zotlabs/Daemon/Delxitems.php | 2 +- Zotlabs/Daemon/Directory.php | 2 +- Zotlabs/Daemon/Expire.php | 2 +- Zotlabs/Daemon/File_importer.php | 2 +- Zotlabs/Daemon/Gprobe.php | 2 +- Zotlabs/Daemon/Importdoc.php | 4 +- Zotlabs/Daemon/Importfile.php | 2 +- Zotlabs/Daemon/Notifier.php | 18 +- Zotlabs/Daemon/Onedirsync.php | 2 +- Zotlabs/Daemon/Onepoll.php | 2 +- Zotlabs/Daemon/Poller.php | 2 +- Zotlabs/Daemon/Queue.php | 2 +- Zotlabs/Daemon/Run.php | 4 +- Zotlabs/Daemon/Thumbnail.php | 2 +- Zotlabs/Daemon/Xchan_photo.php | 2 +- Zotlabs/Extend/Hook.php | 10 +- Zotlabs/Extend/Route.php | 78 +- Zotlabs/Extend/Widget.php | 78 +- Zotlabs/Import/Friendica.php | 613 +- Zotlabs/Lib/AConfig.php | 8 +- Zotlabs/Lib/ASCollection.php | 235 +- Zotlabs/Lib/AbConfig.php | 8 +- Zotlabs/Lib/AccessList.php | 794 +- Zotlabs/Lib/Activity.php | 8183 ++++++++++---------- Zotlabs/Lib/ActivityPub.php | 1055 +-- Zotlabs/Lib/ActivityStreams.php | 817 +- Zotlabs/Lib/Api_router.php | 40 +- Zotlabs/Lib/Apps.php | 2675 +++---- Zotlabs/Lib/Chatroom.php | 444 +- Zotlabs/Lib/Config.php | 10 +- Zotlabs/Lib/Connect.php | 450 +- Zotlabs/Lib/Crypto.php | 16 +- Zotlabs/Lib/DB_Upgrade.php | 178 +- Zotlabs/Lib/DReport.php | 212 +- Zotlabs/Lib/Enotify.php | 6 +- Zotlabs/Lib/Hashpath.php | 47 +- Zotlabs/Lib/IConfig.php | 8 +- Zotlabs/Lib/Img_cache.php | 125 +- Zotlabs/Lib/Img_filesize.php | 78 +- Zotlabs/Lib/JSalmon.php | 98 +- Zotlabs/Lib/LDSignatures.php | 187 +- Zotlabs/Lib/LibBlock.php | 182 +- Zotlabs/Lib/Libprofile.php | 1024 ++- Zotlabs/Lib/Libsync.php | 2212 +++--- Zotlabs/Lib/Libzot.php | 6330 ++++++++------- Zotlabs/Lib/Libzotdir.php | 817 +- Zotlabs/Lib/Markdown.php | 516 +- Zotlabs/Lib/MarkdownSoap.php | 172 +- Zotlabs/Lib/MastAPI.php | 129 +- Zotlabs/Lib/MessageFilter.php | 2 +- Zotlabs/Lib/Nodeinfo.php | 2 +- Zotlabs/Lib/PConfig.php | 8 +- Zotlabs/Lib/Permcat.php | 6 +- Zotlabs/Lib/PermissionDescription.php | 2 +- Zotlabs/Lib/Queue.php | 797 +- Zotlabs/Lib/SConfig.php | 8 +- Zotlabs/Lib/SvgSanitizer.php | 240 +- Zotlabs/Lib/System.php | 32 +- Zotlabs/Lib/ThreadListener.php | 10 +- Zotlabs/Lib/Verify.php | 109 +- Zotlabs/Lib/Webfinger.php | 161 +- Zotlabs/Lib/XConfig.php | 10 +- Zotlabs/Lib/ZotURL.php | 8 +- Zotlabs/Lib/Zotfinger.php | 87 +- Zotlabs/Module/Acl.php | 555 +- Zotlabs/Module/Activity.php | 438 +- Zotlabs/Module/Admin.php | 270 +- Zotlabs/Module/Admin/Account_edit.php | 108 +- Zotlabs/Module/Admin/Accounts.php | 369 +- Zotlabs/Module/Admin/Addons.php | 870 +-- Zotlabs/Module/Admin/Channels.php | 289 +- Zotlabs/Module/Admin/Cover_photo.php | 785 +- Zotlabs/Module/Admin/Dbsync.php | 192 +- Zotlabs/Module/Admin/Logs.php | 174 +- Zotlabs/Module/Admin/Profile_photo.php | 957 ++- Zotlabs/Module/Admin/Profs.php | 349 +- Zotlabs/Module/Admin/Queue.php | 78 +- Zotlabs/Module/Admin/Security.php | 311 +- Zotlabs/Module/Admin/Site.php | 663 +- Zotlabs/Module/Admin/Themes.php | 384 +- Zotlabs/Module/Affinity.php | 107 +- Zotlabs/Module/Album.php | 142 +- Zotlabs/Module/Ap_probe.php | 52 +- Zotlabs/Module/Api.php | 222 +- Zotlabs/Module/Appman.php | 261 +- Zotlabs/Module/Apporder.php | 68 +- Zotlabs/Module/Apps.php | 93 +- Zotlabs/Module/Apschema.php | 22 +- Zotlabs/Module/Attach.php | 87 +- Zotlabs/Module/Authorize.php | 212 +- Zotlabs/Module/Block.php | 158 +- Zotlabs/Module/Blocks.php | 319 +- Zotlabs/Module/Ca.php | 6 +- Zotlabs/Module/Cal.php | 675 +- Zotlabs/Module/Calendar.php | 876 ++- Zotlabs/Module/Card_edit.php | 205 +- Zotlabs/Module/Cards.php | 290 +- Zotlabs/Module/Categories.php | 33 +- Zotlabs/Module/Cdav.php | 2647 ++++--- Zotlabs/Module/Changeaddr.php | 195 +- Zotlabs/Module/Channel.php | 974 ++- Zotlabs/Module/Chanview.php | 309 +- Zotlabs/Module/Chat.php | 469 +- Zotlabs/Module/Chatsvc.php | 346 +- Zotlabs/Module/Clients.php | 16 +- Zotlabs/Module/Cloud.php | 179 +- Zotlabs/Module/Cloud_tiles.php | 24 +- Zotlabs/Module/Comment_control.php | 16 +- Zotlabs/Module/Common.php | 127 +- Zotlabs/Module/Connac.php | 38 +- Zotlabs/Module/Connect.php | 225 +- Zotlabs/Module/Connections.php | 713 +- Zotlabs/Module/Connedit.php | 1583 ++-- Zotlabs/Module/Contactgroup.php | 73 +- Zotlabs/Module/Content_filter.php | 83 +- Zotlabs/Module/Conversation.php | 226 +- Zotlabs/Module/Cover_photo.php | 888 ++- Zotlabs/Module/Dav.php | 178 +- Zotlabs/Module/Defperms.php | 456 +- Zotlabs/Module/Dircensor.php | 65 +- Zotlabs/Module/Directory.php | 1000 ++- Zotlabs/Module/Dirsearch.php | 851 +- Zotlabs/Module/Display.php | 848 +- Zotlabs/Module/Drafts.php | 19 +- Zotlabs/Module/Dreport.php | 360 +- Zotlabs/Module/Editblock.php | 226 +- Zotlabs/Module/Editlayout.php | 216 +- Zotlabs/Module/Editpost.php | 214 +- Zotlabs/Module/Editwebpage.php | 269 +- Zotlabs/Module/Email_resend.php | 54 +- Zotlabs/Module/Email_validation.php | 71 +- Zotlabs/Module/Embed.php | 20 +- Zotlabs/Module/Embedphotos.php | 400 +- Zotlabs/Module/Event.php | 65 +- Zotlabs/Module/Events.php | 1545 ++-- Zotlabs/Module/Expire.php | 56 +- Zotlabs/Module/Fastping.php | 89 +- Zotlabs/Module/Fbrowser.php | 228 +- Zotlabs/Module/Fedi_id.php | 81 +- Zotlabs/Module/Feed.php | 74 +- Zotlabs/Module/File_upload.php | 164 +- Zotlabs/Module/Filer.php | 105 +- Zotlabs/Module/Filerm.php | 68 +- Zotlabs/Module/Filestorage.php | 374 +- Zotlabs/Module/Finger.php | 36 +- Zotlabs/Module/Follow.php | 293 +- Zotlabs/Module/Followers.php | 91 +- Zotlabs/Module/Following.php | 93 +- Zotlabs/Module/Future.php | 10 +- Zotlabs/Module/Getfile.php | 201 +- Zotlabs/Module/Hashtags.php | 36 +- Zotlabs/Module/Hcard.php | 128 +- Zotlabs/Module/Help.php | 234 +- Zotlabs/Module/Home.php | 275 +- Zotlabs/Module/Hostxrd.php | 40 +- Zotlabs/Module/Hq.php | 436 +- Zotlabs/Module/Id.php | 133 +- Zotlabs/Module/Impel.php | 362 +- Zotlabs/Module/Import.php | 1076 ++- Zotlabs/Module/Import_items.php | 179 +- Zotlabs/Module/Inbox.php | 679 +- Zotlabs/Module/Inspect.php | 140 +- Zotlabs/Module/Invite.php | 294 +- Zotlabs/Module/Item.php | 3727 +++++---- Zotlabs/Module/Jwks.php | 90 +- Zotlabs/Module/Lang.php | 32 +- Zotlabs/Module/Layouts.php | 317 +- Zotlabs/Module/Linkinfo.php | 1118 +-- Zotlabs/Module/Lists.php | 741 +- Zotlabs/Module/Lockview.php | 315 +- Zotlabs/Module/Locs.php | 254 +- Zotlabs/Module/Login.php | 20 +- Zotlabs/Module/Logout.php | 21 +- Zotlabs/Module/Lostpass.php | 266 +- Zotlabs/Module/Magic.php | 226 +- Zotlabs/Module/Manage.php | 349 +- Zotlabs/Module/Manifest.php | 82 +- Zotlabs/Module/Markup.php | 10 +- Zotlabs/Module/Menu.php | 409 +- Zotlabs/Module/Mitem.php | 498 +- Zotlabs/Module/Moderate.php | 180 +- Zotlabs/Module/Mood.php | 289 +- Zotlabs/Module/New_channel.php | 350 +- Zotlabs/Module/Notes.php | 72 +- Zotlabs/Module/Notifications.php | 120 +- Zotlabs/Module/Notify.php | 144 +- Zotlabs/Module/Nullbox.php | 10 +- Zotlabs/Module/Oauthinfo.php | 28 +- Zotlabs/Module/Oembed.php | 56 +- Zotlabs/Module/Oep.php | 1147 +-- Zotlabs/Module/Oexchange.php | 138 +- Zotlabs/Module/Online.php | 18 +- Zotlabs/Module/Outbox.php | 444 +- Zotlabs/Module/Owa.php | 97 +- Zotlabs/Module/Page.php | 328 +- Zotlabs/Module/Pconfig.php | 255 +- Zotlabs/Module/Pdledit.php | 195 +- Zotlabs/Module/Photo.php | 597 +- Zotlabs/Module/Photomap.php | 12 +- Zotlabs/Module/Photos.php | 2654 ++++--- Zotlabs/Module/Pin.php | 83 +- Zotlabs/Module/Ping.php | 1169 ++- Zotlabs/Module/Poco.php | 12 +- Zotlabs/Module/Poke.php | 254 +- Zotlabs/Module/Poster.php | 54 +- Zotlabs/Module/Pretheme.php | 45 +- Zotlabs/Module/Profile.php | 211 +- Zotlabs/Module/Profile_photo.php | 1034 ++- Zotlabs/Module/Profiles.php | 1950 ++--- Zotlabs/Module/Profperm.php | 318 +- Zotlabs/Module/Pubstream.php | 469 +- Zotlabs/Module/Q.php | 35 +- Zotlabs/Module/Randprof.php | 22 +- Zotlabs/Module/React.php | 137 +- Zotlabs/Module/Register.php | 590 +- Zotlabs/Module/Regmod.php | 68 +- Zotlabs/Module/Regver.php | 50 +- Zotlabs/Module/Removeaccount.php | 131 +- Zotlabs/Module/Removeme.php | 137 +- Zotlabs/Module/Rmagic.php | 161 +- Zotlabs/Module/Rpost.php | 400 +- Zotlabs/Module/Safe.php | 24 +- Zotlabs/Module/Search.php | 645 +- Zotlabs/Module/Search_ac.php | 159 +- Zotlabs/Module/Secrets.php | 16 +- Zotlabs/Module/Service_limits.php | 44 +- Zotlabs/Module/Settings.php | 139 +- Zotlabs/Module/Settings/Account.php | 206 +- Zotlabs/Module/Settings/Channel.php | 1343 ++-- Zotlabs/Module/Settings/Display.php | 350 +- Zotlabs/Module/Settings/Featured.php | 140 +- Zotlabs/Module/Settings/Features.php | 101 +- Zotlabs/Module/Settings/Network.php | 208 +- Zotlabs/Module/Settings/Oauth.php | 283 +- Zotlabs/Module/Settings/Oauth2.php | 363 +- Zotlabs/Module/Settings/Permcats.php | 182 +- Zotlabs/Module/Settings/Tokens.php | 484 +- Zotlabs/Module/Setup.php | 1611 ++-- Zotlabs/Module/Share.php | 206 +- Zotlabs/Module/Sharedwithme.php | 211 +- Zotlabs/Module/Siteinfo.php | 93 +- Zotlabs/Module/Sites.php | 236 +- Zotlabs/Module/Smilies.php | 31 +- Zotlabs/Module/Sources.php | 354 +- Zotlabs/Module/Sslify.php | 38 +- Zotlabs/Module/Starred.php | 14 +- Zotlabs/Module/Stream.php | 1204 ++- Zotlabs/Module/Subthread.php | 321 +- Zotlabs/Module/Suggestions.php | 55 +- Zotlabs/Module/Superblock.php | 422 +- Zotlabs/Module/Tagadelic.php | 33 +- Zotlabs/Module/Tagger.php | 300 +- Zotlabs/Module/Tagrm.php | 280 +- Zotlabs/Module/Tasks.php | 189 +- Zotlabs/Module/Theme_info.php | 116 +- Zotlabs/Module/Thing.php | 762 +- Zotlabs/Module/Toggle_safesearch.php | 52 +- Zotlabs/Module/Token.php | 58 +- Zotlabs/Module/Uexport.php | 131 +- Zotlabs/Module/Update.php | 84 +- Zotlabs/Module/Userinfo.php | 16 +- Zotlabs/Module/View.php | 24 +- Zotlabs/Module/Viewconnections.php | 211 +- Zotlabs/Module/Viewsrc.php | 115 +- Zotlabs/Module/Vlists.php | 14 +- Zotlabs/Module/Vote.php | 201 +- Zotlabs/Module/Wall_attach.php | 288 +- Zotlabs/Module/Wall_upload.php | 85 +- Zotlabs/Module/Webfinger.php | 290 +- Zotlabs/Module/Webpages.php | 1360 ++-- Zotlabs/Module/Well_known.php | 115 +- Zotlabs/Module/Xchan.php | 81 +- Zotlabs/Module/Xp.php | 108 +- Zotlabs/Module/Xref.php | 42 +- Zotlabs/Module/Zot.php | 13 +- Zotlabs/Module/Zot_probe.php | 61 +- Zotlabs/Module/Zotfinger.php | 44 +- Zotlabs/Photo/PhotoDriver.php | 40 +- Zotlabs/Photo/PhotoGd.php | 2 +- Zotlabs/Photo/PhotoImagick.php | 2 +- Zotlabs/Render/Comanche.php | 1164 +-- Zotlabs/Render/SimpleTemplate.php | 20 +- Zotlabs/Render/SmartyInterface.php | 97 +- Zotlabs/Render/SmartyTemplate.php | 2 +- Zotlabs/Render/Theme.php | 184 +- Zotlabs/Storage/BasicAuth.php | 388 +- Zotlabs/Storage/CalDAVClient.php | 138 +- Zotlabs/Storage/Directory.php | 1735 ++--- Zotlabs/Storage/GitRepo.php | 266 +- Zotlabs/Text/Tagadelic.php | 4 +- Zotlabs/Thumbs/Epubthumb.php | 78 +- Zotlabs/Thumbs/Mp3audio.php | 57 +- Zotlabs/Thumbs/Pdf.php | 74 +- Zotlabs/Thumbs/Text.php | 77 +- Zotlabs/Thumbs/Video.php | 97 +- Zotlabs/Update/_1000.php | 17 +- Zotlabs/Update/_1001.php | 19 +- Zotlabs/Update/_1002.php | 23 +- Zotlabs/Update/_1003.php | 16 +- Zotlabs/Update/_1004.php | 19 +- Zotlabs/Update/_1005.php | 14 +- Zotlabs/Update/_1006.php | 19 +- Zotlabs/Update/_1007.php | 16 +- Zotlabs/Update/_1008.php | 16 +- Zotlabs/Update/_1009.php | 17 +- Zotlabs/Update/_1010.php | 18 +- Zotlabs/Update/_1011.php | 18 +- Zotlabs/Update/_1012.php | 16 +- Zotlabs/Update/_1013.php | 18 +- Zotlabs/Update/_1014.php | 16 +- Zotlabs/Update/_1015.php | 19 +- Zotlabs/Update/_1016.php | 18 +- Zotlabs/Update/_1017.php | 16 +- Zotlabs/Update/_1018.php | 17 +- Zotlabs/Update/_1019.php | 16 +- Zotlabs/Update/_1020.php | 16 +- Zotlabs/Update/_1021.php | 18 +- Zotlabs/Update/_1022.php | 16 +- Zotlabs/Update/_1023.php | 16 +- Zotlabs/Update/_1024.php | 16 +- Zotlabs/Update/_1025.php | 16 +- Zotlabs/Update/_1026.php | 17 +- Zotlabs/Update/_1027.php | 16 +- Zotlabs/Update/_1028.php | 16 +- Zotlabs/Update/_1029.php | 16 +- Zotlabs/Update/_1030.php | 16 +- Zotlabs/Update/_1031.php | 17 +- Zotlabs/Update/_1032.php | 16 +- Zotlabs/Update/_1033.php | 24 +- Zotlabs/Update/_1034.php | 16 +- Zotlabs/Update/_1035.php | 16 +- Zotlabs/Update/_1036.php | 17 +- Zotlabs/Update/_1037.php | 19 +- Zotlabs/Update/_1038.php | 17 +- Zotlabs/Update/_1039.php | 16 +- Zotlabs/Update/_1040.php | 18 +- Zotlabs/Update/_1041.php | 17 +- Zotlabs/Update/_1042.php | 17 +- Zotlabs/Update/_1043.php | 16 +- Zotlabs/Update/_1044.php | 16 +- Zotlabs/Update/_1045.php | 18 +- Zotlabs/Update/_1046.php | 16 +- Zotlabs/Update/_1047.php | 16 +- Zotlabs/Update/_1048.php | 17 +- Zotlabs/Update/_1049.php | 16 +- Zotlabs/Update/_1050.php | 16 +- Zotlabs/Update/_1051.php | 17 +- Zotlabs/Update/_1052.php | 16 +- Zotlabs/Update/_1053.php | 16 +- Zotlabs/Update/_1054.php | 16 +- Zotlabs/Update/_1055.php | 16 +- Zotlabs/Update/_1056.php | 16 +- Zotlabs/Update/_1057.php | 16 +- Zotlabs/Update/_1058.php | 18 +- Zotlabs/Update/_1059.php | 16 +- Zotlabs/Update/_1060.php | 16 +- Zotlabs/Update/_1061.php | 16 +- Zotlabs/Update/_1062.php | 18 +- Zotlabs/Update/_1063.php | 16 +- Zotlabs/Update/_1064.php | 16 +- Zotlabs/Update/_1065.php | 16 +- Zotlabs/Update/_1066.php | 16 +- Zotlabs/Update/_1067.php | 16 +- Zotlabs/Update/_1068.php | 12 +- Zotlabs/Update/_1069.php | 16 +- Zotlabs/Update/_1070.php | 16 +- Zotlabs/Update/_1071.php | 16 +- Zotlabs/Update/_1072.php | 17 +- Zotlabs/Update/_1073.php | 18 +- Zotlabs/Update/_1074.php | 19 +- Zotlabs/Update/_1075.php | 16 +- Zotlabs/Update/_1076.php | 16 +- Zotlabs/Update/_1077.php | 16 +- Zotlabs/Update/_1078.php | 16 +- Zotlabs/Update/_1079.php | 16 +- Zotlabs/Update/_1080.php | 16 +- Zotlabs/Update/_1081.php | 16 +- Zotlabs/Update/_1082.php | 16 +- Zotlabs/Update/_1083.php | 16 +- Zotlabs/Update/_1084.php | 16 +- Zotlabs/Update/_1085.php | 20 +- Zotlabs/Update/_1086.php | 16 +- Zotlabs/Update/_1087.php | 16 +- Zotlabs/Update/_1088.php | 16 +- Zotlabs/Update/_1089.php | 17 +- Zotlabs/Update/_1090.php | 16 +- Zotlabs/Update/_1091.php | 14 +- Zotlabs/Update/_1092.php | 23 +- Zotlabs/Update/_1093.php | 16 +- Zotlabs/Update/_1094.php | 16 +- Zotlabs/Update/_1095.php | 16 +- Zotlabs/Update/_1096.php | 16 +- Zotlabs/Update/_1097.php | 32 +- Zotlabs/Update/_1098.php | 38 +- Zotlabs/Update/_1099.php | 16 +- Zotlabs/Update/_1100.php | 17 +- Zotlabs/Update/_1101.php | 14 +- Zotlabs/Update/_1102.php | 18 +- Zotlabs/Update/_1103.php | 16 +- Zotlabs/Update/_1104.php | 16 +- Zotlabs/Update/_1105.php | 16 +- Zotlabs/Update/_1106.php | 16 +- Zotlabs/Update/_1107.php | 17 +- Zotlabs/Update/_1108.php | 16 +- Zotlabs/Update/_1109.php | 16 +- Zotlabs/Update/_1110.php | 12 +- Zotlabs/Update/_1111.php | 16 +- Zotlabs/Update/_1112.php | 16 +- Zotlabs/Update/_1113.php | 16 +- Zotlabs/Update/_1114.php | 18 +- Zotlabs/Update/_1115.php | 16 +- Zotlabs/Update/_1116.php | 12 +- Zotlabs/Update/_1117.php | 16 +- Zotlabs/Update/_1118.php | 17 +- Zotlabs/Update/_1119.php | 18 +- Zotlabs/Update/_1120.php | 17 +- Zotlabs/Update/_1121.php | 17 +- Zotlabs/Update/_1122.php | 20 +- Zotlabs/Update/_1123.php | 18 +- Zotlabs/Update/_1124.php | 18 +- Zotlabs/Update/_1125.php | 17 +- Zotlabs/Update/_1126.php | 16 +- Zotlabs/Update/_1127.php | 16 +- Zotlabs/Update/_1128.php | 16 +- Zotlabs/Update/_1129.php | 16 +- Zotlabs/Update/_1130.php | 40 +- Zotlabs/Update/_1131.php | 24 +- Zotlabs/Update/_1132.php | 22 +- Zotlabs/Update/_1133.php | 35 +- Zotlabs/Update/_1134.php | 27 +- Zotlabs/Update/_1135.php | 16 +- Zotlabs/Update/_1136.php | 20 +- Zotlabs/Update/_1137.php | 19 +- Zotlabs/Update/_1138.php | 18 +- Zotlabs/Update/_1139.php | 27 +- Zotlabs/Update/_1140.php | 41 +- Zotlabs/Update/_1141.php | 39 +- Zotlabs/Update/_1142.php | 18 +- Zotlabs/Update/_1143.php | 18 +- Zotlabs/Update/_1144.php | 40 +- Zotlabs/Update/_1145.php | 29 +- Zotlabs/Update/_1146.php | 18 +- Zotlabs/Update/_1147.php | 18 +- Zotlabs/Update/_1148.php | 18 +- Zotlabs/Update/_1149.php | 37 +- Zotlabs/Update/_1150.php | 31 +- Zotlabs/Update/_1151.php | 28 +- Zotlabs/Update/_1152.php | 37 +- Zotlabs/Update/_1153.php | 18 +- Zotlabs/Update/_1154.php | 17 +- Zotlabs/Update/_1155.php | 19 +- Zotlabs/Update/_1156.php | 42 +- Zotlabs/Update/_1157.php | 19 +- Zotlabs/Update/_1158.php | 31 +- Zotlabs/Update/_1159.php | 37 +- Zotlabs/Update/_1160.php | 16 +- Zotlabs/Update/_1161.php | 33 +- Zotlabs/Update/_1162.php | 24 +- Zotlabs/Update/_1163.php | 29 +- Zotlabs/Update/_1164.php | 35 +- Zotlabs/Update/_1165.php | 24 +- Zotlabs/Update/_1166.php | 16 +- Zotlabs/Update/_1167.php | 33 +- Zotlabs/Update/_1168.php | 27 +- Zotlabs/Update/_1169.php | 34 +- Zotlabs/Update/_1170.php | 24 +- Zotlabs/Update/_1171.php | 27 +- Zotlabs/Update/_1172.php | 39 +- Zotlabs/Update/_1173.php | 33 +- Zotlabs/Update/_1174.php | 45 +- Zotlabs/Update/_1175.php | 38 +- Zotlabs/Update/_1176.php | 22 +- Zotlabs/Update/_1177.php | 46 +- Zotlabs/Update/_1178.php | 62 +- Zotlabs/Update/_1179.php | 41 +- Zotlabs/Update/_1180.php | 46 +- Zotlabs/Update/_1181.php | 10 +- Zotlabs/Update/_1182.php | 17 +- Zotlabs/Update/_1183.php | 33 +- Zotlabs/Update/_1184.php | 16 +- Zotlabs/Update/_1185.php | 16 +- Zotlabs/Update/_1186.php | 16 +- Zotlabs/Update/_1187.php | 27 +- Zotlabs/Update/_1188.php | 18 +- Zotlabs/Update/_1189.php | 27 +- Zotlabs/Update/_1190.php | 18 +- Zotlabs/Update/_1191.php | 224 +- Zotlabs/Update/_1192.php | 25 +- Zotlabs/Update/_1193.php | 26 +- Zotlabs/Update/_1194.php | 30 +- Zotlabs/Update/_1195.php | 25 +- Zotlabs/Update/_1196.php | 37 +- Zotlabs/Update/_1197.php | 18 +- Zotlabs/Update/_1198.php | 16 +- Zotlabs/Update/_1199.php | 16 +- Zotlabs/Update/_1200.php | 27 +- Zotlabs/Update/_1201.php | 25 +- Zotlabs/Update/_1202.php | 14 +- Zotlabs/Update/_1203.php | 25 +- Zotlabs/Update/_1204.php | 45 +- Zotlabs/Update/_1205.php | 43 +- Zotlabs/Update/_1206.php | 25 +- Zotlabs/Update/_1207.php | 25 +- Zotlabs/Update/_1208.php | 29 +- Zotlabs/Update/_1209.php | 29 +- Zotlabs/Update/_1210.php | 36 +- Zotlabs/Update/_1211.php | 29 +- Zotlabs/Update/_1212.php | 34 +- Zotlabs/Update/_1213.php | 31 +- Zotlabs/Update/_1214.php | 81 +- Zotlabs/Update/_1215.php | 33 +- Zotlabs/Update/_1216.php | 21 +- Zotlabs/Update/_1217.php | 29 +- Zotlabs/Update/_1218.php | 38 +- Zotlabs/Update/_1219.php | 31 +- Zotlabs/Update/_1220.php | 36 +- Zotlabs/Update/_1221.php | 20 +- Zotlabs/Update/_1222.php | 21 +- Zotlabs/Update/_1223.php | 58 +- Zotlabs/Update/_1224.php | 14 +- Zotlabs/Update/_1225.php | 32 +- Zotlabs/Update/_1226.php | 29 +- Zotlabs/Update/_1227.php | 37 +- Zotlabs/Update/_1228.php | 22 +- Zotlabs/Update/_1229.php | 27 +- Zotlabs/Update/_1230.php | 20 +- Zotlabs/Update/_1231.php | 37 +- Zotlabs/Update/_1232.php | 39 +- Zotlabs/Update/_1233.php | 41 +- Zotlabs/Update/_1234.php | 41 +- Zotlabs/Update/_1235.php | 31 +- Zotlabs/Update/_1236.php | 56 +- Zotlabs/Update/_1237.php | 33 +- Zotlabs/Update/_1238.php | 34 +- Zotlabs/Update/_1239.php | 69 +- Zotlabs/Update/_1240.php | 57 +- Zotlabs/Update/_1241.php | 52 +- Zotlabs/Update/_1242.php | 56 +- Zotlabs/Update/_1243.php | 60 +- Zotlabs/Update/_1244.php | 54 +- Zotlabs/Update/_1245.php | 19 +- Zotlabs/Update/_1246.php | 29 +- Zotlabs/Update/_1247.php | 23 +- Zotlabs/Update/_1248.php | 54 +- Zotlabs/Update/_1249.php | 53 +- Zotlabs/Update/_1250.php | 23 +- Zotlabs/Update/_1251.php | 41 +- Zotlabs/Update/_1252.php | 69 +- Zotlabs/Update/_1253.php | 39 +- Zotlabs/Update/_1254.php | 23 +- Zotlabs/Web/Controller.php | 17 +- Zotlabs/Web/HTTPHeaders.php | 93 +- Zotlabs/Web/HTTPSig.php | 1348 ++-- Zotlabs/Web/HttpMeta.php | 194 +- Zotlabs/Web/Router.php | 388 +- Zotlabs/Web/SessionHandler.php | 136 +- Zotlabs/Web/SubModule.php | 108 +- Zotlabs/Widget/Activity.php | 96 +- Zotlabs/Widget/Activity_filter.php | 540 +- Zotlabs/Widget/Admin.php | 94 +- Zotlabs/Widget/Affinity.php | 70 +- Zotlabs/Widget/Album.php | 160 +- Zotlabs/Widget/Appcategories.php | 62 +- Zotlabs/Widget/Appcloud.php | 14 +- Zotlabs/Widget/Appstore.php | 24 +- Zotlabs/Widget/Archive.php | 72 +- Zotlabs/Widget/Bookmarkedchats.php | 42 +- Zotlabs/Widget/Catcloud.php | 50 +- Zotlabs/Widget/Catcloud_wall.php | 20 +- Zotlabs/Widget/Categories.php | 219 +- Zotlabs/Widget/Cdav.php | 299 +- Zotlabs/Widget/Chatroom_list.php | 32 +- Zotlabs/Widget/Chatroom_members.php | 16 +- Zotlabs/Widget/Clock.php | 14 +- Zotlabs/Widget/Collections.php | 86 +- Zotlabs/Widget/Common_friends.php | 63 +- Zotlabs/Widget/Cover_photo.php | 126 +- Zotlabs/Widget/Design_tools.php | 14 +- Zotlabs/Widget/Dirsort.php | 16 +- Zotlabs/Widget/Dirtags.php | 10 +- Zotlabs/Widget/Eventstools.php | 24 +- Zotlabs/Widget/Filer.php | 48 +- Zotlabs/Widget/Findpeople.php | 65 +- Zotlabs/Widget/Follow.php | 59 +- Zotlabs/Widget/Fullprofile.php | 16 +- Zotlabs/Widget/Groups.php | 209 +- Zotlabs/Widget/Helpindex.php | 86 +- Zotlabs/Widget/Hq_controls.php | 38 +- Zotlabs/Widget/Item.php | 71 +- Zotlabs/Widget/Mailmenu.php | 58 +- Zotlabs/Widget/Menu_preview.php | 14 +- Zotlabs/Widget/Newmember.php | 104 +- Zotlabs/Widget/Notes.php | 34 +- Zotlabs/Widget/Notifications.php | 272 +- Zotlabs/Widget/Photo.php | 68 +- Zotlabs/Widget/Photo_albums.php | 28 +- Zotlabs/Widget/Photo_rand.php | 88 +- Zotlabs/Widget/Pinned.php | 159 +- Zotlabs/Widget/Portfolio.php | 176 +- Zotlabs/Widget/Profile.php | 18 +- Zotlabs/Widget/Pubtagcloud.php | 29 +- Zotlabs/Widget/Random_block.php | 60 +- Zotlabs/Widget/Rating.php | 90 +- Zotlabs/Widget/Savedsearch.php | 140 +- Zotlabs/Widget/Sblock.php | 30 +- Zotlabs/Widget/Settings_menu.php | 132 +- Zotlabs/Widget/Shortprofile.php | 16 +- Zotlabs/Widget/Site_projects.php | 74 +- Zotlabs/Widget/Sitesearch.php | 44 +- Zotlabs/Widget/Stream_order.php | 207 +- Zotlabs/Widget/Suggestedchats.php | 52 +- Zotlabs/Widget/Suggestions.php | 80 +- Zotlabs/Widget/Tagcloud.php | 40 +- Zotlabs/Widget/Tagcloud_wall.php | 24 +- Zotlabs/Widget/Tasklist.php | 24 +- Zotlabs/Widget/Vcard.php | 10 +- Zotlabs/Widget/Website_portation_tools.php | 24 +- Zotlabs/Widget/Zcard.php | 12 +- Zotlabs/Zot6/IHandler.php | 11 +- Zotlabs/Zot6/Receiver.php | 374 +- Zotlabs/Zot6/Zot6Handler.php | 265 +- boot.php | 18 +- include/account.php | 16 +- include/acl_selectors.php | 4 +- include/addon.php | 8 +- include/attach.php | 14 +- include/channel.php | 30 +- include/conversation.php | 6 +- include/datetime.php | 6 +- include/dba/dba_driver.php | 258 +- include/dba/dba_pdo.php | 291 +- include/feedutils.php | 2 +- include/help.php | 6 +- include/hubloc.php | 4 +- include/import.php | 14 +- include/items.php | 38 +- include/language.php | 8 +- include/network.php | 26 +- include/oauth.php | 280 +- include/permissions.php | 2 +- include/photo_factory.php | 6 +- include/photos.php | 8 +- include/security.php | 2 +- include/text.php | 134 +- include/zid.php | 2 +- tests/unit/Access/PermissionsTest.php | 2 +- tests/unit/DatabaseTestCase.php | 2 +- tests/unit/Web/HttpSigTest.php | 169 +- tests/unit/get_tags_test.php | 10 +- tests/unit/includes/LanguageTest.php | 2 +- tests/unit/template_test.php | 180 +- util/addons | 8 +- util/admins | 8 +- util/config | 2 +- util/db_update | 6 +- util/dcp | 2 +- util/dmkdir | 2 +- util/docblox_errorchecker.php | 30 +- util/pconfig | 4 +- util/php2po.php | 36 +- util/phplogtime | 8 +- util/po2php.php | 40 +- util/precompile_smarty3.php | 6 +- util/schemaspy | 2 +- util/service_class | 2 +- util/storageconv | 10 +- util/strings.php | 5422 ++++++------- 687 files changed, 63552 insertions(+), 62782 deletions(-) diff --git a/ServiceWorker.js b/ServiceWorker.js index f13c0dccd..09d6137df 100644 --- a/ServiceWorker.js +++ b/ServiceWorker.js @@ -5,5 +5,5 @@ self.addEventListener('install', function(e) { self.addEventListener('fetch', function(e) { // nothing here yet - return; + }); diff --git a/Zotlabs/Access/AccessControl.php b/Zotlabs/Access/AccessControl.php index c46e282e9..9eeef3594 100644 --- a/Zotlabs/Access/AccessControl.php +++ b/Zotlabs/Access/AccessControl.php @@ -12,153 +12,158 @@ namespace Zotlabs\Access; * and @ref ::Zotlabs::Lib::Permcat "Permcat"s individual content ACLs are evaluated. * These answer the question "Can Joe view *this* album/photo?". */ -class AccessControl { - /** - * @brief Allow contacts - * @var string - */ - private $allow_cid; - /** - * @brief Allow groups - * @var string - */ - private $allow_gid; - /** - * @brief Deny contacts - * @var string - */ - private $deny_cid; - /** - * @brief Deny groups - * @var string - */ - private $deny_gid; - /** - * @brief Indicates if we are using the default constructor values or - * values that have been set explicitly. - * @var boolean - */ - private $explicit; +class AccessControl +{ + /** + * @brief Allow contacts + * @var string + */ + private $allow_cid; + /** + * @brief Allow groups + * @var string + */ + private $allow_gid; + /** + * @brief Deny contacts + * @var string + */ + private $deny_cid; + /** + * @brief Deny groups + * @var string + */ + private $deny_gid; + /** + * @brief Indicates if we are using the default constructor values or + * values that have been set explicitly. + * @var bool + */ + private $explicit; - /** - * @brief Constructor for AccessList class. - * - * @note The array to pass to the constructor is different from the array - * that you provide to the set() or set_from_array() functions. - * - * @param array $channel A channel array, where these entries are evaluated: - * * \e string \b channel_allow_cid => string of allowed cids - * * \e string \b channel_allow_gid => string of allowed gids - * * \e string \b channel_deny_cid => string of denied cids - * * \e string \b channel_deny_gid => string of denied gids - */ - function __construct($channel) { - if($channel) { - $this->allow_cid = $channel['channel_allow_cid']; - $this->allow_gid = $channel['channel_allow_gid']; - $this->deny_cid = $channel['channel_deny_cid']; - $this->deny_gid = $channel['channel_deny_gid']; - } - else { - $this->allow_cid = ''; - $this->allow_gid = ''; - $this->deny_cid = ''; - $this->deny_gid = ''; - } + /** + * @brief Constructor for AccessList class. + * + * @note The array to pass to the constructor is different from the array + * that you provide to the set() or set_from_array() functions. + * + * @param array $channel A channel array, where these entries are evaluated: + * * \e string \b channel_allow_cid => string of allowed cids + * * \e string \b channel_allow_gid => string of allowed gids + * * \e string \b channel_deny_cid => string of denied cids + * * \e string \b channel_deny_gid => string of denied gids + */ + public function __construct($channel) + { + if ($channel) { + $this->allow_cid = $channel['channel_allow_cid']; + $this->allow_gid = $channel['channel_allow_gid']; + $this->deny_cid = $channel['channel_deny_cid']; + $this->deny_gid = $channel['channel_deny_gid']; + } else { + $this->allow_cid = ''; + $this->allow_gid = ''; + $this->deny_cid = ''; + $this->deny_gid = ''; + } - $this->explicit = false; - } + $this->explicit = false; + } - /** - * @brief Get if we are using the default constructor values - * or values that have been set explicitly. - * - * @return boolean - */ - function get_explicit() { - return $this->explicit; - } + /** + * @brief Get if we are using the default constructor values + * or values that have been set explicitly. + * + * @return bool + */ + public function get_explicit() + { + return $this->explicit; + } - /** - * @brief Set access list from strings such as those in already - * existing stored data items. - * - * @note The array to pass to this set function is different from the array - * that you provide to the constructor or set_from_array(). - * - * @param array $arr - * * \e string \b allow_cid => string of allowed cids - * * \e string \b allow_gid => string of allowed gids - * * \e string \b deny_cid => string of denied cids - * * \e string \b deny_gid => string of denied gids - * @param boolean $explicit (optional) default true - */ - function set($arr, $explicit = true) { - $this->allow_cid = $arr['allow_cid']; - $this->allow_gid = $arr['allow_gid']; - $this->deny_cid = $arr['deny_cid']; - $this->deny_gid = $arr['deny_gid']; + /** + * @brief Set access list from strings such as those in already + * existing stored data items. + * + * @note The array to pass to this set function is different from the array + * that you provide to the constructor or set_from_array(). + * + * @param array $arr + * * \e string \b allow_cid => string of allowed cids + * * \e string \b allow_gid => string of allowed gids + * * \e string \b deny_cid => string of denied cids + * * \e string \b deny_gid => string of denied gids + * @param bool $explicit (optional) default true + */ + public function set($arr, $explicit = true) + { + $this->allow_cid = $arr['allow_cid']; + $this->allow_gid = $arr['allow_gid']; + $this->deny_cid = $arr['deny_cid']; + $this->deny_gid = $arr['deny_gid']; - $this->explicit = $explicit; - } + $this->explicit = $explicit; + } - /** - * @brief Return an array consisting of the current access list components - * where the elements are directly storable. - * - * @return array An associative array with: - * * \e string \b allow_cid => string of allowed cids - * * \e string \b allow_gid => string of allowed gids - * * \e string \b deny_cid => string of denied cids - * * \e string \b deny_gid => string of denied gids - */ - function get() { - return [ - 'allow_cid' => $this->allow_cid, - 'allow_gid' => $this->allow_gid, - 'deny_cid' => $this->deny_cid, - 'deny_gid' => $this->deny_gid, - ]; - } + /** + * @brief Return an array consisting of the current access list components + * where the elements are directly storable. + * + * @return array An associative array with: + * * \e string \b allow_cid => string of allowed cids + * * \e string \b allow_gid => string of allowed gids + * * \e string \b deny_cid => string of denied cids + * * \e string \b deny_gid => string of denied gids + */ + public function get() + { + return [ + 'allow_cid' => $this->allow_cid, + 'allow_gid' => $this->allow_gid, + 'deny_cid' => $this->deny_cid, + 'deny_gid' => $this->deny_gid, + ]; + } - /** - * @brief Set access list components from arrays, such as those provided by - * acl_selector(). - * - * For convenience, a string (or non-array) input is assumed to be a - * comma-separated list and auto-converted into an array. - * - * @note The array to pass to this set function is different from the array - * that you provide to the constructor or set(). - * - * @param array $arr An associative array with: - * * \e array|string \b contact_allow => array with cids or comma-seperated string - * * \e array|string \b group_allow => array with gids or comma-seperated string - * * \e array|string \b contact_deny => array with cids or comma-seperated string - * * \e array|string \b group_deny => array with gids or comma-seperated string - * @param boolean $explicit (optional) default true - */ - function set_from_array($arr, $explicit = true) { - $this->allow_cid = perms2str((is_array($arr['contact_allow'])) - ? $arr['contact_allow'] : explode(',', $arr['contact_allow'])); - $this->allow_gid = perms2str((is_array($arr['group_allow'])) - ? $arr['group_allow'] : explode(',', $arr['group_allow'])); - $this->deny_cid = perms2str((is_array($arr['contact_deny'])) - ? $arr['contact_deny'] : explode(',', $arr['contact_deny'])); - $this->deny_gid = perms2str((is_array($arr['group_deny'])) - ? $arr['group_deny'] : explode(',', $arr['group_deny'])); + /** + * @brief Set access list components from arrays, such as those provided by + * acl_selector(). + * + * For convenience, a string (or non-array) input is assumed to be a + * comma-separated list and auto-converted into an array. + * + * @note The array to pass to this set function is different from the array + * that you provide to the constructor or set(). + * + * @param array $arr An associative array with: + * * \e array|string \b contact_allow => array with cids or comma-seperated string + * * \e array|string \b group_allow => array with gids or comma-seperated string + * * \e array|string \b contact_deny => array with cids or comma-seperated string + * * \e array|string \b group_deny => array with gids or comma-seperated string + * @param bool $explicit (optional) default true + */ + public function set_from_array($arr, $explicit = true) + { + $this->allow_cid = perms2str((is_array($arr['contact_allow'])) + ? $arr['contact_allow'] : explode(',', $arr['contact_allow'])); + $this->allow_gid = perms2str((is_array($arr['group_allow'])) + ? $arr['group_allow'] : explode(',', $arr['group_allow'])); + $this->deny_cid = perms2str((is_array($arr['contact_deny'])) + ? $arr['contact_deny'] : explode(',', $arr['contact_deny'])); + $this->deny_gid = perms2str((is_array($arr['group_deny'])) + ? $arr['group_deny'] : explode(',', $arr['group_deny'])); - $this->explicit = $explicit; - } - - /** - * @brief Returns true if any access lists component is set. - * - * @return boolean Return true if any of allow_* deny_* values is set. - */ - function is_private() { - return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false); - } + $this->explicit = $explicit; + } + /** + * @brief Returns true if any access lists component is set. + * + * @return bool Return true if any of allow_* deny_* values is set. + */ + public function is_private() + { + return (($this->allow_cid || $this->allow_gid || $this->deny_cid || $this->deny_gid) ? true : false); + } } diff --git a/Zotlabs/Access/PermissionLimits.php b/Zotlabs/Access/PermissionLimits.php index 608e62599..1ad259d95 100644 --- a/Zotlabs/Access/PermissionLimits.php +++ b/Zotlabs/Access/PermissionLimits.php @@ -26,78 +26,83 @@ use Zotlabs\Lib\PConfig; * * @see Permissions */ -class PermissionLimits { +class PermissionLimits +{ - /** - * @brief Get standard permission limits. - * - * Viewing permissions and post_comments permission are set to 'anybody', - * other permissions are set to 'those I allow'. - * - * The list of permissions comes from Permissions::Perms(). - * - * @return array - */ - static public function Std_Limits() { - $limits = []; - $perms = Permissions::Perms(); + /** + * @brief Get standard permission limits. + * + * Viewing permissions and post_comments permission are set to 'anybody', + * other permissions are set to 'those I allow'. + * + * The list of permissions comes from Permissions::Perms(). + * + * @return array + */ + public static function Std_Limits() + { + $limits = []; + $perms = Permissions::Perms(); - foreach($perms as $k => $v) { - if(strstr($k, 'view')) - $limits[$k] = PERMS_PUBLIC; - else - $limits[$k] = PERMS_SPECIFIC; - } + foreach ($perms as $k => $v) { + if (strstr($k, 'view')) { + $limits[$k] = PERMS_PUBLIC; + } else { + $limits[$k] = PERMS_SPECIFIC; + } + } - return $limits; - } + return $limits; + } - /** - * @brief Sets a permission limit for a channel. - * - * @param int $channel_id - * @param string $perm - * @param int $perm_limit one of PERMS_* constants - */ - static public function Set($channel_id, $perm, $perm_limit) { - PConfig::Set($channel_id, 'perm_limits', $perm, $perm_limit); - } + /** + * @brief Sets a permission limit for a channel. + * + * @param int $channel_id + * @param string $perm + * @param int $perm_limit one of PERMS_* constants + */ + public static function Set($channel_id, $perm, $perm_limit) + { + PConfig::Set($channel_id, 'perm_limits', $perm, $perm_limit); + } - /** - * @brief Get a channel's permission limits. - * - * Return a channel's permission limits from PConfig. If $perm is set just - * return this permission limit, if not set, return an array with all - * permission limits. - * - * @param int $channel_id - * @param string $perm (optional) - * @return - * * \b false if no perm_limits set for this channel - * * \b int if $perm is set, return one of PERMS_* constants for this permission, default 0 - * * \b array with all permission limits, if $perm is not set - */ - static public function Get($channel_id, $perm = '') { + /** + * @brief Get a channel's permission limits. + * + * Return a channel's permission limits from PConfig. If $perm is set just + * return this permission limit, if not set, return an array with all + * permission limits. + * + * @param int $channel_id + * @param string $perm (optional) + * @return + * * \b false if no perm_limits set for this channel + * * \b int if $perm is set, return one of PERMS_* constants for this permission, default 0 + * * \b array with all permission limits, if $perm is not set + */ + public static function Get($channel_id, $perm = '') + { - if (! intval($channel_id)) { - return false; - } - - if($perm) { - $x = PConfig::Get($channel_id, 'perm_limits', $perm); - if($x === false) { - $a = [ 'channel_id' => $channel_id, 'permission' => $perm, 'value' => $x ]; - call_hooks('permission_limits_get',$a); - return intval($a['value']); - } - return intval($x); - } + if (! intval($channel_id)) { + return false; + } + + if ($perm) { + $x = PConfig::Get($channel_id, 'perm_limits', $perm); + if ($x === false) { + $a = [ 'channel_id' => $channel_id, 'permission' => $perm, 'value' => $x ]; + call_hooks('permission_limits_get', $a); + return intval($a['value']); + } + return intval($x); + } - PConfig::Load($channel_id); - if(array_key_exists($channel_id, App::$config) && array_key_exists('perm_limits', App::$config[$channel_id])) { - return App::$config[$channel_id]['perm_limits']; - } + PConfig::Load($channel_id); + if (array_key_exists($channel_id, App::$config) && array_key_exists('perm_limits', App::$config[$channel_id])) { + return App::$config[$channel_id]['perm_limits']; + } - return false; - } -} \ No newline at end of file + return false; + } +} diff --git a/Zotlabs/Access/PermissionRoles.php b/Zotlabs/Access/PermissionRoles.php index ab386b442..bd7e1980d 100644 --- a/Zotlabs/Access/PermissionRoles.php +++ b/Zotlabs/Access/PermissionRoles.php @@ -7,193 +7,197 @@ namespace Zotlabs\Access; * * @see Permissions */ -class PermissionRoles { +class PermissionRoles +{ - /** - * @brief PermissionRoles version. - * - * This must match the version in Permissions.php before permission updates can run. - * - * @return number - */ - static public function version() { - return 3; - } + /** + * @brief PermissionRoles version. + * + * This must match the version in Permissions.php before permission updates can run. + * + * @return number + */ + public static function version() + { + return 3; + } - static function role_perms($role) { + public static function role_perms($role) + { - $ret = []; + $ret = []; - $ret['role'] = $role; + $ret['role'] = $role; - switch($role) { - case 'social': - $ret['perms_auto'] = false; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = true; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); - break; + switch ($role) { + case 'social': + $ret['perms_auto'] = false; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = true; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', + 'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + break; - case 'social_restricted': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_storage', - 'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); - $ret['limits']['view_contacts'] = PERMS_SPECIFIC; - break; + case 'social_restricted': + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_storage', + 'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['limits']['view_contacts'] = PERMS_SPECIFIC; + break; - case 'forum': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage', - 'view_pages', 'post_mail', 'post_wall', 'post_comments' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); - $ret['channel_type'] = 'group'; - - break; + case 'forum': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage', + 'view_pages', 'post_mail', 'post_wall', 'post_comments' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['channel_type'] = 'group'; + + break; - case 'forum_moderated': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'post_mail', 'post_wall', 'post_comments', 'moderated' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); - $ret['channel_type'] = 'group'; - - break; + case 'forum_moderated': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', + 'view_pages', 'post_mail', 'post_wall', 'post_comments', 'moderated' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['channel_type'] = 'group'; - case 'forum_restricted': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage', - 'view_pages', 'post_mail', 'post_wall', 'post_comments' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); - $ret['limits']['view_contacts'] = PERMS_SPECIFIC; - $ret['channel_type'] = 'group'; - break; + break; - case 'collection': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'post_mail', 'post_comments' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); - $ret['channel_type'] = 'collection'; - - break; + case 'forum_restricted': + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', 'write_storage', + 'view_pages', 'post_mail', 'post_wall', 'post_comments' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['limits']['view_contacts'] = PERMS_SPECIFIC; + $ret['channel_type'] = 'group'; + break; - case 'collection_restricted': - $ret['perms_auto'] = false; - $ret['default_collection'] = true; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_storage', - 'view_pages', 'post_mail', 'post_comments' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); - $ret['limits']['view_contacts'] = PERMS_SPECIFIC; - $ret['channel_type'] = 'collection'; - break; + case 'collection': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', + 'view_pages', 'post_mail', 'post_comments' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['channel_type'] = 'collection'; - case 'feed': - $ret['perms_auto'] = true; - $ret['default_collection'] = false; - $ret['directory_publish'] = true; - $ret['online'] = false; - $ret['perms_connect'] = [ - 'view_stream', 'view_profile', 'view_contacts', 'view_storage', - 'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments', - 'republish' - ]; - $ret['limits'] = PermissionLimits::Std_Limits(); + break; - break; + case 'collection_restricted': + $ret['perms_auto'] = false; + $ret['default_collection'] = true; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_storage', + 'view_pages', 'post_mail', 'post_comments' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); + $ret['limits']['view_contacts'] = PERMS_SPECIFIC; + $ret['channel_type'] = 'collection'; + break; - case 'repository': - // Legacy settings to cover all channel_types previously in Libzot.php - $ret['channel_type'] = 'group'; + case 'feed': + $ret['perms_auto'] = true; + $ret['default_collection'] = false; + $ret['directory_publish'] = true; + $ret['online'] = false; + $ret['perms_connect'] = [ + 'view_stream', 'view_profile', 'view_contacts', 'view_storage', + 'view_pages', 'send_stream', 'post_mail', 'post_wall', 'post_comments', + 'republish' + ]; + $ret['limits'] = PermissionLimits::Std_Limits(); - default: - break; - } + break; + + case 'repository': + // Legacy settings to cover all channel_types previously in Libzot.php + $ret['channel_type'] = 'group'; + + default: + break; + } - $x = get_config('system','role_perms'); - // let system settings over-ride any or all - if($x && is_array($x) && array_key_exists($role,$x)) - $ret = array_merge($ret,$x[$role]); + $x = get_config('system', 'role_perms'); + // let system settings over-ride any or all + if ($x && is_array($x) && array_key_exists($role, $x)) { + $ret = array_merge($ret, $x[$role]); + } - /** - * @hooks get_role_perms - * * \e array - */ - $x = [ 'role' => $role, 'result' => $ret ]; + /** + * @hooks get_role_perms + * * \e array + */ + $x = ['role' => $role, 'result' => $ret]; - call_hooks('get_role_perms', $x); + call_hooks('get_role_perms', $x); - return $x['result']; - } + return $x['result']; + } - /** - * @brief Array with translated role names and grouping. - * - * Return an associative array with grouped role names that can be used - * to create select groups like in \e field_select_grouped.tpl. - * - * @return array - */ - static public function roles() { - $roles = [ - t('Social Networking') => [ - 'social' => t('Social - Normal'), - 'social_restricted' => t('Social - Restricted') - ], + /** + * @brief Array with translated role names and grouping. + * + * Return an associative array with grouped role names that can be used + * to create select groups like in \e field_select_grouped.tpl. + * + * @return array + */ + public static function roles() + { + $roles = [ + t('Social Networking') => [ + 'social' => t('Social - Normal'), + 'social_restricted' => t('Social - Restricted') + ], - t('Community Group') => [ - 'forum' => t('Group - Normal'), - 'forum_restricted' => t('Group - Restricted'), - 'forum_moderated' => t('Group - Moderated') - ], + t('Community Group') => [ + 'forum' => t('Group - Normal'), + 'forum_restricted' => t('Group - Restricted'), + 'forum_moderated' => t('Group - Moderated') + ], - t('Collection') => [ - 'collection' => t('Collection - Normal'), - 'collection_restricted' => t('Collection - Restricted') - ] + t('Collection') => [ + 'collection' => t('Collection - Normal'), + 'collection_restricted' => t('Collection - Restricted') + ] - ]; + ]; - call_hooks('list_permission_roles',$roles); - - return $roles; - } + call_hooks('list_permission_roles', $roles); + return $roles; + } } diff --git a/Zotlabs/Access/Permissions.php b/Zotlabs/Access/Permissions.php index bb4ff3d53..cf8eddb2e 100644 --- a/Zotlabs/Access/Permissions.php +++ b/Zotlabs/Access/Permissions.php @@ -31,252 +31,266 @@ use Zotlabs\Lib as Zlib; * something different for a specific permission within the given role. * */ -class Permissions { +class Permissions +{ - /** - * @brief Permissions version. - * - * This must match the version in PermissionRoles.php before permission updates can run. - * - * @return number - */ - static public function version() { - return 3; - } + /** + * @brief Permissions version. + * + * This must match the version in PermissionRoles.php before permission updates can run. + * + * @return number + */ + public static function version() + { + return 3; + } - /** - * @brief Return an array with Permissions. - * - * @param string $filter (optional) only passed to hook permissions_list - * @return array Associative array with permissions and short description. - */ - static public function Perms($filter = '') { + /** + * @brief Return an array with Permissions. + * + * @param string $filter (optional) only passed to hook permissions_list + * @return array Associative array with permissions and short description. + */ + public static function Perms($filter = '') + { - $perms = [ - 'view_stream' => t('Grant viewing access to and delivery of your channel stream and posts'), - 'view_profile' => t('Grant viewing access to your default channel profile'), - 'view_contacts' => t('Grant viewing access to your address book (connections)'), - 'view_storage' => t('Grant viewing access to your file storage and photos'), - 'post_wall' => t('Grant permission to post on your channel (wall) page'), - 'post_mail' => t('Accept delivery of direct messages and personal mail'), - 'send_stream' => t('Accept delivery of their posts and all comments to their posts'), - 'post_comments' => t('Accept delivery of their comments and likes on your posts'), - 'write_storage' => t('Grant upload permissions to your file storage and photos'), - 'republish' => t('Grant permission to republish/mirror your posts'), - 'moderated' => t('Accept comments and wall posts only after approval (moderation)'), - 'delegate' => t('Grant channel administration (delegation) permission') - ]; + $perms = [ + 'view_stream' => t('Grant viewing access to and delivery of your channel stream and posts'), + 'view_profile' => t('Grant viewing access to your default channel profile'), + 'view_contacts' => t('Grant viewing access to your address book (connections)'), + 'view_storage' => t('Grant viewing access to your file storage and photos'), + 'post_wall' => t('Grant permission to post on your channel (wall) page'), + 'post_mail' => t('Accept delivery of direct messages and personal mail'), + 'send_stream' => t('Accept delivery of their posts and all comments to their posts'), + 'post_comments' => t('Accept delivery of their comments and likes on your posts'), + 'write_storage' => t('Grant upload permissions to your file storage and photos'), + 'republish' => t('Grant permission to republish/mirror your posts'), + 'moderated' => t('Accept comments and wall posts only after approval (moderation)'), + 'delegate' => t('Grant channel administration (delegation) permission') + ]; - $x = [ - 'permissions' => $perms, - 'filter' => $filter - ]; - /** - * @hooks permissions_list - * * \e array \b permissions - * * \e string \b filter - */ - call_hooks('permissions_list', $x); + $x = [ + 'permissions' => $perms, + 'filter' => $filter + ]; + /** + * @hooks permissions_list + * * \e array \b permissions + * * \e string \b filter + */ + call_hooks('permissions_list', $x); - return($x['permissions']); - } + return($x['permissions']); + } - /** - * @brief Perms from the above list that are blocked from anonymous observers. - * - * e.g. you must be authenticated. - * - * @return array Associative array with permissions and short description. - */ - static public function BlockedAnonPerms() { + /** + * @brief Perms from the above list that are blocked from anonymous observers. + * + * e.g. you must be authenticated. + * + * @return array Associative array with permissions and short description. + */ + public static function BlockedAnonPerms() + { - $res = []; - $perms = PermissionLimits::Std_limits(); - foreach($perms as $perm => $limit) { - if($limit != PERMS_PUBLIC) { - $res[] = $perm; - } - } + $res = []; + $perms = PermissionLimits::Std_limits(); + foreach ($perms as $perm => $limit) { + if ($limit != PERMS_PUBLIC) { + $res[] = $perm; + } + } - $x = ['permissions' => $res]; - /** - * @hooks write_perms - * * \e array \b permissions - */ - call_hooks('write_perms', $x); + $x = ['permissions' => $res]; + /** + * @hooks write_perms + * * \e array \b permissions + */ + call_hooks('write_perms', $x); - return($x['permissions']); - } + return($x['permissions']); + } - /** - * @brief Converts indexed perms array to associative perms array. - * - * Converts [ 0 => 'view_stream', ... ] - * to [ 'view_stream' => 1 ] for any permissions in $arr; - * Undeclared permissions which exist in Perms() are added and set to 0. - * - * @param array $arr - * @return array - */ - static public function FilledPerms($arr) { - if(is_null($arr) || (! is_array($arr))) { - btlogger('FilledPerms: ' . print_r($arr,true)); - $arr = []; - } + /** + * @brief Converts indexed perms array to associative perms array. + * + * Converts [ 0 => 'view_stream', ... ] + * to [ 'view_stream' => 1 ] for any permissions in $arr; + * Undeclared permissions which exist in Perms() are added and set to 0. + * + * @param array $arr + * @return array + */ + public static function FilledPerms($arr) + { + if (is_null($arr) || (! is_array($arr))) { + btlogger('FilledPerms: ' . print_r($arr, true)); + $arr = []; + } - $everything = self::Perms(); - $ret = []; - foreach($everything as $k => $v) { - if(in_array($k, $arr)) - $ret[$k] = 1; - else - $ret[$k] = 0; - } + $everything = self::Perms(); + $ret = []; + foreach ($everything as $k => $v) { + if (in_array($k, $arr)) { + $ret[$k] = 1; + } else { + $ret[$k] = 0; + } + } - return $ret; - } + return $ret; + } - /** - * @brief Convert perms array to indexed array. - * - * Converts [ 'view_stream' => 1 ] for any permissions in $arr - * to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ] - * - * @param array $arr associative perms array 'view_stream' => 1 - * @return array Indexed array with elements that look like - * * \e string \b name the perm name (e.g. view_stream) - * * \e int \b value the value of the perm (e.g. 1) - */ - static public function OPerms($arr) { - $ret = []; - if($arr) { - foreach($arr as $k => $v) { - $ret[] = [ 'name' => $k, 'value' => $v ]; - } - } - return $ret; - } + /** + * @brief Convert perms array to indexed array. + * + * Converts [ 'view_stream' => 1 ] for any permissions in $arr + * to [ 0 => ['name' => 'view_stream', 'value' => 1], ... ] + * + * @param array $arr associative perms array 'view_stream' => 1 + * @return array Indexed array with elements that look like + * * \e string \b name the perm name (e.g. view_stream) + * * \e int \b value the value of the perm (e.g. 1) + */ + public static function OPerms($arr) + { + $ret = []; + if ($arr) { + foreach ($arr as $k => $v) { + $ret[] = [ 'name' => $k, 'value' => $v ]; + } + } + return $ret; + } - /** - * @brief - * - * @param int $channel_id - * @return boolean|array - */ - static public function FilledAutoperms($channel_id) { - if(! intval(get_pconfig($channel_id,'system','autoperms'))) - return false; + /** + * @brief + * + * @param int $channel_id + * @return bool|array + */ + public static function FilledAutoperms($channel_id) + { + if (! intval(get_pconfig($channel_id, 'system', 'autoperms'))) { + return false; + } - $arr = []; - $r = q("select * from pconfig where uid = %d and cat = 'autoperms'", - intval($channel_id) - ); - if($r) { - foreach($r as $rr) { - $arr[$rr['k']] = intval($rr['v']); - } - } - return $arr; - } + $arr = []; + $r = q( + "select * from pconfig where uid = %d and cat = 'autoperms'", + intval($channel_id) + ); + if ($r) { + foreach ($r as $rr) { + $arr[$rr['k']] = intval($rr['v']); + } + } + return $arr; + } - /** - * @brief Compares that all Permissions from $p1 exist also in $p2. - * - * @param array $p1 The perms that have to exist in $p2 - * @param array $p2 The perms to compare against - * @return boolean true if all perms from $p1 exist also in $p2 - */ - static public function PermsCompare($p1, $p2) { - foreach($p1 as $k => $v) { - if(! array_key_exists($k, $p2)) - return false; + /** + * @brief Compares that all Permissions from $p1 exist also in $p2. + * + * @param array $p1 The perms that have to exist in $p2 + * @param array $p2 The perms to compare against + * @return bool true if all perms from $p1 exist also in $p2 + */ + public static function PermsCompare($p1, $p2) + { + foreach ($p1 as $k => $v) { + if (! array_key_exists($k, $p2)) { + return false; + } - if($p1[$k] != $p2[$k]) - return false; - } + if ($p1[$k] != $p2[$k]) { + return false; + } + } - return true; - } + return true; + } - /** - * @brief - * - * @param int $channel_id A channel id - * @return array Associative array with - * * \e array \b perms Permission array - * * \e int \b automatic 0 or 1 - */ - static public function connect_perms($channel_id) { + /** + * @brief + * + * @param int $channel_id A channel id + * @return array Associative array with + * * \e array \b perms Permission array + * * \e int \b automatic 0 or 1 + */ + public static function connect_perms($channel_id) + { - $my_perms = []; - $permcat = null; - $automatic = 0; + $my_perms = []; + $permcat = null; + $automatic = 0; - // If a default permcat exists, use that + // If a default permcat exists, use that - $pc = ((feature_enabled($channel_id,'permcats')) ? get_pconfig($channel_id,'system','default_permcat') : 'default'); - if(! in_array($pc, [ '','default' ])) { - $pcp = new Zlib\Permcat($channel_id); - $permcat = $pcp->fetch($pc); - if($permcat && $permcat['perms']) { - foreach($permcat['perms'] as $p) { - $my_perms[$p['name']] = $p['value']; - } - } - } + $pc = ((feature_enabled($channel_id, 'permcats')) ? get_pconfig($channel_id, 'system', 'default_permcat') : 'default'); + if (! in_array($pc, [ '','default' ])) { + $pcp = new Zlib\Permcat($channel_id); + $permcat = $pcp->fetch($pc); + if ($permcat && $permcat['perms']) { + foreach ($permcat['perms'] as $p) { + $my_perms[$p['name']] = $p['value']; + } + } + } - $automatic = intval(get_pconfig($channel_id,'system','autoperms')); + $automatic = intval(get_pconfig($channel_id, 'system', 'autoperms')); - // look up the permission role to see if it specified auto-connect - // and if there was no permcat or a default permcat, set the perms - // from the role + // look up the permission role to see if it specified auto-connect + // and if there was no permcat or a default permcat, set the perms + // from the role - $role = get_pconfig($channel_id,'system','permissions_role'); - if($role) { - $xx = PermissionRoles::role_perms($role); + $role = get_pconfig($channel_id, 'system', 'permissions_role'); + if ($role) { + $xx = PermissionRoles::role_perms($role); - if((! $my_perms) && ($xx['perms_connect'])) { - $default_perms = $xx['perms_connect']; - $my_perms = Permissions::FilledPerms($default_perms); - } - } + if ((! $my_perms) && ($xx['perms_connect'])) { + $default_perms = $xx['perms_connect']; + $my_perms = Permissions::FilledPerms($default_perms); + } + } - // If we reached this point without having any permission information, - // it is likely a custom permissions role. First see if there are any - // automatic permissions. + // If we reached this point without having any permission information, + // it is likely a custom permissions role. First see if there are any + // automatic permissions. - if(! $my_perms) { - $m = Permissions::FilledAutoperms($channel_id); - if($m) { - $my_perms = $m; - } - } + if (! $my_perms) { + $m = Permissions::FilledAutoperms($channel_id); + if ($m) { + $my_perms = $m; + } + } - // If we reached this point with no permissions, the channel is using - // custom perms but they are not automatic. They will be stored in abconfig with - // the channel's channel_hash (the 'self' connection). + // If we reached this point with no permissions, the channel is using + // custom perms but they are not automatic. They will be stored in abconfig with + // the channel's channel_hash (the 'self' connection). - if(! $my_perms) { - $c = channelx_by_n($channel_id); - if($c) { - $my_perms = Permissions::FilledPerms(explode(',',get_abconfig($channel_id,$c['channel_hash'],'system','my_perms',EMPTY_STR))); - } - } + if (! $my_perms) { + $c = channelx_by_n($channel_id); + if ($c) { + $my_perms = Permissions::FilledPerms(explode(',', get_abconfig($channel_id, $c['channel_hash'], 'system', 'my_perms', EMPTY_STR))); + } + } - return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] ); - } + return ( [ 'perms' => $my_perms, 'automatic' => $automatic ] ); + } - static public function serialise($p) { - $n = []; - if($p) { - foreach($p as $k => $v) { - if(intval($v)) { - $n[] = $k; - } - } - } - return implode(',',$n); - } - + public static function serialise($p) + { + $n = []; + if ($p) { + foreach ($p as $k => $v) { + if (intval($v)) { + $n[] = $k; + } + } + } + return implode(',', $n); + } } diff --git a/Zotlabs/Daemon/Addon.php b/Zotlabs/Daemon/Addon.php index 76b9bcbb4..50afea23b 100644 --- a/Zotlabs/Daemon/Addon.php +++ b/Zotlabs/Daemon/Addon.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Addon { - static public function run($argc,$argv) { + public static function run($argc, $argv) { call_hooks('daemon_addon',$argv); diff --git a/Zotlabs/Daemon/CacheThumb.php b/Zotlabs/Daemon/CacheThumb.php index 3508590cb..75f17b707 100644 --- a/Zotlabs/Daemon/CacheThumb.php +++ b/Zotlabs/Daemon/CacheThumb.php @@ -6,7 +6,7 @@ require_once('include/photos.php'); class CacheThumb { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if (! $argc == 2) { return; diff --git a/Zotlabs/Daemon/Cache_embeds.php b/Zotlabs/Daemon/Cache_embeds.php index 8dd6d5c9c..353fd048a 100644 --- a/Zotlabs/Daemon/Cache_embeds.php +++ b/Zotlabs/Daemon/Cache_embeds.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Cache_embeds { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if (! $argc == 2) { return; diff --git a/Zotlabs/Daemon/Cache_image.php b/Zotlabs/Daemon/Cache_image.php index b5256f75a..e960cf09e 100644 --- a/Zotlabs/Daemon/Cache_image.php +++ b/Zotlabs/Daemon/Cache_image.php @@ -6,7 +6,7 @@ use Zotlabs\Lib\Img_cache; class Cache_image { - static public function run($argc,$argv) { + public static function run($argc, $argv) { cli_startup(); logger('caching: ' . $argv[1] . ' to ' . $argv[2]); diff --git a/Zotlabs/Daemon/Channel_purge.php b/Zotlabs/Daemon/Channel_purge.php index b02045cd2..0c68c8f86 100644 --- a/Zotlabs/Daemon/Channel_purge.php +++ b/Zotlabs/Daemon/Channel_purge.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Channel_purge { - static public function run($argc,$argv) { + public static function run($argc, $argv) { cli_startup(); diff --git a/Zotlabs/Daemon/Checksites.php b/Zotlabs/Daemon/Checksites.php index 1c05450b9..1cb2c48ad 100644 --- a/Zotlabs/Daemon/Checksites.php +++ b/Zotlabs/Daemon/Checksites.php @@ -7,7 +7,7 @@ require_once('include/hubloc.php'); class Checksites { - static public function run($argc,$argv) { + public static function run($argc, $argv) { logger('checksites: start'); diff --git a/Zotlabs/Daemon/Content_importer.php b/Zotlabs/Daemon/Content_importer.php index adc180a2c..08588b26c 100644 --- a/Zotlabs/Daemon/Content_importer.php +++ b/Zotlabs/Daemon/Content_importer.php @@ -10,7 +10,7 @@ require_once('include/import.php'); class Content_importer { - static public function run($argc,$argv) { + public static function run($argc, $argv) { cli_startup(); $page = $argv[1]; diff --git a/Zotlabs/Daemon/Convo.php b/Zotlabs/Daemon/Convo.php index 482f70c53..b44de178a 100644 --- a/Zotlabs/Daemon/Convo.php +++ b/Zotlabs/Daemon/Convo.php @@ -8,7 +8,7 @@ use Zotlabs\Lib\ASCollection; class Convo { - static public function run($argc,$argv) { + public static function run($argc, $argv) { logger('convo invoked: ' . print_r($argv,true)); diff --git a/Zotlabs/Daemon/Cron.php b/Zotlabs/Daemon/Cron.php index bb1bf2dee..6d6344cc0 100644 --- a/Zotlabs/Daemon/Cron.php +++ b/Zotlabs/Daemon/Cron.php @@ -6,7 +6,7 @@ use Zotlabs\Lib\Libsync; class Cron { - static public function run($argc,$argv) { + public static function run($argc, $argv) { $maxsysload = intval(get_config('system','maxloadavg')); if($maxsysload < 1) diff --git a/Zotlabs/Daemon/Cron_daily.php b/Zotlabs/Daemon/Cron_daily.php index 8d33b9fc9..65c8a6d3d 100644 --- a/Zotlabs/Daemon/Cron_daily.php +++ b/Zotlabs/Daemon/Cron_daily.php @@ -6,7 +6,7 @@ use Zotlabs\Lib\Libzot; class Cron_daily { - static public function run($argc,$argv) { + public static function run($argc, $argv) { logger('cron_daily: start'); diff --git a/Zotlabs/Daemon/Cron_weekly.php b/Zotlabs/Daemon/Cron_weekly.php index 56ef61730..b3f88c4ee 100644 --- a/Zotlabs/Daemon/Cron_weekly.php +++ b/Zotlabs/Daemon/Cron_weekly.php @@ -4,7 +4,7 @@ namespace Zotlabs\Daemon; class Cron_weekly { - static public function run($argc,$argv) { + public static function run($argc, $argv) { /** * Cron Weekly diff --git a/Zotlabs/Daemon/Cronhooks.php b/Zotlabs/Daemon/Cronhooks.php index df0a5442e..b0fc4ef38 100644 --- a/Zotlabs/Daemon/Cronhooks.php +++ b/Zotlabs/Daemon/Cronhooks.php @@ -4,7 +4,7 @@ namespace Zotlabs\Daemon; class Cronhooks { - static public function run($argc,$argv){ + public static function run($argc, $argv){ logger('cronhooks: start'); diff --git a/Zotlabs/Daemon/CurlAuth.php b/Zotlabs/Daemon/CurlAuth.php index 9c9bbbbc8..0a1fe188a 100644 --- a/Zotlabs/Daemon/CurlAuth.php +++ b/Zotlabs/Daemon/CurlAuth.php @@ -12,7 +12,7 @@ use App; class CurlAuth { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if($argc != 2) return; diff --git a/Zotlabs/Daemon/Deliver.php b/Zotlabs/Daemon/Deliver.php index 3844f0b4e..3a0833562 100644 --- a/Zotlabs/Daemon/Deliver.php +++ b/Zotlabs/Daemon/Deliver.php @@ -8,7 +8,7 @@ use Zotlabs\Lib\Queue; class Deliver { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if($argc < 2) return; diff --git a/Zotlabs/Daemon/Deliver_hooks.php b/Zotlabs/Daemon/Deliver_hooks.php index 649ec3f4b..ec14b7b7d 100644 --- a/Zotlabs/Daemon/Deliver_hooks.php +++ b/Zotlabs/Daemon/Deliver_hooks.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Deliver_hooks { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if($argc < 2) return; diff --git a/Zotlabs/Daemon/Delxitems.php b/Zotlabs/Daemon/Delxitems.php index db4dd392d..b8fca820e 100644 --- a/Zotlabs/Daemon/Delxitems.php +++ b/Zotlabs/Daemon/Delxitems.php @@ -8,7 +8,7 @@ namespace Zotlabs\Daemon; class Delxitems { - static public function run($argc,$argv) { + public static function run($argc, $argv) { cli_startup(); diff --git a/Zotlabs/Daemon/Directory.php b/Zotlabs/Daemon/Directory.php index 7816649f3..fa40da9a8 100644 --- a/Zotlabs/Daemon/Directory.php +++ b/Zotlabs/Daemon/Directory.php @@ -11,7 +11,7 @@ use Zotlabs\Lib\Queue; class Directory { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if ($argc < 2) { return; diff --git a/Zotlabs/Daemon/Expire.php b/Zotlabs/Daemon/Expire.php index fee1e021d..e48b4922a 100644 --- a/Zotlabs/Daemon/Expire.php +++ b/Zotlabs/Daemon/Expire.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Expire { - static public function run($argc,$argv){ + public static function run($argc, $argv){ cli_startup(); diff --git a/Zotlabs/Daemon/File_importer.php b/Zotlabs/Daemon/File_importer.php index f3fe785bb..60cc57abc 100644 --- a/Zotlabs/Daemon/File_importer.php +++ b/Zotlabs/Daemon/File_importer.php @@ -10,7 +10,7 @@ require_once('include/import.php'); class File_importer { - static public function run($argc,$argv) { + public static function run($argc, $argv) { cli_startup(); diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php index 450962d6b..d5415265b 100644 --- a/Zotlabs/Daemon/Gprobe.php +++ b/Zotlabs/Daemon/Gprobe.php @@ -10,7 +10,7 @@ use Zotlabs\Lib\Zotfinger; class Gprobe { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if ($argc != 2) { diff --git a/Zotlabs/Daemon/Importdoc.php b/Zotlabs/Daemon/Importdoc.php index fcafbbdb8..a1427cb84 100755 --- a/Zotlabs/Daemon/Importdoc.php +++ b/Zotlabs/Daemon/Importdoc.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Importdoc { - static public function run($argc,$argv) { + public static function run($argc, $argv) { require_once('include/help.php'); @@ -13,7 +13,7 @@ class Importdoc { } - static public function update_docs_dir($s) { + public static function update_docs_dir($s) { $f = basename($s); $d = dirname($s); if($s === 'doc/html') diff --git a/Zotlabs/Daemon/Importfile.php b/Zotlabs/Daemon/Importfile.php index 749949679..86180fd4a 100644 --- a/Zotlabs/Daemon/Importfile.php +++ b/Zotlabs/Daemon/Importfile.php @@ -6,7 +6,7 @@ use Zotlabs\Lib\Libsync; class Importfile { - static public function run($argc,$argv){ + public static function run($argc, $argv){ logger('Importfile: ' . print_r($argv,true)); diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php index 18630ac05..d9b43189e 100644 --- a/Zotlabs/Daemon/Notifier.php +++ b/Zotlabs/Daemon/Notifier.php @@ -78,16 +78,16 @@ require_once('include/bbcode.php'); class Notifier { - static public $deliveries = []; - static public $recipients = []; - static public $env_recips = []; - static public $packet_type = 'activity'; - static public $encoding = 'activitystreams'; - static public $encoded_item = null; - static public $channel = null; - static public $private = false; + public static $deliveries = []; + public static $recipients = []; + public static $env_recips = []; + public static $packet_type = 'activity'; + public static $encoding = 'activitystreams'; + public static $encoded_item = null; + public static $channel = null; + public static $private = false; - static public function run($argc,$argv) { + public static function run($argc, $argv) { if ($argc < 3) { return; diff --git a/Zotlabs/Daemon/Onedirsync.php b/Zotlabs/Daemon/Onedirsync.php index 29e49993b..bc2e7c4b0 100644 --- a/Zotlabs/Daemon/Onedirsync.php +++ b/Zotlabs/Daemon/Onedirsync.php @@ -7,7 +7,7 @@ use Zotlabs\Lib\Libzotdir; class Onedirsync { - static public function run($argc,$argv) { + public static function run($argc, $argv) { logger('onedirsync: start ' . intval($argv[1])); diff --git a/Zotlabs/Daemon/Onepoll.php b/Zotlabs/Daemon/Onepoll.php index 43d624250..6c1372643 100644 --- a/Zotlabs/Daemon/Onepoll.php +++ b/Zotlabs/Daemon/Onepoll.php @@ -13,7 +13,7 @@ require_once('include/socgraph.php'); class Onepoll { - static public function run($argc,$argv) { + public static function run($argc, $argv) { logger('onepoll: start'); diff --git a/Zotlabs/Daemon/Poller.php b/Zotlabs/Daemon/Poller.php index 71ee1122c..ace58b35b 100644 --- a/Zotlabs/Daemon/Poller.php +++ b/Zotlabs/Daemon/Poller.php @@ -4,7 +4,7 @@ namespace Zotlabs\Daemon; class Poller { - static public function run($argc,$argv) { + public static function run($argc, $argv) { $maxsysload = intval(get_config('system','maxloadavg')); if($maxsysload < 1) diff --git a/Zotlabs/Daemon/Queue.php b/Zotlabs/Daemon/Queue.php index 491fc7c3d..7e3c50882 100644 --- a/Zotlabs/Daemon/Queue.php +++ b/Zotlabs/Daemon/Queue.php @@ -7,7 +7,7 @@ use Zotlabs\Lib as Zlib; class Queue { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if($argc > 1) $queue_id = $argv[1]; diff --git a/Zotlabs/Daemon/Run.php b/Zotlabs/Daemon/Run.php index 8f573e457..5b63d845b 100644 --- a/Zotlabs/Daemon/Run.php +++ b/Zotlabs/Daemon/Run.php @@ -27,7 +27,7 @@ class Run { 'Cron', 'Cron_daily', 'Cron_weekly', 'Delxitems', 'Expire', 'File_importer', 'Importfile' ]; - static public function Summon($arr) { + public static function Summon($arr) { if (file_exists('maintenance_lock') || file_exists('cache/maintenance_lock')) { return; } @@ -50,7 +50,7 @@ class Run { proc_run('php','Zotlabs/Daemon/Run.php',$arr); } - static public function Release($argc,$argv) { + public static function Release($argc, $argv) { cli_startup(); $hookinfo = [ diff --git a/Zotlabs/Daemon/Thumbnail.php b/Zotlabs/Daemon/Thumbnail.php index 793ed088f..75a9cea92 100644 --- a/Zotlabs/Daemon/Thumbnail.php +++ b/Zotlabs/Daemon/Thumbnail.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Thumbnail { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if (! ($argc == 2)) { return; diff --git a/Zotlabs/Daemon/Xchan_photo.php b/Zotlabs/Daemon/Xchan_photo.php index 8263b4126..8a2b71b6c 100644 --- a/Zotlabs/Daemon/Xchan_photo.php +++ b/Zotlabs/Daemon/Xchan_photo.php @@ -5,7 +5,7 @@ namespace Zotlabs\Daemon; class Xchan_photo { - static public function run($argc,$argv) { + public static function run($argc, $argv) { if ($argc != 3) { return; diff --git a/Zotlabs/Extend/Hook.php b/Zotlabs/Extend/Hook.php index 51c3f68cb..2bf5cccb1 100644 --- a/Zotlabs/Extend/Hook.php +++ b/Zotlabs/Extend/Hook.php @@ -10,7 +10,7 @@ use App; */ class Hook { - static public function register($hook,$file,$function,$version = 1,$priority = 0) { + public static function register($hook, $file, $function, $version = 1, $priority = 0) { if (is_array($function)) { $function = serialize($function); } @@ -46,7 +46,7 @@ class Hook { return $r; } - static public function register_array($file,$arr) { + public static function register_array($file, $arr) { if ($arr) { foreach ($arr as $k => $v) { self::register($k,$file,$v); @@ -55,7 +55,7 @@ class Hook { } - static public function unregister($hook,$file,$function,$version = 1,$priority = 0) { + public static function unregister($hook, $file, $function, $version = 1, $priority = 0) { if (is_array($function)) { $function = serialize($function); } @@ -78,7 +78,7 @@ class Hook { * @param string $file */ - static public function unregister_by_file($file) { + public static function unregister_by_file($file) { $r = q("DELETE FROM hook WHERE file = '%s' ", dbesc($file) ); @@ -107,7 +107,7 @@ class Hook { * @param int $priority * currently not implemented in this function, would require the hook array to be resorted */ - static public function insert($hook, $fn, $version = 0, $priority = 0) { + public static function insert($hook, $fn, $version = 0, $priority = 0) { if (is_array($fn)) { $fn = serialize($fn); } diff --git a/Zotlabs/Extend/Route.php b/Zotlabs/Extend/Route.php index c93f04aac..096f94598 100644 --- a/Zotlabs/Extend/Route.php +++ b/Zotlabs/Extend/Route.php @@ -3,46 +3,52 @@ namespace Zotlabs\Extend; -class Route { +class Route +{ - static function register($file,$modname) { - $rt = self::get(); - $rt[] = [ $file, $modname ]; - self::set($rt); - } + public static function register($file, $modname) + { + $rt = self::get(); + $rt[] = [$file, $modname]; + self::set($rt); + } - static function unregister($file,$modname) { - $rt = self::get(); - if ($rt) { - $n = []; - foreach ($rt as $r) { - if ($r[0] !== $file && $r[1] !== $modname) { - $n[] = $r; - } - } - self::set($n); - } - } + public static function unregister($file, $modname) + { + $rt = self::get(); + if ($rt) { + $n = []; + foreach ($rt as $r) { + if ($r[0] !== $file && $r[1] !== $modname) { + $n[] = $r; + } + } + self::set($n); + } + } - static function unregister_by_file($file) { - $rt = self::get(); - if ($rt) { - $n = []; - foreach ($rt as $r) { - if ($r[0] !== $file) { - $n[] = $r; - } - } - self::set($n); - } - } + public static function unregister_by_file($file) + { + $rt = self::get(); + if ($rt) { + $n = []; + foreach ($rt as $r) { + if ($r[0] !== $file) { + $n[] = $r; + } + } + self::set($n); + } + } - static function get() { - return get_config('system','routes',[]); - } + public static function get() + { + return get_config('system', 'routes', []); + } - static function set($r) { - return set_config('system','routes',$r); - } + public static function set($r) + { + return set_config('system', 'routes', $r); + } } diff --git a/Zotlabs/Extend/Widget.php b/Zotlabs/Extend/Widget.php index 44597b952..78e3add6d 100644 --- a/Zotlabs/Extend/Widget.php +++ b/Zotlabs/Extend/Widget.php @@ -3,45 +3,51 @@ namespace Zotlabs\Extend; -class Widget { +class Widget +{ - static function register($file,$widget) { - $rt = self::get(); - $rt[] = [ $file, $widget ]; - self::set($rt); - } + public static function register($file, $widget) + { + $rt = self::get(); + $rt[] = [$file, $widget]; + self::set($rt); + } - static function unregister($file,$widget) { - $rt = self::get(); - if ($rt) { - $n = []; - foreach ($rt as $r) { - if ($r[0] !== $file && $r[1] !== $widget) { - $n[] = $r; - } - } - self::set($n); - } - } + public static function unregister($file, $widget) + { + $rt = self::get(); + if ($rt) { + $n = []; + foreach ($rt as $r) { + if ($r[0] !== $file && $r[1] !== $widget) { + $n[] = $r; + } + } + self::set($n); + } + } - static function unregister_by_file($file) { - $rt = self::get(); - if ($rt) { - $n = []; - foreach ($rt as $r) { - if ($r[0] !== $file) { - $n[] = $r; - } - } - self::set($n); - } - } + public static function unregister_by_file($file) + { + $rt = self::get(); + if ($rt) { + $n = []; + foreach ($rt as $r) { + if ($r[0] !== $file) { + $n[] = $r; + } + } + self::set($n); + } + } - static function get() { - return get_config('system','widgets',[]); - } + public static function get() + { + return get_config('system', 'widgets', []); + } - static function set($r) { - return set_config('system','widgets',$r); - } + public static function set($r) + { + return set_config('system', 'widgets', $r); + } } diff --git a/Zotlabs/Import/Friendica.php b/Zotlabs/Import/Friendica.php index a952d5699..f6682b568 100644 --- a/Zotlabs/Import/Friendica.php +++ b/Zotlabs/Import/Friendica.php @@ -12,352 +12,353 @@ use Zotlabs\Access\Permissions; use Zotlabs\Daemon\Run; -class Friendica { +class Friendica +{ - private $data; - private $settings; + private $data; + private $settings; - private $default_group = null; + private $default_group = null; - private $groups = null; - private $members = null; - private $contacts = null; - - - function __construct($data, $settings) { - $this->data = $data; - $this->settings = $settings; - $this->extract(); - } - - function extract() { - - // channel stuff - - $channel = [ - 'channel_name' => escape_tags($this->data['user']['username']), - 'channel_address' => escape_tags($this->data['user']['nickname']), - 'channel_guid' => escape_tags($this->data['user']['guid']), - 'channel_guid_sig' => Libzot::sign($this->data['user']['guid'],$this->data['user']['prvkey']), - 'channel_hash' => Libzot::make_xchan_hash($this->data['user']['guid'],$this->data['user']['pubkey']), - 'channel_prvkey' => $this->data['user']['prvkey'], - 'channel_pubkey' => $this->data['user']['pubkey'], - 'channel_pageflags' => PAGE_NORMAL, - 'channel_expire_days' => intval($this->data['user']['expire']), - 'channel_timezone' => escape_tags($this->data['user']['timezone']), - 'channel_location' => escape_tags($this->data['user']['default-location']) - ]; - - $account_id = $this->settings['account_id']; - - $max_identities = account_service_class_fetch($account_id,'total_identities'); - - if ($max_identities !== false) { - $r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 ", - intval($account_id) - ); - if ($r && count($r) > $max_identities) { - notice( sprintf( t('Your service plan only allows %d channels.'), $max_identities) . EOL); - return; - } - } - - // save channel or die + private $groups = null; + private $members = null; + private $contacts = null; - $channel = import_channel($channel,$this->settings['account_id'],$this->settings['sieze'],$this->settings['newname']); - if (! $channel) { - logger('no channel'); - return; - } + public function __construct($data, $settings) + { + $this->data = $data; + $this->settings = $settings; + $this->extract(); + } + + public function extract() + { + + // channel stuff + + $channel = [ + 'channel_name' => escape_tags($this->data['user']['username']), + 'channel_address' => escape_tags($this->data['user']['nickname']), + 'channel_guid' => escape_tags($this->data['user']['guid']), + 'channel_guid_sig' => Libzot::sign($this->data['user']['guid'], $this->data['user']['prvkey']), + 'channel_hash' => Libzot::make_xchan_hash($this->data['user']['guid'], $this->data['user']['pubkey']), + 'channel_prvkey' => $this->data['user']['prvkey'], + 'channel_pubkey' => $this->data['user']['pubkey'], + 'channel_pageflags' => PAGE_NORMAL, + 'channel_expire_days' => intval($this->data['user']['expire']), + 'channel_timezone' => escape_tags($this->data['user']['timezone']), + 'channel_location' => escape_tags($this->data['user']['default-location']) + ]; + + $account_id = $this->settings['account_id']; + + $max_identities = account_service_class_fetch($account_id, 'total_identities'); + + if ($max_identities !== false) { + $r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 ", + intval($account_id) + ); + if ($r && count($r) > $max_identities) { + notice(sprintf(t('Your service plan only allows %d channels.'), $max_identities) . EOL); + return; + } + } + + // save channel or die - // figure out channel permission roles - - $permissions_role = 'social'; - - $pageflags = ((isset($this->data['user']['page-flags'])) ? intval($this->data['user']['page-flags']) : 0); - - if ($pageflags === 2) { - $permissions_role = 'forum'; - } - if ($pageflags === 5) { - $permissions_role = 'forum_restricted'; - } - - if ($pageflags === 0 && isset($this->data['user']['allow_gid']) && $this->data['user']['allow_gid']) { - $permissions_role = 'social_restricted'; - } - - // Friendica folks only have PERMS_AUTHED and "just me" - - $post_comments = (($pageflags === 1) ? 0 : PERMS_AUTHED); - PermissionLimits::Set(local_channel(),'post_comments',$post_comments); - - PConfig::Set($channel['channel_id'],'system','permissions_role',$permissions_role); - PConfig::Set($channel['channel_id'],'system','use_browser_location', (string) intval($this->data['user']['allow_location'])); - - // find the self contact - - $self_contact = null; - - if (isset($this->data['contact']) && is_array($this->data['contact'])) { - foreach ($this->data['contact'] as $contact) { - if (isset($contact['self']) && intval($contact['self'])) { - $self_contact = $contact; - break; - } - } - } - - if (! is_array($self_contact)) { - logger('self contact not found.'); - return; - } - - // Create a verified hub location pointing to this site. - - $r = hubloc_store_lowlevel( - [ - 'hubloc_guid' => $channel['channel_guid'], - 'hubloc_guid_sig' => $channel['channel_guid_sig'], - 'hubloc_id_url' => channel_url($channel), - 'hubloc_hash' => $channel['channel_hash'], - 'hubloc_addr' => channel_reddress($channel), - 'hubloc_primary' => 1, - 'hubloc_url' => z_root(), - 'hubloc_url_sig' => Libzot::sign(z_root(),$channel['channel_prvkey']), - 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey')), - 'hubloc_host' => App::get_hostname(), - 'hubloc_callback' => z_root() . '/zot', - 'hubloc_sitekey' => get_config('system','pubkey'), - 'hubloc_network' => 'zot6', - 'hubloc_updated' => datetime_convert() - ] - ); - if (! $r) { - logger('Unable to store hub location'); - } + $channel = import_channel($channel, $this->settings['account_id'], $this->settings['sieze'], $this->settings['newname']); + if (!$channel) { + logger('no channel'); + return; + } - if ($self_contact['avatar']) { - $p = z_fetch_url($self_contact['avatar'],true); - if ($p['success']) { - $h = explode("\n",$p['header']); - foreach ($h as $l) { - list($k,$v) = array_map("trim", explode(":", trim($l), 2)); - $hdrs[strtolower($k)] = $v; - } - if (array_key_exists('content-type', $hdrs)) { - $phototype = $hdrs['content-type']; - } - else { - $phototype = 'image/jpeg'; - } + // figure out channel permission roles - import_channel_photo($p['body'],$phototype,$account_id,$channel['channel_id']); - } - } + $permissions_role = 'social'; - $newuid = $channel['channel_id']; + $pageflags = ((isset($this->data['user']['page-flags'])) ? intval($this->data['user']['page-flags']) : 0); - $r = xchan_store_lowlevel( - [ - 'xchan_hash' => $channel['channel_hash'], - 'xchan_guid' => $channel['channel_guid'], - 'xchan_guid_sig' => $channel['channel_guid_sig'], - 'xchan_pubkey' => $channel['channel_pubkey'], - 'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'), - 'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}", - 'xchan_photo_m' => z_root() . "/photo/profile/m/{$newuid}", - 'xchan_photo_s' => z_root() . "/photo/profile/s/{$newuid}", - 'xchan_addr' => channel_reddress($channel), - 'xchan_url' => channel_url($channel), - 'xchan_follow' => z_root() . '/follow?f=&url=%s', - 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'], - 'xchan_name' => $channel['channel_name'], - 'xchan_network' => 'zot6', - 'xchan_updated' => datetime_convert(), - 'xchan_photo_date' => datetime_convert(), - 'xchan_name_date' => datetime_convert(), - 'xchan_system' => 0 - ] - ); + if ($pageflags === 2) { + $permissions_role = 'forum'; + } + if ($pageflags === 5) { + $permissions_role = 'forum_restricted'; + } - $r = profile_store_lowlevel( - [ - 'aid' => intval($channel['channel_account_id']), - 'uid' => intval($newuid), - 'profile_guid' => new_uuid(), - 'profile_name' => t('Default Profile'), - 'is_default' => 1, - 'publish' => ((isset($this->data['profile']['publish'])) ? $this->data['profile']['publish'] : 1), - 'fullname' => $channel['channel_name'], - 'photo' => z_root() . "/photo/profile/l/{$newuid}", - 'thumb' => z_root() . "/photo/profile/m/{$newuid}", - 'homepage' => ((isset($this->data['profile']['homepage'])) ? $this->data['profile']['homepage'] : EMPTY_STR), - ] - ); + if ($pageflags === 0 && isset($this->data['user']['allow_gid']) && $this->data['user']['allow_gid']) { + $permissions_role = 'social_restricted'; + } - if($role_permissions) { - $myperms = ((array_key_exists('perms_connect',$role_permissions)) ? $role_permissions['perms_connect'] : [] ); - } - else { - $x = PermissionRoles::role_perms('social'); - $myperms = $x['perms_connect']; - } + // Friendica folks only have PERMS_AUTHED and "just me" - $r = abook_store_lowlevel( - [ - 'abook_account' => intval($channel['channel_account_id']), - 'abook_channel' => intval($newuid), - 'abook_xchan' => $channel['channel_hash'], - 'abook_closeness' => 0, - 'abook_created' => datetime_convert(), - 'abook_updated' => datetime_convert(), - 'abook_self' => 1 - ] - ); + $post_comments = (($pageflags === 1) ? 0 : PERMS_AUTHED); + PermissionLimits::Set(local_channel(), 'post_comments', $post_comments); + + PConfig::Set($channel['channel_id'], 'system', 'permissions_role', $permissions_role); + PConfig::Set($channel['channel_id'], 'system', 'use_browser_location', (string)intval($this->data['user']['allow_location'])); + + // find the self contact + + $self_contact = null; + + if (isset($this->data['contact']) && is_array($this->data['contact'])) { + foreach ($this->data['contact'] as $contact) { + if (isset($contact['self']) && intval($contact['self'])) { + $self_contact = $contact; + break; + } + } + } + + if (!is_array($self_contact)) { + logger('self contact not found.'); + return; + } + + // Create a verified hub location pointing to this site. + + $r = hubloc_store_lowlevel( + [ + 'hubloc_guid' => $channel['channel_guid'], + 'hubloc_guid_sig' => $channel['channel_guid_sig'], + 'hubloc_id_url' => channel_url($channel), + 'hubloc_hash' => $channel['channel_hash'], + 'hubloc_addr' => channel_reddress($channel), + 'hubloc_primary' => 1, + 'hubloc_url' => z_root(), + 'hubloc_url_sig' => Libzot::sign(z_root(), $channel['channel_prvkey']), + 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), get_config('system', 'pubkey')), + 'hubloc_host' => App::get_hostname(), + 'hubloc_callback' => z_root() . '/zot', + 'hubloc_sitekey' => get_config('system', 'pubkey'), + 'hubloc_network' => 'zot6', + 'hubloc_updated' => datetime_convert() + ] + ); + if (!$r) { + logger('Unable to store hub location'); + } - $x = Permissions::serialise(Permissions::FilledPerms($myperms)); - set_abconfig($newuid,$channel['channel_hash'],'system','my_perms',$x); + if ($self_contact['avatar']) { + $p = z_fetch_url($self_contact['avatar'], true); + if ($p['success']) { + $h = explode("\n", $p['header']); + foreach ($h as $l) { + list($k, $v) = array_map("trim", explode(":", trim($l), 2)); + $hdrs[strtolower($k)] = $v; + } + if (array_key_exists('content-type', $hdrs)) { + $phototype = $hdrs['content-type']; + } else { + $phototype = 'image/jpeg'; + } - if(intval($channel['channel_account_id'])) { + import_channel_photo($p['body'], $phototype, $account_id, $channel['channel_id']); + } + } - // Save our permissions role so we can perhaps call it up and modify it later. + $newuid = $channel['channel_id']; - if($role_permissions) { - if(array_key_exists('online',$role_permissions)) - set_pconfig($newuid,'system','hide_presence',1-intval($role_permissions['online'])); - if(array_key_exists('perms_auto',$role_permissions)) { - $autoperms = intval($role_permissions['perms_auto']); - set_pconfig($newuid,'system','autoperms',$autoperms); - } - } + $r = xchan_store_lowlevel( + [ + 'xchan_hash' => $channel['channel_hash'], + 'xchan_guid' => $channel['channel_guid'], + 'xchan_guid_sig' => $channel['channel_guid_sig'], + 'xchan_pubkey' => $channel['channel_pubkey'], + 'xchan_photo_mimetype' => (($photo_type) ? $photo_type : 'image/png'), + 'xchan_photo_l' => z_root() . "/photo/profile/l/{$newuid}", + 'xchan_photo_m' => z_root() . "/photo/profile/m/{$newuid}", + 'xchan_photo_s' => z_root() . "/photo/profile/s/{$newuid}", + 'xchan_addr' => channel_reddress($channel), + 'xchan_url' => channel_url($channel), + 'xchan_follow' => z_root() . '/follow?f=&url=%s', + 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'], + 'xchan_name' => $channel['channel_name'], + 'xchan_network' => 'zot6', + 'xchan_updated' => datetime_convert(), + 'xchan_photo_date' => datetime_convert(), + 'xchan_name_date' => datetime_convert(), + 'xchan_system' => 0 + ] + ); - // Create a group with yourself as a member. This allows somebody to use it - // right away as a default group for new contacts. + $r = profile_store_lowlevel( + [ + 'aid' => intval($channel['channel_account_id']), + 'uid' => intval($newuid), + 'profile_guid' => new_uuid(), + 'profile_name' => t('Default Profile'), + 'is_default' => 1, + 'publish' => ((isset($this->data['profile']['publish'])) ? $this->data['profile']['publish'] : 1), + 'fullname' => $channel['channel_name'], + 'photo' => z_root() . "/photo/profile/l/{$newuid}", + 'thumb' => z_root() . "/photo/profile/m/{$newuid}", + 'homepage' => ((isset($this->data['profile']['homepage'])) ? $this->data['profile']['homepage'] : EMPTY_STR), + ] + ); - AccessList::add($newuid, t('Friends')); - AccessList::member_add($newuid,t('Friends'),$ret['channel']['channel_hash']); + if ($role_permissions) { + $myperms = ((array_key_exists('perms_connect', $role_permissions)) ? $role_permissions['perms_connect'] : []); + } else { + $x = PermissionRoles::role_perms('social'); + $myperms = $x['perms_connect']; + } - // if our role_permissions indicate that we're using a default collection ACL, add it. - - if(is_array($role_permissions) && $role_permissions['default_collection']) { - $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", - intval($newuid), - dbesc( t('Friends') ) - ); - if($r) { - q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d", - dbesc($r[0]['hash']), - dbesc('<' . $r[0]['hash'] . '>'), - intval($newuid) - ); - } - } - - set_pconfig($channel['channel_id'],'system','photo_path', '%Y/%Y-%m'); - set_pconfig($channel['channel_id'],'system','attach_path','%Y/%Y-%m'); + $r = abook_store_lowlevel( + [ + 'abook_account' => intval($channel['channel_account_id']), + 'abook_channel' => intval($newuid), + 'abook_xchan' => $channel['channel_hash'], + 'abook_closeness' => 0, + 'abook_created' => datetime_convert(), + 'abook_updated' => datetime_convert(), + 'abook_self' => 1 + ] + ); - // auto-follow any of the hub's pre-configured channel choices. - // Only do this if it's the first channel for this account; - // otherwise it could get annoying. Don't make this list too big - // or it will impact registration time. + $x = Permissions::serialise(Permissions::FilledPerms($myperms)); + set_abconfig($newuid, $channel['channel_hash'], 'system', 'my_perms', $x); - $accts = get_config('system','auto_follow'); - if(($accts) && (! $total_identities)) { - if(! is_array($accts)) - $accts = array($accts); + if (intval($channel['channel_account_id'])) { - foreach($accts as $acct) { - if(trim($acct)) { - $f = connect_and_sync($channel,trim($acct)); - if($f['success']) { + // Save our permissions role so we can perhaps call it up and modify it later. - $can_view_stream = their_perms_contains($channel['channel_id'],$f['abook']['abook_xchan'],'view_stream'); + if ($role_permissions) { + if (array_key_exists('online', $role_permissions)) + set_pconfig($newuid, 'system', 'hide_presence', 1 - intval($role_permissions['online'])); + if (array_key_exists('perms_auto', $role_permissions)) { + $autoperms = intval($role_permissions['perms_auto']); + set_pconfig($newuid, 'system', 'autoperms', $autoperms); + } + } - // If we can view their stream, pull in some posts + // Create a group with yourself as a member. This allows somebody to use it + // right away as a default group for new contacts. - if(($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) { - Run::Summon([ 'Onepoll',$f['abook']['abook_id'] ]); - } - } - } - } - } + AccessList::add($newuid, t('Friends')); + AccessList::member_add($newuid, t('Friends'), $ret['channel']['channel_hash']); - call_hooks('create_identity', $newuid); - } + // if our role_permissions indicate that we're using a default collection ACL, add it. - $this->groups = ((isset($this->data['group'])) ? $this->data['group'] : null); - $this->members = ((isset($this->data['group_member'])) ? $this->data['group_member'] : null); + if (is_array($role_permissions) && $role_permissions['default_collection']) { + $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", + intval($newuid), + dbesc(t('Friends')) + ); + if ($r) { + q("update channel set channel_default_group = '%s', channel_allow_gid = '%s' where channel_id = %d", + dbesc($r[0]['hash']), + dbesc('<' . $r[0]['hash'] . '>'), + intval($newuid) + ); + } + } - // import contacts + set_pconfig($channel['channel_id'], 'system', 'photo_path', '%Y/%Y-%m'); + set_pconfig($channel['channel_id'], 'system', 'attach_path', '%Y/%Y-%m'); - if (isset($this->data['contact']) && is_array($this->data['contact'])) { - foreach ($this->data['contact'] as $contact) { - if (isset($contact['self']) && intval($contact['self'])) { - continue; - } - logger('connecting: ' . $contact['url'], LOGGER_DEBUG); - $result = Connect::connect($channel,(($contact['addr']) ? $contact['addr'] : $contact['url'])); - if ($result['success'] && isset($result['abook'])) { - $contact['xchan_hash'] = $result['abook']['abook_xchan']; - $this->contacts[] = $contact; - } - } - } - // import pconfig - // it is unlikely we can make use of these unless we recongise them. - - if (isset($this->data['pconfig']) && is_array($this->data['pconfig'])) { - foreach ($this->data['pconfig'] as $pc) { - $entry = [ - 'cat' => escape_tags(str_replace('.','__',$pc['cat'])), - 'k' => escape_tags(str_replace('.','__',$pc['k'])), - 'v' => ((preg_match('|^a:[0-9]+:{.*}$|s', $pc['v'])) ? serialise(unserialize($pc['v'])) : $pc['v']), - ]; - PConfig::Set($channel['channel_id'],$entry['cat'],$entry['k'],$entry['v']); - } - } + // auto-follow any of the hub's pre-configured channel choices. + // Only do this if it's the first channel for this account; + // otherwise it could get annoying. Don't make this list too big + // or it will impact registration time. - // The default 'Friends' group is already created and possibly populated. - // So some of the following code is redundant in that regard. - // Mostly this is used to create and populate any other groups. + $accts = get_config('system', 'auto_follow'); + if (($accts) && (!$total_identities)) { + if (!is_array($accts)) + $accts = array($accts); - if ($this->groups) { - foreach ($this->groups as $group) { - if (! intval($group['deleted'])) { - AccessList::add($channel['channel_id'], $group['name'], intval($group['visible'])); - if ($this->members) { - foreach ($this->members as $member) { - if (intval($member['gid']) === intval(AccessList::byname($channel['channel_id'],$group['name']))) { - $contact_id = $member['contact-id']; - if ($this->contacts) { - foreach ($this->contacts as $contact) { - if (intval($contact['id']) === intval($contact_id)) { - AccessList::member_add($channel['channel_id'],$group['name'],$contact['xchan_hash']); - break; - } - } - } - } - } - } - } - } - } + foreach ($accts as $acct) { + if (trim($acct)) { + $f = connect_and_sync($channel, trim($acct)); + if ($f['success']) { - change_channel($channel['channel_id']); - notice( t('Import complete.') . EOL); + $can_view_stream = their_perms_contains($channel['channel_id'], $f['abook']['abook_xchan'], 'view_stream'); - goaway(z_root() . '/stream' ); + // If we can view their stream, pull in some posts - } + if (($can_view_stream) || ($f['abook']['xchan_network'] === 'rss')) { + Run::Summon(['Onepoll', $f['abook']['abook_id']]); + } + } + } + } + } + + call_hooks('create_identity', $newuid); + } + + $this->groups = ((isset($this->data['group'])) ? $this->data['group'] : null); + $this->members = ((isset($this->data['group_member'])) ? $this->data['group_member'] : null); + + // import contacts + + if (isset($this->data['contact']) && is_array($this->data['contact'])) { + foreach ($this->data['contact'] as $contact) { + if (isset($contact['self']) && intval($contact['self'])) { + continue; + } + logger('connecting: ' . $contact['url'], LOGGER_DEBUG); + $result = Connect::connect($channel, (($contact['addr']) ? $contact['addr'] : $contact['url'])); + if ($result['success'] && isset($result['abook'])) { + $contact['xchan_hash'] = $result['abook']['abook_xchan']; + $this->contacts[] = $contact; + } + } + } + + // import pconfig + // it is unlikely we can make use of these unless we recongise them. + + if (isset($this->data['pconfig']) && is_array($this->data['pconfig'])) { + foreach ($this->data['pconfig'] as $pc) { + $entry = [ + 'cat' => escape_tags(str_replace('.', '__', $pc['cat'])), + 'k' => escape_tags(str_replace('.', '__', $pc['k'])), + 'v' => ((preg_match('|^a:[0-9]+:{.*}$|s', $pc['v'])) ? serialise(unserialize($pc['v'])) : $pc['v']), + ]; + PConfig::Set($channel['channel_id'], $entry['cat'], $entry['k'], $entry['v']); + } + } + + // The default 'Friends' group is already created and possibly populated. + // So some of the following code is redundant in that regard. + // Mostly this is used to create and populate any other groups. + + if ($this->groups) { + foreach ($this->groups as $group) { + if (!intval($group['deleted'])) { + AccessList::add($channel['channel_id'], $group['name'], intval($group['visible'])); + if ($this->members) { + foreach ($this->members as $member) { + if (intval($member['gid']) === intval(AccessList::byname($channel['channel_id'], $group['name']))) { + $contact_id = $member['contact-id']; + if ($this->contacts) { + foreach ($this->contacts as $contact) { + if (intval($contact['id']) === intval($contact_id)) { + AccessList::member_add($channel['channel_id'], $group['name'], $contact['xchan_hash']); + break; + } + } + } + } + } + } + } + } + } + + change_channel($channel['channel_id']); + notice(t('Import complete.') . EOL); + + goaway(z_root() . '/stream'); + + } } \ No newline at end of file diff --git a/Zotlabs/Lib/AConfig.php b/Zotlabs/Lib/AConfig.php index 4e7c5483f..5da554691 100644 --- a/Zotlabs/Lib/AConfig.php +++ b/Zotlabs/Lib/AConfig.php @@ -6,19 +6,19 @@ namespace Zotlabs\Lib; class AConfig { - static public function Load($account_id) { + public static function Load($account_id) { return XConfig::Load('a_' . $account_id); } - static public function Get($account_id,$family,$key,$default = false) { + public static function Get($account_id, $family, $key, $default = false) { return XConfig::Get('a_' . $account_id,$family,$key, $default); } - static public function Set($account_id,$family,$key,$value) { + public static function Set($account_id, $family, $key, $value) { return XConfig::Set('a_' . $account_id,$family,$key,$value); } - static public function Delete($account_id,$family,$key) { + public static function Delete($account_id, $family, $key) { return XConfig::Delete('a_' . $account_id,$family,$key); } diff --git a/Zotlabs/Lib/ASCollection.php b/Zotlabs/Lib/ASCollection.php index 2865625be..c45890673 100644 --- a/Zotlabs/Lib/ASCollection.php +++ b/Zotlabs/Lib/ASCollection.php @@ -12,147 +12,140 @@ use Zotlabs\Lib\Activity; * An optional limit to the number of records returned may also be specified. * Use $class->get() to return an array of collection members. */ - +class ASCollection +{ + + private $channel = null; + private $nextpage = null; + private $limit = 0; + private $direction = 0; // 0 = forward, 1 = reverse + private $data = []; + private $history = []; + public function __construct($obj, $channel = null, $direction = 0, $limit = 0) + { -class ASCollection { + $this->channel = $channel; + $this->direction = $direction; + $this->limit = $limit; - private $channel = null; - private $nextpage = null; - private $limit = 0; - private $direction = 0; // 0 = forward, 1 = reverse - private $data = []; - private $history = []; + if (is_array($obj)) { + $data = $obj; + } + if (is_string($obj)) { + $data = Activity::fetch($obj, $channel); + $this->history[] = $obj; + } - function __construct($obj, $channel = null, $direction = 0, $limit = 0) { + if (!is_array($data)) { + return; + } - $this->channel = $channel; - $this->direction = $direction; - $this->limit = $limit; - - if (is_array($obj)) { - $data = $obj; - } + if (!in_array($data['type'], ['Collection', 'OrderedCollection'])) { + return false; + } - if (is_string($obj)) { - $data = Activity::fetch($obj,$channel); - $this->history[] = $obj; - } - - if (! is_array($data)) { - return; - } + if ($this->direction) { + if (array_key_exists('last', $data) && $data['last']) { + $this->nextpage = $data['last']; + } + } else { + if (array_key_exists('first', $data) && $data['first']) { + $this->nextpage = $data['first']; + } + } - if (! in_array($data['type'], ['Collection','OrderedCollection'])) { - return false; - } + if (isset($data['items']) && is_array($data['items'])) { + $this->data = (($this->direction) ? array_reverse($data['items']) : $data['items']); + } elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) { + $this->data = (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']); + } - if ($this->direction) { - if (array_key_exists('last',$data) && $data['last']) { - $this->nextpage = $data['last']; - } - } - else { - if (array_key_exists('first',$data) && $data['first']) { - $this->nextpage = $data['first']; - } - } + if ($limit) { + if (count($this->data) > $limit) { + $this->data = array_slice($this->data, 0, $limit); + return; + } + } - if (isset($data['items']) && is_array($data['items'])) { - $this->data = (($this->direction) ? array_reverse($data['items']) : $data['items']); - } - elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) { - $this->data = (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems']); - } + do { + $x = $this->next(); + } while ($x); + } - if ($limit) { - if (count($this->data) > $limit) { - $this->data = array_slice($this->data,0,$limit); - return; - } - } + public function get() + { + return $this->data; + } - do { - $x = $this->next(); - } while ($x); - } + public function next() + { - function get() { - return $this->data; - } + if (!$this->nextpage) { + return false; + } - function next() { + if (is_array($this->nextpage)) { + $data = $this->nextpage; + } - if (! $this->nextpage) { - return false; - } - - if (is_array($this->nextpage)) { - $data = $this->nextpage; - } - - if (is_string($this->nextpage)) { - if (in_array($this->nextpage,$this->history)) { - // recursion detected - return false; - } - $data = Activity::fetch($this->nextpage,$this->channel); - $this->history[] = $this->nextpage; - } + if (is_string($this->nextpage)) { + if (in_array($this->nextpage, $this->history)) { + // recursion detected + return false; + } + $data = Activity::fetch($this->nextpage, $this->channel); + $this->history[] = $this->nextpage; + } - if (! is_array($data)) { - return false; - } - - if (! in_array($data['type'], ['CollectionPage','OrderedCollectionPage'])) { - return false; - } + if (!is_array($data)) { + return false; + } - $this->setnext($data); + if (!in_array($data['type'], ['CollectionPage', 'OrderedCollectionPage'])) { + return false; + } - if (isset($data['items']) && is_array($data['items'])) { - $this->data = array_merge($this->data,(($this->direction) ? array_reverse($data['items']) : $data['items'])); - } - elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) { - $this->data = array_merge($this->data,(($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems'])); - } + $this->setnext($data); - if ($limit) { - if (count($this->data) > $limit) { - $this->data = array_slice($this->data,0,$limit); - $this->nextpage = false; - return true; - } - } + if (isset($data['items']) && is_array($data['items'])) { + $this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['items']) : $data['items'])); + } elseif (isset($data['orderedItems']) && is_array($data['orderedItems'])) { + $this->data = array_merge($this->data, (($this->direction) ? array_reverse($data['orderedItems']) : $data['orderedItems'])); + } - return true; - } + if ($limit) { + if (count($this->data) > $limit) { + $this->data = array_slice($this->data, 0, $limit); + $this->nextpage = false; + return true; + } + } - function setnext($data) { - if ($this->direction) { - if (array_key_exists('prev',$data) && $data['prev']) { - $this->nextpage = $data['prev']; - } - elseif (array_key_exists('first',$data) && $data['first']) { - $this->nextpage = $data['first']; - } - else { - $this->nextpage = false; - } - } - else { - if (array_key_exists('next',$data) && $data['next']) { - $this->nextpage = $data['next']; - } - elseif (array_key_exists('last',$data) && $data['last']) { - $this->nextpage = $data['last']; - } - else { - $this->nextpage = false; - } - } - logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG); - } + return true; + } + + public function setnext($data) + { + if ($this->direction) { + if (array_key_exists('prev', $data) && $data['prev']) { + $this->nextpage = $data['prev']; + } elseif (array_key_exists('first', $data) && $data['first']) { + $this->nextpage = $data['first']; + } else { + $this->nextpage = false; + } + } else { + if (array_key_exists('next', $data) && $data['next']) { + $this->nextpage = $data['next']; + } elseif (array_key_exists('last', $data) && $data['last']) { + $this->nextpage = $data['last']; + } else { + $this->nextpage = false; + } + } + logger('nextpage: ' . $this->nextpage, LOGGER_DEBUG); + } } diff --git a/Zotlabs/Lib/AbConfig.php b/Zotlabs/Lib/AbConfig.php index d205071f8..581aae9e2 100644 --- a/Zotlabs/Lib/AbConfig.php +++ b/Zotlabs/Lib/AbConfig.php @@ -5,7 +5,7 @@ namespace Zotlabs\Lib; class AbConfig { - static public function Load($chan,$xhash,$family = '') { + public static function Load($chan, $xhash, $family = '') { if($family) $where = sprintf(" and cat = '%s' ",dbesc($family)); $r = q("select * from abconfig where chan = %d and xchan = '%s' $where", @@ -16,7 +16,7 @@ class AbConfig { } - static public function Get($chan,$xhash,$family,$key, $default = false) { + public static function Get($chan, $xhash, $family, $key, $default = false) { $r = q("select * from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' limit 1", intval($chan), dbesc($xhash), @@ -30,7 +30,7 @@ class AbConfig { } - static public function Set($chan,$xhash,$family,$key,$value) { + public static function Set($chan, $xhash, $family, $key, $value) { $dbvalue = ((is_array($value)) ? serialise($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); @@ -60,7 +60,7 @@ class AbConfig { } - static public function Delete($chan,$xhash,$family,$key) { + public static function Delete($chan, $xhash, $family, $key) { $r = q("delete from abconfig where chan = %d and xchan = '%s' and cat = '%s' and k = '%s' ", intval($chan), diff --git a/Zotlabs/Lib/AccessList.php b/Zotlabs/Lib/AccessList.php index c114bb3d0..0714ef621 100644 --- a/Zotlabs/Lib/AccessList.php +++ b/Zotlabs/Lib/AccessList.php @@ -5,460 +5,470 @@ namespace Zotlabs\Lib; use Zotlabs\Lib\Libsync; -class AccessList { - - static function add($uid,$name,$public = 0) { +class AccessList +{ - $ret = false; - if ($uid && $name) { - $r = self::byname($uid,$name); // check for dups - if ($r !== false) { + public static function add($uid, $name, $public = 0) + { - // This could be a problem. - // Let's assume we've just created a list which we once deleted - // all the old members are gone, but the list remains so we don't break any security - // access lists. What we're doing here is reviving the dead list, but old content which - // was restricted to this list may now be seen by the new list members. + $ret = false; + if ($uid && $name) { + $r = self::byname($uid, $name); // check for dups + if ($r !== false) { - $z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1", - intval($r) - ); - if(($z) && $z[0]['deleted']) { - q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id'])); - notice( t('A deleted list with this name was revived. Existing item permissions may apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL); - } - $hash = self::by_id($uid,$r); - return $hash; - } + // This could be a problem. + // Let's assume we've just created a list which we once deleted + // all the old members are gone, but the list remains so we don't break any security + // access lists. What we're doing here is reviving the dead list, but old content which + // was restricted to this list may now be seen by the new list members. - $hash = new_uuid(); + $z = q("SELECT * FROM pgrp WHERE id = %d LIMIT 1", + intval($r) + ); + if (($z) && $z[0]['deleted']) { + q('UPDATE pgrp SET deleted = 0 WHERE id = %d', intval($z[0]['id'])); + notice(t('A deleted list with this name was revived. Existing item permissions may apply to this list and any future members. If this is not what you intended, please create another list with a different name.') . EOL); + } + $hash = self::by_id($uid, $r); + return $hash; + } - $r = q("INSERT INTO pgrp ( hash, uid, visible, gname, rule ) + $hash = new_uuid(); + + $r = q("INSERT INTO pgrp ( hash, uid, visible, gname, rule ) VALUES( '%s', %d, %d, '%s', '' ) ", - dbesc($hash), - intval($uid), - intval($public), - dbesc($name) - ); - $ret = $r; - } + dbesc($hash), + intval($uid), + intval($public), + dbesc($name) + ); + $ret = $r; + } - Libsync::build_sync_packet($uid,null,true); - - return (($ret) ? $hash : $ret); - } + Libsync::build_sync_packet($uid, null, true); + + return (($ret) ? $hash : $ret); + } - static function remove($uid,$name) { - $ret = false; - if ($uid && $name) { - $r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", - intval($uid), - dbesc($name) - ); - if ($r) { - $group_id = $r[0]['id']; - $group_hash = $r[0]['hash']; - } - else { - return false; - } - - // remove group from default posting lists - $r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1", - intval($uid) - ); - if ($r) { - $user_info = array_shift($r); - $change = false; + public static function remove($uid, $name) + { + $ret = false; + if ($uid && $name) { + $r = q("SELECT id, hash FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", + intval($uid), + dbesc($name) + ); + if ($r) { + $group_id = $r[0]['id']; + $group_hash = $r[0]['hash']; + } else { + return false; + } - if ($user_info['channel_default_group'] == $group_hash) { - $user_info['channel_default_group'] = ''; - $change = true; - } - if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) { - $user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']); - $change = true; - } - if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) { - $user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']); - $change = true; - } + // remove group from default posting lists + $r = q("SELECT channel_default_group, channel_allow_gid, channel_deny_gid FROM channel WHERE channel_id = %d LIMIT 1", + intval($uid) + ); + if ($r) { + $user_info = array_shift($r); + $change = false; - if ($change) { - q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s' + if ($user_info['channel_default_group'] == $group_hash) { + $user_info['channel_default_group'] = ''; + $change = true; + } + if (strpos($user_info['channel_allow_gid'], '<' . $group_hash . '>') !== false) { + $user_info['channel_allow_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_allow_gid']); + $change = true; + } + if (strpos($user_info['channel_deny_gid'], '<' . $group_hash . '>') !== false) { + $user_info['channel_deny_gid'] = str_replace('<' . $group_hash . '>', '', $user_info['channel_deny_gid']); + $change = true; + } + + if ($change) { + q("UPDATE channel SET channel_default_group = '%s', channel_allow_gid = '%s', channel_deny_gid = '%s' WHERE channel_id = %d", - intval($user_info['channel_default_group']), - dbesc($user_info['channel_allow_gid']), - dbesc($user_info['channel_deny_gid']), - intval($uid) - ); - } - } + intval($user_info['channel_default_group']), + dbesc($user_info['channel_allow_gid']), + dbesc($user_info['channel_deny_gid']), + intval($uid) + ); + } + } - // remove all members - $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ", - intval($uid), - intval($group_id) - ); + // remove all members + $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d ", + intval($uid), + intval($group_id) + ); - // remove group - $r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'", - intval($uid), - dbesc($name) - ); + // remove group + $r = q("UPDATE pgrp SET deleted = 1 WHERE uid = %d AND gname = '%s'", + intval($uid), + dbesc($name) + ); - $ret = $r; + $ret = $r; - } + } - Libsync::build_sync_packet($uid,null,true); + Libsync::build_sync_packet($uid, null, true); - return $ret; - } + return $ret; + } - // returns the integer id of an access group owned by $uid and named $name - // or false. - - static function byname($uid,$name) { - if (! ($uid && $name)) { - return false; - } - $r = q("SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", - intval($uid), - dbesc($name) - ); - if ($r) { - return $r[0]['id']; - } - return false; - } + // returns the integer id of an access group owned by $uid and named $name + // or false. - static function by_id($uid,$id) { - if (! ($uid && $id)) { - return false; - } - - $r = q("SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0", - intval($uid), - intval($id) - ); - if ($r) { - return array_shift($r); - } - return false; - } + public static function byname($uid, $name) + { + if (!($uid && $name)) { + return false; + } + $r = q("SELECT id FROM pgrp WHERE uid = %d AND gname = '%s' LIMIT 1", + intval($uid), + dbesc($name) + ); + if ($r) { + return $r[0]['id']; + } + return false; + } + + public static function by_id($uid, $id) + { + if (!($uid && $id)) { + return false; + } + + $r = q("SELECT * FROM pgrp WHERE uid = %d AND id = %d and deleted = 0", + intval($uid), + intval($id) + ); + if ($r) { + return array_shift($r); + } + return false; + } - - static function rec_byhash($uid,$hash) { - if (! ( $uid && $hash)) { - return false; - } - $r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1", - intval($uid), - dbesc($hash) - ); - if ($r) { - return array_shift($r); - } - return false; - } + public static function rec_byhash($uid, $hash) + { + if (!($uid && $hash)) { + return false; + } + $r = q("SELECT * FROM pgrp WHERE uid = %d AND hash = '%s' LIMIT 1", + intval($uid), + dbesc($hash) + ); + if ($r) { + return array_shift($r); + } + return false; + } - static function member_remove($uid,$name,$member) { - $gid = self::byname($uid,$name); - if (! $gid) { - return false; - } - if (! ($uid && $gid && $member)) { - return false; - } - $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ", - intval($uid), - intval($gid), - dbesc($member) - ); + public static function member_remove($uid, $name, $member) + { + $gid = self::byname($uid, $name); + if (!$gid) { + return false; + } + if (!($uid && $gid && $member)) { + return false; + } + $r = q("DELETE FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' ", + intval($uid), + intval($gid), + dbesc($member) + ); - Libsync::build_sync_packet($uid,null,true); + Libsync::build_sync_packet($uid, null, true); - return $r; - } + return $r; + } - static function member_add($uid,$name,$member,$gid = 0) { - if (! $gid) { - $gid = self::byname($uid,$name); - } - if (! ($gid && $uid && $member)) { - return false; - } + public static function member_add($uid, $name, $member, $gid = 0) + { + if (!$gid) { + $gid = self::byname($uid, $name); + } + if (!($gid && $uid && $member)) { + return false; + } - $r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1", - intval($uid), - intval($gid), - dbesc($member) - ); - if ($r) { - return true; // You might question this, but - // we indicate success because the group member was in fact created - // -- It was just created at another time - } - else { - $r = q("INSERT INTO pgrp_member (uid, gid, xchan) + $r = q("SELECT * FROM pgrp_member WHERE uid = %d AND gid = %d AND xchan = '%s' LIMIT 1", + intval($uid), + intval($gid), + dbesc($member) + ); + if ($r) { + return true; // You might question this, but + // we indicate success because the group member was in fact created + // -- It was just created at another time + } else { + $r = q("INSERT INTO pgrp_member (uid, gid, xchan) VALUES( %d, %d, '%s' ) ", - intval($uid), - intval($gid), - dbesc($member) - ); - } - Libsync::build_sync_packet($uid,null,true); - return $r; - } + intval($uid), + intval($gid), + dbesc($member) + ); + } + Libsync::build_sync_packet($uid, null, true); + return $r; + } - static function members($uid, $gid, $total = false, $start = 0, $records = 0) { - $ret = []; - if ($records) { - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($records), intval($start)); - } + public static function members($uid, $gid, $total = false, $start = 0, $records = 0) + { + $ret = []; + if ($records) { + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($records), intval($start)); + } - // process virtual groups - if (strpos($gid,':') === 0) { - $vg = substr($gid,1); - switch ($vg) { - case '1': - $sql_extra = EMPTY_STR; - break; - case '2': - $sql_extra = " and xchan_network = 'zot6' "; - break; - case '3': - $sql_extra = " and xchan_network = 'activitypub' "; - break; - default: - break; - } - if ($total) { - $r = q("SELECT count(*) FROM abook left join xchan on xchan_hash = abook_xchan WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql", - intval($uid) - ); - return ($r) ? $r[0]['total'] : false; - } + // process virtual groups + if (strpos($gid, ':') === 0) { + $vg = substr($gid, 1); + switch ($vg) { + case '1': + $sql_extra = EMPTY_STR; + break; + case '2': + $sql_extra = " and xchan_network = 'zot6' "; + break; + case '3': + $sql_extra = " and xchan_network = 'activitypub' "; + break; + default: + break; + } + if ($total) { + $r = q("SELECT count(*) FROM abook left join xchan on xchan_hash = abook_xchan WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql", + intval($uid) + ); + return ($r) ? $r[0]['total'] : false; + } - $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan + $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql", - intval($uid) - ); - if ($r) { - for($x = 0; $x < count($r); $x ++) { - $r[$x]['xchan'] = $r[$x]['abook_xchan']; - } - } - return $r; - } - - if (intval($gid)) { - if ($total) { - $r = q("SELECT count(xchan) as total FROM pgrp_member + intval($uid) + ); + if ($r) { + for ($x = 0; $x < count($r); $x++) { + $r[$x]['xchan'] = $r[$x]['abook_xchan']; + } + } + return $r; + } + + if (intval($gid)) { + if ($total) { + $r = q("SELECT count(xchan) as total FROM pgrp_member LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0", - intval($gid), - intval($uid), - intval($uid) - ); - if ($r) { - return $r[0]['total']; - } - } - - $r = q("SELECT * FROM pgrp_member + intval($gid), + intval($uid), + intval($uid) + ); + if ($r) { + return $r[0]['total']; + } + } + + $r = q("SELECT * FROM pgrp_member LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC $pager_sql", - intval($gid), - intval($uid), - intval($uid) - ); - if ($r) { - $ret = $r; - } - } - return $ret; - } + intval($gid), + intval($uid), + intval($uid) + ); + if ($r) { + $ret = $r; + } + } + return $ret; + } - static function members_xchan($uid,$gid) { - $ret = []; - if (intval($gid)) { - $r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d", - intval($gid), - intval($uid) - ); - if ($r) { - foreach ($r as $rv) { - $ret[] = $rv['xchan']; - } - } - } - return $ret; - } + public static function members_xchan($uid, $gid) + { + $ret = []; + if (intval($gid)) { + $r = q("SELECT xchan FROM pgrp_member WHERE gid = %d AND uid = %d", + intval($gid), + intval($uid) + ); + if ($r) { + foreach ($r as $rv) { + $ret[] = $rv['xchan']; + } + } + } + return $ret; + } - static function select($uid,$group = '') { - - $grps = []; + public static function select($uid, $group = '') + { - $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", - intval($uid) - ); - $grps[] = [ 'name' => '', 'hash' => '0', 'selected' => '' ]; - if ($r) { - foreach ($r as $rr) { - $grps[] = [ 'name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '') ]; - } + $grps = []; - } - - return replace_macros(get_markup_template('group_selection.tpl'), [ - '$label' => t('Add new connections to this access list'), - '$groups' => $grps - ]); - } + $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + intval($uid) + ); + $grps[] = ['name' => '', 'hash' => '0', 'selected' => '']; + if ($r) { + foreach ($r as $rr) { + $grps[] = ['name' => $rr['gname'], 'id' => $rr['hash'], 'selected' => (($group == $rr['hash']) ? 'true' : '')]; + } + + } + + return replace_macros(get_markup_template('group_selection.tpl'), [ + '$label' => t('Add new connections to this access list'), + '$groups' => $grps + ]); + } - static function widget($every="connections",$each="lists",$edit = false, $group_id = 0, $cid = '',$mode = 1) { + public static function widget($every = "connections", $each = "lists", $edit = false, $group_id = 0, $cid = '', $mode = 1) + { - $o = ''; + $o = ''; - $groups = []; + $groups = []; - $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", - intval($_SESSION['uid']) - ); - $member_of = []; - if ($cid) { - $member_of = self::containing(local_channel(),$cid); - } + $r = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + intval($_SESSION['uid']) + ); + $member_of = []; + if ($cid) { + $member_of = self::containing(local_channel(), $cid); + } - if ($r) { - foreach ($r as $rr) { - $selected = (($group_id == $rr['id']) ? ' group-selected' : ''); - - if ($edit) { - $groupedit = [ 'href' => "lists/".$rr['id'], 'title' => t('edit') ]; - } - else { - $groupedit = null; - } - - $groups[] = [ - 'id' => $rr['id'], - 'enc_cid' => base64url_encode($cid), - 'cid' => $cid, - 'text' => $rr['gname'], - 'selected' => $selected, - 'href' => (($mode == 0) ? $each.'?f=&gid='.$rr['id'] : $each."/".$rr['id']) . ((x($_GET,'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET,'order')) ? '&order=' . $_GET['order'] : ''), - 'edit' => $groupedit, - 'ismember' => in_array($rr['id'],$member_of), - ]; - } - } - - return replace_macros(get_markup_template('group_side.tpl'), [ - '$title' => t('Lists'), - '$edittext' => t('Edit list'), - '$createtext' => t('Create new list'), - '$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''), - '$groups' => $groups, - '$add' => t('add'), - ]); + if ($r) { + foreach ($r as $rr) { + $selected = (($group_id == $rr['id']) ? ' group-selected' : ''); - } + if ($edit) { + $groupedit = ['href' => "lists/" . $rr['id'], 'title' => t('edit')]; + } else { + $groupedit = null; + } + + $groups[] = [ + 'id' => $rr['id'], + 'enc_cid' => base64url_encode($cid), + 'cid' => $cid, + 'text' => $rr['gname'], + 'selected' => $selected, + 'href' => (($mode == 0) ? $each . '?f=&gid=' . $rr['id'] : $each . "/" . $rr['id']) . ((x($_GET, 'new')) ? '&new=' . $_GET['new'] : '') . ((x($_GET, 'order')) ? '&order=' . $_GET['order'] : ''), + 'edit' => $groupedit, + 'ismember' => in_array($rr['id'], $member_of), + ]; + } + } + + return replace_macros(get_markup_template('group_side.tpl'), [ + '$title' => t('Lists'), + '$edittext' => t('Edit list'), + '$createtext' => t('Create new list'), + '$ungrouped' => (($every === 'contacts') ? t('Channels not in any access list') : ''), + '$groups' => $groups, + '$add' => t('add'), + ]); + + } - static function expand($g) { - if (! (is_array($g) && count($g))) { - return []; - } + public static function expand($g) + { + if (!(is_array($g) && count($g))) { + return []; + } - $ret = []; - $x = []; + $ret = []; + $x = []; - foreach ($g as $gv) { + foreach ($g as $gv) { - // virtual access lists - // connections:abc is all the connection sof the channel with channel_hash abc - // zot:abc is all of abc's zot6 connections - // activitypub:abc is all of abc's activitypub connections - - if (strpos($gv,'connections:') === 0 || strpos($gv,'zot:') === 0 || strpos($gv,'activitypub:') === 0) { - $sql_extra = EMPTY_STR; - $channel_hash = substr($gv,strpos($gv,':') + 1); - if (strpos($gv,'zot:') === 0) { - $sql_extra = " and xchan_network = 'zot6' "; - } - if (strpos($gv,'activitypub:') === 0) { - $sql_extra = " and xchan_network = 'activitypub' "; - } - $r = q("select channel_id from channel where channel_hash = '%s' ", - dbesc($channel_hash) - ); - if ($r) { - foreach ($r as $rv) { - $y = q("select abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 $sql_extra", - intval($rv['channel_id']) - ); - if ($y) { - foreach ($y as $yv) { - $ret[] = $yv['abook_xchan']; - } - } - } - } - } - else { - $x[] = $gv; - } - } + // virtual access lists + // connections:abc is all the connection sof the channel with channel_hash abc + // zot:abc is all of abc's zot6 connections + // activitypub:abc is all of abc's activitypub connections - if ($x) { - stringify_array_elms($x,true); - $groups = implode(',', $x); - if ($groups) { - $r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))"); - if ($r) { - foreach ($r as $rv) { - $ret[] = $rv['xchan']; - } - } - - } - } - return $ret; - } + if (strpos($gv, 'connections:') === 0 || strpos($gv, 'zot:') === 0 || strpos($gv, 'activitypub:') === 0) { + $sql_extra = EMPTY_STR; + $channel_hash = substr($gv, strpos($gv, ':') + 1); + if (strpos($gv, 'zot:') === 0) { + $sql_extra = " and xchan_network = 'zot6' "; + } + if (strpos($gv, 'activitypub:') === 0) { + $sql_extra = " and xchan_network = 'activitypub' "; + } + $r = q("select channel_id from channel where channel_hash = '%s' ", + dbesc($channel_hash) + ); + if ($r) { + foreach ($r as $rv) { + $y = q("select abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 $sql_extra", + intval($rv['channel_id']) + ); + if ($y) { + foreach ($y as $yv) { + $ret[] = $yv['abook_xchan']; + } + } + } + } + } else { + $x[] = $gv; + } + } + + if ($x) { + stringify_array_elms($x, true); + $groups = implode(',', $x); + if ($groups) { + $r = q("SELECT xchan FROM pgrp_member WHERE gid IN ( select id from pgrp where hash in ( $groups ))"); + if ($r) { + foreach ($r as $rv) { + $ret[] = $rv['xchan']; + } + } + + } + } + return $ret; + } - static function member_of($c) { - $r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id + public static function member_of($c) + { + $r = q("SELECT pgrp.gname, pgrp.id FROM pgrp LEFT JOIN pgrp_member ON pgrp_member.gid = pgrp.id WHERE pgrp_member.xchan = '%s' AND pgrp.deleted = 0 ORDER BY pgrp.gname ASC ", - dbesc($c) - ); + dbesc($c) + ); - return $r; - } + return $r; + } - static function containing($uid,$c) { + public static function containing($uid, $c) + { - $r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ", - intval($uid), - dbesc($c) - ); + $r = q("SELECT gid FROM pgrp_member WHERE uid = %d AND pgrp_member.xchan = '%s' ", + intval($uid), + dbesc($c) + ); - $ret = []; - if ($r) { - foreach ($r as $rv) - $ret[] = $rv['gid']; - } - - return $ret; - } + $ret = []; + if ($r) { + foreach ($r as $rv) + $ret[] = $rv['gid']; + } + + return $ret; + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php index d6504d49d..857e19c67 100644 --- a/Zotlabs/Lib/Activity.php +++ b/Zotlabs/Lib/Activity.php @@ -23,1082 +23,1066 @@ require_once('include/html2bbcode.php'); require_once('include/html2plain.php'); require_once('include/event.php'); -class Activity { +class Activity +{ - static $ACTOR_CACHE_DAYS = 3; + static public $ACTOR_CACHE_DAYS = 3; - // $x (string|array) - // if json string, decode it - // returns activitystreams object as an array except if it is a URL - // which returns the URL as string - - static function encode_object($x) { + // $x (string|array) + // if json string, decode it + // returns activitystreams object as an array except if it is a URL + // which returns the URL as string - if ($x) { - if (is_string($x)) { - $tmp = json_decode($x,true); - if ($tmp !== NULL) { - $x = $tmp; - } - } - } + public static function encode_object($x) + { - if (is_string($x)) { - return ($x); - } - - if ($x['type'] === ACTIVITY_OBJ_PERSON) { - return self::fetch_person($x); - } - if ($x['type'] === ACTIVITY_OBJ_PROFILE) { - return self::fetch_profile($x); - } - if (in_array($x['type'], [ ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE ] )) { - - // Use Mastodon-specific note and media hacks if nomadic. Else HTML. - // Eventually this needs to be passed in much further up the stack - // and base the decision on whether or not we are encoding for ActivityPub or Zot6 - - return self::fetch_item($x,((get_config('system','activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); - } - if ($x['type'] === ACTIVITY_OBJ_THING) { - return self::fetch_thing($x); - } - - call_hooks('encode_object',$x); - - return $x; - - } - - - - static function fetch($url,$channel = null,$hub = null,$debug = false) { - $redirects = 0; - if (! check_siteallowed($url)) { - logger('denied: ' . $url); - return null; - } - if (! $channel) { - $channel = get_sys_channel(); - } - - $parsed = parse_url($url); - - // perform IDN substitution - - if ($parsed['host'] !== punify($parsed['host'])) { - $url = str_replace($parsed['host'],punify($parsed['host']),$url); - } - - logger('fetch: ' . $url, LOGGER_DEBUG); - - if (isset($parsed['scheme']) && $parsed['scheme'] === 'x-zot') { - $x = ZotURL::fetch($url,$channel,$hub); - } - else { - // handle bearcaps - if (isset($parsed['scheme']) && isset($parsed['query']) && $parsed['scheme'] === 'bear' && $parsed['query'] !== EMPTY_STR) { - $params = explode('&', $parsed['query']); - if ($params) { - foreach ($params as $p) { - if (substr($p,0,2) === 'u=') { - $url = substr($p,2); - } - if (substr($p,0,2) === 't=') { - $token = substr($p,2); - } - } - // the entire URL just changed so parse it again - $parsed = parse_url($url); - } - } - - // Ignore fragments; as we are not in a browser and some platforms (e.g. Django or at least funkwhale) don't handle them well - unset($parsed['fragment']); - - // rebuild the url - $url = unparse_url($parsed); - - logger('fetch_actual: ' . $url, LOGGER_DEBUG); - - $headers = [ - 'Accept' => 'application/activity+json, application/x-zot-activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', - 'Host' => $parsed['host'], - 'Date' => datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'), - '(request-target)' => 'get ' . get_request_string($url) - ]; - - if (isset($token)) { - $headers['Authorization'] = 'Bearer ' . $token; - } - $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); - $x = z_fetch_url($url, true, $redirects, [ 'headers' => $h ] ); - } - - if ($x['success']) { - - $y = json_decode($x['body'],true); - logger('returned: ' . json_encode($y,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)); - - $site_url = unparse_url( ['scheme' => $parsed['scheme'], 'host' => $parsed['host'], 'port' => ((array_key_exists('port',$parsed) && intval($parsed['port'])) ? $parsed['port'] : 0) ] ); - q("update site set site_update = '%s' where site_url = '%s' and site_update < %s - INTERVAL %s", - dbesc(datetime_convert()), - dbesc($site_url), - db_utcnow(), db_quoteinterval('1 DAY') - ); - - // check for a valid signature, but only if this is not an actor object. If it is signed, it must be valid. - // Ignore actors because of the potential for infinite recursion if we perform this step while - // fetching an actor key to validate a signature elsewhere. This should validate relayed activities - // over litepub which arrived at our inbox that do not use LD signatures - - if (($y['type']) && (! ActivityStreams::is_an_actor($y['type']))) { - $sigblock = HTTPSig::verify($x); - - if (($sigblock['header_signed']) && (! $sigblock['header_valid'])) { - return null; - } - } - - return json_decode($x['body'], true); - } - else { - logger('fetch failed: ' . $url); - if ($debug) { - return $x; - } - } - return null; - } - - - - static function fetch_person($x) { - return self::fetch_profile($x); - } - - static function fetch_profile($x) { - $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1", - dbesc($x['id']) - ); - if (! $r) { - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($x['id']) - ); - - } - if (! $r) { - return []; - } - - return self::encode_person($r[0],false); - } - - static function fetch_thing($x) { - - $r = q("select * from obj where obj_type = %d and obj_obj = '%s' limit 1", - intval(TERM_OBJ_THING), - dbesc($x['id']) - ); - - if (! $r) { - return []; - } - - $x = [ - 'type' => 'Object', - 'id' => z_root() . '/thing/' . $r[0]['obj_obj'], - 'name' => $r[0]['obj_term'] - ]; - - if ($r[0]['obj_image']) { - $x['image'] = $r[0]['obj_image']; - } - return $x; - - } - - static function fetch_item($x,$activitypub = false) { - - if (array_key_exists('source',$x)) { - // This item is already processed and encoded - return $x; - } - - $r = q("select * from item where mid = '%s' limit 1", - dbesc($x['id']) - ); - if ($r) { - xchan_query($r,true); - $r = fetch_post_tags($r,true); - if ($r[0]['verb'] === 'Invite') { - return self::encode_activity($r[0],$activitypub); - } - return self::encode_item($r[0],$activitypub); - } - } - - static function paged_collection_init($total,$id, $type = 'OrderedCollection') { - - $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type, - 'totalItems' => $total, - ]; - - $numpages = $total / App::$pager['itemspage']; - $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); - - $ret['first'] = z_root() . '/' . App::$query_string . '?page=1'; - $ret['last'] = z_root() . '/' . App::$query_string . '?page=' . $lastpage; - - return $ret; - - } - - - static function encode_item_collection($items,$id,$type,$activitypub = false,$total = 0) { - - if ($total > 100) { - $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type . 'Page', - ]; - - $numpages = $total / App::$pager['itemspage']; - $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); - - $url_parts = parse_url($id); - - $ret['partOf'] = z_root() . '/' . $url_parts['path']; - - $extra_query_args = ''; - $query_args = null; - if (isset($url_parts['query'])) { - parse_str($url_parts['query'], $query_args); - } - - if (is_array($query_args)) { - unset($query_args['page']); - foreach ($query_args as $k => $v) { - $extra_query_args .= '&' . urlencode($k) . '=' . urlencode($v); - } - } - - if (App::$pager['page'] < $lastpage) { - $ret['next'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) + 1) . $extra_query_args; - } - if (App::$pager['page'] > 1) { - $ret['prev'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) - 1) . $extra_query_args; - } - } - else { - $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type, - 'totalItems' => $total, - ]; - } - - - if ($items) { - $x = []; - foreach ($items as $i) { - $m = get_iconfig($i['id'],'activitypub','rawmsg'); - if ($m) { - $t = json_decode($m,true); - } - else { - $t = self::encode_activity($i,$activitypub); - } - if ($t) { - $x[] = $t; - } - } - if ($type === 'OrderedCollection') { - $ret['orderedItems'] = $x; - } - else { - $ret['items'] = $x; - } - } - - return $ret; - } - - static function encode_follow_collection($items,$id,$type,$total = 0,$extra = null) { - - if ($total > 100) { - $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type . 'Page', - ]; - - $numpages = $total / App::$pager['itemspage']; - $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); - - $stripped = preg_replace('/([&|\?]page=[0-9]*)/','',$id); - $stripped = rtrim($stripped,'/'); - - $ret['partOf'] = z_root() . '/' . $stripped; - - if (App::$pager['page'] < $lastpage) { - $ret['next'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) + 1); - } - if (App::$pager['page'] > 1) { - $ret['prev'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) - 1); - } - } - else { - $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type, - 'totalItems' => $total, - ]; - } - - if ($extra) { - $ret = array_merge($ret,$extra); - } - - if ($items) { - $x = []; - foreach ($items as $i) { - if ($i['xchan_network'] === 'activitypub') { - $x[] = $i['xchan_hash']; - } - else { - $x[] = $i['xchan_url']; - } - } - - if ($type === 'OrderedCollection') { - $ret['orderedItems'] = $x; - } - else { - $ret['items'] = $x; - } - } - - return $ret; - } - - - - static function encode_simple_collection($items,$id,$type,$total = 0,$extra = null) { - - $ret = [ - 'id' => z_root() . '/' . $id, - 'type' => $type, - 'totalItems' => $total, - ]; - - if ($extra) { - $ret = array_merge($ret,$extra); - } - - if ($items) { - if ($type === 'OrderedCollection') { - $ret['orderedItems'] = $items; - } - else { - $ret['items'] = $items; - } - } - - return $ret; - } - - - - - - static function decode_taxonomy($item) { - - $ret = []; - - if (array_key_exists('tag',$item) && is_array($item['tag'])) { - $ptr = $item['tag']; - if (! array_key_exists(0,$ptr)) { - $ptr = [ $ptr ]; - } - foreach ($ptr as $t) { - if (! is_array($t)) { - continue; - } - if (! array_key_exists('type',$t)) { - $t['type'] = 'Hashtag'; - } - if (! (array_key_exists('name',$t))) { - continue; - } - if (! (array_path_exists('icon/url',$t) || array_key_exists('href',$t))) { - continue; - } - - switch($t['type']) { - case 'Hashtag': - $ret[] = [ 'ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']) ]; - break; - - case 'topicalCollection': - $ret[] = [ 'ttype' => TERM_PCATEGORY, 'url' => $t['href'], 'term' => escape_tags($t['name']) ]; - break; - - case 'Category': - $ret[] = [ 'ttype' => TERM_CATEGORY, 'url' => $t['href'], 'term' => escape_tags($t['name']) ]; - break; - - case 'Mention': - $mention_type = substr($t['name'],0,1); - if ($mention_type === '!') { - $ret[] = [ 'ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'],1)) ]; - } - else { - $ret[] = [ 'ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'],0,1) === '@') ? substr($t['name'],1) : $t['name']) ]; - } - break; - - case 'Emoji': - $ret[] = [ 'ttype' => TERM_EMOJI, 'url' => $t['icon']['url'], 'term' => escape_tags($t['name']) ]; - break; - - default: - break; - } - } - } - - return $ret; - } - - - static function encode_taxonomy($item) { - - $ret = []; - - if (isset($item['term']) && is_array($item['term']) && $item['term']) { - foreach ($item['term'] as $t) { - switch($t['ttype']) { - case TERM_HASHTAG: - // An id is required so if we don't have a url in the taxonomy, ignore it and keep going. - if ($t['url']) { - $ret[] = [ 'id' => $t['url'], 'name' => '#' . $t['term'] ]; - } - break; - - case TERM_PCATEGORY: - if ($t['url'] && $t['term']) { - $ret[] = [ 'type' => 'topicalCollection', 'href' => $t['url'], 'name' => $t['term'] ]; - } - break; - - case TERM_CATEGORY: - if ($t['url'] && $t['term']) { - $ret[] = [ 'type' => 'Category', 'href' => $t['url'], 'name' => $t['term'] ]; - } - break; - - case TERM_FORUM: - $term = self::lookup_term_addr($t['url'],$t['term']); - $ret[] = [ 'type' => 'Mention', 'href' => $t['url'], 'name' => '!' . (($term) ? $term : $t['term']) ]; - break; - - case TERM_MENTION: - $term = self::lookup_term_addr($t['url'],$t['term']); - $ret[] = [ 'type' => 'Mention', 'href' => $t['url'], 'name' => '@' . (($term) ? $term : $t['term']) ]; - break; - - default: - break; - } - } - } - - return $ret; - } - - - static function lookup_term_addr($url,$name) { - - // The visible mention in our activities is always the full name. - // In the object taxonomy change this to the webfinger handle in case - // platforms expect the Mastodon form in order to generate notifications - // Try a couple of different things in case the url provided isn't the canonical id. - // If all else fails, try to match the name. - - $r = false; - - if ($url) { - $r = q("select xchan_addr from xchan where ( xchan_url = '%s' OR xchan_hash = '%s' ) limit 1", - dbesc($url), - dbesc($url) - ); - - if ($r) { - return $r[0]['xchan_addr']; - } - } - if ($name) { - $r = q("select xchan_addr from xchan where xchan_name = '%s' limit 1", - dbesc($name) - ); - if ($r) { - return $r[0]['xchan_addr']; - } - - } - - return EMPTY_STR; - } - - - - static function lookup_term_url($url) { - - // The xchan_url for mastodon is a text/html rendering. This is called from map_mentions where we need - // to convert the mention url to an ActivityPub id. If this fails for any reason, return the url we have - - $r = q("select * from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", - dbesc($url), - dbesc($url) - ); - - if ($r) { - if ($r[0]['hubloc_network'] === 'activitypub') { - return $r[0]['hubloc_hash']; - } - return $r[0]['hubloc_id_url']; - } - - return $url; - } - - - static function encode_attachment($item) { - - $ret = []; - - if (array_key_exists('attach',$item)) { - $atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'],true)); - if ($atts) { - foreach ($atts as $att) { - if (strpos($att['type'],'image')) { - $ret[] = [ 'type' => 'Image', 'url' => $att['href'] ]; - } - else { - $ret[] = [ 'type' => 'Link', 'mediaType' => $att['type'], 'href' => $att['href'] ]; - } - } - } - } - if (array_key_exists('iconfig',$item) && is_array($item['iconfig'])) { - foreach ($item['iconfig'] as $att) { - if ($att['sharing']) { - $ret[] = [ 'type' => 'PropertyValue', 'name' => 'zot.' . $att['cat'] . '.' . $att['k'], 'value' => unserialise($att['v']) ]; - } - } - } - - return $ret; - } - - - static function decode_iconfig($item) { - - $ret = []; - - if (is_array($item['attachment']) && $item['attachment']) { - $ptr = $item['attachment']; - if (! array_key_exists(0,$ptr)) { - $ptr = [ $ptr ]; - } - foreach ($ptr as $att) { - $entry = []; - if ($att['type'] === 'PropertyValue') { - if (array_key_exists('name',$att) && $att['name']) { - $key = explode('.',$att['name']); - if (count($key) === 3 && $key[0] === 'zot') { - $entry['cat'] = $key[1]; - $entry['k'] = $key[2]; - $entry['v'] = $att['value']; - $entry['sharing'] = '1'; - $ret[] = $entry; - } - } - } - } - } - return $ret; - } - - - - - static function decode_attachment($item) { - - $ret = []; - - if (array_key_exists('attachment',$item) && is_array($item['attachment'])) { - $ptr = $item['attachment']; - if (! array_key_exists(0,$ptr)) { - $ptr = [ $ptr ]; - } - foreach ($ptr as $att) { - $entry = []; - if (array_key_exists('href',$att) && $att['href']) - $entry['href'] = $att['href']; - elseif (array_key_exists('url',$att) && $att['url']) - $entry['href'] = $att['url']; - if (array_key_exists('mediaType',$att) && $att['mediaType']) - $entry['type'] = $att['mediaType']; - elseif (array_key_exists('type',$att) && $att['type'] === 'Image') - $entry['type'] = 'image/jpeg'; - if (array_key_exists('name',$att) && $att['name']) { - $entry['name'] = html2plain(purify_html($att['name']),256); - } - if ($entry) - $ret[] = $entry; - } - } - elseif (is_string($item['attachment'])) { - btlogger('not an array: ' . $item['attachment']); - } - - return $ret; - } - - - // the $recurse flag encodes the original non-deleted object of a deleted activity - - static function encode_activity($i,$activitypub = false,$recurse = false) { - - $ret = []; - $reply = false; - - if (intval($i['item_deleted']) && (! $recurse)) { - - $is_response = ActivityStreams::is_response_activity($i['verb']); - - if ($is_response) { - $ret['type'] = 'Undo'; - $fragment = '#undo'; - } - else { - $ret['type'] = 'Delete'; - $fragment = '#delete'; - } - - $ret['id'] = str_replace('/item/','/activity/',$i['mid']) . $fragment; - $actor = self::encode_person($i['author'],false); - if ($actor) - $ret['actor'] = $actor; - else - return []; - - $obj = (($is_response) ? self::encode_activity($i,$activitypub,true) : self::encode_item($i,$activitypub)); - if ($obj) { - if (array_path_exists('object/id',$obj)) { - $obj['object'] = $obj['object']['id']; - } - if ($obj) { - $ret['object'] = $obj; - } + if ($x) { + if (is_string($x)) { + $tmp = json_decode($x, true); + if ($tmp !== NULL) { + $x = $tmp; + } } - else { + } + + if (is_string($x)) { + return ($x); + } + + if ($x['type'] === ACTIVITY_OBJ_PERSON) { + return self::fetch_person($x); + } + if ($x['type'] === ACTIVITY_OBJ_PROFILE) { + return self::fetch_profile($x); + } + if (in_array($x['type'], [ACTIVITY_OBJ_NOTE, ACTIVITY_OBJ_ARTICLE])) { + + // Use Mastodon-specific note and media hacks if nomadic. Else HTML. + // Eventually this needs to be passed in much further up the stack + // and base the decision on whether or not we are encoding for ActivityPub or Zot6 + + return self::fetch_item($x, ((get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); + } + if ($x['type'] === ACTIVITY_OBJ_THING) { + return self::fetch_thing($x); + } + + call_hooks('encode_object', $x); + + return $x; + + } + + + public static function fetch($url, $channel = null, $hub = null, $debug = false) + { + $redirects = 0; + if (!check_siteallowed($url)) { + logger('denied: ' . $url); + return null; + } + if (!$channel) { + $channel = get_sys_channel(); + } + + $parsed = parse_url($url); + + // perform IDN substitution + + if ($parsed['host'] !== punify($parsed['host'])) { + $url = str_replace($parsed['host'], punify($parsed['host']), $url); + } + + logger('fetch: ' . $url, LOGGER_DEBUG); + + if (isset($parsed['scheme']) && $parsed['scheme'] === 'x-zot') { + $x = ZotURL::fetch($url, $channel, $hub); + } else { + // handle bearcaps + if (isset($parsed['scheme']) && isset($parsed['query']) && $parsed['scheme'] === 'bear' && $parsed['query'] !== EMPTY_STR) { + $params = explode('&', $parsed['query']); + if ($params) { + foreach ($params as $p) { + if (substr($p, 0, 2) === 'u=') { + $url = substr($p, 2); + } + if (substr($p, 0, 2) === 't=') { + $token = substr($p, 2); + } + } + // the entire URL just changed so parse it again + $parsed = parse_url($url); + } + } + + // Ignore fragments; as we are not in a browser and some platforms (e.g. Django or at least funkwhale) don't handle them well + unset($parsed['fragment']); + + // rebuild the url + $url = unparse_url($parsed); + + logger('fetch_actual: ' . $url, LOGGER_DEBUG); + + $headers = [ + 'Accept' => 'application/activity+json, application/x-zot-activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + 'Host' => $parsed['host'], + 'Date' => datetime_convert('UTC', 'UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'), + '(request-target)' => 'get ' . get_request_string($url) + ]; + + if (isset($token)) { + $headers['Authorization'] = 'Bearer ' . $token; + } + $h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), false); + $x = z_fetch_url($url, true, $redirects, ['headers' => $h]); + } + + if ($x['success']) { + + $y = json_decode($x['body'], true); + logger('returned: ' . json_encode($y, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)); + + $site_url = unparse_url(['scheme' => $parsed['scheme'], 'host' => $parsed['host'], 'port' => ((array_key_exists('port', $parsed) && intval($parsed['port'])) ? $parsed['port'] : 0)]); + q("update site set site_update = '%s' where site_url = '%s' and site_update < %s - INTERVAL %s", + dbesc(datetime_convert()), + dbesc($site_url), + db_utcnow(), db_quoteinterval('1 DAY') + ); + + // check for a valid signature, but only if this is not an actor object. If it is signed, it must be valid. + // Ignore actors because of the potential for infinite recursion if we perform this step while + // fetching an actor key to validate a signature elsewhere. This should validate relayed activities + // over litepub which arrived at our inbox that do not use LD signatures + + if (($y['type']) && (!ActivityStreams::is_an_actor($y['type']))) { + $sigblock = HTTPSig::verify($x); + + if (($sigblock['header_signed']) && (!$sigblock['header_valid'])) { + return null; + } + } + + return json_decode($x['body'], true); + } else { + logger('fetch failed: ' . $url); + if ($debug) { + return $x; + } + } + return null; + } + + + public static function fetch_person($x) + { + return self::fetch_profile($x); + } + + public static function fetch_profile($x) + { + $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' limit 1", + dbesc($x['id']) + ); + if (!$r) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($x['id']) + ); + + } + if (!$r) { + return []; + } + + return self::encode_person($r[0], false); + } + + public static function fetch_thing($x) + { + + $r = q("select * from obj where obj_type = %d and obj_obj = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($x['id']) + ); + + if (!$r) { + return []; + } + + $x = [ + 'type' => 'Object', + 'id' => z_root() . '/thing/' . $r[0]['obj_obj'], + 'name' => $r[0]['obj_term'] + ]; + + if ($r[0]['obj_image']) { + $x['image'] = $r[0]['obj_image']; + } + return $x; + + } + + public static function fetch_item($x, $activitypub = false) + { + + if (array_key_exists('source', $x)) { + // This item is already processed and encoded + return $x; + } + + $r = q("select * from item where mid = '%s' limit 1", + dbesc($x['id']) + ); + if ($r) { + xchan_query($r, true); + $r = fetch_post_tags($r, true); + if ($r[0]['verb'] === 'Invite') { + return self::encode_activity($r[0], $activitypub); + } + return self::encode_item($r[0], $activitypub); + } + } + + public static function paged_collection_init($total, $id, $type = 'OrderedCollection') + { + + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + + $ret['first'] = z_root() . '/' . App::$query_string . '?page=1'; + $ret['last'] = z_root() . '/' . App::$query_string . '?page=' . $lastpage; + + return $ret; + + } + + + public static function encode_item_collection($items, $id, $type, $activitypub = false, $total = 0) + { + + if ($total > 100) { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type . 'Page', + ]; + + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + + $url_parts = parse_url($id); + + $ret['partOf'] = z_root() . '/' . $url_parts['path']; + + $extra_query_args = ''; + $query_args = null; + if (isset($url_parts['query'])) { + parse_str($url_parts['query'], $query_args); + } + + if (is_array($query_args)) { + unset($query_args['page']); + foreach ($query_args as $k => $v) { + $extra_query_args .= '&' . urlencode($k) . '=' . urlencode($v); + } + } + + if (App::$pager['page'] < $lastpage) { + $ret['next'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) + 1) . $extra_query_args; + } + if (App::$pager['page'] > 1) { + $ret['prev'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) - 1) . $extra_query_args; + } + } else { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + } + + + if ($items) { + $x = []; + foreach ($items as $i) { + $m = get_iconfig($i['id'], 'activitypub', 'rawmsg'); + if ($m) { + $t = json_decode($m, true); + } else { + $t = self::encode_activity($i, $activitypub); + } + if ($t) { + $x[] = $t; + } + } + if ($type === 'OrderedCollection') { + $ret['orderedItems'] = $x; + } else { + $ret['items'] = $x; + } + } + + return $ret; + } + + public static function encode_follow_collection($items, $id, $type, $total = 0, $extra = null) + { + + if ($total > 100) { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type . 'Page', + ]; + + $numpages = $total / App::$pager['itemspage']; + $lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages); + + $stripped = preg_replace('/([&|\?]page=[0-9]*)/', '', $id); + $stripped = rtrim($stripped, '/'); + + $ret['partOf'] = z_root() . '/' . $stripped; + + if (App::$pager['page'] < $lastpage) { + $ret['next'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) + 1); + } + if (App::$pager['page'] > 1) { + $ret['prev'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) - 1); + } + } else { + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + } + + if ($extra) { + $ret = array_merge($ret, $extra); + } + + if ($items) { + $x = []; + foreach ($items as $i) { + if ($i['xchan_network'] === 'activitypub') { + $x[] = $i['xchan_hash']; + } else { + $x[] = $i['xchan_url']; + } + } + + if ($type === 'OrderedCollection') { + $ret['orderedItems'] = $x; + } else { + $ret['items'] = $x; + } + } + + return $ret; + } + + + public static function encode_simple_collection($items, $id, $type, $total = 0, $extra = null) + { + + $ret = [ + 'id' => z_root() . '/' . $id, + 'type' => $type, + 'totalItems' => $total, + ]; + + if ($extra) { + $ret = array_merge($ret, $extra); + } + + if ($items) { + if ($type === 'OrderedCollection') { + $ret['orderedItems'] = $items; + } else { + $ret['items'] = $items; + } + } + + return $ret; + } + + + public static function decode_taxonomy($item) + { + + $ret = []; + + if (array_key_exists('tag', $item) && is_array($item['tag'])) { + $ptr = $item['tag']; + if (!array_key_exists(0, $ptr)) { + $ptr = [$ptr]; + } + foreach ($ptr as $t) { + if (!is_array($t)) { + continue; + } + if (!array_key_exists('type', $t)) { + $t['type'] = 'Hashtag'; + } + if (!(array_key_exists('name', $t))) { + continue; + } + if (!(array_path_exists('icon/url', $t) || array_key_exists('href', $t))) { + continue; + } + + switch ($t['type']) { + case 'Hashtag': + $ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])]; + break; + + case 'topicalCollection': + $ret[] = ['ttype' => TERM_PCATEGORY, 'url' => $t['href'], 'term' => escape_tags($t['name'])]; + break; + + case 'Category': + $ret[] = ['ttype' => TERM_CATEGORY, 'url' => $t['href'], 'term' => escape_tags($t['name'])]; + break; + + case 'Mention': + $mention_type = substr($t['name'], 0, 1); + if ($mention_type === '!') { + $ret[] = ['ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'], 1))]; + } else { + $ret[] = ['ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '@') ? substr($t['name'], 1) : $t['name'])]; + } + break; + + case 'Emoji': + $ret[] = ['ttype' => TERM_EMOJI, 'url' => $t['icon']['url'], 'term' => escape_tags($t['name'])]; + break; + + default: + break; + } + } + } + + return $ret; + } + + + public static function encode_taxonomy($item) + { + + $ret = []; + + if (isset($item['term']) && is_array($item['term']) && $item['term']) { + foreach ($item['term'] as $t) { + switch ($t['ttype']) { + case TERM_HASHTAG: + // An id is required so if we don't have a url in the taxonomy, ignore it and keep going. + if ($t['url']) { + $ret[] = ['id' => $t['url'], 'name' => '#' . $t['term']]; + } + break; + + case TERM_PCATEGORY: + if ($t['url'] && $t['term']) { + $ret[] = ['type' => 'topicalCollection', 'href' => $t['url'], 'name' => $t['term']]; + } + break; + + case TERM_CATEGORY: + if ($t['url'] && $t['term']) { + $ret[] = ['type' => 'Category', 'href' => $t['url'], 'name' => $t['term']]; + } + break; + + case TERM_FORUM: + $term = self::lookup_term_addr($t['url'], $t['term']); + $ret[] = ['type' => 'Mention', 'href' => $t['url'], 'name' => '!' . (($term) ? $term : $t['term'])]; + break; + + case TERM_MENTION: + $term = self::lookup_term_addr($t['url'], $t['term']); + $ret[] = ['type' => 'Mention', 'href' => $t['url'], 'name' => '@' . (($term) ? $term : $t['term'])]; + break; + + default: + break; + } + } + } + + return $ret; + } + + + public static function lookup_term_addr($url, $name) + { + + // The visible mention in our activities is always the full name. + // In the object taxonomy change this to the webfinger handle in case + // platforms expect the Mastodon form in order to generate notifications + // Try a couple of different things in case the url provided isn't the canonical id. + // If all else fails, try to match the name. + + $r = false; + + if ($url) { + $r = q("select xchan_addr from xchan where ( xchan_url = '%s' OR xchan_hash = '%s' ) limit 1", + dbesc($url), + dbesc($url) + ); + + if ($r) { + return $r[0]['xchan_addr']; + } + } + if ($name) { + $r = q("select xchan_addr from xchan where xchan_name = '%s' limit 1", + dbesc($name) + ); + if ($r) { + return $r[0]['xchan_addr']; + } + + } + + return EMPTY_STR; + } + + + public static function lookup_term_url($url) + { + + // The xchan_url for mastodon is a text/html rendering. This is called from map_mentions where we need + // to convert the mention url to an ActivityPub id. If this fails for any reason, return the url we have + + $r = q("select * from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", + dbesc($url), + dbesc($url) + ); + + if ($r) { + if ($r[0]['hubloc_network'] === 'activitypub') { + return $r[0]['hubloc_hash']; + } + return $r[0]['hubloc_id_url']; + } + + return $url; + } + + + public static function encode_attachment($item) + { + + $ret = []; + + if (array_key_exists('attach', $item)) { + $atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true)); + if ($atts) { + foreach ($atts as $att) { + if (strpos($att['type'], 'image')) { + $ret[] = ['type' => 'Image', 'url' => $att['href']]; + } else { + $ret[] = ['type' => 'Link', 'mediaType' => $att['type'], 'href' => $att['href']]; + } + } + } + } + if (array_key_exists('iconfig', $item) && is_array($item['iconfig'])) { + foreach ($item['iconfig'] as $att) { + if ($att['sharing']) { + $ret[] = ['type' => 'PropertyValue', 'name' => 'zot.' . $att['cat'] . '.' . $att['k'], 'value' => unserialise($att['v'])]; + } + } + } + + return $ret; + } + + + public static function decode_iconfig($item) + { + + $ret = []; + + if (is_array($item['attachment']) && $item['attachment']) { + $ptr = $item['attachment']; + if (!array_key_exists(0, $ptr)) { + $ptr = [$ptr]; + } + foreach ($ptr as $att) { + $entry = []; + if ($att['type'] === 'PropertyValue') { + if (array_key_exists('name', $att) && $att['name']) { + $key = explode('.', $att['name']); + if (count($key) === 3 && $key[0] === 'zot') { + $entry['cat'] = $key[1]; + $entry['k'] = $key[2]; + $entry['v'] = $att['value']; + $entry['sharing'] = '1'; + $ret[] = $entry; + } + } + } + } + } + return $ret; + } + + + public static function decode_attachment($item) + { + + $ret = []; + + if (array_key_exists('attachment', $item) && is_array($item['attachment'])) { + $ptr = $item['attachment']; + if (!array_key_exists(0, $ptr)) { + $ptr = [$ptr]; + } + foreach ($ptr as $att) { + $entry = []; + if (array_key_exists('href', $att) && $att['href']) + $entry['href'] = $att['href']; + elseif (array_key_exists('url', $att) && $att['url']) + $entry['href'] = $att['url']; + if (array_key_exists('mediaType', $att) && $att['mediaType']) + $entry['type'] = $att['mediaType']; + elseif (array_key_exists('type', $att) && $att['type'] === 'Image') + $entry['type'] = 'image/jpeg'; + if (array_key_exists('name', $att) && $att['name']) { + $entry['name'] = html2plain(purify_html($att['name']), 256); + } + if ($entry) + $ret[] = $entry; + } + } elseif (is_string($item['attachment'])) { + btlogger('not an array: ' . $item['attachment']); + } + + return $ret; + } + + + // the $recurse flag encodes the original non-deleted object of a deleted activity + + public static function encode_activity($i, $activitypub = false, $recurse = false) + { + + $ret = []; + $reply = false; + + if (intval($i['item_deleted']) && (!$recurse)) { + + $is_response = ActivityStreams::is_response_activity($i['verb']); + + if ($is_response) { + $ret['type'] = 'Undo'; + $fragment = '#undo'; + } else { + $ret['type'] = 'Delete'; + $fragment = '#delete'; + } + + $ret['id'] = str_replace('/item/', '/activity/', $i['mid']) . $fragment; + $actor = self::encode_person($i['author'], false); + if ($actor) + $ret['actor'] = $actor; + else return []; - } - - $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; - return $ret; - } + $obj = (($is_response) ? self::encode_activity($i, $activitypub, true) : self::encode_item($i, $activitypub)); + if ($obj) { + if (array_path_exists('object/id', $obj)) { + $obj['object'] = $obj['object']['id']; + } + if ($obj) { + $ret['object'] = $obj; + } + } else { + return []; + } - $ret['type'] = self::activity_mapper($i['verb']); + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; + return $ret; - if (strpos($i['mid'],z_root() . '/item/') !== false) { - $ret['id'] = str_replace('/item/','/activity/',$i['mid']); - } - elseif (strpos($i['mid'],z_root() . '/event/') !== false) { - $ret['id'] = str_replace('/event/','/activity/',$i['mid']); - } - else { - $ret['id'] = $i['mid']; - } + } - if ($i['title']) { - $ret['name'] = $i['title']; - } + $ret['type'] = self::activity_mapper($i['verb']); - if ($i['summary']) { - $ret['summary'] = bbcode($i['summary'], [ 'export' => true ]); - } + if (strpos($i['mid'], z_root() . '/item/') !== false) { + $ret['id'] = str_replace('/item/', '/activity/', $i['mid']); + } elseif (strpos($i['mid'], z_root() . '/event/') !== false) { + $ret['id'] = str_replace('/event/', '/activity/', $i['mid']); + } else { + $ret['id'] = $i['mid']; + } - if ($ret['type'] === 'Announce') { - $tmp = $i['body']; - $ret['content'] = bbcode($tmp, [ 'export' => true ]); - $ret['source'] = [ - 'content' => $i['body'], - 'mediaType' => 'text/bbcode' - ]; - if ($i['summary']) { - $ret['source']['summary'] = $i['summary']; - } - } + if ($i['title']) { + $ret['name'] = $i['title']; + } - $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); - if ($i['created'] !== $i['edited']) { - $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME); - if ($ret['type'] === 'Create') { - $ret['type'] = 'Update'; - } - } - if ($i['app']) { - $ret['generator'] = [ 'type' => 'Application', 'name' => $i['app'] ]; - } - if ($i['location'] || $i['coord']) { - $ret['location'] = [ 'type' => 'Place' ]; - if ($i['location']) { - $ret['location']['name'] = $i['location']; - } - if ($i['coord']) { - $l = explode(' ',$i['coord']); - $ret['location']['latitude'] = $l[0]; - $ret['location']['longitude'] = $l[1]; - } - } + if ($i['summary']) { + $ret['summary'] = bbcode($i['summary'], ['export' => true]); + } - if ($i['mid'] !== $i['parent_mid']) { - $reply = true; + if ($ret['type'] === 'Announce') { + $tmp = $i['body']; + $ret['content'] = bbcode($tmp, ['export' => true]); + $ret['source'] = [ + 'content' => $i['body'], + 'mediaType' => 'text/bbcode' + ]; + if ($i['summary']) { + $ret['source']['summary'] = $i['summary']; + } + } - // inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.), - // but *not* for comments and RSVPs, where it should only be present in the object - - if (! in_array($ret['type'],[ 'Create','Update','Accept','Reject','TentativeAccept','TentativeReject' ])) { - $ret['inReplyTo'] = $i['thr_parent']; - $cnv = get_iconfig($i['parent'],'activitypub','context'); - if (! $cnv) { - $cnv = get_iconfig($i['parent'],'ostatus','conversation'); - } - if (! $cnv) { - $cnv = $ret['parent_mid']; - } - } - } + $ret['published'] = datetime_convert('UTC', 'UTC', $i['created'], ATOM_TIME); + if ($i['created'] !== $i['edited']) { + $ret['updated'] = datetime_convert('UTC', 'UTC', $i['edited'], ATOM_TIME); + if ($ret['type'] === 'Create') { + $ret['type'] = 'Update'; + } + } + if ($i['app']) { + $ret['generator'] = ['type' => 'Application', 'name' => $i['app']]; + } + if ($i['location'] || $i['coord']) { + $ret['location'] = ['type' => 'Place']; + if ($i['location']) { + $ret['location']['name'] = $i['location']; + } + if ($i['coord']) { + $l = explode(' ', $i['coord']); + $ret['location']['latitude'] = $l[0]; + $ret['location']['longitude'] = $l[1]; + } + } - if (! (isset($cnv) && $cnv)) { - $cnv = get_iconfig($i,'activitypub','context'); - if (! $cnv) { - $cnv = get_iconfig($i,'ostatus','conversation'); - } - if (! $cnv) { - $cnv = $i['parent_mid']; - } - } - if (isset($cnv) && $cnv) { - if (strpos($cnv,z_root()) === 0) { - $cnv = str_replace(['/item/','/activity/'],[ '/conversation/', '/conversation/' ], $cnv); - } - $ret['context'] = $cnv; - $ret['conversation'] = $cnv; - } - - if (intval($i['item_private']) === 2) { - $ret['directMessage'] = true; - } + if ($i['mid'] !== $i['parent_mid']) { + $reply = true; - $actor = self::encode_person($i['author'],false); - if ($actor) - $ret['actor'] = $actor; - else - return []; + // inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.), + // but *not* for comments and RSVPs, where it should only be present in the object - - $replyto = unserialise($i['replyto']); - if ($replyto) { - $ret['replyTo'] = $replyto; - } + if (!in_array($ret['type'], ['Create', 'Update', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) { + $ret['inReplyTo'] = $i['thr_parent']; + $cnv = get_iconfig($i['parent'], 'activitypub', 'context'); + if (!$cnv) { + $cnv = get_iconfig($i['parent'], 'ostatus', 'conversation'); + } + if (!$cnv) { + $cnv = $ret['parent_mid']; + } + } + } + + if (!(isset($cnv) && $cnv)) { + $cnv = get_iconfig($i, 'activitypub', 'context'); + if (!$cnv) { + $cnv = get_iconfig($i, 'ostatus', 'conversation'); + } + if (!$cnv) { + $cnv = $i['parent_mid']; + } + } + if (isset($cnv) && $cnv) { + if (strpos($cnv, z_root()) === 0) { + $cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv); + } + $ret['context'] = $cnv; + $ret['conversation'] = $cnv; + } + + if (intval($i['item_private']) === 2) { + $ret['directMessage'] = true; + } + + $actor = self::encode_person($i['author'], false); + if ($actor) + $ret['actor'] = $actor; + else + return []; + $replyto = unserialise($i['replyto']); + if ($replyto) { + $ret['replyTo'] = $replyto; + } - if (! isset($ret['url'])) { - $urls = []; - if (intval($i['item_wall'])) { - $locs = self::nomadic_locations($i); - if ($locs) { - foreach ($locs as $l) { - if (strpos($ret['id'],$l['hubloc_url']) !== false) { - continue; - } - $urls[] = [ - 'type' => 'Link', - 'href' => str_replace(z_root(),$l['hubloc_url'],$ret['id']), - 'rel' => 'alternate', - 'mediaType' => 'text/html' - ]; - $urls[] = [ - 'type' => 'Link', - 'href' => str_replace(z_root(),$l['hubloc_url'],$ret['id']), - 'rel' => 'alternate', - 'mediaType' => 'application/activity+json' - ]; - $urls[] = [ - 'type' => 'Link', - 'href' => str_replace(z_root(),$l['hubloc_url'],$ret['id']), - 'rel' => 'alternate', - 'mediaType' => 'application/x-zot+json' - ]; - } - } - } - if ($urls) { - $curr[] = [ - 'type' => 'Link', - 'href' => $ret['id'], - 'rel' => 'alternate', - 'mediaType' => 'text/html' - ]; - $ret['url'] = array_merge($curr, $urls); - } - else { - $ret['url'] = $ret['id']; - } - } + if (!isset($ret['url'])) { + $urls = []; + if (intval($i['item_wall'])) { + $locs = self::nomadic_locations($i); + if ($locs) { + foreach ($locs as $l) { + if (strpos($ret['id'], $l['hubloc_url']) !== false) { + continue; + } + $urls[] = [ + 'type' => 'Link', + 'href' => str_replace(z_root(), $l['hubloc_url'], $ret['id']), + 'rel' => 'alternate', + 'mediaType' => 'text/html' + ]; + $urls[] = [ + 'type' => 'Link', + 'href' => str_replace(z_root(), $l['hubloc_url'], $ret['id']), + 'rel' => 'alternate', + 'mediaType' => 'application/activity+json' + ]; + $urls[] = [ + 'type' => 'Link', + 'href' => str_replace(z_root(), $l['hubloc_url'], $ret['id']), + 'rel' => 'alternate', + 'mediaType' => 'application/x-zot+json' + ]; + } + } + } + if ($urls) { + $curr[] = [ + 'type' => 'Link', + 'href' => $ret['id'], + 'rel' => 'alternate', + 'mediaType' => 'text/html' + ]; + $ret['url'] = array_merge($curr, $urls); + } else { + $ret['url'] = $ret['id']; + } + } - if ($i['obj']) { - if (is_string($i['obj'])) { - $tmp = json_decode($i['obj'],true); - if ($tmp !== NULL) { - $i['obj'] = $tmp; - } - } - $obj = self::encode_object($i['obj']); - if ($obj) - $ret['object'] = $obj; - else - return []; - } - else { - $obj = self::encode_item($i,$activitypub); - if ($obj) { - $ret['object'] = $obj; - } - else { - return []; - } - } + if ($i['obj']) { + if (is_string($i['obj'])) { + $tmp = json_decode($i['obj'], true); + if ($tmp !== NULL) { + $i['obj'] = $tmp; + } + } + $obj = self::encode_object($i['obj']); + if ($obj) + $ret['object'] = $obj; + else + return []; + } else { + $obj = self::encode_item($i, $activitypub); + if ($obj) { + $ret['object'] = $obj; + } else { + return []; + } + } - if ($i['target']) { - if (is_string($i['target'])) { - $tmp = json_decode($i['target'],true); - if ($tmp !== NULL) { - $i['target'] = $tmp; - } - } - $tgt = self::encode_object($i['target']); - if ($tgt) { - $ret['target'] = $tgt; - } - } + if ($i['target']) { + if (is_string($i['target'])) { + $tmp = json_decode($i['target'], true); + if ($tmp !== NULL) { + $i['target'] = $tmp; + } + } + $tgt = self::encode_object($i['target']); + if ($tgt) { + $ret['target'] = $tgt; + } + } - $t = self::encode_taxonomy($i); - if ($t) { - $ret['tag'] = $t; - } + $t = self::encode_taxonomy($i); + if ($t) { + $ret['tag'] = $t; + } - // addressing madness - - if ($activitypub) { + // addressing madness - $parent_i = []; - $public = (($i['item_private']) ? false : true); - $top_level = (($reply) ? false : true); - $ret['to'] = []; - $ret['cc'] = []; + if ($activitypub) { - if (! $top_level) { - $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); - if ($recips) { - $parent_i['to'] = $recips['to']; - $parent_i['cc'] = $recips['cc']; - } - } + $parent_i = []; + $public = (($i['item_private']) ? false : true); + $top_level = (($reply) ? false : true); + $ret['to'] = []; + $ret['cc'] = []; - if ($public) { - $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; - if (isset($parent_i['to']) && is_array($parent_i['to'])) { - $ret['to'] = array_values(array_unique(array_merge($ret['to'],$parent_i['to']))); - } - if ($i['item_origin']) { - $ret['cc'] = [ z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')) ]; - } - if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { - $ret['cc'] = array_values(array_unique(array_merge($ret['cc'],$parent_i['cc']))); - } - } - else { - - // private activity - - if ($top_level) { - $ret['to'] = self::map_acl($i); - if (isset($parent_i['to']) && is_array($parent_i['to'])) { - $ret['to'] = array_values(array_unique(array_merge($ret['to'],$parent_i['to']))); - } - } - else { - $ret['cc'] = self::map_acl($i); - if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { - $ret['cc'] = array_values(array_unique(array_merge($ret['cc'],$parent_i['cc']))); - } + if (!$top_level) { + $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); + if ($recips) { + $parent_i['to'] = $recips['to']; + $parent_i['cc'] = $recips['cc']; + } + } - if ($ret['tag']) { - foreach ($ret['tag'] as $mention) { - if (is_array($mention) && array_key_exists('ttype',$mention) && in_array($mention['ttype'],[ TERM_FORUM, TERM_MENTION]) && array_key_exists('href',$mention) && $mention['href']) { - $h = q("select * from hubloc where hubloc_id_url = '%s' limit 1", - dbesc($mention['href']) - ); - if ($h) { - if ($h[0]['hubloc_network'] === 'activitypub') { - $addr = $h[0]['hubloc_hash']; - } - else { - $addr = $h[0]['hubloc_id_url']; - } - if (! in_array($addr,$ret['to'])) { - $ret['to'][] = $addr; - } - } - } - } - } + if ($public) { + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; + if (isset($parent_i['to']) && is_array($parent_i['to'])) { + $ret['to'] = array_values(array_unique(array_merge($ret['to'], $parent_i['to']))); + } + if ($i['item_origin']) { + $ret['cc'] = [z_root() . '/followers/' . substr($i['author']['xchan_addr'], 0, strpos($i['author']['xchan_addr'], '@'))]; + } + if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { + $ret['cc'] = array_values(array_unique(array_merge($ret['cc'], $parent_i['cc']))); + } + } else { - $d = q("select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d limit 1", - dbesc($i['parent_mid']), - intval($i['uid']) - ); - if ($d) { - if ($d[0]['hubloc_network'] === 'activitypub') { - $addr = $d[0]['hubloc_hash']; - } - else { - $addr = $d[0]['hubloc_id_url']; - } - $ret['cc'][] = $addr; - } - } - } + // private activity - $mentions = self::map_mentions($i); - if (count($mentions) > 0) { - if (! $ret['to']) { - $ret['to'] = $mentions; - } - else { - $ret['to'] = array_values(array_unique(array_merge($ret['to'], $mentions))); - } - } - } + if ($top_level) { + $ret['to'] = self::map_acl($i); + if (isset($parent_i['to']) && is_array($parent_i['to'])) { + $ret['to'] = array_values(array_unique(array_merge($ret['to'], $parent_i['to']))); + } + } else { + $ret['cc'] = self::map_acl($i); + if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { + $ret['cc'] = array_values(array_unique(array_merge($ret['cc'], $parent_i['cc']))); + } - $cc = []; - if ($ret['cc'] && is_array($ret['cc'])) { - foreach ($ret['cc'] as $e) { - if (! is_array($ret['to'])) { - $cc[] = $e; - } - elseif (! in_array($e,$ret['to'])) { - $cc[] = $e; - } - } - } - $ret['cc'] = $cc; + if ($ret['tag']) { + foreach ($ret['tag'] as $mention) { + if (is_array($mention) && array_key_exists('ttype', $mention) && in_array($mention['ttype'], [TERM_FORUM, TERM_MENTION]) && array_key_exists('href', $mention) && $mention['href']) { + $h = q("select * from hubloc where hubloc_id_url = '%s' limit 1", + dbesc($mention['href']) + ); + if ($h) { + if ($h[0]['hubloc_network'] === 'activitypub') { + $addr = $h[0]['hubloc_hash']; + } else { + $addr = $h[0]['hubloc_id_url']; + } + if (!in_array($addr, $ret['to'])) { + $ret['to'][] = $addr; + } + } + } + } + } - return $ret; - } + $d = q("select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d limit 1", + dbesc($i['parent_mid']), + intval($i['uid']) + ); + if ($d) { + if ($d[0]['hubloc_network'] === 'activitypub') { + $addr = $d[0]['hubloc_hash']; + } else { + $addr = $d[0]['hubloc_id_url']; + } + $ret['cc'][] = $addr; + } + } + } + + $mentions = self::map_mentions($i); + if (count($mentions) > 0) { + if (!$ret['to']) { + $ret['to'] = $mentions; + } else { + $ret['to'] = array_values(array_unique(array_merge($ret['to'], $mentions))); + } + } + } + + $cc = []; + if ($ret['cc'] && is_array($ret['cc'])) { + foreach ($ret['cc'] as $e) { + if (!is_array($ret['to'])) { + $cc[] = $e; + } elseif (!in_array($e, $ret['to'])) { + $cc[] = $e; + } + } + } + $ret['cc'] = $cc; + + return $ret; + } - static function nomadic_locations($item) { - $synchubs = []; - $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url + public static function nomadic_locations($item) + { + $synchubs = []; + $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash = '%s' and hubloc_network = 'zot6' and hubloc_deleted = 0", - dbesc($item['author_xchan']) - ); + dbesc($item['author_xchan']) + ); - if (! $h) { - return []; - } + if (!$h) { + return []; + } - foreach ($h as $x) { - $y = q("select site_dead from site where site_url = '%s' limit 1", - dbesc($x['hubloc_url']) - ); + foreach ($h as $x) { + $y = q("select site_dead from site where site_url = '%s' limit 1", + dbesc($x['hubloc_url']) + ); - if ((! $y) || intval($y[0]['site_dead']) === 0) { - $synchubs[] = $x; - } - } - - return $synchubs; - } + if ((!$y) || intval($y[0]['site_dead']) === 0) { + $synchubs[] = $x; + } + } + + return $synchubs; + } - static function encode_item($i, $activitypub = false) { + public static function encode_item($i, $activitypub = false) + { - $ret = []; - $reply = false; - $is_directmessage = false; + $ret = []; + $reply = false; + $is_directmessage = false; - $bbopts = (($activitypub) ? 'activitypub' : 'export'); + $bbopts = (($activitypub) ? 'activitypub' : 'export'); - $objtype = self::activity_obj_mapper($i['obj_type']); + $objtype = self::activity_obj_mapper($i['obj_type']); - if (intval($i['item_deleted'])) { - $ret['type'] = 'Tombstone'; - $ret['formerType'] = $objtype; - $ret['id'] = $i['mid']; - $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; - return $ret; - } + if (intval($i['item_deleted'])) { + $ret['type'] = 'Tombstone'; + $ret['formerType'] = $objtype; + $ret['id'] = $i['mid']; + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; + return $ret; + } - if (isset($i['obj']) && $i['obj']) { - if (is_string($i['obj'])) { - $tmp = json_decode($i['obj'],true); - if ($tmp !== NULL) { - $i['obj'] = $tmp; - } - } - $ret = $i['obj']; - if (is_string($ret)) { - return $ret; - } - } + if (isset($i['obj']) && $i['obj']) { + if (is_string($i['obj'])) { + $tmp = json_decode($i['obj'], true); + if ($tmp !== NULL) { + $i['obj'] = $tmp; + } + } + $ret = $i['obj']; + if (is_string($ret)) { + return $ret; + } + } - $ret['type'] = $objtype; + $ret['type'] = $objtype; - if ($objtype === 'Question') { - if ($i['obj']) { - if (is_array($i['obj'])) { - $ret = $i['obj']; - } - else { - $ret = json_decode($i['obj'],true); - } - - if(array_path_exists('actor/id',$ret)) { - $ret['actor'] = $ret['actor']['id']; - } - } - } + if ($objtype === 'Question') { + if ($i['obj']) { + if (is_array($i['obj'])) { + $ret = $i['obj']; + } else { + $ret = json_decode($i['obj'], true); + } + + if (array_path_exists('actor/id', $ret)) { + $ret['actor'] = $ret['actor']['id']; + } + } + } - $images = false; - $has_images = preg_match_all('/\[[zi]mg(.*?)\](.*?)\[/ism',$i['body'],$images,PREG_SET_ORDER); + $images = false; + $has_images = preg_match_all('/\[[zi]mg(.*?)\](.*?)\[/ism', $i['body'], $images, PREG_SET_ORDER); - $ret['id'] = $i['mid']; + $ret['id'] = $i['mid']; // $token = IConfig::get($i,'ocap','relay'); // if ($token) { @@ -1110,2712 +1094,2658 @@ class Activity { // } // } - $ret['published'] = datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); - if ($i['created'] !== $i['edited']) { - $ret['updated'] = datetime_convert('UTC','UTC',$i['edited'],ATOM_TIME); - } - if ($i['expires'] > NULL_DATE) { - $ret['expires'] = datetime_convert('UTC','UTC',$i['expires'],ATOM_TIME); - } - if ($i['app']) { - $ret['generator'] = [ 'type' => 'Application', 'name' => $i['app'] ]; - } - if ($i['location'] || $i['coord']) { - $ret['location'] = [ 'type' => 'Place' ]; - if ($i['location']) { - $ret['location']['name'] = $i['location']; - } - if ($i['coord']) { - $l = explode(' ',$i['coord']); - $ret['location']['latitude'] = $l[0]; - $ret['location']['longitude'] = $l[1]; - } - } - - if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) { - $ret['commentPolicy'] = $i['comment_policy']; - } - - if (intval($i['item_private']) === 2) { - $ret['directMessage'] = true; - } - - if (intval($i['item_nocomment'])) { - if($ret['commentPolicy']) { - $ret['commentPolicy'] .= ' '; - } - $ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['created'],ATOM_TIME); - } - elseif (array_key_exists('comments_closed',$i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] > NULL_DATE) { - if($ret['commentPolicy']) { - $ret['commentPolicy'] .= ' '; - } - $ret['commentPolicy'] .= 'until=' . datetime_convert('UTC','UTC',$i['comments_closed'],ATOM_TIME); - } - - $ret['attributedTo'] = (($i['author']['xchan_network'] === 'zot6') ? $i['author']['xchan_url'] : $i['author']['xchan_hash']); - - if ($i['mid'] !== $i['parent_mid']) { - $ret['inReplyTo'] = $i['thr_parent']; - $cnv = get_iconfig($i['parent'],'activitypub','context'); - if (! $cnv) { - $cnv = get_iconfig($i['parent'],'ostatus','conversation'); - } - if (! $cnv) { - $cnv = $ret['parent_mid']; - } - - $reply = true; - - if ($i['item_private']) { - $d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1", - intval($i['parent']) - ); - if ($d) { - $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); - - if (is_array($recips) && in_array($i['author']['xchan_url'], $recips['to'])) { - $reply_url = $d[0]['xchan_url']; - $is_directmessage = true; - } - else { - $reply_url = z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')); - } - $reply_addr = (($d[0]['xchan_addr']) ? $d[0]['xchan_addr'] : $d[0]['xchan_name']); - } - } - } - if (! isset($cnv)) { - $cnv = get_iconfig($i,'activitypub','context'); - if (! $cnv) { - $cnv = get_iconfig($i,'ostatus','conversation'); - } - if (! $cnv) { - $cnv = $i['parent_mid']; - } - } - if (isset($cnv) && $cnv) { - if (strpos($cnv,z_root()) === 0) { - $cnv = str_replace(['/item/','/activity/'],[ '/conversation/', '/conversation/' ], $cnv); - } - $ret['context'] = $cnv; - $ret['conversation'] = $cnv; - } - - // provide ocap access token for private media. - // set this for descendants even if the current item is not private - // because it may have been relayed from a private item. - - $token = get_iconfig($i,'ocap','relay'); - if ($token && $has_images) { - for ($n = 0; $n < count($images); $n ++) { - $match = $images[$n]; - if (strpos($match[1],'=http') === 0 && strpos($match[1],'/photo/' !== false)) { - $i['body'] = str_replace($match[1],$match[1] . '?token=' . $token, $i['body']); - $images[$n][2] = substr($match[1],1) . '?token=' . $token; - } - elseif (strpos($match[2],z_root() . '/photo/') !== false) { - $i['body'] = str_replace($match[2],$match[2] . '?token=' . $token, $i['body']); - $images[$n][2] = $match[2] . '?token=' . $token; - } - } - } - - if ($i['title']) { - $ret['name'] = $i['title']; - } - - if ($i['mimetype'] === 'text/bbcode') { - if ($i['summary']) { - $ret['summary'] = bbcode($i['summary'], [ $bbopts => true ]); - } - $opts = [ $bbopts => true ]; - $ret['content'] = bbcode($i['body'], $opts); - $ret['source'] = [ 'content' => $i['body'], 'mediaType' => 'text/bbcode' ]; - if (isset($ret['summary'])) { - $ret['source']['summary'] = $i['summary']; - } - } - else { - $ret['mediaType'] = $i['mimetype']; - $ret['content'] = $i['body']; - } - - if (! (isset($ret['actor']) || isset($ret['attributedTo']))) { - $actor = self::encode_person($i['author'],false); - if ($actor) { - $ret['actor'] = $actor; - } - else { - return []; - } - } - - $replyto = unserialise($i['replyto']); - if ($replyto) { - $ret['replyTo'] = $replyto; - } - - if (! isset($ret['url'])) { - $urls = []; - if (intval($i['item_wall'])) { - $locs = self::nomadic_locations($i); - if ($locs) { - foreach ($locs as $l) { - if (strpos($i['mid'],$l['hubloc_url']) !== false) { - continue; - } - $urls[] = [ - 'type' => 'Link', - 'href' => str_replace(z_root(),$l['hubloc_url'],$ret['id']), - 'rel' => 'alternate', - 'mediaType' => 'text/html' - ]; - $urls[] = [ - 'type' => 'Link', - 'href' => str_replace(z_root(),$l['hubloc_url'],$ret['id']), - 'rel' => 'alternate', - 'mediaType' => 'application/activity+json' - ]; - $urls[] = [ - 'type' => 'Link', - 'href' => str_replace(z_root(),$l['hubloc_url'],$ret['id']), - 'rel' => 'alternate', - 'mediaType' => 'application/x-zot+json' - ]; - } - } - } - if ($urls) { - $curr[] = [ - 'type' => 'Link', - 'href' => $ret['id'], - 'rel' => 'alternate', - 'mediaType' => 'text/html' - ]; - $ret['url'] = array_merge($curr, $urls); - } - else { - $ret['url'] = $ret['id']; - } - } - - $t = self::encode_taxonomy($i); - if ($t) { - $ret['tag'] = $t; - } - - $a = self::encode_attachment($i); - if ($a) { - $ret['attachment'] = $a; - } - - - if ($activitypub && $has_images && $ret['type'] === 'Note') { - foreach ($images as $match) { - $img = []; - // handle Friendica/Hubzilla style img links with [img=$url]$alttext[/img] - if (strpos($match[1],'=http') === 0) { - $img[] = [ 'type' => 'Image', 'url' => substr($match[1],1), 'name' => $match[2] ]; - } - // preferred mechanism for adding alt text - elseif (strpos($match[1],'alt=') !== false) { - $txt = str_replace('"','"',$match[1]); - $txt = substr($match[1],strpos($match[1],'alt="')+5,-1); - $img[] = [ 'type' => 'Image', 'url' => $match[2], 'name' => $txt ]; - } - else { - $img[] = [ 'type' => 'Image', 'url' => $match[2] ]; - } - - if (! $ret['attachment']) { - $ret['attachment'] = []; - } - $already_added = false; - if ($img) { - for ($pc = 0; $pc < count($ret['attachment']); $pc ++) { - // caution: image attachments use url and links use href, and our own links will be 'attach' links based on the image href - // We could alternatively supply the correct attachment info when item is saved, but by replacing here we will pick up - // any "per-post" or manual changes to the image alt-text before sending. - - if ((isset($ret['attachment'][$pc]['href']) && strpos($img[0]['url'],str_replace('/attach/','/photo/',$ret['attachment'][$pc]['href'])) !== false) || (isset($ret['attachment'][$pc]['url']) && $ret['attachment'][$pc]['url'] === $img[0]['url'])) { - // if it's already there, replace it with our alt-text aware version - $ret['attachment'][$pc] = $img[0]; - $already_added = true; - } - } - if (! $already_added) { - // add it - $ret['attachment'] = array_merge($img,$ret['attachment']); - } - } - } - } - - // addressing madness - - if ($activitypub) { - - $parent_i = []; - $ret['to'] = []; - $ret['cc'] = []; - - $public = (($i['item_private']) ? false : true); - $top_level = (($i['mid'] === $i['parent_mid']) ? true : false); - - if (! $top_level) { - - if (intval($i['parent'])) { - $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); - } - else { - // if we are encoding this item for storage there won't be a parent. - $p = q("select parent from item where parent_mid = '%s' and uid = %d", - dbesc($i['parent_mid']), - intval($i['uid']) - ); - if ($p) { - $recips = get_iconfig($p[0]['parent'], 'activitypub', 'recips'); - } - } - if ($recips) { - $parent_i['to'] = $recips['to']; - $parent_i['cc'] = $recips['cc']; - } - } - - - if ($public) { - $ret['to'] = [ ACTIVITY_PUBLIC_INBOX ]; - if (isset($parent_i['to']) && is_array($parent_i['to'])) { - $ret['to'] = array_values(array_unique(array_merge($ret['to'],$parent_i['to']))); - } - if ($i['item_origin']) { - $ret['cc'] = [ z_root() . '/followers/' . substr($i['author']['xchan_addr'],0,strpos($i['author']['xchan_addr'],'@')) ]; - } - if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { - $ret['cc'] = array_values(array_unique(array_merge($ret['cc'],$parent_i['cc']))); - } - - } - else { - - // private activity - - if ($top_level) { - $ret['to'] = self::map_acl($i); - if (isset($parent_i['to']) && is_array($parent_i['to'])) { - $ret['to'] = array_values(array_unique(array_merge($ret['to'],$parent_i['to']))); - } - } - else { - $ret['cc'] = self::map_acl($i); - if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { - $ret['cc'] = array_values(array_unique(array_merge($ret['cc'],$parent_i['cc']))); - } - if ($ret['tag']) { - foreach ($ret['tag'] as $mention) { - if (is_array($mention) && array_key_exists('ttype',$mention) && in_array($mention['ttype'],[ TERM_FORUM, TERM_MENTION]) && array_key_exists('href',$mention) && $mention['href']) { - $h = q("select * from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", - dbesc($mention['href']), - dbesc($mention['href']) - ); - if ($h) { - if ($h[0]['hubloc_network'] === 'activitypub') { - $addr = $h[0]['hubloc_hash']; - } - else { - $addr = $h[0]['hubloc_id_url']; - } - if (! in_array($addr,$ret['to'])) { - $ret['to'][] = $addr; - } - } - } - } - } - - - $d = q("select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d limit 1", - dbesc($i['parent_mid']), - intval($i['uid']) - ); - - if ($d) { - if ($d[0]['hubloc_network'] === 'activitypub') { - $addr = $d[0]['hubloc_hash']; - } - else { - $addr = $d[0]['hubloc_id_url']; - } - $ret['cc'][] = $addr; - } - } - } - - $mentions = self::map_mentions($i); - if (count($mentions) > 0) { - if (! $ret['to']) { - $ret['to'] = $mentions; - } - else { - $ret['to'] = array_values(array_unique(array_merge($ret['to'], $mentions))); - } - } - } - - // remove any duplicates from 'cc' that are present in 'to' - // as this may indicate that mentions changed the audience from secondary to primary - - $cc = []; - if ($ret['cc'] && is_array($ret['cc'])) { - foreach ($ret['cc'] as $e) { - if (! is_array($ret['to'])) { - $cc[] = $e; - } - elseif (! in_array($e,$ret['to'])) { - $cc[] = $e; - } - } - } - $ret['cc'] = $cc; - - return $ret; - } - - - - - // Returns an array of URLS for any mention tags found in the item array $i. - - static function map_mentions($i) { - if (! (array_key_exists('term',$i) && is_array($i['term']))) { - return []; - } - - $list = []; - - foreach ($i['term'] as $t) { - if (! (array_key_exists('url',$t) && $t['url'])) { - continue; - } - if (array_key_exists('ttype',$t) && $t['ttype'] == TERM_MENTION) { - $url = self::lookup_term_url($t['url']); - $list[] = (($url) ? $url : $t['url']); - } - } - - return $list; - } - - // Returns an array of all recipients targeted by private item array $i. - - static function map_acl($i) { - $ret = []; - - if (! $i['item_private']) { - return $ret; - } - - if ($i['mid'] !== $i['parent_mid']) { - $i = q("select * from item where parent_mid = '%s' and uid = %d", - dbesc($i['parent_mid']), - intval($i['uid']) - ); - if ($i) { - $i = array_shift($i); - } - } - if ($i['allow_gid']) { - $tmp = expand_acl($i['allow_gid']); - if ($tmp) { - foreach ($tmp as $t) { - $ret[] = z_root() . '/lists/' . $t; - } - } - } - - if ($i['allow_cid']) { - $tmp = expand_acl($i['allow_cid']); - $list = stringify_array($tmp,true); - if ($list) { - $details = q("select hubloc_id_url, hubloc_hash, hubloc_network from hubloc where hubloc_hash in (" . $list . ") "); - if ($details) { - foreach ($details as $d) { - if ($d['hubloc_network'] === 'activitypub') { - $ret[] = $d['hubloc_hash']; - } - else { - $ret[] = $d['hubloc_id_url']; - } - } - } - } - } - - $x = get_iconfig($i['id'],'activitypub','recips'); - if ($x) { - foreach ([ 'to','cc' ] as $k) { - if (isset($x[$k])) { - if (is_string($x[$k])) { - $ret[] = $x[$k]; - } - else { - $ret = array_merge($ret,$x[$k]); - } - } - } - } - - return array_values(array_unique($ret)); - - } - - - static function encode_person($p, $extended = true, $activitypub = false) { - - $ret = []; - - if (! $p['xchan_url']) - return $ret; - - if (! $extended) { - return $p['xchan_url']; - } - - $c = ((array_key_exists('channel_id',$p)) ? $p : channelx_by_hash($p['xchan_hash'])); - - $ret['type'] = 'Person'; - $auto_follow = false; - - if ($c) { - $role = PConfig::Get($c['channel_id'],'system','permissions_role'); - if (strpos($role,'forum') !== false) { - $ret['type'] = 'Group'; - } - $role_permissions = PermissionRoles::role_perms($role); - if (is_array($role_permissions) && isset($role_permissions['perms_auto'])) { - $auto_follow = intval($role_permissions['perms_auto']); - } - } - - if ($c) { - $ret['id'] = channel_url($c); - } - else { - $ret['id'] = ((strpos($p['xchan_hash'],'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']); - } - if ($p['xchan_addr'] && strpos($p['xchan_addr'],'@')) - $ret['preferredUsername'] = substr($p['xchan_addr'],0,strpos($p['xchan_addr'],'@')); - $ret['name'] = $p['xchan_name']; - $ret['updated'] = datetime_convert('UTC','UTC',$p['xchan_name_date'],ATOM_TIME); - $ret['icon'] = [ - 'type' => 'Image', - 'mediaType' => (($p['xchan_photo_mimetype']) ? $p['xchan_photo_mimetype'] : 'image/png' ), - 'updated' => datetime_convert('UTC','UTC',$p['xchan_photo_date'],ATOM_TIME), - 'url' => $p['xchan_photo_l'], - 'height' => 300, - 'width' => 300, - ]; - $ret['url'] = $p['xchan_url']; - if (isset($p['channel_location']) && $p['channel_location']) { - $ret['location'] = [ 'type' => 'Place', 'name' => $p['channel_location'] ]; - } - - $ret['tag'] = [ [ 'type' => 'PropertyValue','name' => 'Protocol','value' => 'zot6'] ]; - - if ($activitypub && get_config('system','activitypub', ACTIVITYPUB_ENABLED)) { - - if ($c) { - if (get_pconfig($c['channel_id'],'system','activitypub', ACTIVITYPUB_ENABLED)) { - $ret['inbox'] = z_root() . '/inbox/' . $c['channel_address']; - $ret['tag'][] = [ 'type' => 'PropertyValue','name' => 'Protocol','value' => 'activitypub']; - } - else { - $ret['inbox'] = null; - } - - $ret['outbox'] = z_root() . '/outbox/' . $c['channel_address']; - $ret['followers'] = z_root() . '/followers/' . $c['channel_address']; - $ret['following'] = z_root() . '/following/' . $c['channel_address']; - - $ret['endpoints'] = [ - 'sharedInbox' => z_root() . '/inbox', - 'oauthRegistrationEndpoint' => z_root() . '/api/client/register', - 'oauthAuthorizationEndpoint' => z_root() . '/authorize', - 'oauthTokenEndpoint' => z_root() . '/token' - ]; - - $ret['discoverable'] = ((1 - intval($p['xchan_hidden'])) ? true : false); - $ret['publicKey'] = [ - 'id' => $p['xchan_url'] . '?operation=getkey', - 'owner' => $p['xchan_url'], - 'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', - 'publicKeyPem' => $p['xchan_pubkey'] - ]; - - $ret['manuallyApprovesFollowers'] = (($auto_follow) ? false : true); - if ($ret['type'] === 'Group') { - $ret['capabilities'] = [ 'acceptsJoins' => true ]; - } - // map other nomadic identities linked with this channel - - $locations = []; - $locs = Libzot::encode_locations($c); - if ($locs) { - foreach ($locs as $loc) { - if ($loc['url'] !== z_root()) { - $locations[] = $loc['id_url']; - } - } - } - - if ($locations) { - if (count($locations) === 1) { - $locations = array_shift($locations); - } - $ret['copiedTo'] = $locations; - $ret['alsoKnownAs'] = $locations; - } - - $cp = get_cover_photo($c['channel_id'],'array'); - if ($cp) { - $ret['image'] = [ - 'type' => 'Image', - 'mediaType' => $cp['type'], - 'url' => $cp['url'] - ]; - } - // only fill in profile information if the profile is publicly visible - if (perm_is_allowed($c['channel_id'],EMPTY_STR,'view_profile')) { - $dp = q("select * from profile where uid = %d and is_default = 1", - intval($c['channel_id']) - ); - if ($dp) { - if ($dp[0]['about']) { - $ret['summary'] = bbcode($dp[0]['about'],['export' => true ]); - } - foreach ( [ 'pdesc', 'address', 'locality', 'region', 'postal_code', 'country_name', - 'hometown', 'gender', 'marital', 'sexual', 'politic', 'religion', 'pronouns', - 'homepage', 'contact', 'dob' ] as $k ) { - if ($dp[0][$k]) { - $key = $k; - if ($key === 'pdesc') { - $key = 'description'; - } - if ($key == 'politic') { - $key = 'political'; - } - if ($key === 'dob') { - $key = 'birthday'; - } - $ret['attachment'][] = [ 'type' => 'PropertyValue', 'name' => $key, 'value' => $dp[0][$k] ]; - } - } - if ($dp[0]['keywords']) { - $kw = explode(' ', $dp[0]['keywords']); - if ($kw) { - foreach ($kw as $k) { - $k = trim($k); - $k = trim($k,'#,'); - $ret['tag'][] = [ 'id' => z_root() . '/search?tag=' . urlencode($k), 'name' => '#' . urlencode($k) ]; - } - } - } - } - } - } - else { - $collections = get_xconfig($p['xchan_hash'],'activitypub','collections',[]); - if ($collections) { - $ret = array_merge($ret,$collections); - } - else { - $ret['inbox'] = null; - $ret['outbox'] = null; - } - } - } - else { - $ret['publicKey'] = [ - 'id' => $p['xchan_url'], - 'owner' => $p['xchan_url'], - 'publicKeyPem' => $p['xchan_pubkey'] - ]; - } - - $arr = [ 'xchan' => $p, 'encoded' => $ret, 'activitypub' => $activitypub ]; - call_hooks('encode_person', $arr); - $ret = $arr['encoded']; - - - return $ret; - } - - - - static function encode_site() { - - - $sys = get_sys_channel(); - - // encode the sys channel information and over-ride with site - // information - $ret = self::encode_person($sys,true,true); - - $ret['type'] = ((is_group($sys['channel_id'])) ? 'Group' : 'Service'); - $ret['id'] = z_root(); - $ret['alsoKnownAs'] = z_root() . '/channel/sys'; - $auto_follow = false; - - $ret['preferredUsername'] = 'sys'; - $ret['name'] = System::get_site_name(); - - $ret['icon'] = [ - 'type' => 'Image', - 'url' => System::get_site_icon(), - ]; - - $ret['generator'] = [ 'type' => 'Application', 'name' => System::get_platform_name() ]; - - $ret['url'] = z_root(); - - $ret['manuallyApprovesFollowers'] = ((get_config('system','allowed_sites')) ? true : false); - - $cp = get_cover_photo($sys['channel_id'],'array'); - if ($cp) { - $ret['image'] = [ - 'type' => 'Image', - 'mediaType' => $cp['type'], - 'url' => $cp['url'] - ]; - } - - $ret['summary'] = bbcode(get_config('system','siteinfo',''),[ 'export' => true ]); - $ret['source'] = [ - 'mediaType' => 'text/bbcode', - 'summary' => get_config('system','siteinfo','') - ]; - - $ret['publicKey'] = [ - 'id' => z_root() . '?operation=getkey', - 'owner' => z_root(), - 'publicKeyPem' => get_config('system','pubkey') - ]; - - return $ret; - } - - - - static function activity_mapper($verb) { - - if (strpos($verb,'/') === false) { - return $verb; - } - - $acts = [ - 'http://activitystrea.ms/schema/1.0/post' => 'Create', - 'http://activitystrea.ms/schema/1.0/share' => 'Announce', - 'http://activitystrea.ms/schema/1.0/update' => 'Update', - 'http://activitystrea.ms/schema/1.0/like' => 'Like', - 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', - 'http://purl.org/zot/activity/dislike' => 'Dislike', - 'http://activitystrea.ms/schema/1.0/tag' => 'Add', - 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', - 'http://activitystrea.ms/schema/1.0/unfollow' => 'Ignore', - ]; - - call_hooks('activity_mapper',$acts); + $ret['published'] = datetime_convert('UTC', 'UTC', $i['created'], ATOM_TIME); + if ($i['created'] !== $i['edited']) { + $ret['updated'] = datetime_convert('UTC', 'UTC', $i['edited'], ATOM_TIME); + } + if ($i['expires'] > NULL_DATE) { + $ret['expires'] = datetime_convert('UTC', 'UTC', $i['expires'], ATOM_TIME); + } + if ($i['app']) { + $ret['generator'] = ['type' => 'Application', 'name' => $i['app']]; + } + if ($i['location'] || $i['coord']) { + $ret['location'] = ['type' => 'Place']; + if ($i['location']) { + $ret['location']['name'] = $i['location']; + } + if ($i['coord']) { + $l = explode(' ', $i['coord']); + $ret['location']['latitude'] = $l[0]; + $ret['location']['longitude'] = $l[1]; + } + } + + if (intval($i['item_wall']) && $i['mid'] === $i['parent_mid']) { + $ret['commentPolicy'] = $i['comment_policy']; + } + + if (intval($i['item_private']) === 2) { + $ret['directMessage'] = true; + } + + if (intval($i['item_nocomment'])) { + if ($ret['commentPolicy']) { + $ret['commentPolicy'] .= ' '; + } + $ret['commentPolicy'] .= 'until=' . datetime_convert('UTC', 'UTC', $i['created'], ATOM_TIME); + } elseif (array_key_exists('comments_closed', $i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] > NULL_DATE) { + if ($ret['commentPolicy']) { + $ret['commentPolicy'] .= ' '; + } + $ret['commentPolicy'] .= 'until=' . datetime_convert('UTC', 'UTC', $i['comments_closed'], ATOM_TIME); + } + + $ret['attributedTo'] = (($i['author']['xchan_network'] === 'zot6') ? $i['author']['xchan_url'] : $i['author']['xchan_hash']); + + if ($i['mid'] !== $i['parent_mid']) { + $ret['inReplyTo'] = $i['thr_parent']; + $cnv = get_iconfig($i['parent'], 'activitypub', 'context'); + if (!$cnv) { + $cnv = get_iconfig($i['parent'], 'ostatus', 'conversation'); + } + if (!$cnv) { + $cnv = $ret['parent_mid']; + } + + $reply = true; + + if ($i['item_private']) { + $d = q("select xchan_url, xchan_addr, xchan_name from item left join xchan on xchan_hash = author_xchan where id = %d limit 1", + intval($i['parent']) + ); + if ($d) { + $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); + + if (is_array($recips) && in_array($i['author']['xchan_url'], $recips['to'])) { + $reply_url = $d[0]['xchan_url']; + $is_directmessage = true; + } else { + $reply_url = z_root() . '/followers/' . substr($i['author']['xchan_addr'], 0, strpos($i['author']['xchan_addr'], '@')); + } + $reply_addr = (($d[0]['xchan_addr']) ? $d[0]['xchan_addr'] : $d[0]['xchan_name']); + } + } + } + if (!isset($cnv)) { + $cnv = get_iconfig($i, 'activitypub', 'context'); + if (!$cnv) { + $cnv = get_iconfig($i, 'ostatus', 'conversation'); + } + if (!$cnv) { + $cnv = $i['parent_mid']; + } + } + if (isset($cnv) && $cnv) { + if (strpos($cnv, z_root()) === 0) { + $cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv); + } + $ret['context'] = $cnv; + $ret['conversation'] = $cnv; + } + + // provide ocap access token for private media. + // set this for descendants even if the current item is not private + // because it may have been relayed from a private item. + + $token = get_iconfig($i, 'ocap', 'relay'); + if ($token && $has_images) { + for ($n = 0; $n < count($images); $n++) { + $match = $images[$n]; + if (strpos($match[1], '=http') === 0 && strpos($match[1], '/photo/' !== false)) { + $i['body'] = str_replace($match[1], $match[1] . '?token=' . $token, $i['body']); + $images[$n][2] = substr($match[1], 1) . '?token=' . $token; + } elseif (strpos($match[2], z_root() . '/photo/') !== false) { + $i['body'] = str_replace($match[2], $match[2] . '?token=' . $token, $i['body']); + $images[$n][2] = $match[2] . '?token=' . $token; + } + } + } + + if ($i['title']) { + $ret['name'] = $i['title']; + } + + if ($i['mimetype'] === 'text/bbcode') { + if ($i['summary']) { + $ret['summary'] = bbcode($i['summary'], [$bbopts => true]); + } + $opts = [$bbopts => true]; + $ret['content'] = bbcode($i['body'], $opts); + $ret['source'] = ['content' => $i['body'], 'mediaType' => 'text/bbcode']; + if (isset($ret['summary'])) { + $ret['source']['summary'] = $i['summary']; + } + } else { + $ret['mediaType'] = $i['mimetype']; + $ret['content'] = $i['body']; + } + + if (!(isset($ret['actor']) || isset($ret['attributedTo']))) { + $actor = self::encode_person($i['author'], false); + if ($actor) { + $ret['actor'] = $actor; + } else { + return []; + } + } + + $replyto = unserialise($i['replyto']); + if ($replyto) { + $ret['replyTo'] = $replyto; + } + + if (!isset($ret['url'])) { + $urls = []; + if (intval($i['item_wall'])) { + $locs = self::nomadic_locations($i); + if ($locs) { + foreach ($locs as $l) { + if (strpos($i['mid'], $l['hubloc_url']) !== false) { + continue; + } + $urls[] = [ + 'type' => 'Link', + 'href' => str_replace(z_root(), $l['hubloc_url'], $ret['id']), + 'rel' => 'alternate', + 'mediaType' => 'text/html' + ]; + $urls[] = [ + 'type' => 'Link', + 'href' => str_replace(z_root(), $l['hubloc_url'], $ret['id']), + 'rel' => 'alternate', + 'mediaType' => 'application/activity+json' + ]; + $urls[] = [ + 'type' => 'Link', + 'href' => str_replace(z_root(), $l['hubloc_url'], $ret['id']), + 'rel' => 'alternate', + 'mediaType' => 'application/x-zot+json' + ]; + } + } + } + if ($urls) { + $curr[] = [ + 'type' => 'Link', + 'href' => $ret['id'], + 'rel' => 'alternate', + 'mediaType' => 'text/html' + ]; + $ret['url'] = array_merge($curr, $urls); + } else { + $ret['url'] = $ret['id']; + } + } + + $t = self::encode_taxonomy($i); + if ($t) { + $ret['tag'] = $t; + } + + $a = self::encode_attachment($i); + if ($a) { + $ret['attachment'] = $a; + } + + + if ($activitypub && $has_images && $ret['type'] === 'Note') { + foreach ($images as $match) { + $img = []; + // handle Friendica/Hubzilla style img links with [img=$url]$alttext[/img] + if (strpos($match[1], '=http') === 0) { + $img[] = ['type' => 'Image', 'url' => substr($match[1], 1), 'name' => $match[2]]; + } // preferred mechanism for adding alt text + elseif (strpos($match[1], 'alt=') !== false) { + $txt = str_replace('"', '"', $match[1]); + $txt = substr($match[1], strpos($match[1], 'alt="') + 5, -1); + $img[] = ['type' => 'Image', 'url' => $match[2], 'name' => $txt]; + } else { + $img[] = ['type' => 'Image', 'url' => $match[2]]; + } + + if (!$ret['attachment']) { + $ret['attachment'] = []; + } + $already_added = false; + if ($img) { + for ($pc = 0; $pc < count($ret['attachment']); $pc++) { + // caution: image attachments use url and links use href, and our own links will be 'attach' links based on the image href + // We could alternatively supply the correct attachment info when item is saved, but by replacing here we will pick up + // any "per-post" or manual changes to the image alt-text before sending. + + if ((isset($ret['attachment'][$pc]['href']) && strpos($img[0]['url'], str_replace('/attach/', '/photo/', $ret['attachment'][$pc]['href'])) !== false) || (isset($ret['attachment'][$pc]['url']) && $ret['attachment'][$pc]['url'] === $img[0]['url'])) { + // if it's already there, replace it with our alt-text aware version + $ret['attachment'][$pc] = $img[0]; + $already_added = true; + } + } + if (!$already_added) { + // add it + $ret['attachment'] = array_merge($img, $ret['attachment']); + } + } + } + } + + // addressing madness + + if ($activitypub) { + + $parent_i = []; + $ret['to'] = []; + $ret['cc'] = []; + + $public = (($i['item_private']) ? false : true); + $top_level = (($i['mid'] === $i['parent_mid']) ? true : false); + + if (!$top_level) { + + if (intval($i['parent'])) { + $recips = get_iconfig($i['parent'], 'activitypub', 'recips'); + } else { + // if we are encoding this item for storage there won't be a parent. + $p = q("select parent from item where parent_mid = '%s' and uid = %d", + dbesc($i['parent_mid']), + intval($i['uid']) + ); + if ($p) { + $recips = get_iconfig($p[0]['parent'], 'activitypub', 'recips'); + } + } + if ($recips) { + $parent_i['to'] = $recips['to']; + $parent_i['cc'] = $recips['cc']; + } + } + + + if ($public) { + $ret['to'] = [ACTIVITY_PUBLIC_INBOX]; + if (isset($parent_i['to']) && is_array($parent_i['to'])) { + $ret['to'] = array_values(array_unique(array_merge($ret['to'], $parent_i['to']))); + } + if ($i['item_origin']) { + $ret['cc'] = [z_root() . '/followers/' . substr($i['author']['xchan_addr'], 0, strpos($i['author']['xchan_addr'], '@'))]; + } + if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { + $ret['cc'] = array_values(array_unique(array_merge($ret['cc'], $parent_i['cc']))); + } + + } else { + + // private activity + + if ($top_level) { + $ret['to'] = self::map_acl($i); + if (isset($parent_i['to']) && is_array($parent_i['to'])) { + $ret['to'] = array_values(array_unique(array_merge($ret['to'], $parent_i['to']))); + } + } else { + $ret['cc'] = self::map_acl($i); + if (isset($parent_i['cc']) && is_array($parent_i['cc'])) { + $ret['cc'] = array_values(array_unique(array_merge($ret['cc'], $parent_i['cc']))); + } + if ($ret['tag']) { + foreach ($ret['tag'] as $mention) { + if (is_array($mention) && array_key_exists('ttype', $mention) && in_array($mention['ttype'], [TERM_FORUM, TERM_MENTION]) && array_key_exists('href', $mention) && $mention['href']) { + $h = q("select * from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", + dbesc($mention['href']), + dbesc($mention['href']) + ); + if ($h) { + if ($h[0]['hubloc_network'] === 'activitypub') { + $addr = $h[0]['hubloc_hash']; + } else { + $addr = $h[0]['hubloc_id_url']; + } + if (!in_array($addr, $ret['to'])) { + $ret['to'][] = $addr; + } + } + } + } + } + + + $d = q("select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d limit 1", + dbesc($i['parent_mid']), + intval($i['uid']) + ); + + if ($d) { + if ($d[0]['hubloc_network'] === 'activitypub') { + $addr = $d[0]['hubloc_hash']; + } else { + $addr = $d[0]['hubloc_id_url']; + } + $ret['cc'][] = $addr; + } + } + } + + $mentions = self::map_mentions($i); + if (count($mentions) > 0) { + if (!$ret['to']) { + $ret['to'] = $mentions; + } else { + $ret['to'] = array_values(array_unique(array_merge($ret['to'], $mentions))); + } + } + } + + // remove any duplicates from 'cc' that are present in 'to' + // as this may indicate that mentions changed the audience from secondary to primary + + $cc = []; + if ($ret['cc'] && is_array($ret['cc'])) { + foreach ($ret['cc'] as $e) { + if (!is_array($ret['to'])) { + $cc[] = $e; + } elseif (!in_array($e, $ret['to'])) { + $cc[] = $e; + } + } + } + $ret['cc'] = $cc; + + return $ret; + } + + + // Returns an array of URLS for any mention tags found in the item array $i. + + public static function map_mentions($i) + { + if (!(array_key_exists('term', $i) && is_array($i['term']))) { + return []; + } + + $list = []; + + foreach ($i['term'] as $t) { + if (!(array_key_exists('url', $t) && $t['url'])) { + continue; + } + if (array_key_exists('ttype', $t) && $t['ttype'] == TERM_MENTION) { + $url = self::lookup_term_url($t['url']); + $list[] = (($url) ? $url : $t['url']); + } + } + + return $list; + } + + // Returns an array of all recipients targeted by private item array $i. + + public static function map_acl($i) + { + $ret = []; + + if (!$i['item_private']) { + return $ret; + } + + if ($i['mid'] !== $i['parent_mid']) { + $i = q("select * from item where parent_mid = '%s' and uid = %d", + dbesc($i['parent_mid']), + intval($i['uid']) + ); + if ($i) { + $i = array_shift($i); + } + } + if ($i['allow_gid']) { + $tmp = expand_acl($i['allow_gid']); + if ($tmp) { + foreach ($tmp as $t) { + $ret[] = z_root() . '/lists/' . $t; + } + } + } + + if ($i['allow_cid']) { + $tmp = expand_acl($i['allow_cid']); + $list = stringify_array($tmp, true); + if ($list) { + $details = q("select hubloc_id_url, hubloc_hash, hubloc_network from hubloc where hubloc_hash in (" . $list . ") "); + if ($details) { + foreach ($details as $d) { + if ($d['hubloc_network'] === 'activitypub') { + $ret[] = $d['hubloc_hash']; + } else { + $ret[] = $d['hubloc_id_url']; + } + } + } + } + } + + $x = get_iconfig($i['id'], 'activitypub', 'recips'); + if ($x) { + foreach (['to', 'cc'] as $k) { + if (isset($x[$k])) { + if (is_string($x[$k])) { + $ret[] = $x[$k]; + } else { + $ret = array_merge($ret, $x[$k]); + } + } + } + } + + return array_values(array_unique($ret)); + + } + + + public static function encode_person($p, $extended = true, $activitypub = false) + { + + $ret = []; + + if (!$p['xchan_url']) + return $ret; + + if (!$extended) { + return $p['xchan_url']; + } + + $c = ((array_key_exists('channel_id', $p)) ? $p : channelx_by_hash($p['xchan_hash'])); + + $ret['type'] = 'Person'; + $auto_follow = false; + + if ($c) { + $role = PConfig::Get($c['channel_id'], 'system', 'permissions_role'); + if (strpos($role, 'forum') !== false) { + $ret['type'] = 'Group'; + } + $role_permissions = PermissionRoles::role_perms($role); + if (is_array($role_permissions) && isset($role_permissions['perms_auto'])) { + $auto_follow = intval($role_permissions['perms_auto']); + } + } + + if ($c) { + $ret['id'] = channel_url($c); + } else { + $ret['id'] = ((strpos($p['xchan_hash'], 'http') === 0) ? $p['xchan_hash'] : $p['xchan_url']); + } + if ($p['xchan_addr'] && strpos($p['xchan_addr'], '@')) + $ret['preferredUsername'] = substr($p['xchan_addr'], 0, strpos($p['xchan_addr'], '@')); + $ret['name'] = $p['xchan_name']; + $ret['updated'] = datetime_convert('UTC', 'UTC', $p['xchan_name_date'], ATOM_TIME); + $ret['icon'] = [ + 'type' => 'Image', + 'mediaType' => (($p['xchan_photo_mimetype']) ? $p['xchan_photo_mimetype'] : 'image/png'), + 'updated' => datetime_convert('UTC', 'UTC', $p['xchan_photo_date'], ATOM_TIME), + 'url' => $p['xchan_photo_l'], + 'height' => 300, + 'width' => 300, + ]; + $ret['url'] = $p['xchan_url']; + if (isset($p['channel_location']) && $p['channel_location']) { + $ret['location'] = ['type' => 'Place', 'name' => $p['channel_location']]; + } + + $ret['tag'] = [['type' => 'PropertyValue', 'name' => 'Protocol', 'value' => 'zot6']]; + + if ($activitypub && get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) { + + if ($c) { + if (get_pconfig($c['channel_id'], 'system', 'activitypub', ACTIVITYPUB_ENABLED)) { + $ret['inbox'] = z_root() . '/inbox/' . $c['channel_address']; + $ret['tag'][] = ['type' => 'PropertyValue', 'name' => 'Protocol', 'value' => 'activitypub']; + } else { + $ret['inbox'] = null; + } + + $ret['outbox'] = z_root() . '/outbox/' . $c['channel_address']; + $ret['followers'] = z_root() . '/followers/' . $c['channel_address']; + $ret['following'] = z_root() . '/following/' . $c['channel_address']; + + $ret['endpoints'] = [ + 'sharedInbox' => z_root() . '/inbox', + 'oauthRegistrationEndpoint' => z_root() . '/api/client/register', + 'oauthAuthorizationEndpoint' => z_root() . '/authorize', + 'oauthTokenEndpoint' => z_root() . '/token' + ]; + + $ret['discoverable'] = ((1 - intval($p['xchan_hidden'])) ? true : false); + $ret['publicKey'] = [ + 'id' => $p['xchan_url'] . '?operation=getkey', + 'owner' => $p['xchan_url'], + 'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + 'publicKeyPem' => $p['xchan_pubkey'] + ]; + + $ret['manuallyApprovesFollowers'] = (($auto_follow) ? false : true); + if ($ret['type'] === 'Group') { + $ret['capabilities'] = ['acceptsJoins' => true]; + } + // map other nomadic identities linked with this channel + + $locations = []; + $locs = Libzot::encode_locations($c); + if ($locs) { + foreach ($locs as $loc) { + if ($loc['url'] !== z_root()) { + $locations[] = $loc['id_url']; + } + } + } + + if ($locations) { + if (count($locations) === 1) { + $locations = array_shift($locations); + } + $ret['copiedTo'] = $locations; + $ret['alsoKnownAs'] = $locations; + } + + $cp = get_cover_photo($c['channel_id'], 'array'); + if ($cp) { + $ret['image'] = [ + 'type' => 'Image', + 'mediaType' => $cp['type'], + 'url' => $cp['url'] + ]; + } + // only fill in profile information if the profile is publicly visible + if (perm_is_allowed($c['channel_id'], EMPTY_STR, 'view_profile')) { + $dp = q("select * from profile where uid = %d and is_default = 1", + intval($c['channel_id']) + ); + if ($dp) { + if ($dp[0]['about']) { + $ret['summary'] = bbcode($dp[0]['about'], ['export' => true]); + } + foreach (['pdesc', 'address', 'locality', 'region', 'postal_code', 'country_name', + 'hometown', 'gender', 'marital', 'sexual', 'politic', 'religion', 'pronouns', + 'homepage', 'contact', 'dob'] as $k) { + if ($dp[0][$k]) { + $key = $k; + if ($key === 'pdesc') { + $key = 'description'; + } + if ($key == 'politic') { + $key = 'political'; + } + if ($key === 'dob') { + $key = 'birthday'; + } + $ret['attachment'][] = ['type' => 'PropertyValue', 'name' => $key, 'value' => $dp[0][$k]]; + } + } + if ($dp[0]['keywords']) { + $kw = explode(' ', $dp[0]['keywords']); + if ($kw) { + foreach ($kw as $k) { + $k = trim($k); + $k = trim($k, '#,'); + $ret['tag'][] = ['id' => z_root() . '/search?tag=' . urlencode($k), 'name' => '#' . urlencode($k)]; + } + } + } + } + } + } else { + $collections = get_xconfig($p['xchan_hash'], 'activitypub', 'collections', []); + if ($collections) { + $ret = array_merge($ret, $collections); + } else { + $ret['inbox'] = null; + $ret['outbox'] = null; + } + } + } else { + $ret['publicKey'] = [ + 'id' => $p['xchan_url'], + 'owner' => $p['xchan_url'], + 'publicKeyPem' => $p['xchan_pubkey'] + ]; + } + + $arr = ['xchan' => $p, 'encoded' => $ret, 'activitypub' => $activitypub]; + call_hooks('encode_person', $arr); + $ret = $arr['encoded']; + + + return $ret; + } + + + public static function encode_site() + { + + + $sys = get_sys_channel(); + + // encode the sys channel information and over-ride with site + // information + $ret = self::encode_person($sys, true, true); + + $ret['type'] = ((is_group($sys['channel_id'])) ? 'Group' : 'Service'); + $ret['id'] = z_root(); + $ret['alsoKnownAs'] = z_root() . '/channel/sys'; + $auto_follow = false; + + $ret['preferredUsername'] = 'sys'; + $ret['name'] = System::get_site_name(); + + $ret['icon'] = [ + 'type' => 'Image', + 'url' => System::get_site_icon(), + ]; + + $ret['generator'] = ['type' => 'Application', 'name' => System::get_platform_name()]; + + $ret['url'] = z_root(); + + $ret['manuallyApprovesFollowers'] = ((get_config('system', 'allowed_sites')) ? true : false); + + $cp = get_cover_photo($sys['channel_id'], 'array'); + if ($cp) { + $ret['image'] = [ + 'type' => 'Image', + 'mediaType' => $cp['type'], + 'url' => $cp['url'] + ]; + } + + $ret['summary'] = bbcode(get_config('system', 'siteinfo', ''), ['export' => true]); + $ret['source'] = [ + 'mediaType' => 'text/bbcode', + 'summary' => get_config('system', 'siteinfo', '') + ]; + + $ret['publicKey'] = [ + 'id' => z_root() . '?operation=getkey', + 'owner' => z_root(), + 'publicKeyPem' => get_config('system', 'pubkey') + ]; + + return $ret; + } + + + public static function activity_mapper($verb) + { + + if (strpos($verb, '/') === false) { + return $verb; + } + + $acts = [ + 'http://activitystrea.ms/schema/1.0/post' => 'Create', + 'http://activitystrea.ms/schema/1.0/share' => 'Announce', + 'http://activitystrea.ms/schema/1.0/update' => 'Update', + 'http://activitystrea.ms/schema/1.0/like' => 'Like', + 'http://activitystrea.ms/schema/1.0/favorite' => 'Like', + 'http://purl.org/zot/activity/dislike' => 'Dislike', + 'http://activitystrea.ms/schema/1.0/tag' => 'Add', + 'http://activitystrea.ms/schema/1.0/follow' => 'Follow', + 'http://activitystrea.ms/schema/1.0/unfollow' => 'Ignore', + ]; - if (array_key_exists($verb,$acts) && $acts[$verb]) { - return $acts[$verb]; - } + call_hooks('activity_mapper', $acts); - // Reactions will just map to normal activities + if (array_key_exists($verb, $acts) && $acts[$verb]) { + return $acts[$verb]; + } - if (strpos($verb,ACTIVITY_REACT) !== false) - return 'Create'; - if (strpos($verb,ACTIVITY_MOOD) !== false) - return 'Create'; + // Reactions will just map to normal activities - if (strpos($verb,ACTIVITY_POKE) !== false) - return 'Activity'; + if (strpos($verb, ACTIVITY_REACT) !== false) + return 'Create'; + if (strpos($verb, ACTIVITY_MOOD) !== false) + return 'Create'; - // We should return false, however this will trigger an uncaught exception and crash - // the delivery system if encountered by the JSON-LDSignature library - - logger('Unmapped activity: ' . $verb); - return 'Create'; - // return false; - } + if (strpos($verb, ACTIVITY_POKE) !== false) + return 'Activity'; + // We should return false, however this will trigger an uncaught exception and crash + // the delivery system if encountered by the JSON-LDSignature library - static function activity_obj_mapper($obj) { + logger('Unmapped activity: ' . $verb); + return 'Create'; + // return false; + } - $objs = [ - 'http://activitystrea.ms/schema/1.0/note' => 'Note', - 'http://activitystrea.ms/schema/1.0/comment' => 'Note', - 'http://activitystrea.ms/schema/1.0/person' => 'Person', - 'http://purl.org/zot/activity/profile' => 'Profile', - 'http://activitystrea.ms/schema/1.0/photo' => 'Image', - 'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon', - 'http://activitystrea.ms/schema/1.0/event' => 'Event', - 'http://activitystrea.ms/schema/1.0/wiki' => 'Document', - 'http://purl.org/zot/activity/location' => 'Place', - 'http://purl.org/zot/activity/chessgame' => 'Game', - 'http://purl.org/zot/activity/tagterm' => 'zot:Tag', - 'http://purl.org/zot/activity/thing' => 'Object', - 'http://purl.org/zot/activity/file' => 'zot:File', - 'http://purl.org/zot/activity/mood' => 'zot:Mood', - - ]; - - call_hooks('activity_obj_mapper',$objs); - - if ($obj === 'Answer') { - return 'Note'; - } - - if (strpos($obj,'/') === false) { - return $obj; - } - - if (array_key_exists($obj,$objs)) { - return $objs[$obj]; - } - - logger('Unmapped activity object: ' . $obj); - return 'Note'; + public static function activity_obj_mapper($obj) + { - // return false; - } + $objs = [ + 'http://activitystrea.ms/schema/1.0/note' => 'Note', + 'http://activitystrea.ms/schema/1.0/comment' => 'Note', + 'http://activitystrea.ms/schema/1.0/person' => 'Person', + 'http://purl.org/zot/activity/profile' => 'Profile', + 'http://activitystrea.ms/schema/1.0/photo' => 'Image', + 'http://activitystrea.ms/schema/1.0/profile-photo' => 'Icon', + 'http://activitystrea.ms/schema/1.0/event' => 'Event', + 'http://activitystrea.ms/schema/1.0/wiki' => 'Document', + 'http://purl.org/zot/activity/location' => 'Place', + 'http://purl.org/zot/activity/chessgame' => 'Game', + 'http://purl.org/zot/activity/tagterm' => 'zot:Tag', + 'http://purl.org/zot/activity/thing' => 'Object', + 'http://purl.org/zot/activity/file' => 'zot:File', + 'http://purl.org/zot/activity/mood' => 'zot:Mood', + ]; - static function follow($channel,$act) { + call_hooks('activity_obj_mapper', $objs); - $contact = null; - $their_follow_id = null; + if ($obj === 'Answer') { + return 'Note'; + } - if (intval($channel['channel_system'])) { - // The system channel ignores all follow requests - return; - } + if (strpos($obj, '/') === false) { + return $obj; + } + + if (array_key_exists($obj, $objs)) { + return $objs[$obj]; + } - /* - * - * if $act->type === 'Follow', actor is now following $channel - * if $act->type === 'Accept', actor has approved a follow request from $channel - * + logger('Unmapped activity object: ' . $obj); + return 'Note'; + + // return false; + + } + + + public static function follow($channel, $act) + { + + $contact = null; + $their_follow_id = null; + + if (intval($channel['channel_system'])) { + // The system channel ignores all follow requests + return; + } + + /* + * + * if $act->type === 'Follow', actor is now following $channel + * if $act->type === 'Accept', actor has approved a follow request from $channel + * */ - $person_obj = $act->actor; + $person_obj = $act->actor; - if (in_array($act->type, [ 'Follow', 'Invite', 'Join'])) { - $their_follow_id = $act->id; - } - elseif ($act->type === 'Accept') { - $my_follow_id = z_root() . '/follow/' . $contact['id']; - } - - if (is_array($person_obj)) { + if (in_array($act->type, ['Follow', 'Invite', 'Join'])) { + $their_follow_id = $act->id; + } elseif ($act->type === 'Accept') { + $my_follow_id = z_root() . '/follow/' . $contact['id']; + } - // store their xchan and hubloc + if (is_array($person_obj)) { - self::actor_store($person_obj['id'],$person_obj); + // store their xchan and hubloc - // Find any existing abook record + self::actor_store($person_obj['id'], $person_obj); - $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($person_obj['id']), - intval($channel['channel_id']) - ); - if ($r) { - $contact = $r[0]; - } - } + // Find any existing abook record - $x = PermissionRoles::role_perms('social'); - $p = Permissions::FilledPerms($x['perms_connect']); - - // add tag_deliver permissions to remote groups + $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($person_obj['id']), + intval($channel['channel_id']) + ); + if ($r) { + $contact = $r[0]; + } + } - if (is_array($person_obj) && $person_obj['type'] === 'Group') { - $p['tag_deliver'] = 1; - } + $x = PermissionRoles::role_perms('social'); + $p = Permissions::FilledPerms($x['perms_connect']); - $their_perms = Permissions::serialise($p); + // add tag_deliver permissions to remote groups + + if (is_array($person_obj) && $person_obj['type'] === 'Group') { + $p['tag_deliver'] = 1; + } + + $their_perms = Permissions::serialise($p); - if ($contact && $contact['abook_id']) { + if ($contact && $contact['abook_id']) { - // A relationship of some form already exists on this site. + // A relationship of some form already exists on this site. - switch($act->type) { + switch ($act->type) { - case 'Follow': - case 'Invite': - case 'Join': + case 'Follow': + case 'Invite': + case 'Join': - // A second Follow request, but we haven't approved the first one + // A second Follow request, but we haven't approved the first one - if ($contact['abook_pending']) { - return; - } + if ($contact['abook_pending']) { + return; + } - // We've already approved them or followed them first - // Send an Accept back to them + // We've already approved them or followed them first + // Send an Accept back to them - set_abconfig($channel['channel_id'],$person_obj['id'],'activitypub','their_follow_id', $their_follow_id); - set_abconfig($channel['channel_id'],$person_obj['id'],'activitypub','their_follow_type', $act->type); - Run::Summon([ 'Notifier', 'permissions_accept', $contact['abook_id'] ]); - return; + set_abconfig($channel['channel_id'], $person_obj['id'], 'activitypub', 'their_follow_id', $their_follow_id); + set_abconfig($channel['channel_id'], $person_obj['id'], 'activitypub', 'their_follow_type', $act->type); + Run::Summon(['Notifier', 'permissions_accept', $contact['abook_id']]); + return; - case 'Accept': + case 'Accept': - // They accepted our Follow request - set default permissions - - set_abconfig($channel['channel_id'],$contact['abook_xchan'],'system','their_perms',$their_perms); + // They accepted our Follow request - set default permissions - $abook_instance = $contact['abook_instance']; - - if (strpos($abook_instance,z_root()) === false) { - if ($abook_instance) - $abook_instance .= ','; - $abook_instance .= z_root(); + set_abconfig($channel['channel_id'], $contact['abook_xchan'], 'system', 'their_perms', $their_perms); - $r = q("update abook set abook_instance = '%s', abook_not_here = 0 + $abook_instance = $contact['abook_instance']; + + if (strpos($abook_instance, z_root()) === false) { + if ($abook_instance) + $abook_instance .= ','; + $abook_instance .= z_root(); + + $r = q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d and abook_channel = %d", - dbesc($abook_instance), - intval($contact['abook_id']), - intval($channel['channel_id']) - ); - } - - return; - default: - return; - - } - } + dbesc($abook_instance), + intval($contact['abook_id']), + intval($channel['channel_id']) + ); + } - // No previous relationship exists. + return; + default: + return; - if ($act->type === 'Accept') { - // This should not happen unless we deleted the connection before it was accepted. - return; - } + } + } - // From here on out we assume a Follow activity to somebody we have no existing relationship with + // No previous relationship exists. - set_abconfig($channel['channel_id'],$person_obj['id'],'activitypub','their_follow_id', $their_follow_id); - set_abconfig($channel['channel_id'],$person_obj['id'],'activitypub','their_follow_type', $act->type); + if ($act->type === 'Accept') { + // This should not happen unless we deleted the connection before it was accepted. + return; + } - // The xchan should have been created by actor_store() above + // From here on out we assume a Follow activity to somebody we have no existing relationship with - $r = q("select * from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' limit 1", - dbesc($person_obj['id']) - ); + set_abconfig($channel['channel_id'], $person_obj['id'], 'activitypub', 'their_follow_id', $their_follow_id); + set_abconfig($channel['channel_id'], $person_obj['id'], 'activitypub', 'their_follow_type', $act->type); - if (! $r) { - logger('xchan not found for ' . $person_obj['id']); - return; - } - $ret = $r[0]; - - $blocked = LibBlock::fetch($channel['channel_id'],BLOCKTYPE_SERVER); - if ($blocked) { - foreach($blocked as $b) { - if (strpos($ret['xchan_url'],$b['block_entity']) !== false) { - logger('siteblock - follower denied'); - return; - } - } - } - if (LibBlock::fetch_by_entity($channel['channel_id'],$ret['xchan_hash'])) { - logger('actorblock - follower denied'); - return; - } - - $p = Permissions::connect_perms($channel['channel_id']); - $my_perms = Permissions::serialise($p['perms']); - $automatic = $p['automatic']; + // The xchan should have been created by actor_store() above - $closeness = PConfig::Get($channel['channel_id'],'system','new_abook_closeness',80); + $r = q("select * from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' limit 1", + dbesc($person_obj['id']) + ); - $r = abook_store_lowlevel( - [ - 'abook_account' => intval($channel['channel_account_id']), - 'abook_channel' => intval($channel['channel_id']), - 'abook_xchan' => $ret['xchan_hash'], - 'abook_closeness' => intval($closeness), - 'abook_created' => datetime_convert(), - 'abook_updated' => datetime_convert(), - 'abook_connected' => datetime_convert(), - 'abook_dob' => NULL_DATE, - 'abook_pending' => intval(($automatic) ? 0 : 1), - 'abook_instance' => z_root() - ] - ); - - if ($my_perms) - AbConfig::Set($channel['channel_id'],$ret['xchan_hash'],'system','my_perms',$my_perms); + if (!$r) { + logger('xchan not found for ' . $person_obj['id']); + return; + } + $ret = $r[0]; - if ($their_perms) - AbConfig::Set($channel['channel_id'],$ret['xchan_hash'],'system','their_perms',$their_perms); + $blocked = LibBlock::fetch($channel['channel_id'], BLOCKTYPE_SERVER); + if ($blocked) { + foreach ($blocked as $b) { + if (strpos($ret['xchan_url'], $b['block_entity']) !== false) { + logger('siteblock - follower denied'); + return; + } + } + } + if (LibBlock::fetch_by_entity($channel['channel_id'], $ret['xchan_hash'])) { + logger('actorblock - follower denied'); + return; + } + + $p = Permissions::connect_perms($channel['channel_id']); + $my_perms = Permissions::serialise($p['perms']); + $automatic = $p['automatic']; + + $closeness = PConfig::Get($channel['channel_id'], 'system', 'new_abook_closeness', 80); + + $r = abook_store_lowlevel( + [ + 'abook_account' => intval($channel['channel_account_id']), + 'abook_channel' => intval($channel['channel_id']), + 'abook_xchan' => $ret['xchan_hash'], + 'abook_closeness' => intval($closeness), + 'abook_created' => datetime_convert(), + 'abook_updated' => datetime_convert(), + 'abook_connected' => datetime_convert(), + 'abook_dob' => NULL_DATE, + 'abook_pending' => intval(($automatic) ? 0 : 1), + 'abook_instance' => z_root() + ] + ); + + if ($my_perms) + AbConfig::Set($channel['channel_id'], $ret['xchan_hash'], 'system', 'my_perms', $my_perms); + + if ($their_perms) + AbConfig::Set($channel['channel_id'], $ret['xchan_hash'], 'system', 'their_perms', $their_perms); - if ($r) { - logger("New ActivityPub follower for {$channel['channel_name']}"); + if ($r) { + logger("New ActivityPub follower for {$channel['channel_name']}"); - $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash left join hubloc on hubloc_hash = xchan_hash where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1", - intval($channel['channel_id']), - dbesc($ret['xchan_hash']) - ); - if ($new_connection) { - Enotify::submit( - [ - 'type' => NOTIFY_INTRO, - 'from_xchan' => $ret['xchan_hash'], - 'to_xchan' => $channel['channel_hash'], - 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], - ] - ); + $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash left join hubloc on hubloc_hash = xchan_hash where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1", + intval($channel['channel_id']), + dbesc($ret['xchan_hash']) + ); + if ($new_connection) { + Enotify::submit( + [ + 'type' => NOTIFY_INTRO, + 'from_xchan' => $ret['xchan_hash'], + 'to_xchan' => $channel['channel_hash'], + 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], + ] + ); - if ($my_perms && $automatic) { - // send an Accept for this Follow activity - Run::Summon([ 'Notifier', 'permissions_accept', $new_connection[0]['abook_id'] ]); - // Send back a Follow notification to them - Run::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); - } + if ($my_perms && $automatic) { + // send an Accept for this Follow activity + Run::Summon(['Notifier', 'permissions_accept', $new_connection[0]['abook_id']]); + // Send back a Follow notification to them + Run::Summon(['Notifier', 'permissions_create', $new_connection[0]['abook_id']]); + } - $clone = []; - foreach ($new_connection[0] as $k => $v) { - if (strpos($k,'abook_') === 0) { - $clone[$k] = $v; - } - } - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); - - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); + $clone = []; + foreach ($new_connection[0] as $k => $v) { + if (strpos($k, 'abook_') === 0) { + $clone[$k] = $v; + } + } + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); - if ($abconfig) { - $clone['abconfig'] = $abconfig; - } - Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ] ] ); - } - } + $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + + if ($abconfig) { + $clone['abconfig'] = $abconfig; + } + Libsync::build_sync_packet($channel['channel_id'], ['abook' => [$clone]]); + } + } - /* If there is a default group for this channel and permissions are automatic, add this member to it */ + /* If there is a default group for this channel and permissions are automatic, add this member to it */ - if ($channel['channel_default_group'] && $automatic) { - $g = AccessList::rec_byhash($channel['channel_id'],$channel['channel_default_group']); - if ($g) { - AccessList::member_add($channel['channel_id'],'',$ret['xchan_hash'],$g['id']); - } - } + if ($channel['channel_default_group'] && $automatic) { + $g = AccessList::rec_byhash($channel['channel_id'], $channel['channel_default_group']); + if ($g) { + AccessList::member_add($channel['channel_id'], '', $ret['xchan_hash'], $g['id']); + } + } - return; + return; - } + } - static function unfollow($channel,$act) { + public static function unfollow($channel, $act) + { - $contact = null; + $contact = null; - /* actor is unfollowing $channel */ + /* actor is unfollowing $channel */ - $person_obj = $act->actor; + $person_obj = $act->actor; - if (is_array($person_obj)) { + if (is_array($person_obj)) { - $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($person_obj['id']), - intval($channel['channel_id']) - ); - if ($r) { - // remove all permissions they provided - del_abconfig($channel['channel_id'],$r[0]['xchan_hash'],'system','their_perms',EMPTY_STR); - } - } + $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($person_obj['id']), + intval($channel['channel_id']) + ); + if ($r) { + // remove all permissions they provided + del_abconfig($channel['channel_id'], $r[0]['xchan_hash'], 'system', 'their_perms', EMPTY_STR); + } + } - return; - } + return; + } + public static function actor_store($url, $person_obj, $force = false) + { - - static function actor_store($url, $person_obj, $force = false) { - - if (! is_array($person_obj)) { - return; - } + if (!is_array($person_obj)) { + return; + } // logger('person_obj: ' . print_r($person_obj,true)); - if (array_key_exists('movedTo',$person_obj) && $person_obj['movedTo'] && ! is_array($person_obj['movedTo'])) { - $tgt = self::fetch($person_obj['movedTo']); - if (is_array($tgt)) { - self::actor_store($person_obj['movedTo'],$tgt); - ActivityPub::move($person_obj['id'],$tgt); - } - return; - } - - - $ap_hubloc = null; - - $hublocs = self::get_actor_hublocs($url); - if ($hublocs) { - foreach ($hublocs as $hub) { - if ($hub['hubloc_network'] === 'activitypub') { - $ap_hubloc = $hub; - } - if ($hub['hubloc_network'] === 'zot6') { - Libzot::update_cached_hubloc($hub); - } - } - } - - if ($ap_hubloc) { - // we already have a stored record. Determine if it needs updating. - if ($ap_hubloc['hubloc_updated'] < datetime_convert('UTC','UTC',' now - ' . self::$ACTOR_CACHE_DAYS . ' days') || $force) { - $person_obj = self::fetch($url); - // ensure we received something - if (! is_array($person_obj)) { - return; - } - } - else { - return; - } - } - - - - if (isset($person_obj['id'])) { - $url = $person_obj['id']; - } - - if (! $url) { - return; - } - - // store the actor record in XConfig - XConfig::Set($url,'system','actor_record',$person_obj); - - $name = escape_tags($person_obj['name']); - if (! $name) - $name = escape_tags($person_obj['preferredUsername']); - if (! $name) - $name = escape_tags( t('Unknown')); - - $username = escape_tags($person_obj['preferredUsername']); - $h = parse_url($url); - if ($h && $h['host']) { - $username .= '@' . $h['host']; - } - - if ($person_obj['icon']) { - if (is_array($person_obj['icon'])) { - if (array_key_exists('url',$person_obj['icon'])) - $icon = $person_obj['icon']['url']; - else { - if (is_string($person_obj['icon'][0])) { - $icon = $person_obj['icon'][0]; - } - elseif (array_key_exists('url',$person_obj['icon'][0])) { - $icon = $person_obj['icon'][0]['url']; - } - } - } - else { - $icon = $person_obj['icon']; - } - } - if (! (isset($icon) && $icon)) { - $icon = z_root() . '/' . get_default_profile_photo(); - } - - $cover_photo = false; - - if (isset($person_obj['image'])) { - if (is_string($person_obj['image'])) { - $cover_photo = $person_obj['image']; - } - if (isset($person_obj['image']['url'])) { - $cover_photo = $person_obj['image']['url']; - } - } - - $hidden = false; - if (array_key_exists('discoverable',$person_obj) && (! intval($person_obj['discoverable']))) { - $hidden = true; - } - - $links = false; - $profile = false; - - if (is_array($person_obj['url'])) { - if (! array_key_exists(0,$person_obj['url'])) { - $links = [ $person_obj['url'] ]; - } - else { - $links = $person_obj['url']; - } - } - - if (is_array($links) && $links) { - foreach ($links as $link) { - if (is_array($link) && array_key_exists('mediaType',$link) && $link['mediaType'] === 'text/html') { - $profile = $link['href']; - } - } - if (! $profile) { - $profile = $links[0]['href']; - } - } - elseif (isset($person_obj['url']) && is_string($person_obj['url'])) { - $profile = $person_obj['url']; - } - - if (! $profile) { - $profile = $url; - } - - $inbox = ((array_key_exists('inbox',$person_obj)) ? $person_obj['inbox'] : null); - - // either an invalid identity or a cached entry of some kind which didn't get caught above - - if ((! $inbox) || strpos($inbox,z_root()) !== false) { - return; - } - - - $collections = []; - - if ($inbox) { - $collections['inbox'] = $inbox; - if (array_key_exists('outbox',$person_obj) && is_string($person_obj['outbox'])) { - $collections['outbox'] = $person_obj['outbox']; - } - if (array_key_exists('followers',$person_obj) && is_string($person_obj['followers'])) { - $collections['followers'] = $person_obj['followers']; - } - if (array_key_exists('following',$person_obj) && is_string($person_obj['following'])) { - $collections['following'] = $person_obj['following']; - } - if (array_key_exists('wall',$person_obj) && is_string($person_obj['wall'])) { - $collections['wall'] = $person_obj['wall']; - } - if (array_path_exists('endpoints/sharedInbox',$person_obj) && is_string($person_obj['endpoints']['sharedInbox'])) { - $collections['sharedInbox'] = $person_obj['endpoints']['sharedInbox']; - } - } - - if (isset($person_obj['publicKey']['publicKeyPem'])) { - if ($person_obj['id'] === $person_obj['publicKey']['owner']) { - $pubkey = $person_obj['publicKey']['publicKeyPem']; - if (strstr($pubkey,'RSA ')) { - $pubkey = Keyutils::rsatopem($pubkey); - } - } - } - - $keywords = []; - - if (isset($person_obj['tag']) && is_array($person_obj['tag'])) { - foreach ($person_obj['tag'] as $t) { - if (is_array($t) && isset($t['type']) && $t['type'] === 'Hashtag') { - if (isset($t['name'])) { - $tag = escape_tags((substr($t['name'],0,1) === '#') ? substr($t['name'],1) : $t['name']); - if ($tag) { - $keywords[] = $tag; - } - } - } - if (is_array($t) && isset($t['type']) && $t['type'] === 'PropertyValue') { - if (isset($t['name']) && isset($t['value']) && $t['name'] === 'Protocol') { - self::update_protocols($url,trim($t['value'])); - } - } - } - } - - $xchan_type = self::get_xchan_type($person_obj['type']); - $about = ((isset($person_obj['summary'])) ? html2bbcode(purify_html($person_obj['summary'])) : EMPTY_STR); - - $p = q("select * from xchan where xchan_url = '%s' and xchan_network = 'zot6' limit 1", - dbesc($url) - ); - if ($p) { - set_xconfig($url,'system','protocols','zot6,activitypub'); - } - - // there is no standard way to represent an 'instance actor' but this will at least subdue the multiple - // pages of Mastodon and Pleroma instance actors in the directory. - // @TODO - (2021-08-27) remove this if they provide a non-person xchan_type - // once extended xchan_type directory filtering is implemented. - $censored = ((strpos($profile,'instance_actor') || strpos($profile,'/internal/fetch')) ? 1 : 0); - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($url) - ); - if (! $r) { - // create a new record - $r = xchan_store_lowlevel( - [ - 'xchan_hash' => $url, - 'xchan_guid' => $url, - 'xchan_pubkey' => $pubkey, - 'xchan_addr' => ((strpos($username,'@')) ? $username : ''), - 'xchan_url' => $profile, - 'xchan_name' => $name, - 'xchan_hidden' => intval($hidden), - 'xchan_updated' => datetime_convert(), - 'xchan_name_date' => datetime_convert(), - 'xchan_network' => 'activitypub', - 'xchan_type' => $xchan_type, - 'xchan_photo_date' => datetime_convert('UTC','UTC','1968-01-01'), - 'xchan_photo_l' => z_root() . '/' . get_default_profile_photo(), - 'xchan_photo_m' => z_root() . '/' . get_default_profile_photo(80), - 'xchan_photo_s' => z_root() . '/' . get_default_profile_photo(48), - 'xchan_photo_mimetype' => 'image/png', - 'xchan_censored' => $censored - - ] - ); - } - else { - - // Record exists. Cache existing records for a set number of days - // then refetch to catch updated profile photos, names, etc. - - if ($r[0]['xchan_name_date'] >= datetime_convert('UTC','UTC','now - ' . self::$ACTOR_CACHE_DAYS . ' days') && (! $force)) { - return; - } - - // update existing record - $u = q("update xchan set xchan_updated = '%s', xchan_name = '%s', xchan_pubkey = '%s', xchan_network = '%s', xchan_name_date = '%s', xchan_hidden = %d, xchan_type = %d, xchan_censored = %d where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc($name), - dbesc($pubkey), - dbesc('activitypub'), - dbesc(datetime_convert()), - intval($hidden), - intval($xchan_type), - intval($censored), - dbesc($url) - ); - - if (strpos($username,'@') && ($r[0]['xchan_addr'] !== $username)) { - $r = q("update xchan set xchan_addr = '%s' where xchan_hash = '%s'", - dbesc($username), - dbesc($url) - ); - } - } - - if ($cover_photo) { - set_xconfig($url,'system','cover_photo',$cover_photo); - } - - - $m = parse_url($url); - if ($m['scheme'] && $m['host']) { - $site_url = $m['scheme'] . '://' . $m['host']; - $ni = Nodeinfo::fetch($site_url); - if ($ni && is_array($ni)) { - $software = ((array_path_exists('software/name',$ni)) ? $ni['software']['name'] : ''); - $version = ((array_path_exists('software/version',$ni)) ? $ni['software']['version'] : ''); - $register = $ni['openRegistrations']; - - $site = q("select * from site where site_url = '%s'", - dbesc($site_url) - ); - if ($site) { - q("update site set site_project = '%s', site_update = '%s', site_version = '%s' where site_url = '%s'", - dbesc($software), - dbesc(datetime_convert()), - dbesc($version), - dbesc($site_url) - ); - // it may have been saved originally as an unknown type, but we now know what it is - if (intval($site[0]['site_type']) === SITE_TYPE_UNKNOWN) { - q("update site set site_type = %d where site_url = '%s'", - intval(SITE_TYPE_NOTZOT), - dbesc($site_url) - ); - } - } - else { - site_store_lowlevel( - [ - 'site_url' => $site_url, - 'site_update' => datetime_convert(), - 'site_dead' => 0, - 'site_type' => SITE_TYPE_NOTZOT, - 'site_project' => $software, - 'site_version' => $version, - 'site_access' => (($register) ? ACCESS_FREE : ACCESS_PRIVATE), - 'site_register' => (($register) ? REGISTER_OPEN : REGISTER_CLOSED) - ] - ); - } - } - } - - Libzotdir::import_directory_profile($url,[ 'about' => $about, 'keywords' => $keywords, 'dob' => '0000-00-00' ], null,0,true); - - if ($collections) { - set_xconfig($url,'activitypub','collections',$collections); - } - - $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($url) - ); - - - $m = parse_url($url); - if ($m) { - $hostname = $m['host']; - $baseurl = $m['scheme'] . '://' . $m['host'] . ((isset($m['port']) && intval($m['port'])) ? ':' . $m['port'] : ''); - } - - if (! $h) { - $r = hubloc_store_lowlevel( - [ - 'hubloc_guid' => $url, - 'hubloc_hash' => $url, - 'hubloc_id_url' => $profile, - 'hubloc_addr' => ((strpos($username,'@')) ? $username : ''), - 'hubloc_network' => 'activitypub', - 'hubloc_url' => $baseurl, - 'hubloc_host' => $hostname, - 'hubloc_callback' => $inbox, - 'hubloc_updated' => datetime_convert(), - 'hubloc_primary' => 1 - ] - ); - } - else { - if (strpos($username,'@') && ($h[0]['hubloc_addr'] !== $username)) { - $r = q("update hubloc set hubloc_addr = '%s' where hubloc_hash = '%s'", - dbesc($username), - dbesc($url) - ); - } - if ($inbox !== $h[0]['hubloc_callback']) { - $r = q("update hubloc set hubloc_callback = '%s' where hubloc_hash = '%s'", - dbesc($inbox), - dbesc($url) - ); - } - if ($profile !== $h[0]['hubloc_id_url']) { - $r = q("update hubloc set hubloc_id_url = '%s' where hubloc_hash = '%s'", - dbesc($profile), - dbesc($url) - ); - } - $r = q("update hubloc set hubloc_updated = '%s' where hubloc_hash = '%s'", - dbesc(datetime_convert()), - dbesc($url) - ); - } - - if (! $icon) { - $icon = z_root() . '/' . get_default_profile_photo(300); - } - - // We store all ActivityPub actors we can resolve. Some of them may be able to communicate over Zot6. Find them. - // Only probe if it looks like it looks something like a zot6 URL as there isn't anything in the actor record which we can reliably use for this purpose - // and adding zot discovery urls to the actor record will cause federation to fail with the 20-30 projects which don't accept arrays in the url field. - - if (strpos($url,'/channel/') !== false) { - $zx = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6'", - dbesc($url) - ); - if (($username) && strpos($username,'@') && (! $zx)) { - Run::Summon( [ 'Gprobe', bin2hex($username) ] ); - } - } - - Run::Summon( [ 'Xchan_photo', bin2hex($icon), bin2hex($url) ] ); - - } - - static function update_protocols($xchan,$str) { - $existing = explode(',',get_xconfig($xchan,'system','protocols',EMPTY_STR)); - if (! in_array($str,$existing)) { - $existing[] = $str; - set_xconfig($xchan,'system','protocols', implode(',',$existing)); - } - } - - - static function drop($channel,$observer,$act) { - $r = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc((is_array($act->obj)) ? $act->obj['id'] : $act->obj), - intval($channel['channel_id']) - ); - - if (! $r) { - return; - } - - if (in_array($observer,[ $r[0]['author_xchan'], $r[0]['owner_xchan'] ])) { - drop_item($r[0]['id'],false); - } - elseif (in_array($act->actor['id'],[ $r[0]['author_xchan'], $r[0]['owner_xchan'] ])) { - drop_item($r[0]['id'],false); - } - - } - - - // sort function width decreasing - - static function vid_sort($a,$b) { - if ($a['width'] === $b['width']) - return 0; - return (($a['width'] > $b['width']) ? -1 : 1); - } - - static function share_bb($obj) { - // @fixme - error check and set defaults - - $name = urlencode($obj['actor']['name']); - $profile = $obj['actor']['id']; - $photo = $obj['icon']['url']; - - $s = "\r\n[share author='" . $name . - "' profile='" . $profile . - "' avatar='" . $photo . - "' link='" . $act->obj['id'] . - "' auth='" . ((is_matrix_url($act->obj['id'])) ? 'true' : 'false' ) . - "' posted='" . $act->obj['published'] . - "' message_id='" . $act->obj['id'] . - "']"; - - return $s; - } - - static function get_actor_bbmention($id) { - - $x = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' or hubloc_id_url = '%s' limit 1", - dbesc($id), - dbesc($id) - ); - - if ($x) { - // a name starting with a left paren can trick the markdown parser into creating a link so insert a zero-width space - if (substr($x[0]['xchan_name'],0,1) === '(') { - $x[0]['xchan_name'] = htmlspecialchars_decode('​',ENT_QUOTES) . $x[0]['xchan_name']; - } - - return sprintf('@[zrl=%s]%s[/zrl]',$x[0]['xchan_url'],$x[0]['xchan_name']); - } - return '@{' . $id . '}'; - - } - - static function update_poll($item,$post) { - - logger('updating poll'); - - $multi = false; - $mid = $post['mid']; - $content = $post['title']; - - if (! $item) { - return false; - } - - $o = json_decode($item['obj'],true); - if ($o && array_key_exists('anyOf',$o)) { - $multi = true; - } - - $r = q("select mid, title from item where parent_mid = '%s' and author_xchan = '%s' and mid != parent_mid ", - dbesc($item['mid']), - dbesc($post['author_xchan']) - ); - - // prevent any duplicate votes by same author for oneOf and duplicate votes with same author and same answer for anyOf - - if ($r) { - if ($multi) { - foreach ($r as $rv) { - if ($rv['title'] === $content && $rv['mid'] !== $mid) { - return false; - } - } - } - else { - foreach ($r as $rv) { - if ($rv['mid'] !== $mid) { - return false; - } - } - } - } - - $answer_found = false; - $found = false; - if ($multi) { - for ($c = 0; $c < count($o['anyOf']); $c ++) { - if ($o['anyOf'][$c]['name'] === $content) { - $answer_found = true; - if (is_array($o['anyOf'][$c]['replies'])) { - foreach($o['anyOf'][$c]['replies'] as $reply) { - if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) { - $found = true; - } - } - } - - if (! $found) { - $o['anyOf'][$c]['replies']['totalItems'] ++; - $o['anyOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ]; - } - } - } - } - else { - for ($c = 0; $c < count($o['oneOf']); $c ++) { - if ($o['oneOf'][$c]['name'] === $content) { - $answer_found = true; - if (is_array($o['oneOf'][$c]['replies'])) { - foreach($o['oneOf'][$c]['replies'] as $reply) { - if(is_array($reply) && array_key_exists('id',$reply) && $reply['id'] === $mid) { - $found = true; - } - } - } - - if (! $found) { - $o['oneOf'][$c]['replies']['totalItems'] ++; - $o['oneOf'][$c]['replies']['items'][] = [ 'id' => $mid, 'type' => 'Note' ]; - } - } - } - } - - if ($item['comments_closed'] > NULL_DATE) { - if ($item['comments_closed'] > datetime_convert()) { - $o['closed'] = datetime_convert('UTC','UTC',$item['comments_closed'], ATOM_TIME); - // set this to force an update - $answer_found = true; - } - } - - logger('updated_poll: ' . print_r($o,true),LOGGER_DATA); - if ($answer_found && ! $found) { - $x = q("update item set obj = '%s', edited = '%s' where id = %d", - dbesc(json_encode($o)), - dbesc(datetime_convert()), - intval($item['id']) - ); - Run::Summon( [ 'Notifier', 'wall-new', $item['id'] ] ); - return true; - } - - return false; - } - - - static function decode_note($act, $cacheable = false) { - - $response_activity = false; - $poll_handled = false; - - $s = []; - - if (is_array($act->obj)) { - $binary = false; - $markdown = false; - - if (array_key_exists('mediaType',$act->obj) && $act->obj['mediaType'] !== 'text/html') { - if ($act->obj['mediaType'] === 'text/markdown') { - $markdown = true; - } - else { - $s['mimetype'] = escape_tags($act->obj['mediaType']); - $binary = true; - } - } - - $content = self::get_content($act->obj,$binary); - - if ($cacheable) { - // Zot6 activities will all be rendered from bbcode source in order to generate dynamic content. - // If the activity came from ActivityPub (hence $cacheable is set), use the HTML rendering - // and discard the bbcode source since it is unlikely that it is compatible with our implementation. - // Friendica for example. - - unset($content['bbcode']); - } - - // handle markdown conversion inline (peertube) - - if ($markdown) { - foreach ( [ 'summary', 'content' ] as $t) { - $content[$t] = Markdown::to_bbcode($content[$t],true, [ 'preserve_lf' => true ]); - } - } - } - - // These activities should have been handled separately in the Inbox module and should not be turned into posts - - if (in_array($act->type, ['Follow', 'Accept', 'Reject', 'Create', 'Update']) && is_array($act->obj) && array_key_exists('type',$act->obj) - && ($act->obj['type'] === 'Follow' || ActivityStreams::is_an_actor($act->obj['type']))) { - return false; - } - - // Within our family of projects, Follow/Unfollow of a thread is an internal activity which should not be transmitted, - // hence if we receive it - ignore or reject it. - // This may have to be revisited if AP projects start using Follow for objects other than actors. - - if (in_array($act->type, [ ACTIVITY_FOLLOW, ACTIVITY_IGNORE ])) { - return false; - } - - // Do not proceed further if there is no actor. - - if (! isset($act->actor['id'])) { - logger('No actor!'); - return false; - } - - $s['owner_xchan'] = $act->actor['id']; - $s['author_xchan'] = $act->actor['id']; - - // ensure we store the original actor - self::actor_store($act->actor['id'],$act->actor); - - $s['mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj); - - if (! $s['mid']) { - return false; - } - - $s['parent_mid'] = $act->parent_id; - - if (array_key_exists('published',$act->data) && $act->data['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); - } - elseif (array_key_exists('published',$act->obj) && $act->obj['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->obj['published']); - } - if (array_key_exists('updated',$act->data) && $act->data['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); - } - elseif (array_key_exists('updated',$act->obj) && $act->obj['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->obj['updated']); - } - if (array_key_exists('expires',$act->data) && $act->data['expires']) { - $s['expires'] = datetime_convert('UTC','UTC',$act->data['expires']); - } - elseif (array_key_exists('expires',$act->obj) && $act->obj['expires']) { - $s['expires'] = datetime_convert('UTC','UTC',$act->obj['expires']); - } - - if ($act->type === 'Invite' && is_array($act->obj) && array_key_exists('type',$act->obj) && $act->obj['type'] === 'Event') { - $s['mid'] = $s['parent_mid'] = $act->id; - } - - if (isset($act->replyto) && ! empty($act->replyto)) { - if (is_array($act->replyto) && isset($act->replyto['id'])) { - $s['replyto'] = $act->replyto['id']; - } - else { - $s['replyto'] = $act->replyto; - } - } - - if (ActivityStreams::is_response_activity($act->type)) { - - $response_activity = true; - - $s['mid'] = $act->id; - $s['parent_mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj); - - - // over-ride the object timestamp with the activity - - if (isset($act->data['published']) && $act->data['published']) { - $s['created'] = datetime_convert('UTC','UTC',$act->data['published']); - } - - if (isset($act->data['updated']) && $act->data['updated']) { - $s['edited'] = datetime_convert('UTC','UTC',$act->data['updated']); - } - - $obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj)); - - // Actor records themselves do not have an actor or attributedTo - if ((! $obj_actor) && isset($act->obj['type']) && Activitystreams::is_an_actor($act->obj['type'])) { - $obj_actor = $act->obj; - } - - // We already check for admin blocks of third-party objects when fetching them explicitly. - // Repeat here just in case the entire object was supplied inline and did not require fetching - - if ($obj_actor && array_key_exists('id',$obj_actor)) { - $m = parse_url($obj_actor['id']); - if ($m && $m['scheme'] && $m['host']) { - if (! check_siteallowed($m['scheme'] . '://' . $m['host'])) { - return; - } - } - if (! check_channelallowed($obj_actor['id'])) { - return; - } - } - - // if the object is an actor, it is not really a response activity, so reset it to a top level post - - if (ActivityStreams::is_an_actor($act->obj['type'])) { - $s['parent_mid'] = $s['mid']; - } - - - // ensure we store the original actor of the associated (parent) object - self::actor_store($obj_actor['id'],$obj_actor); - - $mention = self::get_actor_bbmention($obj_actor['id']); - - $quoted_content = '[quote]' . $content['content'] . '[/quote]'; - - if ($act->type === 'Like') { - $content['content'] = sprintf( t('Likes %1$s\'s %2$s'),$mention, ((ActivityStreams::is_an_actor($act->obj['type'])) ? t('Profile') : $act->obj['type'])) . EOL . EOL . $quoted_content; - } - if ($act->type === 'Dislike') { - $content['content'] = sprintf( t('Doesn\'t like %1$s\'s %2$s'),$mention, ((ActivityStreams::is_an_actor($act->obj['type'])) ? t('Profile') : $act->obj['type'])) . EOL . EOL . $quoted_content; - } - - // handle event RSVPs - if (($act->obj['type'] === 'Event') || ($act->obj['type'] === 'Invite' && array_path_exists('object/type',$act->obj) && $act->obj['object']['type'] === 'Event')) { - if ($act->type === 'Accept') { - $content['content'] = sprintf( t('Will attend %s\'s event'),$mention) . EOL . EOL . $quoted_content; - } - if ($act->type === 'Reject') { - $content['content'] = sprintf( t('Will not attend %s\'s event'),$mention) . EOL . EOL . $quoted_content; - } - if ($act->type === 'TentativeAccept') { - $content['content'] = sprintf( t('May attend %s\'s event'),$mention) . EOL . EOL . $quoted_content; - } - if ($act->type === 'TentativeReject') { - $content['content'] = sprintf( t('May not attend %s\'s event'),$mention) . EOL . EOL . $quoted_content; - } - } - - if ($act->type === 'Announce') { - $content['content'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, ((ActivityStreams::is_an_actor($act->obj['type'])) ? t('Profile') : $act->obj['type'])); - } - - if ($act->type === 'emojiReaction') { - // Hubzilla reactions - $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';'); - } - - if (in_array($act->type,[ 'EmojiReaction', 'EmojiReact' ])) { - // Pleroma reactions - $t = trim(self::get_textfield($act->data,'content')); - $e = Emoji\is_single_emoji($t) || mb_strlen($t) === 1; - if ($e) { - $content['content'] = $t; - } - } - } - - $s['comment_policy'] = 'authenticated'; - - if ($s['mid'] === $s['parent_mid']) { - // it is a parent node - decode the comment policy info if present - if (isset($act->obj['commentPolicy'])) { - $until = strpos($act->obj['commentPolicy'],'until='); - if ($until !== false) { - $s['comments_closed'] = datetime_convert('UTC','UTC',substr($act->obj['commentPolicy'],$until + 6)); - if ($s['comments_closed'] < datetime_convert()) { - $s['nocomment'] = true; - } - } - $remainder = substr($act->obj['commentPolicy'],0,(($until) ? $until : strlen($act->obj['commentPolicy']))); - if ($remainder) { - $s['comment_policy'] = $remainder; - } - if (! (isset($item['comment_policy']) && strlen($item['comment_policy']))) { - $s['comment_policy'] = 'contacts'; - } - } - } - - if (! (array_key_exists('created',$s) && $s['created'])) { - $s['created'] = datetime_convert(); - } - if (! (array_key_exists('edited',$s) && $s['edited'])) { - $s['edited'] = $s['created']; - } - $s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content,'name')); - $s['summary'] = self::bb_content($content,'summary'); - - if (array_key_exists('mimetype',$s) && (! in_array($s['mimetype'], [ 'text/bbcode', 'text/x-multicode' ]))) { - $s['body'] = $content['content']; - } - else { - $s['body'] = ((self::bb_content($content,'bbcode') && (! $response_activity)) ? self::bb_content($content,'bbcode') : self::bb_content($content,'content')); - } - - - // handle some of the more widely used of the numerous and varied ways of deleting something - - if (in_array($act->type, [ 'Delete', 'Undo', 'Tombstone' ])) { - $s['item_deleted'] = 1; - } - - if ($act->type === 'Create' && $act->obj['type'] === 'Tombstone') { - $s['item_deleted'] = 1; - } - - if ($act->obj && array_key_exists('sensitive',$act->obj) && boolval($act->obj['sensitive'])) { - $s['item_nsfw'] = 1; - } - - $s['verb'] = self::activity_mapper($act->type); - - // Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here. - if ($act->type === 'Update' && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) { - $s['edited'] = datetime_convert(); - } - - - $s['obj_type'] = self::activity_obj_mapper($act->obj['type']); - $s['obj'] = $act->obj; - if (is_array($s['obj']) && array_path_exists('actor/id',$s['obj'])) { - $s['obj']['actor'] = $s['obj']['actor']['id']; - } - - if (is_array($act->tgt) && $act->tgt) { - if (array_key_exists('type',$act->tgt)) { - $s['tgt_type'] = self::activity_obj_mapper($act->tgt['type']); - } - // We shouldn't need to store collection contents which could be large. We will often only require the meta-data - if (isset($s['tgt_type']) && strpos($s['tgt_type'],'Collection') !== false) { - $s['target'] = [ 'id' => $act->tgt['id'], 'type' => $s['tgt_type'], 'attributedTo' => ((isset($act->tgt['attributedTo'])) ? $act->tgt['attributedTo'] : $act->tgt['actor']) ]; - } - } - - $generator = $act->get_property_obj('generator'); - if ((! $generator) && (! $response_activity)) { - $generator = $act->get_property_obj('generator',$act->obj); - } - - if ($generator && array_key_exists('type',$generator) - && in_array($generator['type'], [ 'Application','Service' ] ) && array_key_exists('name',$generator)) { - $s['app'] = escape_tags($generator['name']); - } - - $location = $act->get_property_obj('location'); - if (is_array($location) && array_key_exists('type',$location) && $location['type'] === 'Place') { - if (array_key_exists('name',$location)) { - $s['location'] = escape_tags($location['name']); - } - if (array_key_exists('content',$location)) { - $s['location'] = html2plain(purify_html($location['content']),256); - } - - if (array_key_exists('latitude',$location) && array_key_exists('longitude',$location)) { - $s['coord'] = escape_tags($location['latitude']) . ' ' . escape_tags($location['longitude']); - } - } - - if (! $response_activity) { - $a = self::decode_taxonomy($act->obj); - if ($a) { - $s['term'] = $a; - foreach ($a as $b) { - if ($b['ttype'] === TERM_EMOJI) { - $s['summary'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['summary']); - - // @todo - @bug - // The emoji reference in the body might be inside a code block. In that case we shouldn't replace it. - // Currently we do. - - $s['body'] = str_replace($b['term'],'[img=16x16]' . $b['url'] . '[/img]',$s['body']); - } - } - } - - $a = self::decode_attachment($act->obj); - if ($a) { - $s['attach'] = $a; - } - - $a = self::decode_iconfig($act->obj); - if ($a) { - $s['iconfig'] = $a; - } - } - - // Objects that might have media attachments which aren't already provided in the content element. - // We'll check specific media objects separately. - - if (in_array($act->obj['type'], [ 'Article', 'Document', 'Event', 'Note', 'Page', 'Place', 'Question' ]) && isset($s['attach']) && $s['attach']) { - $s['body'] .= self::bb_attach($s['attach'],$s['body']); - } - - if ($act->obj['type'] === 'Question' && in_array($act->type,['Create','Update'])) { - if ($act->obj['endTime']) { - $s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['endTime']); - } - } - - if (array_key_exists('closed',$act->obj) && $act->obj['closed']) { - $s['comments_closed'] = datetime_convert('UTC','UTC', $act->obj['closed']); - } - - - // we will need a hook here to extract magnet links e.g. peertube - // right now just link to the largest mp4 we find that will fit in our - // standard content region - - if (! $response_activity) { - if ($act->obj['type'] === 'Video') { - - $vtypes = [ - 'video/mp4', - 'video/ogg', - 'video/webm' - ]; - - $mps = []; - $poster = null; - $ptr = null; - - // try to find a poster to display on the video element - - if (array_key_exists('icon',$act->obj)) { - if (is_array($act->obj['icon'])) { - if (array_key_exists(0,$act->obj['icon'])) { - $ptr = $act->obj['icon']; - } - else { - $ptr = [ $act->obj['icon'] ]; - } - } - if ($ptr) { - foreach ($ptr as $foo) { - if (is_array($foo) && array_key_exists('type',$foo) && $foo['type'] === 'Image' && is_string($foo['url'])) { - $poster = $foo['url']; - } - } - } - } - - $tag = (($poster) ? '[video poster="' . $poster . '"]' : '[video]' ); - $ptr = null; - - if (array_key_exists('url',$act->obj)) { - if (is_array($act->obj['url'])) { - if (array_key_exists(0,$act->obj['url'])) { - $ptr = $act->obj['url']; - } - else { - $ptr = [ $act->obj['url'] ]; - } - // handle peertube's weird url link tree if we find it here - // 0 => html link, 1 => application/x-mpegURL with 'tag' set to an array of actual media links - foreach ($ptr as $idex) { - if (is_array($idex) && array_key_exists('mediaType',$idex)) { - if ($idex['mediaType'] === 'application/x-mpegURL' && isset($idex['tag']) && is_array($idex['tag'])) { - $ptr = $idex['tag']; - break; - } - } - } - foreach ($ptr as $vurl) { - if (array_key_exists('mediaType',$vurl)) { - if (in_array($vurl['mediaType'], $vtypes)) { - if (! array_key_exists('width',$vurl)) { - $vurl['width'] = 0; - } - $mps[] = $vurl; - } - } - } - } - if ($mps) { - usort($mps,[ __CLASS__, 'vid_sort' ]); - foreach ($mps as $m) { - if (intval($m['width']) < 500 && self::media_not_in_body($m['href'],$s['body'])) { - $s['body'] .= "\n\n" . $tag . $m['href'] . '[/video]'; - break; - } - } - } - elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) { - $s['body'] .= "\n\n" . $tag . $act->obj['url'] . '[/video]'; - } - } - } - - if ($act->obj['type'] === 'Audio') { - - $atypes = [ - 'audio/mpeg', - 'audio/ogg', - 'audio/wav' - ]; - - $ptr = null; - - if (array_key_exists('url',$act->obj)) { - if (is_array($act->obj['url'])) { - if (array_key_exists(0,$act->obj['url'])) { - $ptr = $act->obj['url']; - } - else { - $ptr = [ $act->obj['url'] ]; - } - foreach ($ptr as $vurl) { - if (isset($vurl['mediaType']) && in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'],$s['body'])) { - $s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]'; - break; - } - } - } - elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'],$s['body'])) { - $s['body'] .= "\n\n" . '[audio]' . $act->obj['url'] . '[/audio]'; - } - } - // Pleroma audio scrobbler - elseif ($act->type === 'Listen' && array_key_exists('artist', $act->obj) && array_key_exists('title',$act->obj) && $s['body'] === EMPTY_STR) { - $s['body'] .= "\n\n" . sprintf('Listening to \"%1$s\" by %2$s', escape_tags($act->obj['title']), escape_tags($act->obj['artist'])); - if(isset($act->obj['album'])) { - $s['body'] .= "\n" . sprintf('(%s)', escape_tags($act->obj['album'])); - } - } - } - - if ($act->obj['type'] === 'Image' && strpos($s['body'],'zrl=') === false) { - - $ptr = null; - - if (array_key_exists('url',$act->obj)) { - if (is_array($act->obj['url'])) { - if (array_key_exists(0,$act->obj['url'])) { - $ptr = $act->obj['url']; - } - else { - $ptr = [ $act->obj['url'] ]; - } - foreach ($ptr as $vurl) { - if (is_array($vurl) && isset($vurl['href']) && strpos($s['body'],$vurl['href']) === false) { - $s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]'; - break; - } - } - } - elseif (is_string($act->obj['url'])) { - if (strpos($s['body'],$act->obj['url']) === false) { - $s['body'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]'; - } - } - } - } - - - if ($act->obj['type'] === 'Page' && ! $s['body']) { - - $ptr = null; - $purl = EMPTY_STR; - - if (array_key_exists('url',$act->obj)) { - if (is_array($act->obj['url'])) { - if (array_key_exists(0,$act->obj['url'])) { - $ptr = $act->obj['url']; - } - else { - $ptr = [ $act->obj['url'] ]; - } - foreach ($ptr as $vurl) { - if (is_array($vurl) && array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { - $purl = $vurl['href']; - break; - } - elseif (array_key_exists('mimeType',$vurl) && $vurl['mimeType'] === 'text/html') { - $purl = $vurl['href']; - break; - } - } - } - elseif (is_string($act->obj['url'])) { - $purl = $act->obj['url']; - } - if ($purl) { - $li = z_fetch_url(z_root() . '/linkinfo?binurl=' . bin2hex($purl)); - if ($li['success'] && $li['body']) { - $s['body'] .= "\n" . $li['body']; - } - else { - $s['body'] .= "\n\n" . $purl; - } - } - } - } - } - - - - if (in_array($act->obj['type'],[ 'Note','Article','Page' ])) { - $ptr = null; - - if (array_key_exists('url',$act->obj)) { - if (is_array($act->obj['url'])) { - if (array_key_exists(0,$act->obj['url'])) { - $ptr = $act->obj['url']; - } - else { - $ptr = [ $act->obj['url'] ]; - } - foreach ($ptr as $vurl) { - if (is_array($vurl) && array_key_exists('mediaType',$vurl) && $vurl['mediaType'] === 'text/html') { - $s['plink'] = $vurl['href']; - break; - } - } - } - elseif (is_string($act->obj['url'])) { - $s['plink'] = $act->obj['url']; - } - } - } - - if (! (isset($s['plink']) && $s['plink'])) { - $s['plink'] = $s['mid']; - } - - // assume this is private unless specifically told otherwise. - - $s['item_private'] = 1; - - if ($act->recips && (in_array(ACTIVITY_PUBLIC_INBOX,$act->recips) || in_array('Public',$act->recips) || in_array('as:Public',$act->recips))) { - $s['item_private'] = 0; - } - - if (is_array($act->obj)) { - if (array_key_exists('directMessage',$act->obj) && intval($act->obj['directMessage'])) { - $s['item_private'] = 2; - } - } - - set_iconfig($s,'activitypub','recips',$act->raw_recips); - - if (array_key_exists('directMessage',$act->data) && intval($act->data['directMessage'])) { - $s['item_private'] = 2; - } - - - set_iconfig($s,'activitypub','rawmsg',$act->raw,1); - - // Restrict html caching to ActivityPub senders. - // Zot has dynamic content and this library is used by both. - - if ($cacheable) { - if ((! array_key_exists('mimetype',$s)) || (in_array($s['mimetype'], [ 'text/bbcode', 'text/x-multicode' ]))) { - - // preserve the original purified HTML content *unless* we've modified $s['body'] - // within this function (to add attachments or reaction descriptions or mention rewrites). - // This avoids/bypasses some markdown rendering issues which can occur when - // converting to our markdown-enhanced bbcode and then back to HTML again. - // Also if we do need bbcode, use the 'bbonly' flag to ignore markdown and only - // interpret bbcode; which is much less susceptible to false positives in the - // conversion regexes. - - if ($s['body'] === self::bb_content($content,'content')) { - $s['html'] = $content['content']; - } - else { - $s['html'] = bbcode($s['body'], [ 'bbonly' => true ]); - } - } - } - - $hookinfo = [ - 'act' => $act, - 's' => $s - ]; - - call_hooks('decode_note',$hookinfo); - - $s = $hookinfo['s']; - - return $s; - - } - - static function rewrite_mentions_sub(&$s, $pref, &$obj = null) { - - if (isset($s['term']) && is_array($s['term'])) { - foreach ($s['term'] as $tag) { - $txt = EMPTY_STR; - if (intval($tag['ttype']) === TERM_MENTION) { - // some platforms put the identity url into href rather than the profile url. Accept either form. - $x = q("select * from xchan where xchan_url = '%s' or xchan_hash = '%s' limit 1", - dbesc($tag['url']), - dbesc($tag['url']) - ); - if ($x) { - switch ($pref) { - case 0: - $txt = $x[0]['xchan_name']; - break; - case 1: - $txt = (($x[0]['xchan_addr']) ? $x[0]['xchan_addr'] : $x[0]['xchan_name']); - break; - case 2: - default; - if ($x[0]['xchan_addr']) { - $txt = sprintf( t('%1$s (%2$s)'), $x[0]['xchan_name'], $x[0]['xchan_addr']); - } - else { - $txt = $x[0]['xchan_name']; - } - break; - } - } - } - - if ($txt) { - - // the Markdown filter will get tripped up and think this is a markdown link - // if $txt begins with parens so put it behind a zero-width space - if (substr($txt,0,1) === '(') { - $txt = htmlspecialchars_decode('​',ENT_QUOTES) . $txt; - } - $s['body'] = preg_replace('/\@\[zrl\=' . preg_quote($x[0]['xchan_url'],'/') . '\](.*?)\[\/zrl\]/ism', - '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]',$s['body']); - $s['body'] = preg_replace('/\@\[url\=' . preg_quote($x[0]['xchan_url'],'/') . '\](.*?)\[\/url\]/ism', - '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]',$s['body']); - $s['body'] = preg_replace('/\[zrl\=' . preg_quote($x[0]['xchan_url'],'/') . '\]@(.*?)\[\/zrl\]/ism', - '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]',$s['body']); - $s['body'] = preg_replace('/\[url\=' . preg_quote($x[0]['xchan_url'],'/') . '\]@(.*?)\[\/url\]/ism', - '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]',$s['body']); - - // replace these just in case the sender (in this case Friendica) got it wrong - $s['body'] = preg_replace('/\@\[zrl\=' . preg_quote($x[0]['xchan_hash'],'/') . '\](.*?)\[\/zrl\]/ism', - '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]',$s['body']); - $s['body'] = preg_replace('/\@\[url\=' . preg_quote($x[0]['xchan_hash'],'/') . '\](.*?)\[\/url\]/ism', - '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]',$s['body']); - $s['body'] = preg_replace('/\[zrl\=' . preg_quote($x[0]['xchan_hash'],'/') . '\]@(.*?)\[\/zrl\]/ism', - '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]',$s['body']); - $s['body'] = preg_replace('/\[url\=' . preg_quote($x[0]['xchan_hash'],'/') . '\]@(.*?)\[\/url\]/ism', - '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]',$s['body']); - - if ($obj && $txt) { - if (! is_array($obj)) { - $obj = json_decode($obj,true); - } - if (array_path_exists('source/content',$obj)) { - $obj['source']['content'] = preg_replace('/\@\[zrl\=' . preg_quote($x[0]['xchan_url'],'/') . '\](.*?)\[\/zrl\]/ism', - '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]',$obj['source']['content']); - $obj['source']['content'] = preg_replace('/\@\[url\=' . preg_quote($x[0]['xchan_url'],'/') . '\](.*?)\[\/url\]/ism', - '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]',$obj['source']['content']); - } - $obj['content'] = preg_replace('/\@(.*?)\(.*?)\<\/a\>/ism', - '@$1' . $txt . '', $obj['content']); - } - } - } - } - - // $s['html'] will be populated if caching was enabled. - // This is usually the case for ActivityPub sourced content, while Zot6 content is not cached. - - if (isset($s['html']) && $s['html']) { - $s['html'] = bbcode($s['body'], [ 'bbonly' => true ] ); - } - - return; - } - - static function rewrite_mentions(&$s) { - // rewrite incoming mentions in accordance with system.tag_username setting - // 0 - displayname - // 1 - username - // 2 - displayname (username) - // 127 - default - - $pref = intval(PConfig::Get($s['uid'],'system','tag_username',Config::Get('system','tag_username',false))); - - if ($pref === 127) { - return; - } - - self::rewrite_mentions_sub($s,$pref); - - - return; - } - - // $force is used when manually fetching a remote item - it assumes you are granting one-time - // permission for the selected item/conversation regardless of your relationship with the author and - // assumes that you are in fact the sender. Please do not use it for anything else. The only permission - // checking that is performed is that the author isn't blocked by the site admin. - - static function store($channel,$observer_hash,$act,$item,$fetch_parents = true, $force = false) { - - if ($act && $act->implied_create && ! $force) { - // This is originally a S2S object with no associated activity - logger('Not storing implied create activity!'); - return; - } - - $is_sys_channel = is_sys_channel($channel['channel_id']); - $is_child_node = false; - - // Pleroma scrobbles can be really noisy and contain lots of duplicate activities. Disable them by default. - - if (($act->type === 'Listen') && ($is_sys_channel || get_pconfig($channel['channel_id'],'system','allow_scrobbles',false))) { - return; - } - - // Mastodon only allows visibility in public timelines if the public inbox is listed in the 'to' field. - // They are hidden in the public timeline if the public inbox is listed in the 'cc' field. - // This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point. - - $pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && is_array($act->obj['to']) && (in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to']) || in_array('Public',$act->obj['to']) || in_array('as:Public',$act->obj['to']))) ? true : false); - - // very unpleasant and imperfect way of determining a Mastodon DM - - if ($act->raw_recips && array_key_exists('to',$act->raw_recips) && is_array($act->raw_recips['to']) && count($act->raw_recips['to']) === 1 && $act->raw_recips['to'][0] === channel_url($channel) && ! $act->raw_recips['cc']) { - $item['item_private'] = 2; - } - - - - if ($item['parent_mid'] && $item['parent_mid'] !== $item['mid']) { - $is_child_node = true; - } - - $allowed = false; - $reason = [ 'init' ]; - $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel,$item)); - - if ($is_child_node) { - $p = q("select * from item where mid = '%s' and uid = %d and item_wall = 1", - dbesc($item['parent_mid']), - intval($channel['channel_id']) - ); - if ($p) { - // set the owner to the owner of the parent - $item['owner_xchan'] = $p[0]['owner_xchan']; - - // quietly reject group comment boosts by group owner - // (usually only sent via ActivityPub so groups will work on microblog platforms) - // This catches those activities if they slipped in via a conversation fetch - - if ($p[0]['parent_mid'] !== $item['parent_mid']) { - if ($item['verb'] === 'Announce' && $item['author_xchan'] === $item['owner_xchan']) { - logger('group boost activity by group owner rejected'); - return; - } - } - - // check permissions against the author, not the sender - $allowed = perm_is_allowed($channel['channel_id'],$item['author_xchan'],'post_comments'); - if (! $allowed) { - $reason[] = 'post_comments perm'; - } - if ((! $allowed) && $permit_mentions) { - if ($p[0]['owner_xchan'] === $channel['channel_hash']) { - $allowed = false; - $reason[] = 'ownership'; - } - else { - $allowed = true; - } - } - if (absolutely_no_comments($p[0])) { - $allowed = false; - $reason[] = 'absolutely'; - } - - if (! $allowed) { - logger('rejected comment from ' . $item['author_xchan'] . ' for ' . $channel['channel_address']); - logger('rejected reason ' . print_r($reason,true)); - logger('rejected: ' . print_r($item,true), LOGGER_DATA); - // let the sender know we received their comment but we don't permit spam here. - self::send_rejection_activity($channel,$item['author_xchan'],$item); - return; - } - - if (perm_is_allowed($channel['channel_id'],$item['author_xchan'],'moderated')) { - $item['item_blocked'] = ITEM_MODERATED; - } - } - else { - - // By default if we allow you to send_stream and comments and this is a comment, it is allowed. - // A side effect of this action is that if you take away send_stream permission, comments to those - // posts you previously allowed will still be accepted. It is possible but might be difficult to fix this. - - $allowed = true; - - // reject public stream comments that weren't sent by the conversation owner - // but only on remote message deliveries to our site ($fetch_parents === true) - - if ($is_sys_channel && $pubstream && $item['owner_xchan'] !== $observer_hash && ! $fetch_parents) { - $allowed = false; - $reason[] = 'sender ' . $observer_hash . ' not owner ' . $item['owner_xchan']; - } - } - - if ($p && $p[0]['obj_type'] === 'Question') { - if ($item['obj_type'] === 'Note' && $item['title'] && (! $item['content'])) { - $item['obj_type'] = 'Answer'; - } - } - } - else { - if (perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') || ($is_sys_channel && $pubstream)) { - logger('allowed: permission allowed', LOGGER_DATA); - $allowed = true; - } - if ($permit_mentions) { - logger('allowed: permitted mention', LOGGER_DATA); - $allowed = true; - } - } - - if (tgroup_check($channel['channel_id'],$item) && (! $is_child_node)) { - // for forum deliveries, make sure we keep a copy of the signed original - set_iconfig($item,'activitypub','rawmsg',$act->raw,1); - logger('allowed: tgroup'); - $allowed = true; - } - - if (get_abconfig($channel['channel_id'],$observer_hash,'system','block_announce', false)) { - if ($item['verb'] === 'Announce' || strpos($item['body'],'[/share]')) { - $allowed = false; - } - } - - if (intval($item['item_private']) === 2) { - if (! perm_is_allowed($channel['channel_id'],$observer_hash,'post_mail')) { - $allowed = false; - } - } - - if ($is_sys_channel) { - - if (! check_pubstream_channelallowed($observer_hash)) { - $allowed = false; - $reason[] = 'pubstream channel blocked'; - } - - // don't allow pubstream posts if the sender even has a clone on a pubstream denied site - - $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", - dbesc($observer_hash) - ); - if ($h) { - foreach ($h as $hub) { - if (! check_pubstream_siteallowed($hub['hubloc_url'])) { - $allowed = false; - $reason = 'pubstream site blocked'; - break; - } - } - } - if (intval($item['item_private'])) { - $allowed = false; - $reason[] = 'private item'; - } - } - - $blocked = LibBlock::fetch($channel['channel_id'],BLOCKTYPE_SERVER); - if ($blocked) { - foreach($blocked as $b) { - if (strpos($observer_hash,$b['block_entity']) !== false) { - $allowed = false; - $reason[] = 'blocked'; - } - } - } - - if (! $allowed && ! $force) { - logger('no permission: channel ' . $channel['channel_address'] . ', id = ' . $item['mid']); - logger('no permission: reason ' . print_r($reason,true)); - return; - } - - $item['aid'] = $channel['channel_account_id']; - $item['uid'] = $channel['channel_id']; - - - // Some authors may be zot6 authors in which case we want to store their nomadic identity - // instead of their ActivityPub identity - - $item['author_xchan'] = self::find_best_identity($item['author_xchan']); - $item['owner_xchan'] = self::find_best_identity($item['owner_xchan']); - - if (! ( $item['author_xchan'] && $item['owner_xchan'])) { - logger('owner or author missing.'); - return; - } - - if ($channel['channel_system']) { - if (! MessageFilter::evaluate($item,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) { - logger('post is filtered'); - return; - } - } - - // fetch allow/deny lists for the sender, author, or both - // if you have them. post_is_importable() assumes true - // and only fails if there was intentional rejection - // due to this channel's filtering rules for content - // provided by either of these entities. - - $abook = q("select * from abook where ( abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ", - dbesc($item['author_xchan']), - dbesc($item['owner_xchan']), - intval($channel['channel_id']) - ); - - - if (! post_is_importable($channel['channel_id'],$item,$abook)) { - logger('post is filtered'); - return; - } - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($item['body']) > $maxlen) { - $item['body'] = mb_substr($item['body'],0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - - if($maxlen && mb_strlen($item['summary']) > $maxlen) { - $item['summary'] = mb_substr($item['summary'],0,$maxlen,'UTF-8'); - logger('message summary length exceeds max_import_size: truncated'); - } - - if ($act->obj['context']) { - set_iconfig($item,'activitypub','context',$act->obj['context'],1); - } - - if ($act->obj['conversation']) { - set_iconfig($item,'ostatus','conversation',$act->obj['conversation'],1); - } - - set_iconfig($item,'activitypub','recips',$act->raw_recips); - - if (intval($act->sigok)) { - $item['item_verified'] = 1; - } - - $parent = null; - - if ($is_child_node) { - - $parent = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($item['parent_mid']), - intval($item['uid']) - ); - if (! $parent) { - if (! get_config('system','activitypub', ACTIVITYPUB_ENABLED)) { - return; - } - else { - $fetch = false; - if (intval($channel['channel_system']) || (perm_is_allowed($channel['channel_id'],$observer_hash,'send_stream') && (PConfig::Get($channel['channel_id'],'system','hyperdrive',true) || $act->type === 'Announce'))) { - $fetch = (($fetch_parents) ? self::fetch_and_store_parents($channel,$observer_hash,$act,$item) : false); - } - if ($fetch) { - $parent = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($item['parent_mid']), - intval($item['uid']) - ); - } - else { - logger('no parent'); - return; - } - } - } - - $item['comment_policy'] = $parent[0]['comment_policy']; - $item['item_nocomment'] = $parent[0]['item_nocomment']; - $item['comments_closed'] = $parent[0]['comments_closed']; - - if ($parent[0]['parent_mid'] !== $item['parent_mid']) { - $item['thr_parent'] = $item['parent_mid']; - } - else { - $item['thr_parent'] = $parent[0]['parent_mid']; - } - $item['parent_mid'] = $parent[0]['parent_mid']; - - /* + if (array_key_exists('movedTo', $person_obj) && $person_obj['movedTo'] && !is_array($person_obj['movedTo'])) { + $tgt = self::fetch($person_obj['movedTo']); + if (is_array($tgt)) { + self::actor_store($person_obj['movedTo'], $tgt); + ActivityPub::move($person_obj['id'], $tgt); + } + return; + } + + + $ap_hubloc = null; + + $hublocs = self::get_actor_hublocs($url); + if ($hublocs) { + foreach ($hublocs as $hub) { + if ($hub['hubloc_network'] === 'activitypub') { + $ap_hubloc = $hub; + } + if ($hub['hubloc_network'] === 'zot6') { + Libzot::update_cached_hubloc($hub); + } + } + } + + if ($ap_hubloc) { + // we already have a stored record. Determine if it needs updating. + if ($ap_hubloc['hubloc_updated'] < datetime_convert('UTC', 'UTC', ' now - ' . self::$ACTOR_CACHE_DAYS . ' days') || $force) { + $person_obj = self::fetch($url); + // ensure we received something + if (!is_array($person_obj)) { + return; + } + } else { + return; + } + } + + + if (isset($person_obj['id'])) { + $url = $person_obj['id']; + } + + if (!$url) { + return; + } + + // store the actor record in XConfig + XConfig::Set($url, 'system', 'actor_record', $person_obj); + + $name = escape_tags($person_obj['name']); + if (!$name) + $name = escape_tags($person_obj['preferredUsername']); + if (!$name) + $name = escape_tags(t('Unknown')); + + $username = escape_tags($person_obj['preferredUsername']); + $h = parse_url($url); + if ($h && $h['host']) { + $username .= '@' . $h['host']; + } + + if ($person_obj['icon']) { + if (is_array($person_obj['icon'])) { + if (array_key_exists('url', $person_obj['icon'])) + $icon = $person_obj['icon']['url']; + else { + if (is_string($person_obj['icon'][0])) { + $icon = $person_obj['icon'][0]; + } elseif (array_key_exists('url', $person_obj['icon'][0])) { + $icon = $person_obj['icon'][0]['url']; + } + } + } else { + $icon = $person_obj['icon']; + } + } + if (!(isset($icon) && $icon)) { + $icon = z_root() . '/' . get_default_profile_photo(); + } + + $cover_photo = false; + + if (isset($person_obj['image'])) { + if (is_string($person_obj['image'])) { + $cover_photo = $person_obj['image']; + } + if (isset($person_obj['image']['url'])) { + $cover_photo = $person_obj['image']['url']; + } + } + + $hidden = false; + if (array_key_exists('discoverable', $person_obj) && (!intval($person_obj['discoverable']))) { + $hidden = true; + } + + $links = false; + $profile = false; + + if (is_array($person_obj['url'])) { + if (!array_key_exists(0, $person_obj['url'])) { + $links = [$person_obj['url']]; + } else { + $links = $person_obj['url']; + } + } + + if (is_array($links) && $links) { + foreach ($links as $link) { + if (is_array($link) && array_key_exists('mediaType', $link) && $link['mediaType'] === 'text/html') { + $profile = $link['href']; + } + } + if (!$profile) { + $profile = $links[0]['href']; + } + } elseif (isset($person_obj['url']) && is_string($person_obj['url'])) { + $profile = $person_obj['url']; + } + + if (!$profile) { + $profile = $url; + } + + $inbox = ((array_key_exists('inbox', $person_obj)) ? $person_obj['inbox'] : null); + + // either an invalid identity or a cached entry of some kind which didn't get caught above + + if ((!$inbox) || strpos($inbox, z_root()) !== false) { + return; + } + + + $collections = []; + + if ($inbox) { + $collections['inbox'] = $inbox; + if (array_key_exists('outbox', $person_obj) && is_string($person_obj['outbox'])) { + $collections['outbox'] = $person_obj['outbox']; + } + if (array_key_exists('followers', $person_obj) && is_string($person_obj['followers'])) { + $collections['followers'] = $person_obj['followers']; + } + if (array_key_exists('following', $person_obj) && is_string($person_obj['following'])) { + $collections['following'] = $person_obj['following']; + } + if (array_key_exists('wall', $person_obj) && is_string($person_obj['wall'])) { + $collections['wall'] = $person_obj['wall']; + } + if (array_path_exists('endpoints/sharedInbox', $person_obj) && is_string($person_obj['endpoints']['sharedInbox'])) { + $collections['sharedInbox'] = $person_obj['endpoints']['sharedInbox']; + } + } + + if (isset($person_obj['publicKey']['publicKeyPem'])) { + if ($person_obj['id'] === $person_obj['publicKey']['owner']) { + $pubkey = $person_obj['publicKey']['publicKeyPem']; + if (strstr($pubkey, 'RSA ')) { + $pubkey = Keyutils::rsatopem($pubkey); + } + } + } + + $keywords = []; + + if (isset($person_obj['tag']) && is_array($person_obj['tag'])) { + foreach ($person_obj['tag'] as $t) { + if (is_array($t) && isset($t['type']) && $t['type'] === 'Hashtag') { + if (isset($t['name'])) { + $tag = escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name']); + if ($tag) { + $keywords[] = $tag; + } + } + } + if (is_array($t) && isset($t['type']) && $t['type'] === 'PropertyValue') { + if (isset($t['name']) && isset($t['value']) && $t['name'] === 'Protocol') { + self::update_protocols($url, trim($t['value'])); + } + } + } + } + + $xchan_type = self::get_xchan_type($person_obj['type']); + $about = ((isset($person_obj['summary'])) ? html2bbcode(purify_html($person_obj['summary'])) : EMPTY_STR); + + $p = q("select * from xchan where xchan_url = '%s' and xchan_network = 'zot6' limit 1", + dbesc($url) + ); + if ($p) { + set_xconfig($url, 'system', 'protocols', 'zot6,activitypub'); + } + + // there is no standard way to represent an 'instance actor' but this will at least subdue the multiple + // pages of Mastodon and Pleroma instance actors in the directory. + // @TODO - (2021-08-27) remove this if they provide a non-person xchan_type + // once extended xchan_type directory filtering is implemented. + $censored = ((strpos($profile, 'instance_actor') || strpos($profile, '/internal/fetch')) ? 1 : 0); + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($url) + ); + if (!$r) { + // create a new record + $r = xchan_store_lowlevel( + [ + 'xchan_hash' => $url, + 'xchan_guid' => $url, + 'xchan_pubkey' => $pubkey, + 'xchan_addr' => ((strpos($username, '@')) ? $username : ''), + 'xchan_url' => $profile, + 'xchan_name' => $name, + 'xchan_hidden' => intval($hidden), + 'xchan_updated' => datetime_convert(), + 'xchan_name_date' => datetime_convert(), + 'xchan_network' => 'activitypub', + 'xchan_type' => $xchan_type, + 'xchan_photo_date' => datetime_convert('UTC', 'UTC', '1968-01-01'), + 'xchan_photo_l' => z_root() . '/' . get_default_profile_photo(), + 'xchan_photo_m' => z_root() . '/' . get_default_profile_photo(80), + 'xchan_photo_s' => z_root() . '/' . get_default_profile_photo(48), + 'xchan_photo_mimetype' => 'image/png', + 'xchan_censored' => $censored + + ] + ); + } else { + + // Record exists. Cache existing records for a set number of days + // then refetch to catch updated profile photos, names, etc. + + if ($r[0]['xchan_name_date'] >= datetime_convert('UTC', 'UTC', 'now - ' . self::$ACTOR_CACHE_DAYS . ' days') && (!$force)) { + return; + } + + // update existing record + $u = q("update xchan set xchan_updated = '%s', xchan_name = '%s', xchan_pubkey = '%s', xchan_network = '%s', xchan_name_date = '%s', xchan_hidden = %d, xchan_type = %d, xchan_censored = %d where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($name), + dbesc($pubkey), + dbesc('activitypub'), + dbesc(datetime_convert()), + intval($hidden), + intval($xchan_type), + intval($censored), + dbesc($url) + ); + + if (strpos($username, '@') && ($r[0]['xchan_addr'] !== $username)) { + $r = q("update xchan set xchan_addr = '%s' where xchan_hash = '%s'", + dbesc($username), + dbesc($url) + ); + } + } + + if ($cover_photo) { + set_xconfig($url, 'system', 'cover_photo', $cover_photo); + } + + + $m = parse_url($url); + if ($m['scheme'] && $m['host']) { + $site_url = $m['scheme'] . '://' . $m['host']; + $ni = Nodeinfo::fetch($site_url); + if ($ni && is_array($ni)) { + $software = ((array_path_exists('software/name', $ni)) ? $ni['software']['name'] : ''); + $version = ((array_path_exists('software/version', $ni)) ? $ni['software']['version'] : ''); + $register = $ni['openRegistrations']; + + $site = q("select * from site where site_url = '%s'", + dbesc($site_url) + ); + if ($site) { + q("update site set site_project = '%s', site_update = '%s', site_version = '%s' where site_url = '%s'", + dbesc($software), + dbesc(datetime_convert()), + dbesc($version), + dbesc($site_url) + ); + // it may have been saved originally as an unknown type, but we now know what it is + if (intval($site[0]['site_type']) === SITE_TYPE_UNKNOWN) { + q("update site set site_type = %d where site_url = '%s'", + intval(SITE_TYPE_NOTZOT), + dbesc($site_url) + ); + } + } else { + site_store_lowlevel( + [ + 'site_url' => $site_url, + 'site_update' => datetime_convert(), + 'site_dead' => 0, + 'site_type' => SITE_TYPE_NOTZOT, + 'site_project' => $software, + 'site_version' => $version, + 'site_access' => (($register) ? ACCESS_FREE : ACCESS_PRIVATE), + 'site_register' => (($register) ? REGISTER_OPEN : REGISTER_CLOSED) + ] + ); + } + } + } + + Libzotdir::import_directory_profile($url, ['about' => $about, 'keywords' => $keywords, 'dob' => '0000-00-00'], null, 0, true); + + if ($collections) { + set_xconfig($url, 'activitypub', 'collections', $collections); + } + + $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($url) + ); + + + $m = parse_url($url); + if ($m) { + $hostname = $m['host']; + $baseurl = $m['scheme'] . '://' . $m['host'] . ((isset($m['port']) && intval($m['port'])) ? ':' . $m['port'] : ''); + } + + if (!$h) { + $r = hubloc_store_lowlevel( + [ + 'hubloc_guid' => $url, + 'hubloc_hash' => $url, + 'hubloc_id_url' => $profile, + 'hubloc_addr' => ((strpos($username, '@')) ? $username : ''), + 'hubloc_network' => 'activitypub', + 'hubloc_url' => $baseurl, + 'hubloc_host' => $hostname, + 'hubloc_callback' => $inbox, + 'hubloc_updated' => datetime_convert(), + 'hubloc_primary' => 1 + ] + ); + } else { + if (strpos($username, '@') && ($h[0]['hubloc_addr'] !== $username)) { + $r = q("update hubloc set hubloc_addr = '%s' where hubloc_hash = '%s'", + dbesc($username), + dbesc($url) + ); + } + if ($inbox !== $h[0]['hubloc_callback']) { + $r = q("update hubloc set hubloc_callback = '%s' where hubloc_hash = '%s'", + dbesc($inbox), + dbesc($url) + ); + } + if ($profile !== $h[0]['hubloc_id_url']) { + $r = q("update hubloc set hubloc_id_url = '%s' where hubloc_hash = '%s'", + dbesc($profile), + dbesc($url) + ); + } + $r = q("update hubloc set hubloc_updated = '%s' where hubloc_hash = '%s'", + dbesc(datetime_convert()), + dbesc($url) + ); + } + + if (!$icon) { + $icon = z_root() . '/' . get_default_profile_photo(300); + } + + // We store all ActivityPub actors we can resolve. Some of them may be able to communicate over Zot6. Find them. + // Only probe if it looks like it looks something like a zot6 URL as there isn't anything in the actor record which we can reliably use for this purpose + // and adding zot discovery urls to the actor record will cause federation to fail with the 20-30 projects which don't accept arrays in the url field. + + if (strpos($url, '/channel/') !== false) { + $zx = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6'", + dbesc($url) + ); + if (($username) && strpos($username, '@') && (!$zx)) { + Run::Summon(['Gprobe', bin2hex($username)]); + } + } + + Run::Summon(['Xchan_photo', bin2hex($icon), bin2hex($url)]); + + } + + public static function update_protocols($xchan, $str) + { + $existing = explode(',', get_xconfig($xchan, 'system', 'protocols', EMPTY_STR)); + if (!in_array($str, $existing)) { + $existing[] = $str; + set_xconfig($xchan, 'system', 'protocols', implode(',', $existing)); + } + } + + + public static function drop($channel, $observer, $act) + { + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc((is_array($act->obj)) ? $act->obj['id'] : $act->obj), + intval($channel['channel_id']) + ); + + if (!$r) { + return; + } + + if (in_array($observer, [$r[0]['author_xchan'], $r[0]['owner_xchan']])) { + drop_item($r[0]['id'], false); + } elseif (in_array($act->actor['id'], [$r[0]['author_xchan'], $r[0]['owner_xchan']])) { + drop_item($r[0]['id'], false); + } + + } + + + // sort function width decreasing + + public static function vid_sort($a, $b) + { + if ($a['width'] === $b['width']) + return 0; + return (($a['width'] > $b['width']) ? -1 : 1); + } + + public static function share_bb($obj) + { + // @fixme - error check and set defaults + + $name = urlencode($obj['actor']['name']); + $profile = $obj['actor']['id']; + $photo = $obj['icon']['url']; + + $s = "\r\n[share author='" . $name . + "' profile='" . $profile . + "' avatar='" . $photo . + "' link='" . $act->obj['id'] . + "' auth='" . ((is_matrix_url($act->obj['id'])) ? 'true' : 'false') . + "' posted='" . $act->obj['published'] . + "' message_id='" . $act->obj['id'] . + "']"; + + return $s; + } + + public static function get_actor_bbmention($id) + { + + $x = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' or hubloc_id_url = '%s' limit 1", + dbesc($id), + dbesc($id) + ); + + if ($x) { + // a name starting with a left paren can trick the markdown parser into creating a link so insert a zero-width space + if (substr($x[0]['xchan_name'], 0, 1) === '(') { + $x[0]['xchan_name'] = htmlspecialchars_decode('​', ENT_QUOTES) . $x[0]['xchan_name']; + } + + return sprintf('@[zrl=%s]%s[/zrl]', $x[0]['xchan_url'], $x[0]['xchan_name']); + } + return '@{' . $id . '}'; + + } + + public static function update_poll($item, $post) + { + + logger('updating poll'); + + $multi = false; + $mid = $post['mid']; + $content = $post['title']; + + if (!$item) { + return false; + } + + $o = json_decode($item['obj'], true); + if ($o && array_key_exists('anyOf', $o)) { + $multi = true; + } + + $r = q("select mid, title from item where parent_mid = '%s' and author_xchan = '%s' and mid != parent_mid ", + dbesc($item['mid']), + dbesc($post['author_xchan']) + ); + + // prevent any duplicate votes by same author for oneOf and duplicate votes with same author and same answer for anyOf + + if ($r) { + if ($multi) { + foreach ($r as $rv) { + if ($rv['title'] === $content && $rv['mid'] !== $mid) { + return false; + } + } + } else { + foreach ($r as $rv) { + if ($rv['mid'] !== $mid) { + return false; + } + } + } + } + + $answer_found = false; + $found = false; + if ($multi) { + for ($c = 0; $c < count($o['anyOf']); $c++) { + if ($o['anyOf'][$c]['name'] === $content) { + $answer_found = true; + if (is_array($o['anyOf'][$c]['replies'])) { + foreach ($o['anyOf'][$c]['replies'] as $reply) { + if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) { + $found = true; + } + } + } + + if (!$found) { + $o['anyOf'][$c]['replies']['totalItems']++; + $o['anyOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note']; + } + } + } + } else { + for ($c = 0; $c < count($o['oneOf']); $c++) { + if ($o['oneOf'][$c]['name'] === $content) { + $answer_found = true; + if (is_array($o['oneOf'][$c]['replies'])) { + foreach ($o['oneOf'][$c]['replies'] as $reply) { + if (is_array($reply) && array_key_exists('id', $reply) && $reply['id'] === $mid) { + $found = true; + } + } + } + + if (!$found) { + $o['oneOf'][$c]['replies']['totalItems']++; + $o['oneOf'][$c]['replies']['items'][] = ['id' => $mid, 'type' => 'Note']; + } + } + } + } + + if ($item['comments_closed'] > NULL_DATE) { + if ($item['comments_closed'] > datetime_convert()) { + $o['closed'] = datetime_convert('UTC', 'UTC', $item['comments_closed'], ATOM_TIME); + // set this to force an update + $answer_found = true; + } + } + + logger('updated_poll: ' . print_r($o, true), LOGGER_DATA); + if ($answer_found && !$found) { + $x = q("update item set obj = '%s', edited = '%s' where id = %d", + dbesc(json_encode($o)), + dbesc(datetime_convert()), + intval($item['id']) + ); + Run::Summon(['Notifier', 'wall-new', $item['id']]); + return true; + } + + return false; + } + + + public static function decode_note($act, $cacheable = false) + { + + $response_activity = false; + $poll_handled = false; + + $s = []; + + if (is_array($act->obj)) { + $binary = false; + $markdown = false; + + if (array_key_exists('mediaType', $act->obj) && $act->obj['mediaType'] !== 'text/html') { + if ($act->obj['mediaType'] === 'text/markdown') { + $markdown = true; + } else { + $s['mimetype'] = escape_tags($act->obj['mediaType']); + $binary = true; + } + } + + $content = self::get_content($act->obj, $binary); + + if ($cacheable) { + // Zot6 activities will all be rendered from bbcode source in order to generate dynamic content. + // If the activity came from ActivityPub (hence $cacheable is set), use the HTML rendering + // and discard the bbcode source since it is unlikely that it is compatible with our implementation. + // Friendica for example. + + unset($content['bbcode']); + } + + // handle markdown conversion inline (peertube) + + if ($markdown) { + foreach (['summary', 'content'] as $t) { + $content[$t] = Markdown::to_bbcode($content[$t], true, ['preserve_lf' => true]); + } + } + } + + // These activities should have been handled separately in the Inbox module and should not be turned into posts + + if (in_array($act->type, ['Follow', 'Accept', 'Reject', 'Create', 'Update']) && is_array($act->obj) && array_key_exists('type', $act->obj) + && ($act->obj['type'] === 'Follow' || ActivityStreams::is_an_actor($act->obj['type']))) { + return false; + } + + // Within our family of projects, Follow/Unfollow of a thread is an internal activity which should not be transmitted, + // hence if we receive it - ignore or reject it. + // This may have to be revisited if AP projects start using Follow for objects other than actors. + + if (in_array($act->type, [ACTIVITY_FOLLOW, ACTIVITY_IGNORE])) { + return false; + } + + // Do not proceed further if there is no actor. + + if (!isset($act->actor['id'])) { + logger('No actor!'); + return false; + } + + $s['owner_xchan'] = $act->actor['id']; + $s['author_xchan'] = $act->actor['id']; + + // ensure we store the original actor + self::actor_store($act->actor['id'], $act->actor); + + $s['mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj); + + if (!$s['mid']) { + return false; + } + + $s['parent_mid'] = $act->parent_id; + + if (array_key_exists('published', $act->data) && $act->data['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); + } elseif (array_key_exists('published', $act->obj) && $act->obj['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']); + } + if (array_key_exists('updated', $act->data) && $act->data['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']); + } elseif (array_key_exists('updated', $act->obj) && $act->obj['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->obj['updated']); + } + if (array_key_exists('expires', $act->data) && $act->data['expires']) { + $s['expires'] = datetime_convert('UTC', 'UTC', $act->data['expires']); + } elseif (array_key_exists('expires', $act->obj) && $act->obj['expires']) { + $s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']); + } + + if ($act->type === 'Invite' && is_array($act->obj) && array_key_exists('type', $act->obj) && $act->obj['type'] === 'Event') { + $s['mid'] = $s['parent_mid'] = $act->id; + } + + if (isset($act->replyto) && !empty($act->replyto)) { + if (is_array($act->replyto) && isset($act->replyto['id'])) { + $s['replyto'] = $act->replyto['id']; + } else { + $s['replyto'] = $act->replyto; + } + } + + if (ActivityStreams::is_response_activity($act->type)) { + + $response_activity = true; + + $s['mid'] = $act->id; + $s['parent_mid'] = ((is_array($act->obj) && isset($act->obj['id'])) ? $act->obj['id'] : $act->obj); + + + // over-ride the object timestamp with the activity + + if (isset($act->data['published']) && $act->data['published']) { + $s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']); + } + + if (isset($act->data['updated']) && $act->data['updated']) { + $s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']); + } + + $obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj)); + + // Actor records themselves do not have an actor or attributedTo + if ((!$obj_actor) && isset($act->obj['type']) && Activitystreams::is_an_actor($act->obj['type'])) { + $obj_actor = $act->obj; + } + + // We already check for admin blocks of third-party objects when fetching them explicitly. + // Repeat here just in case the entire object was supplied inline and did not require fetching + + if ($obj_actor && array_key_exists('id', $obj_actor)) { + $m = parse_url($obj_actor['id']); + if ($m && $m['scheme'] && $m['host']) { + if (!check_siteallowed($m['scheme'] . '://' . $m['host'])) { + return; + } + } + if (!check_channelallowed($obj_actor['id'])) { + return; + } + } + + // if the object is an actor, it is not really a response activity, so reset it to a top level post + + if (ActivityStreams::is_an_actor($act->obj['type'])) { + $s['parent_mid'] = $s['mid']; + } + + + // ensure we store the original actor of the associated (parent) object + self::actor_store($obj_actor['id'], $obj_actor); + + $mention = self::get_actor_bbmention($obj_actor['id']); + + $quoted_content = '[quote]' . $content['content'] . '[/quote]'; + + if ($act->type === 'Like') { + $content['content'] = sprintf(t('Likes %1$s\'s %2$s'), $mention, ((ActivityStreams::is_an_actor($act->obj['type'])) ? t('Profile') : $act->obj['type'])) . EOL . EOL . $quoted_content; + } + if ($act->type === 'Dislike') { + $content['content'] = sprintf(t('Doesn\'t like %1$s\'s %2$s'), $mention, ((ActivityStreams::is_an_actor($act->obj['type'])) ? t('Profile') : $act->obj['type'])) . EOL . EOL . $quoted_content; + } + + // handle event RSVPs + if (($act->obj['type'] === 'Event') || ($act->obj['type'] === 'Invite' && array_path_exists('object/type', $act->obj) && $act->obj['object']['type'] === 'Event')) { + if ($act->type === 'Accept') { + $content['content'] = sprintf(t('Will attend %s\'s event'), $mention) . EOL . EOL . $quoted_content; + } + if ($act->type === 'Reject') { + $content['content'] = sprintf(t('Will not attend %s\'s event'), $mention) . EOL . EOL . $quoted_content; + } + if ($act->type === 'TentativeAccept') { + $content['content'] = sprintf(t('May attend %s\'s event'), $mention) . EOL . EOL . $quoted_content; + } + if ($act->type === 'TentativeReject') { + $content['content'] = sprintf(t('May not attend %s\'s event'), $mention) . EOL . EOL . $quoted_content; + } + } + + if ($act->type === 'Announce') { + $content['content'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, ((ActivityStreams::is_an_actor($act->obj['type'])) ? t('Profile') : $act->obj['type'])); + } + + if ($act->type === 'emojiReaction') { + // Hubzilla reactions + $content['content'] = (($act->tgt && $act->tgt['type'] === 'Image') ? '[img=32x32]' . $act->tgt['url'] . '[/img]' : '&#x' . $act->tgt['name'] . ';'); + } + + if (in_array($act->type, ['EmojiReaction', 'EmojiReact'])) { + // Pleroma reactions + $t = trim(self::get_textfield($act->data, 'content')); + $e = Emoji\is_single_emoji($t) || mb_strlen($t) === 1; + if ($e) { + $content['content'] = $t; + } + } + } + + $s['comment_policy'] = 'authenticated'; + + if ($s['mid'] === $s['parent_mid']) { + // it is a parent node - decode the comment policy info if present + if (isset($act->obj['commentPolicy'])) { + $until = strpos($act->obj['commentPolicy'], 'until='); + if ($until !== false) { + $s['comments_closed'] = datetime_convert('UTC', 'UTC', substr($act->obj['commentPolicy'], $until + 6)); + if ($s['comments_closed'] < datetime_convert()) { + $s['nocomment'] = true; + } + } + $remainder = substr($act->obj['commentPolicy'], 0, (($until) ? $until : strlen($act->obj['commentPolicy']))); + if ($remainder) { + $s['comment_policy'] = $remainder; + } + if (!(isset($item['comment_policy']) && strlen($item['comment_policy']))) { + $s['comment_policy'] = 'contacts'; + } + } + } + + if (!(array_key_exists('created', $s) && $s['created'])) { + $s['created'] = datetime_convert(); + } + if (!(array_key_exists('edited', $s) && $s['edited'])) { + $s['edited'] = $s['created']; + } + $s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content, 'name')); + $s['summary'] = self::bb_content($content, 'summary'); + + if (array_key_exists('mimetype', $s) && (!in_array($s['mimetype'], ['text/bbcode', 'text/x-multicode']))) { + $s['body'] = $content['content']; + } else { + $s['body'] = ((self::bb_content($content, 'bbcode') && (!$response_activity)) ? self::bb_content($content, 'bbcode') : self::bb_content($content, 'content')); + } + + + // handle some of the more widely used of the numerous and varied ways of deleting something + + if (in_array($act->type, ['Delete', 'Undo', 'Tombstone'])) { + $s['item_deleted'] = 1; + } + + if ($act->type === 'Create' && $act->obj['type'] === 'Tombstone') { + $s['item_deleted'] = 1; + } + + if ($act->obj && array_key_exists('sensitive', $act->obj) && boolval($act->obj['sensitive'])) { + $s['item_nsfw'] = 1; + } + + $s['verb'] = self::activity_mapper($act->type); + + // Mastodon does not provide update timestamps when updating poll tallies which means race conditions may occur here. + if ($act->type === 'Update' && $act->obj['type'] === 'Question' && $s['edited'] === $s['created']) { + $s['edited'] = datetime_convert(); + } + + + $s['obj_type'] = self::activity_obj_mapper($act->obj['type']); + $s['obj'] = $act->obj; + if (is_array($s['obj']) && array_path_exists('actor/id', $s['obj'])) { + $s['obj']['actor'] = $s['obj']['actor']['id']; + } + + if (is_array($act->tgt) && $act->tgt) { + if (array_key_exists('type', $act->tgt)) { + $s['tgt_type'] = self::activity_obj_mapper($act->tgt['type']); + } + // We shouldn't need to store collection contents which could be large. We will often only require the meta-data + if (isset($s['tgt_type']) && strpos($s['tgt_type'], 'Collection') !== false) { + $s['target'] = ['id' => $act->tgt['id'], 'type' => $s['tgt_type'], 'attributedTo' => ((isset($act->tgt['attributedTo'])) ? $act->tgt['attributedTo'] : $act->tgt['actor'])]; + } + } + + $generator = $act->get_property_obj('generator'); + if ((!$generator) && (!$response_activity)) { + $generator = $act->get_property_obj('generator', $act->obj); + } + + if ($generator && array_key_exists('type', $generator) + && in_array($generator['type'], ['Application', 'Service']) && array_key_exists('name', $generator)) { + $s['app'] = escape_tags($generator['name']); + } + + $location = $act->get_property_obj('location'); + if (is_array($location) && array_key_exists('type', $location) && $location['type'] === 'Place') { + if (array_key_exists('name', $location)) { + $s['location'] = escape_tags($location['name']); + } + if (array_key_exists('content', $location)) { + $s['location'] = html2plain(purify_html($location['content']), 256); + } + + if (array_key_exists('latitude', $location) && array_key_exists('longitude', $location)) { + $s['coord'] = escape_tags($location['latitude']) . ' ' . escape_tags($location['longitude']); + } + } + + if (!$response_activity) { + $a = self::decode_taxonomy($act->obj); + if ($a) { + $s['term'] = $a; + foreach ($a as $b) { + if ($b['ttype'] === TERM_EMOJI) { + $s['summary'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['summary']); + + // @todo - @bug + // The emoji reference in the body might be inside a code block. In that case we shouldn't replace it. + // Currently we do. + + $s['body'] = str_replace($b['term'], '[img=16x16]' . $b['url'] . '[/img]', $s['body']); + } + } + } + + $a = self::decode_attachment($act->obj); + if ($a) { + $s['attach'] = $a; + } + + $a = self::decode_iconfig($act->obj); + if ($a) { + $s['iconfig'] = $a; + } + } + + // Objects that might have media attachments which aren't already provided in the content element. + // We'll check specific media objects separately. + + if (in_array($act->obj['type'], ['Article', 'Document', 'Event', 'Note', 'Page', 'Place', 'Question']) && isset($s['attach']) && $s['attach']) { + $s['body'] .= self::bb_attach($s['attach'], $s['body']); + } + + if ($act->obj['type'] === 'Question' && in_array($act->type, ['Create', 'Update'])) { + if ($act->obj['endTime']) { + $s['comments_closed'] = datetime_convert('UTC', 'UTC', $act->obj['endTime']); + } + } + + if (array_key_exists('closed', $act->obj) && $act->obj['closed']) { + $s['comments_closed'] = datetime_convert('UTC', 'UTC', $act->obj['closed']); + } + + + // we will need a hook here to extract magnet links e.g. peertube + // right now just link to the largest mp4 we find that will fit in our + // standard content region + + if (!$response_activity) { + if ($act->obj['type'] === 'Video') { + + $vtypes = [ + 'video/mp4', + 'video/ogg', + 'video/webm' + ]; + + $mps = []; + $poster = null; + $ptr = null; + + // try to find a poster to display on the video element + + if (array_key_exists('icon', $act->obj)) { + if (is_array($act->obj['icon'])) { + if (array_key_exists(0, $act->obj['icon'])) { + $ptr = $act->obj['icon']; + } else { + $ptr = [$act->obj['icon']]; + } + } + if ($ptr) { + foreach ($ptr as $foo) { + if (is_array($foo) && array_key_exists('type', $foo) && $foo['type'] === 'Image' && is_string($foo['url'])) { + $poster = $foo['url']; + } + } + } + } + + $tag = (($poster) ? '[video poster="' . $poster . '"]' : '[video]'); + $ptr = null; + + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { + $ptr = $act->obj['url']; + } else { + $ptr = [$act->obj['url']]; + } + // handle peertube's weird url link tree if we find it here + // 0 => html link, 1 => application/x-mpegURL with 'tag' set to an array of actual media links + foreach ($ptr as $idex) { + if (is_array($idex) && array_key_exists('mediaType', $idex)) { + if ($idex['mediaType'] === 'application/x-mpegURL' && isset($idex['tag']) && is_array($idex['tag'])) { + $ptr = $idex['tag']; + break; + } + } + } + foreach ($ptr as $vurl) { + if (array_key_exists('mediaType', $vurl)) { + if (in_array($vurl['mediaType'], $vtypes)) { + if (!array_key_exists('width', $vurl)) { + $vurl['width'] = 0; + } + $mps[] = $vurl; + } + } + } + } + if ($mps) { + usort($mps, [__CLASS__, 'vid_sort']); + foreach ($mps as $m) { + if (intval($m['width']) < 500 && self::media_not_in_body($m['href'], $s['body'])) { + $s['body'] .= "\n\n" . $tag . $m['href'] . '[/video]'; + break; + } + } + } elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) { + $s['body'] .= "\n\n" . $tag . $act->obj['url'] . '[/video]'; + } + } + } + + if ($act->obj['type'] === 'Audio') { + + $atypes = [ + 'audio/mpeg', + 'audio/ogg', + 'audio/wav' + ]; + + $ptr = null; + + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { + $ptr = $act->obj['url']; + } else { + $ptr = [$act->obj['url']]; + } + foreach ($ptr as $vurl) { + if (isset($vurl['mediaType']) && in_array($vurl['mediaType'], $atypes) && self::media_not_in_body($vurl['href'], $s['body'])) { + $s['body'] .= "\n\n" . '[audio]' . $vurl['href'] . '[/audio]'; + break; + } + } + } elseif (is_string($act->obj['url']) && self::media_not_in_body($act->obj['url'], $s['body'])) { + $s['body'] .= "\n\n" . '[audio]' . $act->obj['url'] . '[/audio]'; + } + } // Pleroma audio scrobbler + elseif ($act->type === 'Listen' && array_key_exists('artist', $act->obj) && array_key_exists('title', $act->obj) && $s['body'] === EMPTY_STR) { + $s['body'] .= "\n\n" . sprintf('Listening to \"%1$s\" by %2$s', escape_tags($act->obj['title']), escape_tags($act->obj['artist'])); + if (isset($act->obj['album'])) { + $s['body'] .= "\n" . sprintf('(%s)', escape_tags($act->obj['album'])); + } + } + } + + if ($act->obj['type'] === 'Image' && strpos($s['body'], 'zrl=') === false) { + + $ptr = null; + + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { + $ptr = $act->obj['url']; + } else { + $ptr = [$act->obj['url']]; + } + foreach ($ptr as $vurl) { + if (is_array($vurl) && isset($vurl['href']) && strpos($s['body'], $vurl['href']) === false) { + $s['body'] .= "\n\n" . '[zmg]' . $vurl['href'] . '[/zmg]'; + break; + } + } + } elseif (is_string($act->obj['url'])) { + if (strpos($s['body'], $act->obj['url']) === false) { + $s['body'] .= "\n\n" . '[zmg]' . $act->obj['url'] . '[/zmg]'; + } + } + } + } + + + if ($act->obj['type'] === 'Page' && !$s['body']) { + + $ptr = null; + $purl = EMPTY_STR; + + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { + $ptr = $act->obj['url']; + } else { + $ptr = [$act->obj['url']]; + } + foreach ($ptr as $vurl) { + if (is_array($vurl) && array_key_exists('mediaType', $vurl) && $vurl['mediaType'] === 'text/html') { + $purl = $vurl['href']; + break; + } elseif (array_key_exists('mimeType', $vurl) && $vurl['mimeType'] === 'text/html') { + $purl = $vurl['href']; + break; + } + } + } elseif (is_string($act->obj['url'])) { + $purl = $act->obj['url']; + } + if ($purl) { + $li = z_fetch_url(z_root() . '/linkinfo?binurl=' . bin2hex($purl)); + if ($li['success'] && $li['body']) { + $s['body'] .= "\n" . $li['body']; + } else { + $s['body'] .= "\n\n" . $purl; + } + } + } + } + } + + + if (in_array($act->obj['type'], ['Note', 'Article', 'Page'])) { + $ptr = null; + + if (array_key_exists('url', $act->obj)) { + if (is_array($act->obj['url'])) { + if (array_key_exists(0, $act->obj['url'])) { + $ptr = $act->obj['url']; + } else { + $ptr = [$act->obj['url']]; + } + foreach ($ptr as $vurl) { + if (is_array($vurl) && array_key_exists('mediaType', $vurl) && $vurl['mediaType'] === 'text/html') { + $s['plink'] = $vurl['href']; + break; + } + } + } elseif (is_string($act->obj['url'])) { + $s['plink'] = $act->obj['url']; + } + } + } + + if (!(isset($s['plink']) && $s['plink'])) { + $s['plink'] = $s['mid']; + } + + // assume this is private unless specifically told otherwise. + + $s['item_private'] = 1; + + if ($act->recips && (in_array(ACTIVITY_PUBLIC_INBOX, $act->recips) || in_array('Public', $act->recips) || in_array('as:Public', $act->recips))) { + $s['item_private'] = 0; + } + + if (is_array($act->obj)) { + if (array_key_exists('directMessage', $act->obj) && intval($act->obj['directMessage'])) { + $s['item_private'] = 2; + } + } + + set_iconfig($s, 'activitypub', 'recips', $act->raw_recips); + + if (array_key_exists('directMessage', $act->data) && intval($act->data['directMessage'])) { + $s['item_private'] = 2; + } + + + set_iconfig($s, 'activitypub', 'rawmsg', $act->raw, 1); + + // Restrict html caching to ActivityPub senders. + // Zot has dynamic content and this library is used by both. + + if ($cacheable) { + if ((!array_key_exists('mimetype', $s)) || (in_array($s['mimetype'], ['text/bbcode', 'text/x-multicode']))) { + + // preserve the original purified HTML content *unless* we've modified $s['body'] + // within this function (to add attachments or reaction descriptions or mention rewrites). + // This avoids/bypasses some markdown rendering issues which can occur when + // converting to our markdown-enhanced bbcode and then back to HTML again. + // Also if we do need bbcode, use the 'bbonly' flag to ignore markdown and only + // interpret bbcode; which is much less susceptible to false positives in the + // conversion regexes. + + if ($s['body'] === self::bb_content($content, 'content')) { + $s['html'] = $content['content']; + } else { + $s['html'] = bbcode($s['body'], ['bbonly' => true]); + } + } + } + + $hookinfo = [ + 'act' => $act, + 's' => $s + ]; + + call_hooks('decode_note', $hookinfo); + + $s = $hookinfo['s']; + + return $s; + + } + + public static function rewrite_mentions_sub(&$s, $pref, &$obj = null) + { + + if (isset($s['term']) && is_array($s['term'])) { + foreach ($s['term'] as $tag) { + $txt = EMPTY_STR; + if (intval($tag['ttype']) === TERM_MENTION) { + // some platforms put the identity url into href rather than the profile url. Accept either form. + $x = q("select * from xchan where xchan_url = '%s' or xchan_hash = '%s' limit 1", + dbesc($tag['url']), + dbesc($tag['url']) + ); + if ($x) { + switch ($pref) { + case 0: + $txt = $x[0]['xchan_name']; + break; + case 1: + $txt = (($x[0]['xchan_addr']) ? $x[0]['xchan_addr'] : $x[0]['xchan_name']); + break; + case 2: + default; + if ($x[0]['xchan_addr']) { + $txt = sprintf(t('%1$s (%2$s)'), $x[0]['xchan_name'], $x[0]['xchan_addr']); + } else { + $txt = $x[0]['xchan_name']; + } + break; + } + } + } + + if ($txt) { + + // the Markdown filter will get tripped up and think this is a markdown link + // if $txt begins with parens so put it behind a zero-width space + if (substr($txt, 0, 1) === '(') { + $txt = htmlspecialchars_decode('​', ENT_QUOTES) . $txt; + } + $s['body'] = preg_replace('/\@\[zrl\=' . preg_quote($x[0]['xchan_url'], '/') . '\](.*?)\[\/zrl\]/ism', + '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]', $s['body']); + $s['body'] = preg_replace('/\@\[url\=' . preg_quote($x[0]['xchan_url'], '/') . '\](.*?)\[\/url\]/ism', + '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]', $s['body']); + $s['body'] = preg_replace('/\[zrl\=' . preg_quote($x[0]['xchan_url'], '/') . '\]@(.*?)\[\/zrl\]/ism', + '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]', $s['body']); + $s['body'] = preg_replace('/\[url\=' . preg_quote($x[0]['xchan_url'], '/') . '\]@(.*?)\[\/url\]/ism', + '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]', $s['body']); + + // replace these just in case the sender (in this case Friendica) got it wrong + $s['body'] = preg_replace('/\@\[zrl\=' . preg_quote($x[0]['xchan_hash'], '/') . '\](.*?)\[\/zrl\]/ism', + '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]', $s['body']); + $s['body'] = preg_replace('/\@\[url\=' . preg_quote($x[0]['xchan_hash'], '/') . '\](.*?)\[\/url\]/ism', + '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]', $s['body']); + $s['body'] = preg_replace('/\[zrl\=' . preg_quote($x[0]['xchan_hash'], '/') . '\]@(.*?)\[\/zrl\]/ism', + '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]', $s['body']); + $s['body'] = preg_replace('/\[url\=' . preg_quote($x[0]['xchan_hash'], '/') . '\]@(.*?)\[\/url\]/ism', + '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]', $s['body']); + + if ($obj && $txt) { + if (!is_array($obj)) { + $obj = json_decode($obj, true); + } + if (array_path_exists('source/content', $obj)) { + $obj['source']['content'] = preg_replace('/\@\[zrl\=' . preg_quote($x[0]['xchan_url'], '/') . '\](.*?)\[\/zrl\]/ism', + '@[zrl=' . $x[0]['xchan_url'] . ']' . $txt . '[/zrl]', $obj['source']['content']); + $obj['source']['content'] = preg_replace('/\@\[url\=' . preg_quote($x[0]['xchan_url'], '/') . '\](.*?)\[\/url\]/ism', + '@[url=' . $x[0]['xchan_url'] . ']' . $txt . '[/url]', $obj['source']['content']); + } + $obj['content'] = preg_replace('/\@(.*?)\(.*?)\<\/a\>/ism', + '@$1' . $txt . '', $obj['content']); + } + } + } + } + + // $s['html'] will be populated if caching was enabled. + // This is usually the case for ActivityPub sourced content, while Zot6 content is not cached. + + if (isset($s['html']) && $s['html']) { + $s['html'] = bbcode($s['body'], ['bbonly' => true]); + } + + return; + } + + public static function rewrite_mentions(&$s) + { + // rewrite incoming mentions in accordance with system.tag_username setting + // 0 - displayname + // 1 - username + // 2 - displayname (username) + // 127 - default + + $pref = intval(PConfig::Get($s['uid'], 'system', 'tag_username', Config::Get('system', 'tag_username', false))); + + if ($pref === 127) { + return; + } + + self::rewrite_mentions_sub($s, $pref); + + + return; + } + + // $force is used when manually fetching a remote item - it assumes you are granting one-time + // permission for the selected item/conversation regardless of your relationship with the author and + // assumes that you are in fact the sender. Please do not use it for anything else. The only permission + // checking that is performed is that the author isn't blocked by the site admin. + + public static function store($channel, $observer_hash, $act, $item, $fetch_parents = true, $force = false) + { + + if ($act && $act->implied_create && !$force) { + // This is originally a S2S object with no associated activity + logger('Not storing implied create activity!'); + return; + } + + $is_sys_channel = is_sys_channel($channel['channel_id']); + $is_child_node = false; + + // Pleroma scrobbles can be really noisy and contain lots of duplicate activities. Disable them by default. + + if (($act->type === 'Listen') && ($is_sys_channel || get_pconfig($channel['channel_id'], 'system', 'allow_scrobbles', false))) { + return; + } + + // Mastodon only allows visibility in public timelines if the public inbox is listed in the 'to' field. + // They are hidden in the public timeline if the public inbox is listed in the 'cc' field. + // This is not part of the activitypub protocol - we might change this to show all public posts in pubstream at some point. + + $pubstream = ((is_array($act->obj) && array_key_exists('to', $act->obj) && is_array($act->obj['to']) && (in_array(ACTIVITY_PUBLIC_INBOX, $act->obj['to']) || in_array('Public', $act->obj['to']) || in_array('as:Public', $act->obj['to']))) ? true : false); + + // very unpleasant and imperfect way of determining a Mastodon DM + + if ($act->raw_recips && array_key_exists('to', $act->raw_recips) && is_array($act->raw_recips['to']) && count($act->raw_recips['to']) === 1 && $act->raw_recips['to'][0] === channel_url($channel) && !$act->raw_recips['cc']) { + $item['item_private'] = 2; + } + + + if ($item['parent_mid'] && $item['parent_mid'] !== $item['mid']) { + $is_child_node = true; + } + + $allowed = false; + $reason = ['init']; + $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $item)); + + if ($is_child_node) { + $p = q("select * from item where mid = '%s' and uid = %d and item_wall = 1", + dbesc($item['parent_mid']), + intval($channel['channel_id']) + ); + if ($p) { + // set the owner to the owner of the parent + $item['owner_xchan'] = $p[0]['owner_xchan']; + + // quietly reject group comment boosts by group owner + // (usually only sent via ActivityPub so groups will work on microblog platforms) + // This catches those activities if they slipped in via a conversation fetch + + if ($p[0]['parent_mid'] !== $item['parent_mid']) { + if ($item['verb'] === 'Announce' && $item['author_xchan'] === $item['owner_xchan']) { + logger('group boost activity by group owner rejected'); + return; + } + } + + // check permissions against the author, not the sender + $allowed = perm_is_allowed($channel['channel_id'], $item['author_xchan'], 'post_comments'); + if (!$allowed) { + $reason[] = 'post_comments perm'; + } + if ((!$allowed) && $permit_mentions) { + if ($p[0]['owner_xchan'] === $channel['channel_hash']) { + $allowed = false; + $reason[] = 'ownership'; + } else { + $allowed = true; + } + } + if (absolutely_no_comments($p[0])) { + $allowed = false; + $reason[] = 'absolutely'; + } + + if (!$allowed) { + logger('rejected comment from ' . $item['author_xchan'] . ' for ' . $channel['channel_address']); + logger('rejected reason ' . print_r($reason, true)); + logger('rejected: ' . print_r($item, true), LOGGER_DATA); + // let the sender know we received their comment but we don't permit spam here. + self::send_rejection_activity($channel, $item['author_xchan'], $item); + return; + } + + if (perm_is_allowed($channel['channel_id'], $item['author_xchan'], 'moderated')) { + $item['item_blocked'] = ITEM_MODERATED; + } + } else { + + // By default if we allow you to send_stream and comments and this is a comment, it is allowed. + // A side effect of this action is that if you take away send_stream permission, comments to those + // posts you previously allowed will still be accepted. It is possible but might be difficult to fix this. + + $allowed = true; + + // reject public stream comments that weren't sent by the conversation owner + // but only on remote message deliveries to our site ($fetch_parents === true) + + if ($is_sys_channel && $pubstream && $item['owner_xchan'] !== $observer_hash && !$fetch_parents) { + $allowed = false; + $reason[] = 'sender ' . $observer_hash . ' not owner ' . $item['owner_xchan']; + } + } + + if ($p && $p[0]['obj_type'] === 'Question') { + if ($item['obj_type'] === 'Note' && $item['title'] && (!$item['content'])) { + $item['obj_type'] = 'Answer'; + } + } + } else { + if (perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') || ($is_sys_channel && $pubstream)) { + logger('allowed: permission allowed', LOGGER_DATA); + $allowed = true; + } + if ($permit_mentions) { + logger('allowed: permitted mention', LOGGER_DATA); + $allowed = true; + } + } + + if (tgroup_check($channel['channel_id'], $item) && (!$is_child_node)) { + // for forum deliveries, make sure we keep a copy of the signed original + set_iconfig($item, 'activitypub', 'rawmsg', $act->raw, 1); + logger('allowed: tgroup'); + $allowed = true; + } + + if (get_abconfig($channel['channel_id'], $observer_hash, 'system', 'block_announce', false)) { + if ($item['verb'] === 'Announce' || strpos($item['body'], '[/share]')) { + $allowed = false; + } + } + + if (intval($item['item_private']) === 2) { + if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'post_mail')) { + $allowed = false; + } + } + + if ($is_sys_channel) { + + if (!check_pubstream_channelallowed($observer_hash)) { + $allowed = false; + $reason[] = 'pubstream channel blocked'; + } + + // don't allow pubstream posts if the sender even has a clone on a pubstream denied site + + $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", + dbesc($observer_hash) + ); + if ($h) { + foreach ($h as $hub) { + if (!check_pubstream_siteallowed($hub['hubloc_url'])) { + $allowed = false; + $reason = 'pubstream site blocked'; + break; + } + } + } + if (intval($item['item_private'])) { + $allowed = false; + $reason[] = 'private item'; + } + } + + $blocked = LibBlock::fetch($channel['channel_id'], BLOCKTYPE_SERVER); + if ($blocked) { + foreach ($blocked as $b) { + if (strpos($observer_hash, $b['block_entity']) !== false) { + $allowed = false; + $reason[] = 'blocked'; + } + } + } + + if (!$allowed && !$force) { + logger('no permission: channel ' . $channel['channel_address'] . ', id = ' . $item['mid']); + logger('no permission: reason ' . print_r($reason, true)); + return; + } + + $item['aid'] = $channel['channel_account_id']; + $item['uid'] = $channel['channel_id']; + + + // Some authors may be zot6 authors in which case we want to store their nomadic identity + // instead of their ActivityPub identity + + $item['author_xchan'] = self::find_best_identity($item['author_xchan']); + $item['owner_xchan'] = self::find_best_identity($item['owner_xchan']); + + if (!($item['author_xchan'] && $item['owner_xchan'])) { + logger('owner or author missing.'); + return; + } + + if ($channel['channel_system']) { + if (!MessageFilter::evaluate($item, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { + logger('post is filtered'); + return; + } + } + + // fetch allow/deny lists for the sender, author, or both + // if you have them. post_is_importable() assumes true + // and only fails if there was intentional rejection + // due to this channel's filtering rules for content + // provided by either of these entities. + + $abook = q("select * from abook where ( abook_xchan = '%s' OR abook_xchan = '%s') and abook_channel = %d ", + dbesc($item['author_xchan']), + dbesc($item['owner_xchan']), + intval($channel['channel_id']) + ); + + + if (!post_is_importable($channel['channel_id'], $item, $abook)) { + logger('post is filtered'); + return; + } + + $maxlen = get_max_import_size(); + + if ($maxlen && mb_strlen($item['body']) > $maxlen) { + $item['body'] = mb_substr($item['body'], 0, $maxlen, 'UTF-8'); + logger('message length exceeds max_import_size: truncated'); + } + + if ($maxlen && mb_strlen($item['summary']) > $maxlen) { + $item['summary'] = mb_substr($item['summary'], 0, $maxlen, 'UTF-8'); + logger('message summary length exceeds max_import_size: truncated'); + } + + if ($act->obj['context']) { + set_iconfig($item, 'activitypub', 'context', $act->obj['context'], 1); + } + + if ($act->obj['conversation']) { + set_iconfig($item, 'ostatus', 'conversation', $act->obj['conversation'], 1); + } + + set_iconfig($item, 'activitypub', 'recips', $act->raw_recips); + + if (intval($act->sigok)) { + $item['item_verified'] = 1; + } + + $parent = null; + + if ($is_child_node) { + + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($item['parent_mid']), + intval($item['uid']) + ); + if (!$parent) { + if (!get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) { + return; + } else { + $fetch = false; + if (intval($channel['channel_system']) || (perm_is_allowed($channel['channel_id'], $observer_hash, 'send_stream') && (PConfig::Get($channel['channel_id'], 'system', 'hyperdrive', true) || $act->type === 'Announce'))) { + $fetch = (($fetch_parents) ? self::fetch_and_store_parents($channel, $observer_hash, $act, $item) : false); + } + if ($fetch) { + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($item['parent_mid']), + intval($item['uid']) + ); + } else { + logger('no parent'); + return; + } + } + } + + $item['comment_policy'] = $parent[0]['comment_policy']; + $item['item_nocomment'] = $parent[0]['item_nocomment']; + $item['comments_closed'] = $parent[0]['comments_closed']; + + if ($parent[0]['parent_mid'] !== $item['parent_mid']) { + $item['thr_parent'] = $item['parent_mid']; + } else { + $item['thr_parent'] = $parent[0]['parent_mid']; + } + $item['parent_mid'] = $parent[0]['parent_mid']; + + /* * * Check for conversation privacy mismatches * We can only do this if we have a channel and we have fetched the parent * */ - - // public conversation, but this comment went rogue and was published privately - // hide it from everybody except the channel owner - - if (intval($parent[0]['item_private']) === 0) { - if (intval($item['item_private'])) { - $item['item_restrict'] = $item['item_restrict'] | 1; - $item['allow_cid'] = '<' . $channel['channel_hash'] . '>'; - $item['allow_gid'] = $item['deny_cid'] = $item['deny_gid'] = ''; - } - } - // Private conversation, but this comment went rogue and was published publicly - // Set item_restrict to indicate this condition so we can flag it in the UI + // public conversation, but this comment went rogue and was published privately + // hide it from everybody except the channel owner - if (intval($parent[0]['item_private']) !== 0 && $act->recips && (in_array(ACTIVITY_PUBLIC_INBOX,$act->recips) || in_array('Public',$act->recips) || in_array('as:Public',$act->recips))) { - $item['item_restrict'] = $item['item_restrict'] | 2; - } + if (intval($parent[0]['item_private']) === 0) { + if (intval($item['item_private'])) { + $item['item_restrict'] = $item['item_restrict'] | 1; + $item['allow_cid'] = '<' . $channel['channel_hash'] . '>'; + $item['allow_gid'] = $item['deny_cid'] = $item['deny_gid'] = ''; + } + } - } + // Private conversation, but this comment went rogue and was published publicly + // Set item_restrict to indicate this condition so we can flag it in the UI - self::rewrite_mentions($item); + if (intval($parent[0]['item_private']) !== 0 && $act->recips && (in_array(ACTIVITY_PUBLIC_INBOX, $act->recips) || in_array('Public', $act->recips) || in_array('as:Public', $act->recips))) { + $item['item_restrict'] = $item['item_restrict'] | 2; + } - $r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1", - dbesc($item['mid']), - intval($item['uid']) - ); - if ($r) { - if ($item['edited'] > $r[0]['edited']) { - $item['id'] = $r[0]['id']; - $x = item_store_update($item); - } - else { - return; - } - } - else { - $x = item_store($item); - } + } + + self::rewrite_mentions($item); + + $r = q("select id, created, edited from item where mid = '%s' and uid = %d limit 1", + dbesc($item['mid']), + intval($item['uid']) + ); + if ($r) { + if ($item['edited'] > $r[0]['edited']) { + $item['id'] = $r[0]['id']; + $x = item_store_update($item); + } else { + return; + } + } else { + $x = item_store($item); + } // experimental code that needs more work. What this did was once we fetched a conversation to find the root node, // start at that root node and fetch children so you get all the branches and not just the branch related to the current node. // Unfortunately there is no standard method for achieving this. Mastodon provides a 'replies' collection and Nomad projects // can fetch the 'context'. For other platforms it's a wild guess. Additionally when we tested this, it started an infinite -// recursion and has been disabled until the recursive behaviour is tracked down and fixed. +// recursion and has been disabled until the recursive behaviour is tracked down and fixed. // if ($fetch_parents && $parent && ! intval($parent[0]['item_private'])) { // logger('topfetch', LOGGER_DEBUG); @@ -3842,492 +3772,497 @@ class Activity { // } // } - if (is_array($x) && $x['item_id']) { - if ($is_child_node) { - if ($item['owner_xchan'] === $channel['channel_hash']) { - // We are the owner of this conversation, so send all received comments back downstream - Run::Summon( [ 'Notifier','comment-import',$x['item_id'] ] ); - } - $r = q("select * from item where id = %d limit 1", - intval($x['item_id']) - ); - if ($r) { - send_status_notifications($x['item_id'],$r[0]); - } - } - sync_an_item($channel['channel_id'],$x['item_id']); - } - - } - - - static public function find_best_identity($xchan) { - - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1", - dbesc($xchan) - ); - if ($r) { - return $r[0]['hubloc_hash']; - } - return $xchan; - } - - - static public function fetch_and_store_parents($channel,$observer_hash,$act,$item) { - - logger('fetching parents'); - - $p = []; - - $current_act = $act; - $current_item = $item; - - while ($current_item['parent_mid'] !== $current_item['mid']) { - $n = self::fetch($current_item['parent_mid']); - if (! $n) { - break; - } - // set client flag to convert objects to implied activities - $a = new ActivityStreams($n,null,true); - if ($a->type === 'Announce' && is_array($a->obj) - && array_key_exists('object',$a->obj) && array_key_exists('actor',$a->obj)) { - // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) - // Reparse the encapsulated Activity and use that instead - logger('relayed activity',LOGGER_DEBUG); - $a = new ActivityStreams($a->obj,null,true); - } - - logger($a->debug(),LOGGER_DATA); - - if (! $a->is_valid()) { - logger('not a valid activity'); - break; - } - if (is_array($a->actor) && array_key_exists('id',$a->actor)) { - self::actor_store($a->actor['id'],$a->actor); - } - - // ActivityPub sourced items are cacheable - $item = self::decode_note($a,true); - - if (! $item) { - break; - } - - $hookinfo = [ - 'a' => $a, - 'item' => $item - ]; - - call_hooks('fetch_and_store',$hookinfo); - - $item = $hookinfo['item']; - - if ($item) { - - // don't leak any private conversations to the public stream - // even if they contain publicly addressed comments/reactions - - if (intval($channel['channel_system']) && intval($item['item_private'])) { - logger('private conversation ignored'); - $p = []; - break; - } - - if (count($p) > 100) { - logger('Conversation overflow'); - $p = []; - break; - } - - array_unshift($p,[ $a, $item ]); - - if ($item['parent_mid'] === $item['mid']) { - break; - } - } - - $current_act = $a; - $current_item = $item; - } - - - - if ($p) { - foreach ($p as $pv) { - if ($pv[0]->is_valid()) { - self::store($channel,$observer_hash,$pv[0],$pv[1],false); - } - } - return true; - } - - return false; - } - - - // This function is designed to work with Zot attachments and item body - - static function bb_attach($attach,$body) { - - $ret = false; - - if (! (is_array($attach) && $attach)) { - return EMPTY_STR; - } - - foreach ($attach as $a) { - if (array_key_exists('type',$a) && stripos($a['type'],'image') !== false) { - // don't add inline image if it's an svg and we already have an inline svg - if ($a['type'] === 'image/svg+xml' && strpos($body,'[/svg]')) { - continue; - } - if (self::media_not_in_body($a['href'],$body)) { - if (isset($a['name']) && $a['name']) { - $alt = htmlspecialchars($a['name'],ENT_QUOTES); - $ret .= "\n\n" . '[img alt="' . $alt . '"]' . $a['href'] . '[/img]'; - } - else { - $ret .= "\n\n" . '[img]' . $a['href'] . '[/img]'; - } - } - } - if (array_key_exists('type',$a) && stripos($a['type'], 'video') !== false) { - if (self::media_not_in_body($a['href'],$body)) { - $ret .= "\n\n" . '[video]' . $a['href'] . '[/video]'; - } - } - if (array_key_exists('type',$a) && stripos($a['type'], 'audio') !== false) { - if (self::media_not_in_body($a['href'],$body)) { - $ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]'; - } - } - } - - return $ret; - } - - - // check for the existence of existing media link in body - - static function media_not_in_body($s,$body) { - - $s_alt = htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); - - if ((strpos($body,']' . $s . '[/img]') === false) && - (strpos($body,']' . $s . '[/zmg]') === false) && - (strpos($body,']' . $s . '[/video]') === false) && - (strpos($body,']' . $s . '[/zvideo]') === false) && - (strpos($body,']' . $s . '[/audio]') === false) && - (strpos($body,']' . $s . '[/zaudio]') === false) && - (strpos($body,']' . $s_alt . '[/img]') === false) && - (strpos($body,']' . $s_alt . '[/zmg]') === false) && - (strpos($body,']' . $s_alt . '[/video]') === false) && - (strpos($body,']' . $s_alt . '[/zvideo]') === false) && - (strpos($body,']' . $s_alt . '[/audio]') === false) && - (strpos($body,']' . $s_alt . '[/zaudio]') === false)) { - return true; - } - return false; - } - - - static function bb_content($content,$field) { - - $ret = false; - - if (! is_array($content)) { - btlogger('content not initialised'); - return $ret; - } - - if (array_key_exists($field,$content) && is_array($content[$field])) { - foreach ($content[$field] as $k => $v) { - $ret .= html2bbcode($v); - // save this for auto-translate or dynamic filtering - // $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]'; - } - } - elseif (isset($content[$field])) { - if ($field === 'bbcode' && array_key_exists('bbcode',$content)) { - $ret = $content[$field]; - } - else { - $ret = html2bbcode($content[$field]); - } - } - else { - $ret = EMPTY_STR; - } - if ($field === 'content' && isset($content['event']) && (! strpos($ret,'[event'))) { - $ret .= format_event_bbcode($content['event']); - } - - return $ret; - } - - - static function get_content($act,$binary = false) { - - $content = []; - $event = null; - - if ((! $act) || (! is_array($act))) { - return $content; - } - - - if ($act['type'] === 'Event') { - $adjust = false; - $event = []; - $event['event_hash'] = $act['id']; - if (array_key_exists('startTime',$act) && strpos($act['startTime'],-1,1) === 'Z') { - $adjust = true; - $event['adjust'] = 1; - $event['dtstart'] = datetime_convert('UTC','UTC',$event['startTime'] . (($adjust) ? '' : 'Z')); - } - if (array_key_exists('endTime',$act)) { - $event['dtend'] = datetime_convert('UTC','UTC',$event['endTime'] . (($adjust) ? '' : 'Z')); - } - else { - $event['nofinish'] = true; - } - - if (array_key_exists('eventRepeat',$act)) { - $event['event_repeat'] = $act['eventRepeat']; - } - } - - foreach ([ 'name', 'summary', 'content' ] as $a) { - if (($x = self::get_textfield($act,$a,$binary)) !== false) { - $content[$a] = $x; - } - if (isset($content['name'])) { - $content['name'] = html2plain(purify_html($content['name']),256); - } - } - - if ($event && ! $binary) { - $event['summary'] = html2plain(purify_html($content['summary']),256); - if (! $event['summary']) { - if ($content['name']) { - $event['summary'] = html2plain(purify_html($content['name']),256); - } - } - if (! $event['summary']) { - if ($content['content']) { - $event['summary'] = html2plain(purify_html($content['content']),256); - } - } - if ($event['summary']) { - $event['summary'] = substr($event['summary'],0,256); - } - $event['description'] = html2bbcode($content['content']); - if ($event['summary'] && $event['dtstart']) { - $content['event'] = $event; - } - } - - if (array_path_exists('source/mediaType',$act) && array_path_exists('source/content',$act)) { - if (in_array($act['source']['mediaType'], [ 'text/bbcode', 'text/x-multicode' ])) { - if (is_string($act['source']['content']) && strpos($act['source']['content'],'<') !== false) { - $content['bbcode'] = multicode_purify($act['source']['content']); - } - else { - $content['bbcode'] = purify_html($act['source']['content'], [ 'escape' ] ); - } - } - } - - return $content; - } - - - static function get_textfield($act,$field,$binary = false) { - - $content = false; - - if (array_key_exists($field,$act) && $act[$field]) - $content = (($binary) ? $act[$field] : purify_html($act[$field])); - elseif (array_key_exists($field . 'Map',$act) && $act[$field . 'Map']) { - foreach ($act[$field . 'Map'] as $k => $v) { - $content[escape_tags($k)] = (($binary) ? $v : purify_html($v)); - } - } - return $content; - } - - static function send_rejection_activity($channel,$observer_hash,$item) { - - $recip = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($observer_hash) - ); - if (! $recip) { - return; - } - - $arr = [ - 'id' => z_root() . '/bounces/' . new_uuid(), - 'to' => [ $observer_hash ], - 'type' => 'Reject', - 'actor' => channel_url($channel), - 'name' => 'Permission denied', - 'object' => $item['message_id'] - ]; - - $msg = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - self::ap_schema() - ]], $arr); - - $queue_id = ActivityPub::queue_message(json_encode($msg, JSON_UNESCAPED_SLASHES),$channel,$recip[0]); - do_delivery( [ $queue_id ] ); - - } - - // Find either an Authorization: Bearer token or 'token' request variable - // in the current web request and return it - - static function token_from_request() { - - foreach ( [ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $s ) { - $auth = ((array_key_exists($s,$_SERVER) && strpos($_SERVER[$s],'Bearer ') === 0) - ? str_replace('Bearer ', EMPTY_STR, $_SERVER[$s]) - : EMPTY_STR - ); - if ($auth) { - break; - } - } - - if (! $auth) { - if (array_key_exists('token',$_REQUEST) && $_REQUEST['token']) { - $auth = $_REQUEST['token']; - } - } - - return $auth; - } - - static function get_xchan_type($type) { - switch ($type) { - case 'Person': - return XCHAN_TYPE_PERSON; - case 'Group': - return XCHAN_TYPE_GROUP; - case 'Service': - return XCHAN_TYPE_SERVICE; - case 'Organization': - return XCHAN_TYPE_ORGANIZATION; - case 'Application': - return XCHAN_TYPE_APPLICATION; - default: - return XCHAN_TYPE_UNKNOWN; - } - } - - static function get_cached_actor($id) { - return (XConfig::Get($id,'system','actor_record')); - } - - - static function get_actor_hublocs($url, $options = 'all,not_deleted') { - - $hublocs = false; - $sql_options = EMPTY_STR; - - $options_arr = explode(',',$options); - if (count($options_arr) > 1) { - for ($x = 1; $x < count($options_arr); $x ++) { - switch (trim($options_arr[$x])) { - case 'not_deleted': - $sql_options .= ' and hubloc_deleted = 0 '; - break; - default: - break; - } - } - } - - switch (trim($options_arr[0])) { - case 'activitypub': - $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' $sql_options ", - dbesc($url) - ); - break; - case 'zot6': - $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_id_url = '%s' $sql_options ", - dbesc($url) - ); - break; - case 'all': - default: - $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where ( hubloc_id_url = '%s' OR hubloc_hash = '%s' ) $sql_options ", - dbesc($url), - dbesc($url) - ); - break; - } - - return $hublocs; - } - - static function get_actor_collections($url) { - $ret = []; - $actor_record = XConfig::Get($url,'system','actor_record'); - if (! $actor_record) { - return $ret; - } - - foreach ( [ 'inbox','outbox','followers','following' ] as $collection) { - if (isset($actor_record[$collection]) && $actor_record[$collection]) { - $ret[$collection] = $actor_record[$collection]; - } - } - if (array_path_exists('endpoints/sharedInbox',$actor_record) && $actor_record['endpoints']['sharedInbox']) { - $ret['sharedInbox'] = $actor_record['endpoints']['sharedInbox']; - } - - return $ret; - } - - static function ap_schema() { - - return [ - 'zot' => z_root() . '/apschema#', - 'toot' => 'http://joinmastodon.org/ns#', - 'ostatus' => 'http://ostatus.org#', - 'schema' => 'http://schema.org#', - 'litepub' => 'http://litepub.social/ns#', - 'sm' => 'http://smithereen.software/ns#', - 'conversation' => 'ostatus:conversation', - 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', - 'oauthRegistrationEndpoint' => 'litepub:oauthRegistrationEndpoint', - 'sensitive' => 'as:sensitive', - 'movedTo' => 'as:movedTo', - 'copiedTo' => 'as:copiedTo', - 'alsoKnownAs' => 'as:alsoKnownAs', - 'EmojiReact' => 'as:EmojiReact', - 'commentPolicy' => 'zot:commentPolicy', - 'topicalCollection' => 'zot:topicalCollection', - 'eventRepeat' => 'zot:eventRepeat', - 'emojiReaction' => 'zot:emojiReaction', - 'expires' => 'zot:expires', - 'directMessage' => 'zot:directMessage', - 'Category' => 'zot:Category', - 'replyTo' => 'zot:replyTo', - 'PropertyValue' => 'schema:PropertyValue', - 'value' => 'schema:value', - 'discoverable' => 'toot:discoverable', - 'wall' => 'sm:wall', - 'capabilities' => 'litepub:capabilities', - 'acceptsJoins' => 'litepub:acceptsJoins', - ]; - - } - - + if (is_array($x) && $x['item_id']) { + if ($is_child_node) { + if ($item['owner_xchan'] === $channel['channel_hash']) { + // We are the owner of this conversation, so send all received comments back downstream + Run::Summon(['Notifier', 'comment-import', $x['item_id']]); + } + $r = q("select * from item where id = %d limit 1", + intval($x['item_id']) + ); + if ($r) { + send_status_notifications($x['item_id'], $r[0]); + } + } + sync_an_item($channel['channel_id'], $x['item_id']); + } + + } + + + public static function find_best_identity($xchan) + { + + $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' limit 1", + dbesc($xchan) + ); + if ($r) { + return $r[0]['hubloc_hash']; + } + return $xchan; + } + + + public static function fetch_and_store_parents($channel, $observer_hash, $act, $item) + { + + logger('fetching parents'); + + $p = []; + + $current_act = $act; + $current_item = $item; + + while ($current_item['parent_mid'] !== $current_item['mid']) { + $n = self::fetch($current_item['parent_mid']); + if (!$n) { + break; + } + // set client flag to convert objects to implied activities + $a = new ActivityStreams($n, null, true); + if ($a->type === 'Announce' && is_array($a->obj) + && array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $a = new ActivityStreams($a->obj, null, true); + } + + logger($a->debug(), LOGGER_DATA); + + if (!$a->is_valid()) { + logger('not a valid activity'); + break; + } + if (is_array($a->actor) && array_key_exists('id', $a->actor)) { + self::actor_store($a->actor['id'], $a->actor); + } + + // ActivityPub sourced items are cacheable + $item = self::decode_note($a, true); + + if (!$item) { + break; + } + + $hookinfo = [ + 'a' => $a, + 'item' => $item + ]; + + call_hooks('fetch_and_store', $hookinfo); + + $item = $hookinfo['item']; + + if ($item) { + + // don't leak any private conversations to the public stream + // even if they contain publicly addressed comments/reactions + + if (intval($channel['channel_system']) && intval($item['item_private'])) { + logger('private conversation ignored'); + $p = []; + break; + } + + if (count($p) > 100) { + logger('Conversation overflow'); + $p = []; + break; + } + + array_unshift($p, [$a, $item]); + + if ($item['parent_mid'] === $item['mid']) { + break; + } + } + + $current_act = $a; + $current_item = $item; + } + + + if ($p) { + foreach ($p as $pv) { + if ($pv[0]->is_valid()) { + self::store($channel, $observer_hash, $pv[0], $pv[1], false); + } + } + return true; + } + + return false; + } + + + // This function is designed to work with Zot attachments and item body + + public static function bb_attach($attach, $body) + { + + $ret = false; + + if (!(is_array($attach) && $attach)) { + return EMPTY_STR; + } + + foreach ($attach as $a) { + if (array_key_exists('type', $a) && stripos($a['type'], 'image') !== false) { + // don't add inline image if it's an svg and we already have an inline svg + if ($a['type'] === 'image/svg+xml' && strpos($body, '[/svg]')) { + continue; + } + if (self::media_not_in_body($a['href'], $body)) { + if (isset($a['name']) && $a['name']) { + $alt = htmlspecialchars($a['name'], ENT_QUOTES); + $ret .= "\n\n" . '[img alt="' . $alt . '"]' . $a['href'] . '[/img]'; + } else { + $ret .= "\n\n" . '[img]' . $a['href'] . '[/img]'; + } + } + } + if (array_key_exists('type', $a) && stripos($a['type'], 'video') !== false) { + if (self::media_not_in_body($a['href'], $body)) { + $ret .= "\n\n" . '[video]' . $a['href'] . '[/video]'; + } + } + if (array_key_exists('type', $a) && stripos($a['type'], 'audio') !== false) { + if (self::media_not_in_body($a['href'], $body)) { + $ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]'; + } + } + } + + return $ret; + } + + + // check for the existence of existing media link in body + + public static function media_not_in_body($s, $body) + { + + $s_alt = htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); + + if ((strpos($body, ']' . $s . '[/img]') === false) && + (strpos($body, ']' . $s . '[/zmg]') === false) && + (strpos($body, ']' . $s . '[/video]') === false) && + (strpos($body, ']' . $s . '[/zvideo]') === false) && + (strpos($body, ']' . $s . '[/audio]') === false) && + (strpos($body, ']' . $s . '[/zaudio]') === false) && + (strpos($body, ']' . $s_alt . '[/img]') === false) && + (strpos($body, ']' . $s_alt . '[/zmg]') === false) && + (strpos($body, ']' . $s_alt . '[/video]') === false) && + (strpos($body, ']' . $s_alt . '[/zvideo]') === false) && + (strpos($body, ']' . $s_alt . '[/audio]') === false) && + (strpos($body, ']' . $s_alt . '[/zaudio]') === false)) { + return true; + } + return false; + } + + + public static function bb_content($content, $field) + { + + $ret = false; + + if (!is_array($content)) { + btlogger('content not initialised'); + return $ret; + } + + if (array_key_exists($field, $content) && is_array($content[$field])) { + foreach ($content[$field] as $k => $v) { + $ret .= html2bbcode($v); + // save this for auto-translate or dynamic filtering + // $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]'; + } + } elseif (isset($content[$field])) { + if ($field === 'bbcode' && array_key_exists('bbcode', $content)) { + $ret = $content[$field]; + } else { + $ret = html2bbcode($content[$field]); + } + } else { + $ret = EMPTY_STR; + } + if ($field === 'content' && isset($content['event']) && (!strpos($ret, '[event'))) { + $ret .= format_event_bbcode($content['event']); + } + + return $ret; + } + + + public static function get_content($act, $binary = false) + { + + $content = []; + $event = null; + + if ((!$act) || (!is_array($act))) { + return $content; + } + + + if ($act['type'] === 'Event') { + $adjust = false; + $event = []; + $event['event_hash'] = $act['id']; + if (array_key_exists('startTime', $act) && strpos($act['startTime'], -1, 1) === 'Z') { + $adjust = true; + $event['adjust'] = 1; + $event['dtstart'] = datetime_convert('UTC', 'UTC', $event['startTime'] . (($adjust) ? '' : 'Z')); + } + if (array_key_exists('endTime', $act)) { + $event['dtend'] = datetime_convert('UTC', 'UTC', $event['endTime'] . (($adjust) ? '' : 'Z')); + } else { + $event['nofinish'] = true; + } + + if (array_key_exists('eventRepeat', $act)) { + $event['event_repeat'] = $act['eventRepeat']; + } + } + + foreach (['name', 'summary', 'content'] as $a) { + if (($x = self::get_textfield($act, $a, $binary)) !== false) { + $content[$a] = $x; + } + if (isset($content['name'])) { + $content['name'] = html2plain(purify_html($content['name']), 256); + } + } + + if ($event && !$binary) { + $event['summary'] = html2plain(purify_html($content['summary']), 256); + if (!$event['summary']) { + if ($content['name']) { + $event['summary'] = html2plain(purify_html($content['name']), 256); + } + } + if (!$event['summary']) { + if ($content['content']) { + $event['summary'] = html2plain(purify_html($content['content']), 256); + } + } + if ($event['summary']) { + $event['summary'] = substr($event['summary'], 0, 256); + } + $event['description'] = html2bbcode($content['content']); + if ($event['summary'] && $event['dtstart']) { + $content['event'] = $event; + } + } + + if (array_path_exists('source/mediaType', $act) && array_path_exists('source/content', $act)) { + if (in_array($act['source']['mediaType'], ['text/bbcode', 'text/x-multicode'])) { + if (is_string($act['source']['content']) && strpos($act['source']['content'], '<') !== false) { + $content['bbcode'] = multicode_purify($act['source']['content']); + } else { + $content['bbcode'] = purify_html($act['source']['content'], ['escape']); + } + } + } + + return $content; + } + + + public static function get_textfield($act, $field, $binary = false) + { + + $content = false; + + if (array_key_exists($field, $act) && $act[$field]) + $content = (($binary) ? $act[$field] : purify_html($act[$field])); + elseif (array_key_exists($field . 'Map', $act) && $act[$field . 'Map']) { + foreach ($act[$field . 'Map'] as $k => $v) { + $content[escape_tags($k)] = (($binary) ? $v : purify_html($v)); + } + } + return $content; + } + + public static function send_rejection_activity($channel, $observer_hash, $item) + { + + $recip = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($observer_hash) + ); + if (!$recip) { + return; + } + + $arr = [ + 'id' => z_root() . '/bounces/' . new_uuid(), + 'to' => [$observer_hash], + 'type' => 'Reject', + 'actor' => channel_url($channel), + 'name' => 'Permission denied', + 'object' => $item['message_id'] + ]; + + $msg = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + self::ap_schema() + ]], $arr); + + $queue_id = ActivityPub::queue_message(json_encode($msg, JSON_UNESCAPED_SLASHES), $channel, $recip[0]); + do_delivery([$queue_id]); + + } + + // Find either an Authorization: Bearer token or 'token' request variable + // in the current web request and return it + + public static function token_from_request() + { + + foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $s) { + $auth = ((array_key_exists($s, $_SERVER) && strpos($_SERVER[$s], 'Bearer ') === 0) + ? str_replace('Bearer ', EMPTY_STR, $_SERVER[$s]) + : EMPTY_STR + ); + if ($auth) { + break; + } + } + + if (!$auth) { + if (array_key_exists('token', $_REQUEST) && $_REQUEST['token']) { + $auth = $_REQUEST['token']; + } + } + + return $auth; + } + + public static function get_xchan_type($type) + { + switch ($type) { + case 'Person': + return XCHAN_TYPE_PERSON; + case 'Group': + return XCHAN_TYPE_GROUP; + case 'Service': + return XCHAN_TYPE_SERVICE; + case 'Organization': + return XCHAN_TYPE_ORGANIZATION; + case 'Application': + return XCHAN_TYPE_APPLICATION; + default: + return XCHAN_TYPE_UNKNOWN; + } + } + + public static function get_cached_actor($id) + { + return (XConfig::Get($id, 'system', 'actor_record')); + } + + + public static function get_actor_hublocs($url, $options = 'all,not_deleted') + { + + $hublocs = false; + $sql_options = EMPTY_STR; + + $options_arr = explode(',', $options); + if (count($options_arr) > 1) { + for ($x = 1; $x < count($options_arr); $x++) { + switch (trim($options_arr[$x])) { + case 'not_deleted': + $sql_options .= ' and hubloc_deleted = 0 '; + break; + default: + break; + } + } + } + + switch (trim($options_arr[0])) { + case 'activitypub': + $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_hash = '%s' $sql_options ", + dbesc($url) + ); + break; + case 'zot6': + $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_id_url = '%s' $sql_options ", + dbesc($url) + ); + break; + case 'all': + default: + $hublocs = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where ( hubloc_id_url = '%s' OR hubloc_hash = '%s' ) $sql_options ", + dbesc($url), + dbesc($url) + ); + break; + } + + return $hublocs; + } + + public static function get_actor_collections($url) + { + $ret = []; + $actor_record = XConfig::Get($url, 'system', 'actor_record'); + if (!$actor_record) { + return $ret; + } + + foreach (['inbox', 'outbox', 'followers', 'following'] as $collection) { + if (isset($actor_record[$collection]) && $actor_record[$collection]) { + $ret[$collection] = $actor_record[$collection]; + } + } + if (array_path_exists('endpoints/sharedInbox', $actor_record) && $actor_record['endpoints']['sharedInbox']) { + $ret['sharedInbox'] = $actor_record['endpoints']['sharedInbox']; + } + + return $ret; + } + + public static function ap_schema() + { + + return [ + 'zot' => z_root() . '/apschema#', + 'toot' => 'http://joinmastodon.org/ns#', + 'ostatus' => 'http://ostatus.org#', + 'schema' => 'http://schema.org#', + 'litepub' => 'http://litepub.social/ns#', + 'sm' => 'http://smithereen.software/ns#', + 'conversation' => 'ostatus:conversation', + 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', + 'oauthRegistrationEndpoint' => 'litepub:oauthRegistrationEndpoint', + 'sensitive' => 'as:sensitive', + 'movedTo' => 'as:movedTo', + 'copiedTo' => 'as:copiedTo', + 'alsoKnownAs' => 'as:alsoKnownAs', + 'EmojiReact' => 'as:EmojiReact', + 'commentPolicy' => 'zot:commentPolicy', + 'topicalCollection' => 'zot:topicalCollection', + 'eventRepeat' => 'zot:eventRepeat', + 'emojiReaction' => 'zot:emojiReaction', + 'expires' => 'zot:expires', + 'directMessage' => 'zot:directMessage', + 'Category' => 'zot:Category', + 'replyTo' => 'zot:replyTo', + 'PropertyValue' => 'schema:PropertyValue', + 'value' => 'schema:value', + 'discoverable' => 'toot:discoverable', + 'wall' => 'sm:wall', + 'capabilities' => 'litepub:capabilities', + 'acceptsJoins' => 'litepub:acceptsJoins', + ]; + + } } diff --git a/Zotlabs/Lib/ActivityPub.php b/Zotlabs/Lib/ActivityPub.php index e79f5d4f5..101552042 100644 --- a/Zotlabs/Lib/ActivityPub.php +++ b/Zotlabs/Lib/ActivityPub.php @@ -9,97 +9,97 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Daemon\Run; use Zotlabs\Lib\IConfig; -class ActivityPub { +class ActivityPub +{ - static public function notifier_process(&$arr) { + public static function notifier_process(&$arr) + { - if ($arr['hub']['hubloc_network'] !== 'activitypub') { - return; - } + if ($arr['hub']['hubloc_network'] !== 'activitypub') { + return; + } - logger('upstream: ' . intval($arr['upstream'])); + logger('upstream: ' . intval($arr['upstream'])); - // logger('notifier_array: ' . print_r($arr,true), LOGGER_ALL, LOG_INFO); + // logger('notifier_array: ' . print_r($arr,true), LOGGER_ALL, LOG_INFO); - $purge_all = (($arr['packet_type'] === 'purge' && (! intval($arr['private']))) ? true : false); - - $signed_msg = null; + $purge_all = (($arr['packet_type'] === 'purge' && (!intval($arr['private']))) ? true : false); - if (array_key_exists('target_item',$arr) && is_array($arr['target_item'])) { + $signed_msg = null; - if (intval($arr['target_item']['item_obscured'])) { - logger('Cannot send raw data as an activitypub activity.'); - return; - } + if (array_key_exists('target_item', $arr) && is_array($arr['target_item'])) { - $signed_msg = get_iconfig($arr['target_item'],'activitypub','rawmsg'); + if (intval($arr['target_item']['item_obscured'])) { + logger('Cannot send raw data as an activitypub activity.'); + return; + } - // If we have an activity already stored with an LD-signature - // which we are sending downstream, use that signed activity as is. - // The channel will then sign the HTTP transaction. + $signed_msg = get_iconfig($arr['target_item'], 'activitypub', 'rawmsg'); - // It is unclear if Mastodon supports the federation delivery model. Initial tests were - // inconclusive and the behaviour varied. + // If we have an activity already stored with an LD-signature + // which we are sending downstream, use that signed activity as is. + // The channel will then sign the HTTP transaction. - if (($arr['channel']['channel_hash'] !== $arr['target_item']['author_xchan']) && (! $signed_msg)) { - logger('relayed post with no signed message'); - return; - } - - } + // It is unclear if Mastodon supports the federation delivery model. Initial tests were + // inconclusive and the behaviour varied. - if ($purge_all) { + if (($arr['channel']['channel_hash'] !== $arr['target_item']['author_xchan']) && (!$signed_msg)) { + logger('relayed post with no signed message'); + return; + } - $ti = [ - 'id' => channel_url($arr['channel']) . '?operation=delete', - 'actor' => channel_url($arr['channel']), - 'type' => 'Delete', - 'object' => channel_url($arr['channel']), - 'to' => [ 'https://www.w3.org/ns/activitystreams#Public' ] - ]; + } - $msg = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], $ti); + if ($purge_all) { - $msg['signature'] = LDSignatures::sign($msg,$arr['channel']); + $ti = [ + 'id' => channel_url($arr['channel']) . '?operation=delete', + 'actor' => channel_url($arr['channel']), + 'type' => 'Delete', + 'object' => channel_url($arr['channel']), + 'to' => ['https://www.w3.org/ns/activitystreams#Public'] + ]; - logger('ActivityPub_encoded (purge_all): ' . json_encode($msg,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT)); - - $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); - - } - else { - $target_item = $arr['target_item']; + $msg = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], $ti); - if (! $target_item['mid']) { - return; - } + $msg['signature'] = LDSignatures::sign($msg, $arr['channel']); - $prv_recips = $arr['env_recips']; + logger('ActivityPub_encoded (purge_all): ' . json_encode($msg, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); + + $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); + + } else { + $target_item = $arr['target_item']; + + if (!$target_item['mid']) { + return; + } + + $prv_recips = $arr['env_recips']; - if ($signed_msg) { - $jmsg = $signed_msg; - } - else { + if ($signed_msg) { + $jmsg = $signed_msg; + } else { - // Rewrite outbound mentions so they match the ActivityPub convention, which - // is to pretend that the preferred display name doesn't exist and instead use - // the username or webfinger address when displaying names. This is likely to - // only cause confusion on nomadic networks where there could be any number - // of applicable webfinger addresses for a given identity. + // Rewrite outbound mentions so they match the ActivityPub convention, which + // is to pretend that the preferred display name doesn't exist and instead use + // the username or webfinger address when displaying names. This is likely to + // only cause confusion on nomadic networks where there could be any number + // of applicable webfinger addresses for a given identity. - Activity::rewrite_mentions_sub($target_item, 1, $target_item['obj']); + Activity::rewrite_mentions_sub($target_item, 1, $target_item['obj']); - $ti = Activity::encode_activity($target_item, true); + $ti = Activity::encode_activity($target_item, true); - if (! $ti) { - return; - } + if (!$ti) { + return; + } // $token = IConfig::get($target_item['id'],'ocap','relay'); // if ($token) { @@ -114,472 +114,475 @@ class ActivityPub { // } // } - $msg = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], $ti); - - $msg['signature'] = LDSignatures::sign($msg,$arr['channel']); + $msg = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], $ti); - logger('ActivityPub_encoded: ' . json_encode($msg,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT)); - - $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); - } - } - if ($prv_recips) { - $hashes = []; + $msg['signature'] = LDSignatures::sign($msg, $arr['channel']); - // re-explode the recipients, but only for this hub/pod + logger('ActivityPub_encoded: ' . json_encode($msg, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); - foreach ($prv_recips as $recip) { - $hashes[] = "'" . $recip . "'"; - } + $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); + } + } + if ($prv_recips) { + $hashes = []; - $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url = '%s' + // re-explode the recipients, but only for this hub/pod + + foreach ($prv_recips as $recip) { + $hashes[] = "'" . $recip . "'"; + } + + $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url = '%s' and xchan_hash in (" . implode(',', $hashes) . ") and xchan_network = 'activitypub' ", - dbesc($arr['hub']['hubloc_url']) - ); - - if (! $r) { - logger('activitypub_process_outbound: no recipients'); - return; - } - - foreach ($r as $contact) { - - // is $contact connected with this channel - and if the channel is cloned, also on this hub? - // 2018-10-19 this probably doesn't apply to activitypub anymore, just send the thing. - // They'll reject it if they don't like it. - // $single = deliverable_singleton($arr['channel']['channel_id'],$contact); - - if (! $arr['normal_mode']) { - continue; - } - - $qi = self::queue_message($jmsg,$arr['channel'],$contact,$target_item['mid']); - if ($qi) { - $arr['queued'][] = $qi; - } - continue; - } - - } - else { - - // public message - - // See if we can deliver all of them at once - - $x = get_xconfig($arr['hub']['hubloc_hash'],'activitypub','collections'); - if ($x && $x['sharedInbox']) { - logger('using publicInbox delivery for ' . $arr['hub']['hubloc_url'], LOGGER_DEBUG); - $contact['hubloc_callback'] = $x['sharedInbox']; - $qi = self::queue_message($jmsg,$arr['channel'],$contact,$target_item['mid']); - if ($qi) { - $arr['queued'][] = $qi; - } - } - else { - - $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url = '%s' and xchan_network = 'activitypub' ", - dbesc($arr['hub']['hubloc_url']) - ); - - if (! $r) { - logger('activitypub_process_outbound: no recipients'); - return; - } - - foreach ($r as $contact) { - - // $single = deliverable_singleton($arr['channel']['channel_id'],$contact); - - $qi = self::queue_message($jmsg,$arr['channel'],$contact,$target_item['mid']); - if ($qi) { - $arr['queued'][] = $qi; - } - } - } - } - - return; - - } - - - static function queue_message($msg,$sender,$recip,$message_id = '') { - - $dest_url = $recip['hubloc_callback']; - - logger('URL: ' . $dest_url, LOGGER_DEBUG); - logger('DATA: ' . jindent($msg), LOGGER_DATA); - - if (intval(get_config('system','activitypub_test')) || intval(get_pconfig($sender['channel_id'],'system','activitypub_test'))) { - logger('test mode - delivery disabled'); - return false; - } - - $hash = random_string(); - - logger('queue: ' . $hash . ' ' . $dest_url, LOGGER_DEBUG); - Queue::insert([ - 'hash' => $hash, - 'account_id' => $sender['channel_account_id'], - 'channel_id' => $sender['channel_id'], - 'driver' => 'activitypub', - 'posturl' => $dest_url, - 'notify' => '', - 'msg' => $msg - ]); - - if ($message_id && (! get_config('system','disable_dreport'))) { - q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue, dreport_log ) values ( '%s','%s','%s','%s','%s','%s','%s','%s' ) ", - dbesc($message_id), - dbesc($dest_url), - dbesc($dest_url), - dbesc('queued'), - dbesc(datetime_convert()), - dbesc($sender['channel_hash']), - dbesc($hash), - dbesc(EMPTY_STR) - ); - } - - return $hash; - } - - - static function permissions_update(&$x) { - - if ($x['recipient']['xchan_network'] !== 'activitypub') { - return; - } - self::discover($x['recipient']['xchan_hash'],true); - $x['success'] = true; - } - - - static function permissions_create(&$x) { - - // send a follow activity to the followee's inbox - - if ($x['recipient']['xchan_network'] !== 'activitypub') { - return; - } - - $p = Activity::encode_person($x['sender'],false); - if (! $p) { - return; - } - - $orig_follow = get_abconfig($x['sender']['channel_id'],$x['recipient']['xchan_hash'],'activitypub','their_follow_id'); - $orig_follow_type = get_abconfig($x['sender']['channel_id'],$x['recipient']['xchan_hash'],'activitypub','their_follow_type'); - - $msg = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], - [ - 'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . (($orig_follow) ? '/' . md5($orig_follow) : EMPTY_STR), - 'type' => (($orig_follow_type) ? $orig_follow_type : 'Follow'), - 'actor' => $p, - 'object' => $x['recipient']['xchan_hash'], - 'to' => [ $x['recipient']['xchan_hash'] ] - ]); - - // for Group actors, send both a Follow and a Join because some platforms only support one and there's - // no way of discovering/knowing in advance which type they support - - $join_msg = null; - - if (intval($x['recipient']['xchan_type']) === XCHAN_TYPE_GROUP) { - $join_msg = $msg; - $join_msg['type'] = 'Join'; - $join_msg['signature'] = LDSignatures::sign($join_msg,$x['sender']); - $jmsg2 = json_encode($join_msg, JSON_UNESCAPED_SLASHES); - } - - $msg['signature'] = LDSignatures::sign($msg,$x['sender']); - $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); - - $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($x['recipient']['xchan_hash']) - ); - - if ($h) { - $qi = self::queue_message($jmsg,$x['sender'],$h[0]); - if ($qi) { - $x['deliveries'] = $qi; - } - if ($join_msg) { - $qi = self::queue_message($jmsg2,$x['sender'],$h[0]); - if ($qi) { - $x['deliveries'] = $qi; - } - } - } - - $x['success'] = true; - } - - - static function permissions_accept(&$x) { - - // send an accept activity to the followee's inbox - - if ($x['recipient']['xchan_network'] !== 'activitypub') { - return; - } - - // we currently are not handling send of reject follow activities; this is permitted by protocol - - $accept = get_abconfig($x['recipient']['abook_channel'],$x['recipient']['xchan_hash'],'activitypub','their_follow_id'); - $follow_type = get_abconfig($x['recipient']['abook_channel'],$x['recipient']['xchan_hash'],'activitypub','their_follow_type'); - if (! $accept) { - return; - } - - $p = Activity::encode_person($x['sender'],false); - if (! $p) { - return; - } - - $msg = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], - [ - 'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . '/' . md5($accept), - 'type' => 'Accept', - 'actor' => $p, - 'object' => [ - 'type' => (($follow_type) ? $follow_type : 'Follow'), - 'id' => $accept, - 'actor' => $x['recipient']['xchan_hash'], - 'object' => z_root() . '/channel/' . $x['sender']['channel_address'] - ], - 'to' => [ $x['recipient']['xchan_hash'] ] - ]); - - $msg['signature'] = LDSignatures::sign($msg,$x['sender']); - - $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); - - $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($x['recipient']['xchan_hash']) - ); - - if ($h) { - $qi = self::queue_message($jmsg,$x['sender'],$h[0]); - if ($qi) { - $x['deliveries'] = $qi; - } - } - - $x['success'] = true; - - } - - static function contact_remove($channel_id,$abook) { - - $recip = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d", - intval($abook['abook_id']) - ); - - if ((! $recip) || $recip[0]['xchan_network'] !== 'activitypub') - return; - - $channel = channelx_by_n($recip[0]['abook_channel']); - if (! $channel) { - return; - } - - $p = Activity::encode_person($channel,true,true); - if (! $p) { - return; - } - - // send an unfollow activity to the followee's inbox - - $orig_activity = get_abconfig($recip[0]['abook_channel'],$recip[0]['xchan_hash'],'activitypub','follow_id'); - - if ($orig_activity && $recip[0]['abook_pending']) { - - // was never approved - - $msg = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], - [ - 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . '/' . md5($orig_activity) . '?operation=reject', - 'type' => 'Reject', - 'actor' => $p, - 'object' => [ - 'type' => 'Follow', - 'id' => $orig_activity, - 'actor' => $recip[0]['xchan_hash'], - 'object' => $p - ], - 'to' => [ $recip[0]['xchan_hash'] ] - ]); - del_abconfig($recip[0]['abook_channel'],$recip[0]['xchan_hash'],'activitypub','follow_id'); - - } - else { - - // send an unfollow - - $msg = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], - [ - 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . (($orig_activity) ? '/' . md5($orig_activity) : EMPTY_STR) . '?operation=unfollow', - 'type' => 'Undo', - 'actor' => $p, - 'object' => [ - 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . (($orig_activity) ? '/' . md5($orig_activity) : EMPTY_STR), - 'type' => 'Follow', - 'actor' => $p, - 'object' => $recip[0]['xchan_hash'] - ], - 'to' => [ $recip[0]['xchan_hash'] ] - ]); - } - - $msg['signature'] = LDSignatures::sign($msg,$channel); - - $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); - - $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", - dbesc($recip[0]['xchan_hash']) - ); - - if ($h) { - $qi = self::queue_message($jmsg,$channel,$h[0]); - if ($qi) { - Run::Summon([ 'Deliver' , $qi ]); - } - } - } - - static function discover($apurl, $force = false) { - - $person_obj = null; - $ap = Activity::fetch($apurl); - if ($ap) { - $AS = new ActivityStreams($ap); - if ($AS->is_valid()) { - if (ActivityStreams::is_an_actor($AS->type)) { - $person_obj = $AS->data; - } - elseif ($AS->obj && ActivityStreams::is_an_actor($AS->obj['type'])) { - $person_obj = $AS->obj; - } - } - } - - if (isset($person_obj)) { - - Activity::actor_store($person_obj['id'],$person_obj, $force); - return $person_obj['id']; - } - return false; - } - - static public function move($src,$dst) { - - if (! ($src && $dst)) { - return; - } - - if ($src && ! is_array($src)) { - $src = Activity::fetch($src); - if (is_array($src)) { - $src_xchan = $src['id']; - } - } - - $approvals = null; - - if ($dst && ! is_array($dst)) { - $dst = Activity::fetch($dst); - if (is_array($dst)) { - $dst_xchan = $dst['id']; - if (array_key_exists('alsoKnownAs',$dst)) { - if(! is_array($dst['alsoKnownAs'])) { - $dst['alsoKnownAs'] = [ $dst['alsoKnownAs'] ]; - } - $approvals = $dst['alsoKnownAs']; - } - } - } - - if(! ($src_xchan && $dst_xchan)) { - return; - } - - if ($approvals) { - foreach($approvals as $approval) { - if($approval === $src_xchan) { - $abooks = q("select abook_channel from abook where abook_xchan = '%s'", - dbesc($src_xchan) - ); - if ($abooks) { - foreach ($abooks as $abook) { - // check to see if we already performed this action - $x = q("select * from abook where abook_xchan = '%s' and abook_channel = %d", - dbesc($dst_xchan), - intval($abook['abook_channel']) - ); - if ($x) { - continue; - } - // update the local abook - q("update abconfig set xchan = '%s' where chan = %d and xchan = '%s'", - dbesc($dst_xchan), - intval($abook['abook_channel']), - dbesc($src_xchan) - ); - q("update pgrp_member set xchan = '%s' where uid = %d and xchan = '%s'", - dbesc($dst_xchan), - intval($abook['abook_channel']), - dbesc($src_xchan) - ); - $r = q("update abook set abook_xchan = '%s' where abook_xchan = '%s' and abook_channel = %d ", - dbesc($dst_xchan), - dbesc($src_xchan), - intval($abook['abook_channel']) - ); - - $r = q("SELECT abook.*, xchan.* + dbesc($arr['hub']['hubloc_url']) + ); + + if (!$r) { + logger('activitypub_process_outbound: no recipients'); + return; + } + + foreach ($r as $contact) { + + // is $contact connected with this channel - and if the channel is cloned, also on this hub? + // 2018-10-19 this probably doesn't apply to activitypub anymore, just send the thing. + // They'll reject it if they don't like it. + // $single = deliverable_singleton($arr['channel']['channel_id'],$contact); + + if (!$arr['normal_mode']) { + continue; + } + + $qi = self::queue_message($jmsg, $arr['channel'], $contact, $target_item['mid']); + if ($qi) { + $arr['queued'][] = $qi; + } + continue; + } + + } else { + + // public message + + // See if we can deliver all of them at once + + $x = get_xconfig($arr['hub']['hubloc_hash'], 'activitypub', 'collections'); + if ($x && $x['sharedInbox']) { + logger('using publicInbox delivery for ' . $arr['hub']['hubloc_url'], LOGGER_DEBUG); + $contact['hubloc_callback'] = $x['sharedInbox']; + $qi = self::queue_message($jmsg, $arr['channel'], $contact, $target_item['mid']); + if ($qi) { + $arr['queued'][] = $qi; + } + } else { + + $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url = '%s' and xchan_network = 'activitypub' ", + dbesc($arr['hub']['hubloc_url']) + ); + + if (!$r) { + logger('activitypub_process_outbound: no recipients'); + return; + } + + foreach ($r as $contact) { + + // $single = deliverable_singleton($arr['channel']['channel_id'],$contact); + + $qi = self::queue_message($jmsg, $arr['channel'], $contact, $target_item['mid']); + if ($qi) { + $arr['queued'][] = $qi; + } + } + } + } + + return; + + } + + + public static function queue_message($msg, $sender, $recip, $message_id = '') + { + + $dest_url = $recip['hubloc_callback']; + + logger('URL: ' . $dest_url, LOGGER_DEBUG); + logger('DATA: ' . jindent($msg), LOGGER_DATA); + + if (intval(get_config('system', 'activitypub_test')) || intval(get_pconfig($sender['channel_id'], 'system', 'activitypub_test'))) { + logger('test mode - delivery disabled'); + return false; + } + + $hash = random_string(); + + logger('queue: ' . $hash . ' ' . $dest_url, LOGGER_DEBUG); + Queue::insert([ + 'hash' => $hash, + 'account_id' => $sender['channel_account_id'], + 'channel_id' => $sender['channel_id'], + 'driver' => 'activitypub', + 'posturl' => $dest_url, + 'notify' => '', + 'msg' => $msg + ]); + + if ($message_id && (!get_config('system', 'disable_dreport'))) { + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_result, dreport_time, dreport_xchan, dreport_queue, dreport_log ) values ( '%s','%s','%s','%s','%s','%s','%s','%s' ) ", + dbesc($message_id), + dbesc($dest_url), + dbesc($dest_url), + dbesc('queued'), + dbesc(datetime_convert()), + dbesc($sender['channel_hash']), + dbesc($hash), + dbesc(EMPTY_STR) + ); + } + + return $hash; + } + + + public static function permissions_update(&$x) + { + + if ($x['recipient']['xchan_network'] !== 'activitypub') { + return; + } + self::discover($x['recipient']['xchan_hash'], true); + $x['success'] = true; + } + + + public static function permissions_create(&$x) + { + + // send a follow activity to the followee's inbox + + if ($x['recipient']['xchan_network'] !== 'activitypub') { + return; + } + + $p = Activity::encode_person($x['sender'], false); + if (!$p) { + return; + } + + $orig_follow = get_abconfig($x['sender']['channel_id'], $x['recipient']['xchan_hash'], 'activitypub', 'their_follow_id'); + $orig_follow_type = get_abconfig($x['sender']['channel_id'], $x['recipient']['xchan_hash'], 'activitypub', 'their_follow_type'); + + $msg = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], + [ + 'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . (($orig_follow) ? '/' . md5($orig_follow) : EMPTY_STR), + 'type' => (($orig_follow_type) ? $orig_follow_type : 'Follow'), + 'actor' => $p, + 'object' => $x['recipient']['xchan_hash'], + 'to' => [$x['recipient']['xchan_hash']] + ]); + + // for Group actors, send both a Follow and a Join because some platforms only support one and there's + // no way of discovering/knowing in advance which type they support + + $join_msg = null; + + if (intval($x['recipient']['xchan_type']) === XCHAN_TYPE_GROUP) { + $join_msg = $msg; + $join_msg['type'] = 'Join'; + $join_msg['signature'] = LDSignatures::sign($join_msg, $x['sender']); + $jmsg2 = json_encode($join_msg, JSON_UNESCAPED_SLASHES); + } + + $msg['signature'] = LDSignatures::sign($msg, $x['sender']); + $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); + + $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($x['recipient']['xchan_hash']) + ); + + if ($h) { + $qi = self::queue_message($jmsg, $x['sender'], $h[0]); + if ($qi) { + $x['deliveries'] = $qi; + } + if ($join_msg) { + $qi = self::queue_message($jmsg2, $x['sender'], $h[0]); + if ($qi) { + $x['deliveries'] = $qi; + } + } + } + + $x['success'] = true; + } + + + public static function permissions_accept(&$x) + { + + // send an accept activity to the followee's inbox + + if ($x['recipient']['xchan_network'] !== 'activitypub') { + return; + } + + // we currently are not handling send of reject follow activities; this is permitted by protocol + + $accept = get_abconfig($x['recipient']['abook_channel'], $x['recipient']['xchan_hash'], 'activitypub', 'their_follow_id'); + $follow_type = get_abconfig($x['recipient']['abook_channel'], $x['recipient']['xchan_hash'], 'activitypub', 'their_follow_type'); + if (!$accept) { + return; + } + + $p = Activity::encode_person($x['sender'], false); + if (!$p) { + return; + } + + $msg = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], + [ + 'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . '/' . md5($accept), + 'type' => 'Accept', + 'actor' => $p, + 'object' => [ + 'type' => (($follow_type) ? $follow_type : 'Follow'), + 'id' => $accept, + 'actor' => $x['recipient']['xchan_hash'], + 'object' => z_root() . '/channel/' . $x['sender']['channel_address'] + ], + 'to' => [$x['recipient']['xchan_hash']] + ]); + + $msg['signature'] = LDSignatures::sign($msg, $x['sender']); + + $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); + + $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($x['recipient']['xchan_hash']) + ); + + if ($h) { + $qi = self::queue_message($jmsg, $x['sender'], $h[0]); + if ($qi) { + $x['deliveries'] = $qi; + } + } + + $x['success'] = true; + + } + + public static function contact_remove($channel_id, $abook) + { + + $recip = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d", + intval($abook['abook_id']) + ); + + if ((!$recip) || $recip[0]['xchan_network'] !== 'activitypub') + return; + + $channel = channelx_by_n($recip[0]['abook_channel']); + if (!$channel) { + return; + } + + $p = Activity::encode_person($channel, true, true); + if (!$p) { + return; + } + + // send an unfollow activity to the followee's inbox + + $orig_activity = get_abconfig($recip[0]['abook_channel'], $recip[0]['xchan_hash'], 'activitypub', 'follow_id'); + + if ($orig_activity && $recip[0]['abook_pending']) { + + // was never approved + + $msg = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], + [ + 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . '/' . md5($orig_activity) . '?operation=reject', + 'type' => 'Reject', + 'actor' => $p, + 'object' => [ + 'type' => 'Follow', + 'id' => $orig_activity, + 'actor' => $recip[0]['xchan_hash'], + 'object' => $p + ], + 'to' => [$recip[0]['xchan_hash']] + ]); + del_abconfig($recip[0]['abook_channel'], $recip[0]['xchan_hash'], 'activitypub', 'follow_id'); + + } else { + + // send an unfollow + + $msg = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], + [ + 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . (($orig_activity) ? '/' . md5($orig_activity) : EMPTY_STR) . '?operation=unfollow', + 'type' => 'Undo', + 'actor' => $p, + 'object' => [ + 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . (($orig_activity) ? '/' . md5($orig_activity) : EMPTY_STR), + 'type' => 'Follow', + 'actor' => $p, + 'object' => $recip[0]['xchan_hash'] + ], + 'to' => [$recip[0]['xchan_hash']] + ]); + } + + $msg['signature'] = LDSignatures::sign($msg, $channel); + + $jmsg = json_encode($msg, JSON_UNESCAPED_SLASHES); + + $h = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($recip[0]['xchan_hash']) + ); + + if ($h) { + $qi = self::queue_message($jmsg, $channel, $h[0]); + if ($qi) { + Run::Summon(['Deliver', $qi]); + } + } + } + + public static function discover($apurl, $force = false) + { + + $person_obj = null; + $ap = Activity::fetch($apurl); + if ($ap) { + $AS = new ActivityStreams($ap); + if ($AS->is_valid()) { + if (ActivityStreams::is_an_actor($AS->type)) { + $person_obj = $AS->data; + } elseif ($AS->obj && ActivityStreams::is_an_actor($AS->obj['type'])) { + $person_obj = $AS->obj; + } + } + } + + if (isset($person_obj)) { + + Activity::actor_store($person_obj['id'], $person_obj, $force); + return $person_obj['id']; + } + return false; + } + + public static function move($src, $dst) + { + + if (!($src && $dst)) { + return; + } + + if ($src && !is_array($src)) { + $src = Activity::fetch($src); + if (is_array($src)) { + $src_xchan = $src['id']; + } + } + + $approvals = null; + + if ($dst && !is_array($dst)) { + $dst = Activity::fetch($dst); + if (is_array($dst)) { + $dst_xchan = $dst['id']; + if (array_key_exists('alsoKnownAs', $dst)) { + if (!is_array($dst['alsoKnownAs'])) { + $dst['alsoKnownAs'] = [$dst['alsoKnownAs']]; + } + $approvals = $dst['alsoKnownAs']; + } + } + } + + if (!($src_xchan && $dst_xchan)) { + return; + } + + if ($approvals) { + foreach ($approvals as $approval) { + if ($approval === $src_xchan) { + $abooks = q("select abook_channel from abook where abook_xchan = '%s'", + dbesc($src_xchan) + ); + if ($abooks) { + foreach ($abooks as $abook) { + // check to see if we already performed this action + $x = q("select * from abook where abook_xchan = '%s' and abook_channel = %d", + dbesc($dst_xchan), + intval($abook['abook_channel']) + ); + if ($x) { + continue; + } + // update the local abook + q("update abconfig set xchan = '%s' where chan = %d and xchan = '%s'", + dbesc($dst_xchan), + intval($abook['abook_channel']), + dbesc($src_xchan) + ); + q("update pgrp_member set xchan = '%s' where uid = %d and xchan = '%s'", + dbesc($dst_xchan), + intval($abook['abook_channel']), + dbesc($src_xchan) + ); + $r = q("update abook set abook_xchan = '%s' where abook_xchan = '%s' and abook_channel = %d ", + dbesc($dst_xchan), + dbesc($src_xchan), + intval($abook['abook_channel']) + ); + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(abook['abook_channel']), - intval($dst_xchan) - ); - if ($r) { - $clone = array_shift($r); - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); - $abconfig = load_abconfig($abook['abook_channel'],$clone['abook_xchan']); - if ($abconfig) { - $clone['abconfig'] = $abconfig; - } - Libsync::build_sync_packet($abook['abook_channel'], [ 'abook' => [ $clone ] ] ); - } - } - } - } - } - } - } + intval(abook['abook_channel']), + intval($dst_xchan) + ); + if ($r) { + $clone = array_shift($r); + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + $abconfig = load_abconfig($abook['abook_channel'], $clone['abook_xchan']); + if ($abconfig) { + $clone['abconfig'] = $abconfig; + } + Libsync::build_sync_packet($abook['abook_channel'], ['abook' => [$clone]]); + } + } + } + } + } + } + } } \ No newline at end of file diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php index 5eecd3938..c42cd8d6c 100644 --- a/Zotlabs/Lib/ActivityStreams.php +++ b/Zotlabs/Lib/ActivityStreams.php @@ -10,457 +10,466 @@ use Zotlabs\Web\HTTPSig; * * Parses an ActivityStream JSON string. */ +class ActivityStreams +{ -class ActivityStreams { + public $raw = null; + public $data = null; + public $hub = null; + public $valid = false; + public $deleted = false; + public $id = ''; + public $parent_id = ''; + public $type = ''; + public $actor = null; + public $obj = null; + public $tgt = null; + public $replyto = null; + public $origin = null; + public $owner = null; + public $signer = null; + public $ldsig = null; + public $sigok = false; + public $recips = null; + public $raw_recips = null; + public $implied_create = false; - public $raw = null; - public $data = null; - public $hub = null; - public $valid = false; - public $deleted = false; - public $id = ''; - public $parent_id = ''; - public $type = ''; - public $actor = null; - public $obj = null; - public $tgt = null; - public $replyto = null; - public $origin = null; - public $owner = null; - public $signer = null; - public $ldsig = null; - public $sigok = false; - public $recips = null; - public $raw_recips = null; - public $implied_create = false; - - /** - * @brief Constructor for ActivityStreams. - * - * Takes a JSON string or previously decode activity array as parameter, - * decodes it and sets up this object/activity, fetching any required attributes - * which were only referenced by @id/URI. - * - * @param string $string - */ - function __construct($string,$hub = null,$client = null) { + /** + * @brief Constructor for ActivityStreams. + * + * Takes a JSON string or previously decode activity array as parameter, + * decodes it and sets up this object/activity, fetching any required attributes + * which were only referenced by @id/URI. + * + * @param string $string + */ + public function __construct($string, $hub = null, $client = null) + { - $this->raw = $string; - $this->hub = $hub; - - if (is_array($string)) { - $this->data = $string; - $this->raw = json_encode($string,JSON_UNESCAPED_SLASHES); - } - else { - $this->data = json_decode($string, true); - } + $this->raw = $string; + $this->hub = $hub; - if ($this->data) { + if (is_array($string)) { + $this->data = $string; + $this->raw = json_encode($string, JSON_UNESCAPED_SLASHES); + } else { + $this->data = json_decode($string, true); + } - // verify and unpack JSalmon signature if present - // This will only be the case for Zot6 packets - - if (is_array($this->data) && array_key_exists('signed',$this->data)) { - $ret = JSalmon::verify($this->data); - $tmp = JSalmon::unpack($this->data['data']); - if ($ret && $ret['success']) { - if ($ret['signer']) { - logger('Unpacked: ' . json_encode($tmp,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT),LOGGER_DATA,LOG_DEBUG); - $saved = json_encode($this->data,JSON_UNESCAPED_SLASHES); - $this->data = $tmp; - $this->data['signer'] = $ret['signer']; - $this->data['signed_data'] = $saved; - if ($ret['hubloc']) { - $this->data['hubloc'] = $ret['hubloc']; - } - } - } - } + if ($this->data) { - // This indicates only that we have sucessfully decoded JSON. - $this->valid = true; + // verify and unpack JSalmon signature if present + // This will only be the case for Zot6 packets - // Special handling for Mastodon "delete actor" activities which will often fail to verify - // because the key cannot be fetched. We will catch this condition elsewhere. - - if (array_key_exists('type',$this->data) && array_key_exists('actor',$this->data) && array_key_exists('object',$this->data)) { - if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) { - $this->deleted = $this->data['actor']; - $this->valid = false; - } - } + if (is_array($this->data) && array_key_exists('signed', $this->data)) { + $ret = JSalmon::verify($this->data); + $tmp = JSalmon::unpack($this->data['data']); + if ($ret && $ret['success']) { + if ($ret['signer']) { + logger('Unpacked: ' . json_encode($tmp, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOGGER_DATA, LOG_DEBUG); + $saved = json_encode($this->data, JSON_UNESCAPED_SLASHES); + $this->data = $tmp; + $this->data['signer'] = $ret['signer']; + $this->data['signed_data'] = $saved; + if ($ret['hubloc']) { + $this->data['hubloc'] = $ret['hubloc']; + } + } + } + } - } + // This indicates only that we have sucessfully decoded JSON. + $this->valid = true; - // Attempt to assemble an Activity from what we were given. - - if ($this->is_valid()) { - $this->id = $this->get_property_obj('id'); - $this->type = $this->get_primary_type(); - $this->actor = $this->get_actor('actor','',''); - $this->obj = $this->get_compound_property('object'); - $this->tgt = $this->get_compound_property('target'); - $this->origin = $this->get_compound_property('origin'); - $this->recips = $this->collect_recips(); - $this->replyto = $this->get_property_obj('replyTo'); - - $this->ldsig = $this->get_compound_property('signature'); - if ($this->ldsig) { - $this->signer = $this->get_compound_property('creator',$this->ldsig); - if ($this->signer && is_array($this->signer) && array_key_exists('publicKey',$this->signer) - && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) { - $this->sigok = LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']); - } - } + // Special handling for Mastodon "delete actor" activities which will often fail to verify + // because the key cannot be fetched. We will catch this condition elsewhere. - // Implied create activity required by C2S specification if no object is present - - if (! $this->obj) { - if (! $client) { - $this->implied_create = true; - } - $this->obj = $this->data; - $this->type = 'Create'; - if (! $this->actor) { - $this->actor = $this->get_actor('attributedTo',$this->obj); - } - } + if (array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) { + if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) { + $this->deleted = $this->data['actor']; + $this->valid = false; + } + } - // fetch recursive or embedded activities - - if ($this->obj && is_array($this->obj) && array_key_exists('object',$this->obj)) { - $this->obj['object'] = $this->get_compound_property($this->obj['object']); - } - - // Enumerate and store actors in referenced objects - - if ($this->obj && is_array($this->obj) && $this->obj['actor']) { - $this->obj['actor'] = $this->get_actor('actor',$this->obj); - } - if ($this->tgt && is_array($this->tgt) && $this->tgt['actor']) { - $this->tgt['actor'] = $this->get_actor('actor',$this->tgt); - } + } - // Determine if this is a followup or response activity - - $this->parent_id = $this->get_property_obj('inReplyTo'); + // Attempt to assemble an Activity from what we were given. - if ((! $this->parent_id) && is_array($this->obj)) { - $this->parent_id = $this->obj['inReplyTo']; - } - if ((! $this->parent_id) && is_array($this->obj)) { - $this->parent_id = $this->obj['id']; - } - } - } + if ($this->is_valid()) { + $this->id = $this->get_property_obj('id'); + $this->type = $this->get_primary_type(); + $this->actor = $this->get_actor('actor', '', ''); + $this->obj = $this->get_compound_property('object'); + $this->tgt = $this->get_compound_property('target'); + $this->origin = $this->get_compound_property('origin'); + $this->recips = $this->collect_recips(); + $this->replyto = $this->get_property_obj('replyTo'); - /** - * @brief Return if instantiated ActivityStream is valid. - * - * @return boolean Return true if the JSON string could be decoded. - */ + $this->ldsig = $this->get_compound_property('signature'); + if ($this->ldsig) { + $this->signer = $this->get_compound_property('creator', $this->ldsig); + if ($this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer) + && is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']) { + $this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']); + } + } - function is_valid() { - return $this->valid; - } + // Implied create activity required by C2S specification if no object is present - function set_recips($arr) { - $this->saved_recips = $arr; - } + if (!$this->obj) { + if (!$client) { + $this->implied_create = true; + } + $this->obj = $this->data; + $this->type = 'Create'; + if (!$this->actor) { + $this->actor = $this->get_actor('attributedTo', $this->obj); + } + } - /** - * @brief Collects all recipients. - * - * @param string $base - * @param string $namespace (optional) default empty - * @return array - */ - function collect_recips($base = '', $namespace = '') { - $x = []; + // fetch recursive or embedded activities + + if ($this->obj && is_array($this->obj) && array_key_exists('object', $this->obj)) { + $this->obj['object'] = $this->get_compound_property($this->obj['object']); + } + + // Enumerate and store actors in referenced objects + + if ($this->obj && is_array($this->obj) && $this->obj['actor']) { + $this->obj['actor'] = $this->get_actor('actor', $this->obj); + } + if ($this->tgt && is_array($this->tgt) && $this->tgt['actor']) { + $this->tgt['actor'] = $this->get_actor('actor', $this->tgt); + } + + // Determine if this is a followup or response activity + + $this->parent_id = $this->get_property_obj('inReplyTo'); + + if ((!$this->parent_id) && is_array($this->obj)) { + $this->parent_id = $this->obj['inReplyTo']; + } + if ((!$this->parent_id) && is_array($this->obj)) { + $this->parent_id = $this->obj['id']; + } + } + } + + /** + * @brief Return if instantiated ActivityStream is valid. + * + * @return bool Return true if the JSON string could be decoded. + */ + + public function is_valid() + { + return $this->valid; + } + + public function set_recips($arr) + { + $this->saved_recips = $arr; + } + + /** + * @brief Collects all recipients. + * + * @param string $base + * @param string $namespace (optional) default empty + * @return array + */ + public function collect_recips($base = '', $namespace = '') + { + $x = []; + + $fields = ['to', 'cc', 'bto', 'bcc', 'audience']; + foreach ($fields as $f) { + // don't expand these yet + $y = $this->get_property_obj($f, $base, $namespace); + if ($y) { + if (!is_array($this->raw_recips)) { + $this->raw_recips = []; + } + if (!is_array($y)) { + $y = [$y]; + } + $this->raw_recips[$f] = $y; + $x = array_merge($x, $y); + } + } - $fields = [ 'to', 'cc', 'bto', 'bcc', 'audience']; - foreach ($fields as $f) { - // don't expand these yet - $y = $this->get_property_obj($f, $base, $namespace); - if ($y) { - if (! is_array($this->raw_recips)) { - $this->raw_recips = []; - } - if (! is_array($y)) { - $y = [ $y ]; - } - $this->raw_recips[$f] = $y; - $x = array_merge($x, $y); - } - } - // not yet ready for prime time // $x = $this->expand($x,$base,$namespace); - return $x; - } + return $x; + } - function expand($arr,$base = '',$namespace = '') { - $ret = []; + public function expand($arr, $base = '', $namespace = '') + { + $ret = []; - // right now use a hardwired recursion depth of 5 + // right now use a hardwired recursion depth of 5 - for ($z = 0; $z < 5; $z ++) { - if (is_array($arr) && $arr) { - foreach ($arr as $a) { - if (is_array($a)) { - $ret[] = $a; - } - else { - $x = $this->get_compound_property($a,$base,$namespace); - if ($x) { - $ret = array_merge($ret,$x); - } - } - } - } - } + for ($z = 0; $z < 5; $z++) { + if (is_array($arr) && $arr) { + foreach ($arr as $a) { + if (is_array($a)) { + $ret[] = $a; + } else { + $x = $this->get_compound_property($a, $base, $namespace); + if ($x) { + $ret = array_merge($ret, $x); + } + } + } + } + } - /// @fixme de-duplicate + /// @fixme de-duplicate - return $ret; - } + return $ret; + } - /** - * @brief - * - * @param array $base - * @param string $namespace if not set return empty string - * @return string|NULL - */ - - function get_namespace($base, $namespace) { + /** + * @brief + * + * @param array $base + * @param string $namespace if not set return empty string + * @return string|NULL + */ - if (! $namespace) { - return EMPTY_STR; - } - - $key = null; + public function get_namespace($base, $namespace) + { - foreach ( [ $this->data, $base ] as $b ) { - if (! $b) { - continue; - } + if (!$namespace) { + return EMPTY_STR; + } - if (array_key_exists('@context', $b)) { - if (is_array($b['@context'])) { - foreach ($b['@context'] as $ns) { - if (is_array($ns)) { - foreach ($ns as $k => $v) { - if ($namespace === $v) { - $key = $k; - } - } - } - else { - if ($namespace === $ns) { - $key = ''; - } - } - } - } - else { - if ($namespace === $b['@context']) { - $key = ''; - } - } - } - } + $key = null; - return $key; - } + foreach ([$this->data, $base] as $b) { + if (!$b) { + continue; + } - /** - * @brief - * - * @param string $property - * @param array $base (optional) - * @param string $namespace (optional) default empty - * @return NULL|mixed - */ - - function get_property_obj($property, $base = '', $namespace = '') { - $prefix = $this->get_namespace($base, $namespace); - if ($prefix === null) { - return null; - } + if (array_key_exists('@context', $b)) { + if (is_array($b['@context'])) { + foreach ($b['@context'] as $ns) { + if (is_array($ns)) { + foreach ($ns as $k => $v) { + if ($namespace === $v) { + $key = $k; + } + } + } else { + if ($namespace === $ns) { + $key = ''; + } + } + } + } else { + if ($namespace === $b['@context']) { + $key = ''; + } + } + } + } - $base = (($base) ? $base : $this->data); - $propname = (($prefix) ? $prefix . ':' : '') . $property; + return $key; + } - if (! is_array($base)) { - btlogger('not an array: ' . print_r($base,true)); - return null; - } + /** + * @brief + * + * @param string $property + * @param array $base (optional) + * @param string $namespace (optional) default empty + * @return NULL|mixed + */ - return ((array_key_exists($propname, $base)) ? $base[$propname] : null); - } + public function get_property_obj($property, $base = '', $namespace = '') + { + $prefix = $this->get_namespace($base, $namespace); + if ($prefix === null) { + return null; + } + + $base = (($base) ? $base : $this->data); + $propname = (($prefix) ? $prefix . ':' : '') . $property; + + if (!is_array($base)) { + btlogger('not an array: ' . print_r($base, true)); + return null; + } + + return ((array_key_exists($propname, $base)) ? $base[$propname] : null); + } - /** - * @brief Fetches a property from an URL. - * - * @param string $url - * @param array $channel (signing channel, default system channel) - * @return NULL|mixed - */ + /** + * @brief Fetches a property from an URL. + * + * @param string $url + * @param array $channel (signing channel, default system channel) + * @return NULL|mixed + */ - function fetch_property($url,$channel = null,$hub = null) { - return Activity::fetch($url,$channel,$hub); - } + public function fetch_property($url, $channel = null, $hub = null) + { + return Activity::fetch($url, $channel, $hub); + } - static function is_an_actor($s) { - if (! $s) { - return false; - } - return (in_array($s,[ 'Application','Group','Organization','Person','Service' ])); - } + public static function is_an_actor($s) + { + if (!$s) { + return false; + } + return (in_array($s, ['Application', 'Group', 'Organization', 'Person', 'Service'])); + } - static function is_response_activity($s) { - if (! $s) { - return false; - } - return (in_array($s, [ 'Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact' ])); - } + public static function is_response_activity($s) + { + if (!$s) { + return false; + } + return (in_array($s, ['Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact'])); + } + /** + * @brief + * + * @param string $property + * @param array $base + * @param string $namespace (optional) default empty + * @return NULL|mixed + */ + + public function get_actor($property, $base = '', $namespace = '') + { + $x = $this->get_property_obj($property, $base, $namespace); + if (self::is_url($x)) { + $y = Activity::get_cached_actor($x); + if ($y) { + return $y; + } + } + + $actor = $this->get_compound_property($property, $base, $namespace, true); + if (is_array($actor) && self::is_an_actor($actor['type'])) { + if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) { + $actor = $this->fetch_property($actor['id']); + } + return $actor; + } + return null; + } + /** + * @brief + * + * @param string $property + * @param array $base + * @param string $namespace (optional) default empty + * @param bool $first (optional) default false, if true and result is a sequential array return only the first element + * @return NULL|mixed + */ - /** - * @brief - * - * @param string $property - * @param array $base - * @param string $namespace (optional) default empty - * @return NULL|mixed - */ + public function get_compound_property($property, $base = '', $namespace = '', $first = false) + { + $x = $this->get_property_obj($property, $base, $namespace); + if (self::is_url($x)) { + $y = $this->fetch_property($x); + if (is_array($y)) { + $x = $y; + } + } - function get_actor($property,$base='',$namespace = '') { - $x = $this->get_property_obj($property, $base, $namespace); - if (self::is_url($x)) { - $y = Activity::get_cached_actor($x); - if ($y) { - return $y; - } - } - - $actor = $this->get_compound_property($property,$base,$namespace,true); - if (is_array($actor) && self::is_an_actor($actor['type'])) { - if (array_key_exists('id',$actor) && (! array_key_exists('inbox',$actor))) { - $actor = $this->fetch_property($actor['id']); - } - return $actor; - } - return null; - } + // verify and unpack JSalmon signature if present + // This may be present in Zot6 packets + + if (is_array($x) && array_key_exists('signed', $x)) { + $ret = JSalmon::verify($x); + $tmp = JSalmon::unpack($x['data']); + if ($ret && $ret['success']) { + if ($ret['signer']) { + logger('Unpacked: ' . json_encode($tmp, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOGGER_DATA, LOG_DEBUG); + $saved = json_encode($x, JSON_UNESCAPED_SLASHES); + $x = $tmp; + $x['signer'] = $ret['signer']; + $x['signed_data'] = $saved; + if ($ret['hubloc']) { + $x['hubloc'] = $ret['hubloc']; + } + } + } + } + if ($first && is_array($x) && array_key_exists(0, $x)) { + return $x[0]; + } + + return $x; + } + + /** + * @brief Check if string starts with http. + * + * @param string $url + * @return bool + */ + + public static function is_url($url) + { + if (($url) && (!is_array($url)) && ((strpos($url, 'http') === 0) || (strpos($url, 'x-zot') === 0) || (strpos($url, 'bear') === 0))) { + return true; + } + + return false; + } + + /** + * @brief Gets the type property. + * + * @param array $base + * @param string $namespace (optional) default empty + * @return NULL|mixed + */ + + public function get_primary_type($base = '', $namespace = '') + { + if (!$base) { + $base = $this->data; + } + $x = $this->get_property_obj('type', $base, $namespace); + if (is_array($x)) { + foreach ($x as $y) { + if (strpos($y, ':') === false) { + return $y; + } + } + } + + return $x; + } + + public function debug() + { + $x = var_export($this, true); + return $x; + } - /** - * @brief - * - * @param string $property - * @param array $base - * @param string $namespace (optional) default empty - * @param boolean $first (optional) default false, if true and result is a sequential array return only the first element - * @return NULL|mixed - */ - - function get_compound_property($property, $base = '', $namespace = '', $first = false) { - $x = $this->get_property_obj($property, $base, $namespace); - if (self::is_url($x)) { - $y = $this->fetch_property($x); - if (is_array($y)) { - $x = $y; - } - } + public static function is_as_request() + { - // verify and unpack JSalmon signature if present - // This may be present in Zot6 packets - - if (is_array($x) && array_key_exists('signed',$x)) { - $ret = JSalmon::verify($x); - $tmp = JSalmon::unpack($x['data']); - if ($ret && $ret['success']) { - if ($ret['signer']) { - logger('Unpacked: ' . json_encode($tmp,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT),LOGGER_DATA,LOG_DEBUG); - $saved = json_encode($x,JSON_UNESCAPED_SLASHES); - $x = $tmp; - $x['signer'] = $ret['signer']; - $x['signed_data'] = $saved; - if ($ret['hubloc']) { - $x['hubloc'] = $ret['hubloc']; - } - } - } - } - if ($first && is_array($x) && array_key_exists(0,$x)) { - return $x[0]; - } + $x = getBestSupportedMimeType([ + 'application/ld+json;profile="https://www.w3.org/ns/activitystreams"', + 'application/activity+json', + 'application/ld+json;profile="http://www.w3.org/ns/activitystreams"', + 'application/ld+json', // required for Friendica ~2021-09, can possibly be removed after next release of that project + 'application/x-zot-activity+json' + ]); - return $x; - } - - /** - * @brief Check if string starts with http. - * - * @param string $url - * @return boolean - */ - - static public function is_url($url) { - if (($url) && (! is_array($url)) && ((strpos($url, 'http') === 0) || (strpos($url,'x-zot') === 0) || (strpos($url,'bear') === 0))) { - return true; - } - - return false; - } - - /** - * @brief Gets the type property. - * - * @param array $base - * @param string $namespace (optional) default empty - * @return NULL|mixed - */ - - function get_primary_type($base = '', $namespace = '') { - if (! $base) { - $base = $this->data; - } - $x = $this->get_property_obj('type', $base, $namespace); - if (is_array($x)) { - foreach ($x as $y) { - if (strpos($y, ':') === false) { - return $y; - } - } - } - - return $x; - } - - function debug() { - $x = var_export($this, true); - return $x; - } - - - static function is_as_request() { - - $x = getBestSupportedMimeType([ - 'application/ld+json;profile="https://www.w3.org/ns/activitystreams"', - 'application/activity+json', - 'application/ld+json;profile="http://www.w3.org/ns/activitystreams"', - 'application/ld+json', // required for Friendica ~2021-09, can possibly be removed after next release of that project - 'application/x-zot-activity+json' - ]); - - return(($x) ? true : false); - } + return (($x) ? true : false); + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Api_router.php b/Zotlabs/Lib/Api_router.php index 147dc86de..5b75698b3 100644 --- a/Zotlabs/Lib/Api_router.php +++ b/Zotlabs/Lib/Api_router.php @@ -3,30 +3,34 @@ namespace Zotlabs\Lib; -class Api_router { +class Api_router +{ - static private $routes = []; + private static $routes = []; - static function register($path,$fn,$auth_required) { - self::$routes[$path] = [ 'func' => $fn, 'auth' => $auth_required ]; - } + public static function register($path, $fn, $auth_required) + { + self::$routes[$path] = ['func' => $fn, 'auth' => $auth_required]; + } - static function find($path) { - if (array_key_exists($path,self::$routes)) { - return self::$routes[$path]; - } + public static function find($path) + { + if (array_key_exists($path, self::$routes)) { + return self::$routes[$path]; + } - $with_params = dirname($path) . '/[id]'; + $with_params = dirname($path) . '/[id]'; - if (array_key_exists($with_params,self::$routes)) { - return self::$routes[$with_params]; - } + if (array_key_exists($with_params, self::$routes)) { + return self::$routes[$with_params]; + } - return null; - } + return null; + } - static function dbg() { - return self::$routes; - } + public static function dbg() + { + return self::$routes; + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php index db280d115..11158a208 100644 --- a/Zotlabs/Lib/Apps.php +++ b/Zotlabs/Lib/Apps.php @@ -9,1340 +9,1355 @@ use Zotlabs\Lib\Libsync; * Apps * */ +class Apps +{ + + public static $available_apps = null; + public static $installed_apps = null; + + public static $base_apps = null; + + + public static function get_system_apps($translate = true) + { + + $ret = []; + if (is_dir('apps')) { + $files = glob('apps/*.apd'); + } else { + $files = glob('app/*.apd'); + } + if ($files) { + foreach ($files as $f) { + $x = self::parse_app_description($f, $translate); + if ($x) { + $ret[] = $x; + } + } + } + $files = glob('addon/*/*.apd'); + if ($files) { + foreach ($files as $f) { + $path = explode('/', $f); + $plugin = trim($path[1]); + if (addon_is_installed($plugin)) { + $x = self::parse_app_description($f, $translate); + if ($x) { + $x['plugin'] = $plugin; + $ret[] = $x; + } + } + } + } + + call_hooks('get_system_apps', $ret); + + return $ret; + + } + + public static function get_base_apps() + { + + // to add additional default "base" apps to your site, put their English name, one per line, + // into 'cache/default_apps'. This will be merged with the default project base apps. + + if (file_exists('cache/default_apps')) { + $custom_apps = file('cache/default_apps', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + // do some cleanup in case the file was edited by hand and contains accidentally introduced whitespace + if (is_array($custom_apps) && $custom_apps) { + $custom_apps = array_map('trim', $custom_apps); + } + } + + $default_apps = [ + 'Channel Home', + 'Connections', + 'Directory', + 'Events', + 'Files', + 'Help', + 'Lists', + 'Photos', + 'Profile Photo', + 'Search', + 'Settings', + 'Stream', + 'Suggest Channels', + 'View Profile' + ]; + if (is_array($custom_apps)) { + $default_apps = array_values(array_unique(array_merge($default_apps, $custom_apps))); + } + + $x = get_config('system', 'base_apps', $default_apps); + call_hooks('get_base_apps', $x); + return $x; + } + + public static function import_system_apps() + { + if (!local_channel()) { + return; + } + + self::$base_apps = self::get_base_apps(); + + $apps = self::get_system_apps(false); + + self::$available_apps = q("select * from app where app_channel = 0"); + + self::$installed_apps = q("select * from app where app_channel = %d", + intval(local_channel()) + ); + + if ($apps) { + foreach ($apps as $app) { + $id = self::check_install_system_app($app); + + // $id will be boolean true or false to install an app, or an integer id to update an existing app + if ($id !== false) { + $app['uid'] = 0; + $app['guid'] = hash('whirlpool', $app['name']); + $app['system'] = 1; + self::app_install(0, $app); + } + + $id = self::check_install_personal_app($app); + // $id will be boolean true or false to install an app, or an integer id to update an existing app + if ($id === false) { + continue; + } + if ($id !== true) { + // if we already installed this app, but it changed, preserve any categories we created + $r = q("select term from term where otype = %d and oid = %d", + intval(TERM_OBJ_APP), + intval($id) + ); + if ($r) { + $app['categories'] = array_elm_to_str($r, 'term'); + } + } + $app['uid'] = local_channel(); + $app['guid'] = hash('whirlpool', $app['name']); + $app['system'] = 1; + self::app_install(local_channel(), $app); + + } + } + } + + /** + * Install the system app if no system apps have been installed, or if a new system app + * is discovered, or if the version of a system app changes. + */ + + public static function check_install_system_app($app) + { + if ((!is_array(self::$available_apps)) || (!count(self::$available_apps))) { + return true; + } + $notfound = true; + foreach (self::$available_apps as $iapp) { + if ($iapp['app_id'] == hash('whirlpool', $app['name'])) { + $notfound = false; + if ((isset($app['version']) && $iapp['app_version'] !== $app['version']) + || ((isset($app['plugin']) && $app['plugin']) && (!(isset($iapp['app_plugin']) && $iapp['app_plugin'])))) { + return intval($iapp['app_id']); + } + + if (($iapp['app_url'] !== $app['url']) + || ($iapp['app_photo'] !== $app['photo'])) { + return intval($iapp['app_id']); + } + } + } + + return $notfound; + } + + + /** + * Install the system app if no system apps have been installed, or if a new system app + * is discovered, or if the version of a system app changes. + */ + + public static function check_install_personal_app($app) + { + $installed = false; + foreach (self::$installed_apps as $iapp) { + if ($iapp['app_id'] == hash('whirlpool', $app['name'])) { + $installed = true; + if (($iapp['app_version'] != $app['version']) + || (isset($app['plugin']) && $app['plugin'] && (!(isset($iapp['app_plugin']) && $iapp['app_plugin'])))) { + return intval($iapp['app_id']); + } + } + } + if (!$installed && in_array($app['name'], self::$base_apps)) { + return true; + } + return false; + } + + + public static function app_name_compare($a, $b) + { + return strcasecmp($a['name'], $b['name']); + } + + + public static function parse_app_description($f, $translate = true) + { + + $ret = []; + + $baseurl = z_root(); + $channel = App::get_channel(); + $address = (($channel) ? $channel['channel_address'] : ''); + + //future expansion + + $observer = App::get_observer(); + + + $lines = @file($f); + if ($lines) { + foreach ($lines as $x) { + if (preg_match('/^([a-zA-Z].*?):(.*?)$/ism', $x, $matches)) { + $ret[$matches[1]] = trim($matches[2]); + } + } + } + + if (!$ret['photo']) { + $ret['photo'] = $baseurl . '/' . get_default_profile_photo(80); + } + + $ret['type'] = 'system'; + + foreach ($ret as $k => $v) { + if (strpos($v, 'http') === 0) { + if (!(local_channel() && strpos($v, z_root()) === 0)) { + $ret[$k] = zid($v); + } + } + } + + if (array_key_exists('desc', $ret)) { + $ret['desc'] = str_replace(array('\'', '"'), array(''', '&dquot;'), $ret['desc']); + } + if (array_key_exists('target', $ret)) { + $ret['target'] = str_replace(array('\'', '"'), array(''', '&dquot;'), $ret['target']); + } + if (array_key_exists('version', $ret)) { + $ret['version'] = str_replace(array('\'', '"'), array(''', '&dquot;'), $ret['version']); + } + if (array_key_exists('categories', $ret)) { + $ret['categories'] = str_replace(array('\'', '"'), array(''', '&dquot;'), $ret['categories']); + } + if (array_key_exists('requires', $ret)) { + $requires = explode(',', $ret['requires']); + foreach ($requires as $require) { + $require = trim(strtolower($require)); + $config = false; + + if (substr($require, 0, 7) == 'config:') { + $config = true; + $require = ltrim($require, 'config:'); + $require = explode('=', $require); + } + + switch ($require) { + case 'nologin': + if (local_channel()) { + unset($ret); + } + break; + case 'admin': + if (!is_site_admin()) { + unset($ret); + } + break; + case 'local_channel': + if (!local_channel()) { + unset($ret); + } + break; + case 'public_profile': + if (!is_public_profile()) { + unset($ret); + } + break; + case 'public_stream': + if (!can_view_public_stream()) { + unset($ret); + } + break; + case 'custom_role': + if (get_pconfig(local_channel(), 'system', 'permissions_role') !== 'custom') { + unset($ret); + } + break; + case 'observer': + if (!$observer) { + unset($ret); + } + break; + default: + if ($config) { + $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true); + } else { + $unset = ((local_channel() && feature_enabled(local_channel(), $require)) ? false : true); + } + if ($unset) { + unset($ret); + } + break; + } + } + } + if (isset($ret)) { + if ($translate) { + self::translate_system_apps($ret); + } + return $ret; + } + return false; + } + + + public static function translate_system_apps(&$arr) + { + $apps = array( + 'Admin' => t('Site Admin'), + 'Apps' => t('Apps'), + 'Articles' => t('Articles'), + 'CalDAV' => t('CalDAV'), + 'CardDAV' => t('CardDAV'), + 'Cards' => t('Cards'), + 'Calendar' => t('Calendar'), + 'Categories' => t('Categories'), + 'Channel Home' => t('Channel Home'), + 'Channel Manager' => t('Channel Manager'), + 'Channel Sources' => t('Channel Sources'), + 'Chat' => t('Chat'), + 'Chatrooms' => t('Chatrooms'), + 'Clients' => t('Clients'), + 'Comment Control' => t('Comment Control'), + 'Connections' => t('Connections'), + 'Content Filter' => t('Content Filter'), + 'Content Import' => t('Content Import'), + 'Directory' => t('Directory'), + 'Drafts' => t('Drafts'), + 'Events' => t('Events'), + 'Expire Posts' => t('Expire Posts'), + 'Features' => t('Features'), + 'Files' => t('Files'), + 'Followlist' => t('Followlist'), + 'Friend Zoom' => t('Friend Zoom'), + 'Future Posting' => t('Future Posting'), + 'Gallery' => t('Gallery'), + 'Guest Pass' => t('Guest Pass'), + 'Help' => t('Help'), + 'Invite' => t('Invite'), + 'Language' => t('Language'), + 'Lists' => t('Lists'), + 'Login' => t('Login'), + 'Mail' => t('Mail'), + 'Markup' => t('Markup'), + 'Mood' => t('Mood'), + 'My Chatrooms' => t('My Chatrooms'), + 'No Comment' => t('No Comment'), + 'Notes' => t('Notes'), + 'Notifications' => t('Notifications'), + 'OAuth Apps Manager' => t('OAuth Apps Manager'), + 'OAuth2 Apps Manager' => t('OAuth2 Apps Manager'), + 'Order Apps' => t('Order Apps'), + 'PDL Editor' => t('PDL Editor'), + 'Permission Categories' => t('Permission Categories'), + 'Photos' => t('Photos'), + 'Photomap' => t('Photomap'), + 'Poke' => t('Poke'), + 'Post' => t('Post'), + 'Premium Channel' => t('Premium Channel'), + 'Probe' => t('Probe'), + 'Profile' => t('Profile'), + 'Profile Photo' => t('Profile Photo'), + 'Profiles' => t('Profiles'), + 'Public Stream' => t('Public Stream'), + 'Random Channel' => t('Random Channel'), + 'Remote Diagnostics' => t('Remote Diagnostics'), + 'Report Bug' => t('Report Bug'), + 'Search' => t('Search'), + 'Secrets' => t('Secrets'), + 'Settings' => t('Settings'), + 'Sites' => t('Sites'), + 'Stream' => t('Stream'), + 'Stream Order' => t('Stream Order'), + 'Suggest' => t('Suggest'), + 'Suggest Channels' => t('Suggest Channels'), + 'Tagadelic' => t('Tagadelic'), + 'Tasks' => t('Tasks'), + 'View Bookmarks' => t('View Bookmarks'), + 'View Profile' => t('View Profile'), + 'Virtual Lists' => t('Virtual Lists'), + 'Webpages' => t('Webpages'), + 'Wiki' => t('Wiki'), + 'ZotPost' => t('ZotPost'), + ); + + if (array_key_exists('name', $arr)) { + if (array_key_exists($arr['name'], $apps)) { + $arr['name'] = $apps[$arr['name']]; + } + } else { + for ($x = 0; $x < count($arr); $x++) { + if (array_key_exists($arr[$x]['name'], $apps)) { + $arr[$x]['name'] = $apps[$arr[$x]['name']]; + } else { + // Try to guess by app name if not in list + $arr[$x]['name'] = t(trim($arr[$x]['name'])); + } + } + } + } + + + // papp is a portable app + + public static function app_render($papp, $mode = 'view') + { + + /** + * modes: + * view: normal mode for viewing an app via bbcode from a conversation or page + * provides install/update button if you're logged in locally + * install: like view but does not display app-bin options if they are present + * list: normal mode for viewing an app on the app page + * no buttons are shown + * edit: viewing the app page in editing mode provides a delete button + * nav: render apps for app-bin + */ + + $installed = false; + + if (!$papp) { + return; + } + + if (!$papp['photo']) { + $papp['photo'] = 'icon:gear'; + } + + self::translate_system_apps($papp); + + if (isset($papp['plugin']) && trim($papp['plugin']) && (!addon_is_installed(trim($papp['plugin'])))) { + return ''; + } + + $papp['papp'] = self::papp_encode($papp); + + // This will catch somebody clicking on a system "available" app that hasn't had the path macros replaced + // and they are allowed to see the app + + + if (strpos($papp['url'], '$baseurl') !== false || strpos($papp['url'], '$nick') !== false || strpos($papp['photo'], '$baseurl') !== false || strpos($papp['photo'], '$nick') !== false) { + $view_channel = local_channel(); + if (!$view_channel) { + $sys = get_sys_channel(); + $view_channel = $sys['channel_id']; + } + self::app_macros($view_channel, $papp); + } + + if (strpos($papp['url'], ',')) { + $urls = explode(',', $papp['url']); + $papp['url'] = trim($urls[0]); + $papp['settings_url'] = trim($urls[1]); + } + + if (!strstr($papp['url'], '://')) { + $papp['url'] = z_root() . ((strpos($papp['url'], '/') === 0) ? '' : '/') . $papp['url']; + } + + + foreach ($papp as $k => $v) { + if (strpos($v, 'http') === 0 && $k != 'papp') { + if (!(local_channel() && strpos($v, z_root()) === 0)) { + $papp[$k] = zid($v); + } + } + if ($k === 'desc') { + $papp['desc'] = str_replace(array('\'', '"'), array(''', '&dquot;'), $papp['desc']); + } + + if ($k === 'requires') { + $requires = explode(',', $v); + + foreach ($requires as $require) { + $require = trim(strtolower($require)); + $config = false; + + if (substr($require, 0, 7) == 'config:') { + $config = true; + $require = ltrim($require, 'config:'); + $require = explode('=', $require); + } + + switch ($require) { + case 'nologin': + if (local_channel()) { + return ''; + } + break; + case 'admin': + if (!is_site_admin()) { + return ''; + } + break; + case 'local_channel': + if (!local_channel()) { + return ''; + } + break; + case 'public_profile': + if (!is_public_profile()) { + return ''; + } + break; + case 'public_stream': + if (!can_view_public_stream()) { + return ''; + } + break; + case 'custom_role': + if (get_pconfig(local_channel(), 'system', 'permissions_role') != 'custom') { + return ''; + } + break; + case 'observer': + $observer = App::get_observer(); + if (!$observer) { + return ''; + } + break; + default: + if ($config) { + $unset = ((get_config('system', $require[0]) === $require[1]) ? false : true); + } else { + $unset = ((local_channel() && feature_enabled(local_channel(), $require)) ? false : true); + } + if ($unset) { + return ''; + } + break; + } + } + } + } + + $hosturl = ''; + + if (local_channel()) { + if (self::app_installed(local_channel(), $papp) && (!(isset($papp['deleted']) && intval($papp['deleted'])))) { + $installed = true; + if ($mode === 'install') { + return ''; + } + } + + $hosturl = z_root() . '/'; + } elseif (remote_channel()) { + $observer = App::get_observer(); + if ($observer && $observer['xchan_network'] === 'zot6') { + // some folks might have xchan_url redirected offsite, use the connurl + $x = parse_url($observer['xchan_connurl']); + if ($x) { + $hosturl = $x['scheme'] . '://' . $x['host'] . '/'; + } + } + } + + $install_action = (($installed) ? t('Installed') : t('Install')); + $icon = ((strpos($papp['photo'], 'icon:') === 0) ? substr($papp['photo'], 5) : ''); + + if ($mode === 'navbar') { + return replace_macros(get_markup_template('app_nav.tpl'), [ + '$app' => $papp, + '$icon' => $icon, + ]); + } + + if ($mode === 'install') { + $papp['embed'] = true; + } + + $featured = $pinned = false; + if (isset($papp['categories'])) { + $featured = ((strpos($papp['categories'], 'nav_featured_app') !== false) ? true : false); + $pinned = ((strpos($papp['categories'], 'nav_pinned_app') !== false) ? true : false); + } + + return replace_macros(get_markup_template('app.tpl'), [ + '$app' => $papp, + '$icon' => $icon, + '$hosturl' => $hosturl, + '$purchase' => ((isset($papp['page']) && $papp['page'] && (!$installed)) ? t('Purchase') : ''), + '$installed' => $installed, + '$action_label' => (($hosturl && in_array($mode, ['view', 'install'])) ? $install_action : ''), + '$edit' => ((local_channel() && $installed && $mode === 'edit') ? t('Edit') : ''), + '$delete' => ((local_channel() && $installed && $mode === 'edit') ? t('Delete') : ''), + '$undelete' => ((local_channel() && $installed && $mode === 'edit') ? t('Undelete') : ''), + '$settings_url' => ((local_channel() && $installed && $mode === 'list' && isset($papp['settings_url'])) ? $papp['settings_url'] : ''), + '$deleted' => ((isset($papp['deleted'])) ? intval($papp['deleted']) : false), + '$feature' => (((isset($papp['embed']) && $papp['embed']) || $mode === 'edit') ? false : true), + '$pin' => (((isset($papp['embed']) && $papp['embed']) || $mode === 'edit') ? false : true), + '$featured' => $featured, + '$pinned' => $pinned, + '$navapps' => (($mode === 'nav') ? true : false), + '$order' => (($mode === 'nav-order' || $mode === 'nav-order-pinned') ? true : false), + '$mode' => $mode, + '$add' => t('Add to app-tray'), + '$remove' => t('Remove from app-tray'), + '$add_nav' => t('Pin to navbar'), + '$remove_nav' => t('Unpin from navbar') + ]); + } + + public static function app_install($uid, $app) + { + + if (!is_array($app)) { + $r = q("select * from app where app_name = '%s' and app_channel = 0", + dbesc($app) + ); + if (!$r) { + return false; + } + + $app = self::app_encode($r[0]); + } + + $app['uid'] = $uid; + + if (self::app_installed($uid, $app, true)) { + $x = self::app_update($app); + } else { + $x = self::app_store($app); + } + + if ($x['success']) { + $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($x['app_id']), + intval($uid) + ); + if ($r) { + if (($app['uid']) && (!$r[0]['app_system'])) { + if ($app['categories'] && (!$app['term'])) { + $r[0]['term'] = q("select * from term where otype = %d and oid = %d", + intval(TERM_OBJ_APP), + intval($r[0]['id']) + ); + if (intval($r[0]['app_system'])) { + Libsync::build_sync_packet($uid, array('sysapp' => $r[0])); + } else { + Libsync::build_sync_packet($uid, array('app' => $r[0])); + } + } + } + } + return $x['app_id']; + } + return false; + } + + + public static function can_delete($uid, $app) + { + if (!$uid) { + return false; + } + + $base_apps = self::get_base_apps(); + if ($base_apps) { + foreach ($base_apps as $b) { + if ($app['guid'] === hash('whirlpool', $b)) { + return false; + } + } + } + return true; + } + + + public static function app_destroy($uid, $app) + { + + if ($uid && $app['guid']) { + + $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($app['guid']), + intval($uid) + ); + if ($x) { + if (!intval($x[0]['app_deleted'])) { + $x[0]['app_deleted'] = 1; + if (self::can_delete($uid, $app)) { + $r = q("delete from app where app_id = '%s' and app_channel = %d", + dbesc($app['guid']), + intval($uid) + ); + q("delete from term where otype = %d and oid = %d", + intval(TERM_OBJ_APP), + intval($x[0]['id']) + ); + call_hooks('app_destroy', $x[0]); + } else { + $r = q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d", + dbesc($app['guid']), + intval($uid) + ); + } + if (intval($x[0]['app_system'])) { + Libsync::build_sync_packet($uid, array('sysapp' => $x)); + } else { + Libsync::build_sync_packet($uid, array('app' => $x)); + } + } else { + self::app_undestroy($uid, $app); + } + } + } + + } + + public static function app_undestroy($uid, $app) + { + + // undelete a system app + + if ($uid && $app['guid']) { + + $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($app['guid']), + intval($uid) + ); + if ($x) { + if ($x[0]['app_system']) { + $r = q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d", + dbesc($app['guid']), + intval($uid) + ); + } + } + } + } + + public static function app_feature($uid, $app, $term) + { + $r = q("select id from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($app['guid']), + intval($uid) + ); + + $x = q("select * from term where otype = %d and oid = %d and term = '%s' limit 1", + intval(TERM_OBJ_APP), + intval($r[0]['id']), + dbesc($term) + ); + + if ($x) { + q("delete from term where otype = %d and oid = %d and term = '%s'", + intval(TERM_OBJ_APP), + intval($x[0]['oid']), + dbesc($term) + ); + } else { + store_item_tag($uid, $r[0]['id'], TERM_OBJ_APP, TERM_CATEGORY, $term, escape_tags(z_root() . '/apps/?f=&cat=' . $term)); + } + } + + public static function app_installed($uid, $app, $bypass_filter = false) + { + + $r = q("select id from app where app_id = '%s' and app_channel = %d limit 1", + dbesc((array_key_exists('guid', $app)) ? $app['guid'] : ''), + intval($uid) + ); + if (!$bypass_filter) { + $filter_arr = [ + 'uid' => $uid, + 'app' => $app, + 'installed' => $r + ]; + call_hooks('app_installed_filter', $filter_arr); + $r = $filter_arr['installed']; + } + + return (($r) ? true : false); + + } + + public static function addon_app_installed($uid, $app, $bypass_filter = false) + { + + $r = q("select id from app where app_plugin = '%s' and app_channel = %d limit 1", + dbesc($app), + intval($uid) + ); + if (!$bypass_filter) { + $filter_arr = [ + 'uid' => $uid, + 'app' => $app, + 'installed' => $r + ]; + call_hooks('addon_app_installed_filter', $filter_arr); + $r = $filter_arr['installed']; + } + + return (($r) ? true : false); + + } + + public static function system_app_installed($uid, $app, $bypass_filter = false) + { + + $r = q("select id from app where app_id = '%s' and app_channel = %d and app_deleted = 0 limit 1", + dbesc(hash('whirlpool', $app)), + intval($uid) + ); + if (!$bypass_filter) { + $filter_arr = [ + 'uid' => $uid, + 'app' => $app, + 'installed' => $r + ]; + call_hooks('system_app_installed_filter', $filter_arr); + $r = $filter_arr['installed']; + } + + return (($r) ? true : false); + } + + public static function app_list($uid, $deleted = false, $cats = []) + { + if ($deleted) { + $sql_extra = ""; + } else { + $sql_extra = " and app_deleted = 0 "; + } + if ($cats) { + + $cat_sql_extra = " and ( "; + + foreach ($cats as $cat) { + if (strpos($cat_sql_extra, 'term')) + $cat_sql_extra .= "or "; + + $cat_sql_extra .= "term = '" . dbesc($cat) . "' "; + } + + $cat_sql_extra .= ") "; + + $r = q("select oid from term where otype = %d $cat_sql_extra", + intval(TERM_OBJ_APP) + ); + if (!$r) { + return $r; + } + $sql_extra .= " and app.id in ( " . array_elm_to_str($r, 'oid') . ') '; + } + + $r = q("select * from app where app_channel = %d $sql_extra order by app_name asc", + intval($uid) + ); + + if ($r) { + $hookinfo = ['uid' => $uid, 'deleted' => $deleted, 'cats' => $cats, 'apps' => $r]; + call_hooks('app_list', $hookinfo); + $r = $hookinfo['apps']; + for ($x = 0; $x < count($r); $x++) { + if (!$r[$x]['app_system']) { + $r[$x]['type'] = 'personal'; + } + $r[$x]['term'] = q("select * from term where otype = %d and oid = %d", + intval(TERM_OBJ_APP), + intval($r[$x]['id']) + ); + } + } + + return ($r); + } + + + public static function app_search_available($str) + { + + // not yet finished + // somehow need to account for translations + + $r = q("select * from app where app_channel = 0 $sql_extra order by app_name asc", + intval($uid) + ); + + return ($r); + } + + + public static function app_order($uid, $apps, $menu) + { + + if (!$apps) + return $apps; + + $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); + + $x = (($uid) ? get_pconfig($uid, 'system', $conf) : get_config('system', $conf)); + if (($x) && (!is_array($x))) { + $y = explode(',', $x); + $y = array_map('trim', $y); + $x = $y; + } + + if (!(is_array($x) && ($x))) { + return $apps; + } + + $ret = []; + foreach ($x as $xx) { + $y = self::find_app_in_array($xx, $apps); + if ($y) { + $ret[] = $y; + } + } + foreach ($apps as $ap) { + if (!self::find_app_in_array($ap['name'], $ret)) { + $ret[] = $ap; + } + } + return $ret; + + } + + public static function find_app_in_array($name, $arr) + { + if (!$arr) { + return false; + } + foreach ($arr as $x) { + if ($x['name'] === $name) { + return $x; + } + } + return false; + } + + public static function moveup($uid, $guid, $menu) + { + $syslist = []; + + $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); + + $list = self::app_list($uid, false, [$menu]); + if ($list) { + foreach ($list as $li) { + $papp = self::app_encode($li); + $syslist[] = $papp; + } + } + self::translate_system_apps($syslist); + + usort($syslist, 'self::app_name_compare'); + + $syslist = self::app_order($uid, $syslist, $menu); + + if (!$syslist) { + return; + } + + $newlist = []; + + foreach ($syslist as $k => $li) { + if ($li['guid'] === $guid) { + $position = $k; + break; + } + } + if (!$position) { + return; + } + $dest_position = $position - 1; + $saved = $syslist[$dest_position]; + $syslist[$dest_position] = $syslist[$position]; + $syslist[$position] = $saved; -class Apps { - - static public $available_apps = null; - static public $installed_apps = null; - - static public $base_apps = null; - - - static public function get_system_apps($translate = true) { - - $ret = []; - if (is_dir('apps')) { - $files = glob('apps/*.apd'); - } - else { - $files = glob('app/*.apd'); - } - if ($files) { - foreach ($files as $f) { - $x = self::parse_app_description($f,$translate); - if ($x) { - $ret[] = $x; - } - } - } - $files = glob('addon/*/*.apd'); - if ($files) { - foreach ($files as $f) { - $path = explode('/',$f); - $plugin = trim($path[1]); - if (addon_is_installed($plugin)) { - $x = self::parse_app_description($f,$translate); - if ($x) { - $x['plugin'] = $plugin; - $ret[] = $x; - } - } - } - } - - call_hooks('get_system_apps',$ret); - - return $ret; - - } - - static public function get_base_apps() { - - // to add additional default "base" apps to your site, put their English name, one per line, - // into 'cache/default_apps'. This will be merged with the default project base apps. - - if (file_exists('cache/default_apps')) { - $custom_apps = file('cache/default_apps', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); - // do some cleanup in case the file was edited by hand and contains accidentally introduced whitespace - if (is_array($custom_apps) && $custom_apps) { - $custom_apps = array_map('trim', $custom_apps); - } - } - - $default_apps = [ - 'Channel Home', - 'Connections', - 'Directory', - 'Events', - 'Files', - 'Help', - 'Lists', - 'Photos', - 'Profile Photo', - 'Search', - 'Settings', - 'Stream', - 'Suggest Channels', - 'View Profile' - ]; - if (is_array($custom_apps)) { - $default_apps = array_values(array_unique(array_merge($default_apps,$custom_apps))); - } - - $x = get_config('system','base_apps',$default_apps); - call_hooks('get_base_apps',$x); - return $x; - } - - static public function import_system_apps() { - if (! local_channel()) { - return; - } - - self::$base_apps = self::get_base_apps(); - - $apps = self::get_system_apps(false); - - self::$available_apps = q("select * from app where app_channel = 0"); - - self::$installed_apps = q("select * from app where app_channel = %d", - intval(local_channel()) - ); - - if ($apps) { - foreach ($apps as $app) { - $id = self::check_install_system_app($app); - - // $id will be boolean true or false to install an app, or an integer id to update an existing app - if ($id !== false) { - $app['uid'] = 0; - $app['guid'] = hash('whirlpool',$app['name']); - $app['system'] = 1; - self::app_install(0,$app); - } - - $id = self::check_install_personal_app($app); - // $id will be boolean true or false to install an app, or an integer id to update an existing app - if ($id === false) { - continue; - } - if ($id !== true) { - // if we already installed this app, but it changed, preserve any categories we created - $r = q("select term from term where otype = %d and oid = %d", - intval(TERM_OBJ_APP), - intval($id) - ); - if ($r) { - $app['categories'] = array_elm_to_str($r,'term'); - } - } - $app['uid'] = local_channel(); - $app['guid'] = hash('whirlpool',$app['name']); - $app['system'] = 1; - self::app_install(local_channel(),$app); - - } - } - } - - /** - * Install the system app if no system apps have been installed, or if a new system app - * is discovered, or if the version of a system app changes. - */ - - static public function check_install_system_app($app) { - if ((! is_array(self::$available_apps)) || (! count(self::$available_apps))) { - return true; - } - $notfound = true; - foreach (self::$available_apps as $iapp) { - if ($iapp['app_id'] == hash('whirlpool',$app['name'])) { - $notfound = false; - if ((isset($app['version']) && $iapp['app_version'] !== $app['version']) - || ((isset($app['plugin']) && $app['plugin']) && (! (isset($iapp['app_plugin']) && $iapp['app_plugin'])))) { - return intval($iapp['app_id']); - } - - if (($iapp['app_url'] !== $app['url']) - || ($iapp['app_photo'] !== $app['photo'])) { - return intval($iapp['app_id']); - } - } - } - - return $notfound; - } - - - /** - * Install the system app if no system apps have been installed, or if a new system app - * is discovered, or if the version of a system app changes. - */ - - static public function check_install_personal_app($app) { - $installed = false; - foreach (self::$installed_apps as $iapp) { - if ($iapp['app_id'] == hash('whirlpool',$app['name'])) { - $installed = true; - if (($iapp['app_version'] != $app['version']) - || (isset($app['plugin']) && $app['plugin'] && (! (isset($iapp['app_plugin']) && $iapp['app_plugin'])))) { - return intval($iapp['app_id']); - } - } - } - if (! $installed && in_array($app['name'],self::$base_apps)) { - return true; - } - return false; - } - - - static public function app_name_compare($a,$b) { - return strcasecmp($a['name'],$b['name']); - } - - - static public function parse_app_description($f,$translate = true) { - - $ret = []; - - $baseurl = z_root(); - $channel = App::get_channel(); - $address = (($channel) ? $channel['channel_address'] : ''); - - //future expansion - - $observer = App::get_observer(); - - - $lines = @file($f); - if ($lines) { - foreach ($lines as $x) { - if (preg_match('/^([a-zA-Z].*?):(.*?)$/ism',$x,$matches)) { - $ret[$matches[1]] = trim($matches[2]); - } - } - } - - if (! $ret['photo']) { - $ret['photo'] = $baseurl . '/' . get_default_profile_photo(80); - } - - $ret['type'] = 'system'; - - foreach ($ret as $k => $v) { - if (strpos($v,'http') === 0) { - if (! (local_channel() && strpos($v,z_root()) === 0)) { - $ret[$k] = zid($v); - } - } - } - - if (array_key_exists('desc',$ret)) { - $ret['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['desc']); - } - if (array_key_exists('target',$ret)) { - $ret['target'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['target']); - } - if (array_key_exists('version',$ret)) { - $ret['version'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['version']); - } - if (array_key_exists('categories',$ret)) { - $ret['categories'] = str_replace(array('\'','"'),array(''','&dquot;'),$ret['categories']); - } - if (array_key_exists('requires',$ret)) { - $requires = explode(',',$ret['requires']); - foreach ($requires as $require) { - $require = trim(strtolower($require)); - $config = false; - - if (substr($require, 0, 7) == 'config:') { - $config = true; - $require = ltrim($require, 'config:'); - $require = explode('=', $require); - } - - switch ($require) { - case 'nologin': - if (local_channel()) { - unset($ret); - } - break; - case 'admin': - if (! is_site_admin()) { - unset($ret); - } - break; - case 'local_channel': - if (! local_channel()) { - unset($ret); - } - break; - case 'public_profile': - if (! is_public_profile()) { - unset($ret); - } - break; - case 'public_stream': - if (! can_view_public_stream()) { - unset($ret); - } - break; - case 'custom_role': - if (get_pconfig(local_channel(),'system','permissions_role') !== 'custom') { - unset($ret); - } - break; - case 'observer': - if (! $observer) { - unset($ret); - } - break; - default: - if ($config) { - $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true); - } - else { - $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true); - } - if ($unset) { - unset($ret); - } - break; - } - } - } - if (isset($ret)) { - if ($translate) { - self::translate_system_apps($ret); - } - return $ret; - } - return false; - } - - - static public function translate_system_apps(&$arr) { - $apps = array( - 'Admin' => t('Site Admin'), - 'Apps' => t('Apps'), - 'Articles' => t('Articles'), - 'CalDAV' => t('CalDAV'), - 'CardDAV' => t('CardDAV'), - 'Cards' => t('Cards'), - 'Calendar' => t('Calendar'), - 'Categories' => t('Categories'), - 'Channel Home' => t('Channel Home'), - 'Channel Manager' => t('Channel Manager'), - 'Channel Sources' => t('Channel Sources'), - 'Chat' => t('Chat'), - 'Chatrooms' => t('Chatrooms'), - 'Clients' => t('Clients'), - 'Comment Control' => t('Comment Control'), - 'Connections' => t('Connections'), - 'Content Filter' => t('Content Filter'), - 'Content Import' => t('Content Import'), - 'Directory' => t('Directory'), - 'Drafts' => t('Drafts'), - 'Events' => t('Events'), - 'Expire Posts' => t('Expire Posts'), - 'Features' => t('Features'), - 'Files' => t('Files'), - 'Followlist' => t('Followlist'), - 'Friend Zoom' => t('Friend Zoom'), - 'Future Posting' => t('Future Posting'), - 'Gallery' => t('Gallery'), - 'Guest Pass' => t('Guest Pass'), - 'Help' => t('Help'), - 'Invite' => t('Invite'), - 'Language' => t('Language'), - 'Lists' => t('Lists'), - 'Login' => t('Login'), - 'Mail' => t('Mail'), - 'Markup' => t('Markup'), - 'Mood' => t('Mood'), - 'My Chatrooms' => t('My Chatrooms'), - 'No Comment' => t('No Comment'), - 'Notes' => t('Notes'), - 'Notifications' => t('Notifications'), - 'OAuth Apps Manager' => t('OAuth Apps Manager'), - 'OAuth2 Apps Manager' => t('OAuth2 Apps Manager'), - 'Order Apps' => t('Order Apps'), - 'PDL Editor' => t('PDL Editor'), - 'Permission Categories' => t('Permission Categories'), - 'Photos' => t('Photos'), - 'Photomap' => t('Photomap'), - 'Poke' => t('Poke'), - 'Post' => t('Post'), - 'Premium Channel' => t('Premium Channel'), - 'Probe' => t('Probe'), - 'Profile' => t('Profile'), - 'Profile Photo' => t('Profile Photo'), - 'Profiles' => t('Profiles'), - 'Public Stream' => t('Public Stream'), - 'Random Channel' => t('Random Channel'), - 'Remote Diagnostics' => t('Remote Diagnostics'), - 'Report Bug' => t('Report Bug'), - 'Search' => t('Search'), - 'Secrets' => t('Secrets'), - 'Settings' => t('Settings'), - 'Sites' => t('Sites'), - 'Stream' => t('Stream'), - 'Stream Order' => t('Stream Order'), - 'Suggest' => t('Suggest'), - 'Suggest Channels' => t('Suggest Channels'), - 'Tagadelic' => t('Tagadelic'), - 'Tasks' => t('Tasks'), - 'View Bookmarks' => t('View Bookmarks'), - 'View Profile' => t('View Profile'), - 'Virtual Lists' => t('Virtual Lists'), - 'Webpages' => t('Webpages'), - 'Wiki' => t('Wiki'), - 'ZotPost' => t('ZotPost'), - ); - - if (array_key_exists('name',$arr)) { - if (array_key_exists($arr['name'],$apps)) { - $arr['name'] = $apps[$arr['name']]; - } - } - else { - for ($x = 0; $x < count($arr); $x++) { - if (array_key_exists($arr[$x]['name'],$apps)) { - $arr[$x]['name'] = $apps[$arr[$x]['name']]; - } - else { - // Try to guess by app name if not in list - $arr[$x]['name'] = t(trim($arr[$x]['name'])); - } - } - } - } - - - // papp is a portable app - - static public function app_render($papp,$mode = 'view') { - - /** - * modes: - * view: normal mode for viewing an app via bbcode from a conversation or page - * provides install/update button if you're logged in locally - * install: like view but does not display app-bin options if they are present - * list: normal mode for viewing an app on the app page - * no buttons are shown - * edit: viewing the app page in editing mode provides a delete button - * nav: render apps for app-bin - */ - - $installed = false; - - if (! $papp) { - return; - } - - if (! $papp['photo']) { - $papp['photo'] = 'icon:gear'; - } - - self::translate_system_apps($papp); - - if (isset($papp['plugin']) && trim($papp['plugin']) && (! addon_is_installed(trim($papp['plugin'])))) { - return ''; - } - - $papp['papp'] = self::papp_encode($papp); - - // This will catch somebody clicking on a system "available" app that hasn't had the path macros replaced - // and they are allowed to see the app - - - if (strpos($papp['url'],'$baseurl') !== false || strpos($papp['url'],'$nick') !== false || strpos($papp['photo'],'$baseurl') !== false || strpos($papp['photo'],'$nick') !== false) { - $view_channel = local_channel(); - if (! $view_channel) { - $sys = get_sys_channel(); - $view_channel = $sys['channel_id']; - } - self::app_macros($view_channel,$papp); - } - - if (strpos($papp['url'], ',')) { - $urls = explode(',', $papp['url']); - $papp['url'] = trim($urls[0]); - $papp['settings_url'] = trim($urls[1]); - } - - if (! strstr($papp['url'],'://')) { - $papp['url'] = z_root() . ((strpos($papp['url'],'/') === 0) ? '' : '/') . $papp['url']; - } - - - foreach ($papp as $k => $v) { - if (strpos($v,'http') === 0 && $k != 'papp') { - if (! (local_channel() && strpos($v,z_root()) === 0)) { - $papp[$k] = zid($v); - } - } - if ($k === 'desc') { - $papp['desc'] = str_replace(array('\'','"'),array(''','&dquot;'),$papp['desc']); - } - - if ($k === 'requires') { - $requires = explode(',',$v); - - foreach ($requires as $require) { - $require = trim(strtolower($require)); - $config = false; - - if (substr($require, 0, 7) == 'config:') { - $config = true; - $require = ltrim($require, 'config:'); - $require = explode('=', $require); - } - - switch ($require) { - case 'nologin': - if (local_channel()) { - return ''; - } - break; - case 'admin': - if (! is_site_admin()) { - return ''; - } - break; - case 'local_channel': - if (! local_channel()) { - return ''; - } - break; - case 'public_profile': - if (! is_public_profile()) { - return ''; - } - break; - case 'public_stream': - if (! can_view_public_stream()) { - return ''; - } - break; - case 'custom_role': - if (get_pconfig(local_channel(),'system','permissions_role') != 'custom') { - return ''; - } - break; - case 'observer': - $observer = App::get_observer(); - if (! $observer) { - return ''; - } - break; - default: - if ($config) { - $unset = ((get_config('system', $require[0]) === $require[1]) ? false : true); - } - else { - $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true); - } - if ($unset) { - return ''; - } - break; - } - } - } - } - - $hosturl = ''; - - if (local_channel()) { - if (self::app_installed(local_channel(),$papp) && (! (isset($papp['deleted']) && intval($papp['deleted'])))) { - $installed = true; - if ($mode === 'install') { - return ''; - } - } - - $hosturl = z_root() . '/'; - } - elseif (remote_channel()) { - $observer = App::get_observer(); - if ($observer && $observer['xchan_network'] === 'zot6') { - // some folks might have xchan_url redirected offsite, use the connurl - $x = parse_url($observer['xchan_connurl']); - if ($x) { - $hosturl = $x['scheme'] . '://' . $x['host'] . '/'; - } - } - } - - $install_action = (($installed) ? t('Installed') : t('Install')); - $icon = ((strpos($papp['photo'],'icon:') === 0) ? substr($papp['photo'],5) : ''); - - if ($mode === 'navbar') { - return replace_macros(get_markup_template('app_nav.tpl'), [ - '$app' => $papp, - '$icon' => $icon, - ]); - } - - if ($mode === 'install') { - $papp['embed'] = true; - } - - $featured = $pinned = false; - if (isset($papp['categories'])) { - $featured = ((strpos($papp['categories'],'nav_featured_app') !== false) ? true : false); - $pinned = ((strpos($papp['categories'],'nav_pinned_app') !== false) ? true : false); - } - - return replace_macros(get_markup_template('app.tpl'), [ - '$app' => $papp, - '$icon' => $icon, - '$hosturl' => $hosturl, - '$purchase' => ((isset($papp['page']) && $papp['page'] && (! $installed)) ? t('Purchase') : ''), - '$installed' => $installed, - '$action_label' => (($hosturl && in_array($mode, ['view','install'])) ? $install_action : ''), - '$edit' => ((local_channel() && $installed && $mode === 'edit') ? t('Edit') : ''), - '$delete' => ((local_channel() && $installed && $mode === 'edit') ? t('Delete') : ''), - '$undelete' => ((local_channel() && $installed && $mode === 'edit') ? t('Undelete') : ''), - '$settings_url' => ((local_channel() && $installed && $mode === 'list' && isset($papp['settings_url'])) ? $papp['settings_url'] : ''), - '$deleted' => ((isset($papp['deleted'])) ? intval($papp['deleted']) : false), - '$feature' => (((isset($papp['embed']) && $papp['embed']) || $mode === 'edit') ? false : true), - '$pin' => (((isset($papp['embed']) && $papp['embed']) || $mode === 'edit') ? false : true), - '$featured' => $featured, - '$pinned' => $pinned, - '$navapps' => (($mode === 'nav') ? true : false), - '$order' => (($mode === 'nav-order' || $mode === 'nav-order-pinned') ? true : false), - '$mode' => $mode, - '$add' => t('Add to app-tray'), - '$remove' => t('Remove from app-tray'), - '$add_nav' => t('Pin to navbar'), - '$remove_nav' => t('Unpin from navbar') - ]); - } - - static public function app_install($uid,$app) { - - if (! is_array($app)) { - $r = q("select * from app where app_name = '%s' and app_channel = 0", - dbesc($app) - ); - if (! $r) { - return false; - } - - $app = self::app_encode($r[0]); - } - - $app['uid'] = $uid; - - if (self::app_installed($uid,$app,true)) { - $x = self::app_update($app); - } - else { - $x = self::app_store($app); - } - - if ($x['success']) { - $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1", - dbesc($x['app_id']), - intval($uid) - ); - if ($r) { - if (($app['uid']) && (! $r[0]['app_system'])) { - if ($app['categories'] && (! $app['term'])) { - $r[0]['term'] = q("select * from term where otype = %d and oid = %d", - intval(TERM_OBJ_APP), - intval($r[0]['id']) - ); - if (intval($r[0]['app_system'])) { - Libsync::build_sync_packet($uid,array('sysapp' => $r[0])); - } - else { - Libsync::build_sync_packet($uid,array('app' => $r[0])); - } - } - } - } - return $x['app_id']; - } - return false; - } - - - static public function can_delete($uid,$app) { - if (! $uid) { - return false; - } - - $base_apps = self::get_base_apps(); - if ($base_apps) { - foreach ($base_apps as $b) { - if ($app['guid'] === hash('whirlpool',$b)) { - return false; - } - } - } - return true; - } - - - static public function app_destroy($uid,$app) { - - if ($uid && $app['guid']) { - - $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", - dbesc($app['guid']), - intval($uid) - ); - if ($x) { - if (! intval($x[0]['app_deleted'])) { - $x[0]['app_deleted'] = 1; - if (self::can_delete($uid,$app)) { - $r = q("delete from app where app_id = '%s' and app_channel = %d", - dbesc($app['guid']), - intval($uid) - ); - q("delete from term where otype = %d and oid = %d", - intval(TERM_OBJ_APP), - intval($x[0]['id']) - ); - call_hooks('app_destroy',$x[0]); - } - else { - $r = q("update app set app_deleted = 1 where app_id = '%s' and app_channel = %d", - dbesc($app['guid']), - intval($uid) - ); - } - if (intval($x[0]['app_system'])) { - Libsync::build_sync_packet($uid,array('sysapp' => $x)); - } - else { - Libsync::build_sync_packet($uid,array('app' => $x)); - } - } - else { - self::app_undestroy($uid,$app); - } - } - } - - } - - static public function app_undestroy($uid,$app) { - - // undelete a system app - - if ($uid && $app['guid']) { - - $x = q("select * from app where app_id = '%s' and app_channel = %d limit 1", - dbesc($app['guid']), - intval($uid) - ); - if ($x) { - if ($x[0]['app_system']) { - $r = q("update app set app_deleted = 0 where app_id = '%s' and app_channel = %d", - dbesc($app['guid']), - intval($uid) - ); - } - } - } - } - - static public function app_feature($uid,$app,$term) { - $r = q("select id from app where app_id = '%s' and app_channel = %d limit 1", - dbesc($app['guid']), - intval($uid) - ); - - $x = q("select * from term where otype = %d and oid = %d and term = '%s' limit 1", - intval(TERM_OBJ_APP), - intval($r[0]['id']), - dbesc($term) - ); - - if ($x) { - q("delete from term where otype = %d and oid = %d and term = '%s'", - intval(TERM_OBJ_APP), - intval($x[0]['oid']), - dbesc($term) - ); - } - else { - store_item_tag($uid, $r[0]['id'], TERM_OBJ_APP, TERM_CATEGORY, $term, escape_tags(z_root() . '/apps/?f=&cat=' . $term)); - } - } - - static public function app_installed($uid,$app,$bypass_filter = false) { - - $r = q("select id from app where app_id = '%s' and app_channel = %d limit 1", - dbesc((array_key_exists('guid',$app)) ? $app['guid'] : ''), - intval($uid) - ); - if (! $bypass_filter) { - $filter_arr = [ - 'uid'=>$uid, - 'app'=>$app, - 'installed'=>$r - ]; - call_hooks('app_installed_filter',$filter_arr); - $r = $filter_arr['installed']; - } - - return (($r) ? true : false); - - } - - static public function addon_app_installed($uid,$app,$bypass_filter = false) { - - $r = q("select id from app where app_plugin = '%s' and app_channel = %d limit 1", - dbesc($app), - intval($uid) - ); - if (! $bypass_filter) { - $filter_arr = [ - 'uid'=>$uid, - 'app'=>$app, - 'installed'=>$r - ]; - call_hooks('addon_app_installed_filter',$filter_arr); - $r = $filter_arr['installed']; - } - - return (($r) ? true : false); - - } - - static public function system_app_installed($uid,$app,$bypass_filter = false) { - - $r = q("select id from app where app_id = '%s' and app_channel = %d and app_deleted = 0 limit 1", - dbesc(hash('whirlpool',$app)), - intval($uid) - ); - if (! $bypass_filter) { - $filter_arr = [ - 'uid'=>$uid, - 'app'=>$app, - 'installed'=>$r - ]; - call_hooks('system_app_installed_filter',$filter_arr); - $r = $filter_arr['installed']; - } - - return (($r) ? true : false); - } - - static public function app_list($uid, $deleted = false, $cats = []) { - if ($deleted) { - $sql_extra = ""; - } - else { - $sql_extra = " and app_deleted = 0 "; - } - if ($cats) { - - $cat_sql_extra = " and ( "; - - foreach ($cats as $cat) { - if (strpos($cat_sql_extra, 'term')) - $cat_sql_extra .= "or "; - - $cat_sql_extra .= "term = '" . dbesc($cat) . "' "; - } - - $cat_sql_extra .= ") "; - - $r = q("select oid from term where otype = %d $cat_sql_extra", - intval(TERM_OBJ_APP) - ); - if (! $r) { - return $r; - } - $sql_extra .= " and app.id in ( " . array_elm_to_str($r,'oid') . ') '; - } - - $r = q("select * from app where app_channel = %d $sql_extra order by app_name asc", - intval($uid) - ); - - if ($r) { - $hookinfo = [ 'uid' => $uid, 'deleted' => $deleted, 'cats' => $cats, 'apps' => $r ]; - call_hooks('app_list',$hookinfo); - $r = $hookinfo['apps']; - for ($x = 0; $x < count($r); $x ++) { - if (! $r[$x]['app_system']) { - $r[$x]['type'] = 'personal'; - } - $r[$x]['term'] = q("select * from term where otype = %d and oid = %d", - intval(TERM_OBJ_APP), - intval($r[$x]['id']) - ); - } - } - - return ($r); - } - - - static public function app_search_available($str) { - - // not yet finished - // somehow need to account for translations - - $r = q("select * from app where app_channel = 0 $sql_extra order by app_name asc", - intval($uid) - ); - - return ($r); - } - - - - static public function app_order($uid,$apps,$menu) { - - if (! $apps) - return $apps; - - $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); - - $x = (($uid) ? get_pconfig($uid,'system',$conf) : get_config('system',$conf)); - if (($x) && (! is_array($x))) { - $y = explode(',',$x); - $y = array_map('trim',$y); - $x = $y; - } - - if (! (is_array($x) && ($x))) { - return $apps; - } - - $ret = []; - foreach ($x as $xx) { - $y = self::find_app_in_array($xx,$apps); - if ($y) { - $ret[] = $y; - } - } - foreach ($apps as $ap) { - if (! self::find_app_in_array($ap['name'],$ret)) { - $ret[] = $ap; - } - } - return $ret; - - } - - static function find_app_in_array($name,$arr) { - if (! $arr) { - return false; - } - foreach ($arr as $x) { - if ($x['name'] === $name) { - return $x; - } - } - return false; - } - - static function moveup($uid,$guid,$menu) { - $syslist = []; - - $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); - - $list = self::app_list($uid, false, [ $menu ]); - if ($list) { - foreach ($list as $li) { - $papp = self::app_encode($li); - $syslist[] = $papp; - } - } - self::translate_system_apps($syslist); - - usort($syslist,'self::app_name_compare'); - - $syslist = self::app_order($uid,$syslist,$menu); - - if (! $syslist) { - return; - } - - $newlist = []; - - foreach ($syslist as $k => $li) { - if ($li['guid'] === $guid) { - $position = $k; - break; - } - } - if (! $position) { - return; - } - $dest_position = $position - 1; - $saved = $syslist[$dest_position]; - $syslist[$dest_position] = $syslist[$position]; - $syslist[$position] = $saved; + $narr = []; + foreach ($syslist as $x) { + $narr[] = $x['name']; + } - $narr = []; - foreach ($syslist as $x) { - $narr[] = $x['name']; - } + set_pconfig($uid, 'system', $conf, implode(',', $narr)); - set_pconfig($uid,'system',$conf,implode(',',$narr)); + } - } - - static function movedown($uid,$guid,$menu) { - $syslist = []; - - $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); - - $list = self::app_list($uid, false, [ $menu ]); - if ($list) { - foreach ($list as $li) { - $papp = self::app_encode($li); - $syslist[] = $papp; - } - } - self::translate_system_apps($syslist); - - usort($syslist,'self::app_name_compare'); - - $syslist = self::app_order($uid,$syslist,$menu); - - if (! $syslist) { - return; - } - - $newlist = []; - - foreach ($syslist as $k => $li) { - if ($li['guid'] === $guid) { - $position = $k; - break; - } - } - if ($position >= count($syslist) - 1) { - return; - } - $dest_position = $position + 1; - $saved = $syslist[$dest_position]; - $syslist[$dest_position] = $syslist[$position]; - $syslist[$position] = $saved; - - $narr = []; - foreach ($syslist as $x) { - $narr[] = $x['name']; - } - - set_pconfig($uid,'system',$conf,implode(',',$narr)); - - } - - static public function app_decode($s) { - $x = base64_decode(str_replace(array('
',"\r","\n",' '),array('','','',''),$s)); - return json_decode($x,true); - } - - - static public function app_macros($uid,&$arr) { - - if (! intval($uid)) { - return; - } - - $baseurl = z_root(); - $channel = channelx_by_n($uid); - $address = (($channel) ? $channel['channel_address'] : ''); - - // future expansion - - $observer = App::get_observer(); - - $arr['url'] = str_replace(array('$baseurl','$nick'),array($baseurl,$address),$arr['url']); - $arr['photo'] = str_replace(array('$baseurl','$nick'),array($baseurl,$address),$arr['photo']); - - } - - - static public function app_store($arr) { - - // logger('app_store: ' . print_r($arr,true)); - - $darray = []; - $ret = [ 'success' => false ]; - - $sys = get_sys_channel(); - - self::app_macros($arr['uid'],$arr); - - $darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : ''); - $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0); - - if (! $darray['app_url']) { - return $ret; - } - - if ((! $arr['uid']) && (! $arr['author'])) { - $arr['author'] = $sys['channel_hash']; - } - - if ($arr['photo'] && (strpos($arr['photo'],'icon:') === false) && (strpos($arr['photo'],z_root()) === false)) { - $x = import_remote_xchan_photo(str_replace('$baseurl',z_root(),$arr['photo']),get_observer_hash(),true); - if ((! $x) || ($x[4])) { - // $x[4] = true indicates storage failure of our cached/resized copy. If this failed, just keep the original url. - $arr['photo'] = $x[1]; - } - } - - - $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : random_string(). '.' . App::get_hostname()); - $darray['app_sig'] = ((x($arr,'sig')) ? $arr['sig'] : ''); - $darray['app_author'] = ((x($arr,'author')) ? $arr['author'] : get_observer_hash()); - $darray['app_name'] = ((x($arr,'name')) ? escape_tags($arr['name']) : t('Unknown')); - $darray['app_desc'] = ((x($arr,'desc')) ? escape_tags($arr['desc']) : ''); - $darray['app_photo'] = ((x($arr,'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80)); - $darray['app_version'] = ((x($arr,'version')) ? escape_tags($arr['version']) : ''); - $darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : ''); - $darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : ''); - $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : ''); - $darray['app_plugin'] = ((x($arr,'plugin')) ? escape_tags(trim($arr['plugin'])) : ''); - $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : ''); - $darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0); - $darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0); - $darray['app_options'] = ((x($arr,'options')) ? intval($arr['options']) : 0); - - $created = datetime_convert(); - - $r = q("insert into app ( app_id, app_sig, app_author, app_name, app_desc, app_url, app_photo, app_version, app_channel, app_addr, app_price, app_page, app_requires, app_created, app_edited, app_system, app_plugin, app_deleted, app_options ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', %d, %d )", - dbesc($darray['app_id']), - dbesc($darray['app_sig']), - dbesc($darray['app_author']), - dbesc($darray['app_name']), - dbesc($darray['app_desc']), - dbesc($darray['app_url']), - dbesc($darray['app_photo']), - dbesc($darray['app_version']), - intval($darray['app_channel']), - dbesc($darray['app_addr']), - dbesc($darray['app_price']), - dbesc($darray['app_page']), - dbesc($darray['app_requires']), - dbesc($created), - dbesc($created), - intval($darray['app_system']), - dbesc($darray['app_plugin']), - intval($darray['app_deleted']), - intval($darray['app_options']) - ); - - if ($r) { - $ret['success'] = true; - $ret['app_id'] = $darray['app_id']; - } - - if ($arr['categories']) { - $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1", - dbesc($darray['app_id']), - intval($darray['app_channel']) - ); - $y = explode(',',$arr['categories']); - if ($y) { - foreach ($y as $t) { - $t = trim($t); - if ($t) { - store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t))); - } - } - } - } - - return $ret; - } - - - static public function app_update($arr) { - - // logger('app_update: ' . print_r($arr,true)); - $darray = []; - $ret = [ 'success' => false ]; - - self::app_macros($arr['uid'],$arr); - - - $darray['app_url'] = ((x($arr,'url')) ? $arr['url'] : ''); - $darray['app_channel'] = ((x($arr,'uid')) ? $arr['uid'] : 0); - $darray['app_id'] = ((x($arr,'guid')) ? $arr['guid'] : 0); - - if ((! $darray['app_url']) || (! $darray['app_id'])) { - return $ret; - } - - if ($arr['photo'] && (strpos($arr['photo'],'icon:') === false) && (strpos($arr['photo'],z_root()) === false)) { - $x = import_remote_xchan_photo(str_replace('$baseurl',z_root(),$arr['photo']),get_observer_hash(),true); - if ((! $x) || ($x[4])) { - // $x[4] = true indicates storage failure of our cached/resized copy. If this failed, just keep the original url. - $arr['photo'] = $x[1]; - } - } - - $darray['app_sig'] = ((x($arr,'sig')) ? $arr['sig'] : ''); - $darray['app_author'] = ((x($arr,'author')) ? $arr['author'] : get_observer_hash()); - $darray['app_name'] = ((x($arr,'name')) ? escape_tags($arr['name']) : t('Unknown')); - $darray['app_desc'] = ((x($arr,'desc')) ? escape_tags($arr['desc']) : ''); - $darray['app_photo'] = ((x($arr,'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80)); - $darray['app_version'] = ((x($arr,'version')) ? escape_tags($arr['version']) : ''); - $darray['app_addr'] = ((x($arr,'addr')) ? escape_tags($arr['addr']) : ''); - $darray['app_price'] = ((x($arr,'price')) ? escape_tags($arr['price']) : ''); - $darray['app_page'] = ((x($arr,'page')) ? escape_tags($arr['page']) : ''); - $darray['app_plugin'] = ((x($arr,'plugin')) ? escape_tags(trim($arr['plugin'])) : ''); - $darray['app_requires'] = ((x($arr,'requires')) ? escape_tags($arr['requires']) : ''); - $darray['app_system'] = ((x($arr,'system')) ? intval($arr['system']) : 0); - $darray['app_deleted'] = ((x($arr,'deleted')) ? intval($arr['deleted']) : 0); - $darray['app_options'] = ((x($arr,'options')) ? intval($arr['options']) : 0); - - $edited = datetime_convert(); - - $r = q("update app set app_sig = '%s', app_author = '%s', app_name = '%s', app_desc = '%s', app_url = '%s', app_photo = '%s', app_version = '%s', app_addr = '%s', app_price = '%s', app_page = '%s', app_requires = '%s', app_edited = '%s', app_system = %d, app_plugin = '%s', app_deleted = %d, app_options = %d where app_id = '%s' and app_channel = %d", - dbesc($darray['app_sig']), - dbesc($darray['app_author']), - dbesc($darray['app_name']), - dbesc($darray['app_desc']), - dbesc($darray['app_url']), - dbesc($darray['app_photo']), - dbesc($darray['app_version']), - dbesc($darray['app_addr']), - dbesc($darray['app_price']), - dbesc($darray['app_page']), - dbesc($darray['app_requires']), - dbesc($edited), - intval($darray['app_system']), - dbesc($darray['app_plugin']), - intval($darray['app_deleted']), - intval($darray['app_options']), - dbesc($darray['app_id']), - intval($darray['app_channel']) - ); - if ($r) { - $ret['success'] = true; - $ret['app_id'] = $darray['app_id']; - } - - $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1", - dbesc($darray['app_id']), - intval($darray['app_channel']) - ); - - // if updating an embed app and we don't have a 0 channel_id don't mess with any existing categories - - if (array_key_exists('embed',$arr) && intval($arr['embed']) && (intval($darray['app_channel']))) - return $ret; - - if ($x) { - q("delete from term where otype = %d and oid = %d", - intval(TERM_OBJ_APP), - intval($x[0]['id']) - ); - if (isset($arr['categories']) && $arr['categories']) { - $y = explode(',',$arr['categories']); - if ($y) { - foreach ($y as $t) { - $t = trim($t); - if ($t) { - store_item_tag($darray['app_channel'],$x[0]['id'],TERM_OBJ_APP,TERM_CATEGORY,escape_tags($t),escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t))); - } - } - } - } - } - - return $ret; - - } - - - static public function app_encode($app,$embed = false) { - - $ret = []; - - $ret['type'] = 'personal'; - - if (isset($app['app_id']) && $app['app_id']) { - $ret['guid'] = $app['app_id']; - } - if (isset($app['app_sig']) && $app['app_sig']) { - $ret['sig'] = $app['app_sig']; - } - if (isset($app['app_author']) && $app['app_author']) { - $ret['author'] = $app['app_author']; - } - if (isset($app['app_name']) && $app['app_name']) { - $ret['name'] = $app['app_name']; - } - if (isset($app['app_desc']) && $app['app_desc']) { - $ret['desc'] = $app['app_desc']; - } - if (isset($app['app_url']) && $app['app_url']) { - $ret['url'] = $app['app_url']; - } - if (isset($app['app_photo']) && $app['app_photo']) { - $ret['photo'] = $app['app_photo']; - } - if (isset($app['app_icon']) && $app['app_icon']) { - $ret['icon'] = $app['app_icon']; - } - if (isset($app['app_version']) && $app['app_version']) { - $ret['version'] = $app['app_version']; - } - if (isset($app['app_addr']) && $app['app_addr']) { - $ret['addr'] = $app['app_addr']; - } - if (isset($app['app_price']) && $app['app_price']) { - $ret['price'] = $app['app_price']; - } - if (isset($app['app_page']) && $app['app_page']) { - $ret['page'] = $app['app_page']; - } - if (isset($app['app_requires']) && $app['app_requires']) { - $ret['requires'] = $app['app_requires']; - } - if (isset($app['app_system']) && $app['app_system']) { - $ret['system'] = $app['app_system']; - } - if (isset($app['app_options']) && $app['app_options']) { - $ret['options'] = $app['app_options']; - } - if (isset($app['app_plugin']) && $app['app_plugin']) { - $ret['plugin'] = trim($app['app_plugin']); - } - if (isset($app['app_deleted']) && $app['app_deleted']) { - $ret['deleted'] = $app['app_deleted']; - } - if (isset($app['term']) && $app['term']) { - $ret['categories'] = array_elm_to_str($app['term'],'term'); - } - - - if (! $embed) { - return $ret; - } - $ret['embed'] = true; - - if (array_key_exists('categories',$ret)) { - unset($ret['categories']); - } - - $j = json_encode($ret); - return '[app]' . chunk_split(base64_encode($j),72,"\n") . '[/app]'; - - } - - - static public function papp_encode($papp) { - return chunk_split(base64_encode(json_encode($papp)),72,"\n"); - } + public static function movedown($uid, $guid, $menu) + { + $syslist = []; + + $conf = (($menu === 'nav_featured_app') ? 'app_order' : 'app_pin_order'); + + $list = self::app_list($uid, false, [$menu]); + if ($list) { + foreach ($list as $li) { + $papp = self::app_encode($li); + $syslist[] = $papp; + } + } + self::translate_system_apps($syslist); + + usort($syslist, 'self::app_name_compare'); + + $syslist = self::app_order($uid, $syslist, $menu); + + if (!$syslist) { + return; + } + + $newlist = []; + + foreach ($syslist as $k => $li) { + if ($li['guid'] === $guid) { + $position = $k; + break; + } + } + if ($position >= count($syslist) - 1) { + return; + } + $dest_position = $position + 1; + $saved = $syslist[$dest_position]; + $syslist[$dest_position] = $syslist[$position]; + $syslist[$position] = $saved; + + $narr = []; + foreach ($syslist as $x) { + $narr[] = $x['name']; + } + + set_pconfig($uid, 'system', $conf, implode(',', $narr)); + + } + + public static function app_decode($s) + { + $x = base64_decode(str_replace(array('
', "\r", "\n", ' '), array('', '', '', ''), $s)); + return json_decode($x, true); + } + + + public static function app_macros($uid, &$arr) + { + + if (!intval($uid)) { + return; + } + + $baseurl = z_root(); + $channel = channelx_by_n($uid); + $address = (($channel) ? $channel['channel_address'] : ''); + + // future expansion + + $observer = App::get_observer(); + + $arr['url'] = str_replace(array('$baseurl', '$nick'), array($baseurl, $address), $arr['url']); + $arr['photo'] = str_replace(array('$baseurl', '$nick'), array($baseurl, $address), $arr['photo']); + + } + + + public static function app_store($arr) + { + + // logger('app_store: ' . print_r($arr,true)); + + $darray = []; + $ret = ['success' => false]; + + $sys = get_sys_channel(); + + self::app_macros($arr['uid'], $arr); + + $darray['app_url'] = ((x($arr, 'url')) ? $arr['url'] : ''); + $darray['app_channel'] = ((x($arr, 'uid')) ? $arr['uid'] : 0); + + if (!$darray['app_url']) { + return $ret; + } + + if ((!$arr['uid']) && (!$arr['author'])) { + $arr['author'] = $sys['channel_hash']; + } + + if ($arr['photo'] && (strpos($arr['photo'], 'icon:') === false) && (strpos($arr['photo'], z_root()) === false)) { + $x = import_remote_xchan_photo(str_replace('$baseurl', z_root(), $arr['photo']), get_observer_hash(), true); + if ((!$x) || ($x[4])) { + // $x[4] = true indicates storage failure of our cached/resized copy. If this failed, just keep the original url. + $arr['photo'] = $x[1]; + } + } + + + $darray['app_id'] = ((x($arr, 'guid')) ? $arr['guid'] : random_string() . '.' . App::get_hostname()); + $darray['app_sig'] = ((x($arr, 'sig')) ? $arr['sig'] : ''); + $darray['app_author'] = ((x($arr, 'author')) ? $arr['author'] : get_observer_hash()); + $darray['app_name'] = ((x($arr, 'name')) ? escape_tags($arr['name']) : t('Unknown')); + $darray['app_desc'] = ((x($arr, 'desc')) ? escape_tags($arr['desc']) : ''); + $darray['app_photo'] = ((x($arr, 'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80)); + $darray['app_version'] = ((x($arr, 'version')) ? escape_tags($arr['version']) : ''); + $darray['app_addr'] = ((x($arr, 'addr')) ? escape_tags($arr['addr']) : ''); + $darray['app_price'] = ((x($arr, 'price')) ? escape_tags($arr['price']) : ''); + $darray['app_page'] = ((x($arr, 'page')) ? escape_tags($arr['page']) : ''); + $darray['app_plugin'] = ((x($arr, 'plugin')) ? escape_tags(trim($arr['plugin'])) : ''); + $darray['app_requires'] = ((x($arr, 'requires')) ? escape_tags($arr['requires']) : ''); + $darray['app_system'] = ((x($arr, 'system')) ? intval($arr['system']) : 0); + $darray['app_deleted'] = ((x($arr, 'deleted')) ? intval($arr['deleted']) : 0); + $darray['app_options'] = ((x($arr, 'options')) ? intval($arr['options']) : 0); + + $created = datetime_convert(); + + $r = q("insert into app ( app_id, app_sig, app_author, app_name, app_desc, app_url, app_photo, app_version, app_channel, app_addr, app_price, app_page, app_requires, app_created, app_edited, app_system, app_plugin, app_deleted, app_options ) values ( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, '%s', %d, %d )", + dbesc($darray['app_id']), + dbesc($darray['app_sig']), + dbesc($darray['app_author']), + dbesc($darray['app_name']), + dbesc($darray['app_desc']), + dbesc($darray['app_url']), + dbesc($darray['app_photo']), + dbesc($darray['app_version']), + intval($darray['app_channel']), + dbesc($darray['app_addr']), + dbesc($darray['app_price']), + dbesc($darray['app_page']), + dbesc($darray['app_requires']), + dbesc($created), + dbesc($created), + intval($darray['app_system']), + dbesc($darray['app_plugin']), + intval($darray['app_deleted']), + intval($darray['app_options']) + ); + + if ($r) { + $ret['success'] = true; + $ret['app_id'] = $darray['app_id']; + } + + if ($arr['categories']) { + $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($darray['app_id']), + intval($darray['app_channel']) + ); + $y = explode(',', $arr['categories']); + if ($y) { + foreach ($y as $t) { + $t = trim($t); + if ($t) { + store_item_tag($darray['app_channel'], $x[0]['id'], TERM_OBJ_APP, TERM_CATEGORY, escape_tags($t), escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t))); + } + } + } + } + + return $ret; + } + + + public static function app_update($arr) + { + + // logger('app_update: ' . print_r($arr,true)); + $darray = []; + $ret = ['success' => false]; + + self::app_macros($arr['uid'], $arr); + + + $darray['app_url'] = ((x($arr, 'url')) ? $arr['url'] : ''); + $darray['app_channel'] = ((x($arr, 'uid')) ? $arr['uid'] : 0); + $darray['app_id'] = ((x($arr, 'guid')) ? $arr['guid'] : 0); + + if ((!$darray['app_url']) || (!$darray['app_id'])) { + return $ret; + } + + if ($arr['photo'] && (strpos($arr['photo'], 'icon:') === false) && (strpos($arr['photo'], z_root()) === false)) { + $x = import_remote_xchan_photo(str_replace('$baseurl', z_root(), $arr['photo']), get_observer_hash(), true); + if ((!$x) || ($x[4])) { + // $x[4] = true indicates storage failure of our cached/resized copy. If this failed, just keep the original url. + $arr['photo'] = $x[1]; + } + } + + $darray['app_sig'] = ((x($arr, 'sig')) ? $arr['sig'] : ''); + $darray['app_author'] = ((x($arr, 'author')) ? $arr['author'] : get_observer_hash()); + $darray['app_name'] = ((x($arr, 'name')) ? escape_tags($arr['name']) : t('Unknown')); + $darray['app_desc'] = ((x($arr, 'desc')) ? escape_tags($arr['desc']) : ''); + $darray['app_photo'] = ((x($arr, 'photo')) ? $arr['photo'] : z_root() . '/' . get_default_profile_photo(80)); + $darray['app_version'] = ((x($arr, 'version')) ? escape_tags($arr['version']) : ''); + $darray['app_addr'] = ((x($arr, 'addr')) ? escape_tags($arr['addr']) : ''); + $darray['app_price'] = ((x($arr, 'price')) ? escape_tags($arr['price']) : ''); + $darray['app_page'] = ((x($arr, 'page')) ? escape_tags($arr['page']) : ''); + $darray['app_plugin'] = ((x($arr, 'plugin')) ? escape_tags(trim($arr['plugin'])) : ''); + $darray['app_requires'] = ((x($arr, 'requires')) ? escape_tags($arr['requires']) : ''); + $darray['app_system'] = ((x($arr, 'system')) ? intval($arr['system']) : 0); + $darray['app_deleted'] = ((x($arr, 'deleted')) ? intval($arr['deleted']) : 0); + $darray['app_options'] = ((x($arr, 'options')) ? intval($arr['options']) : 0); + + $edited = datetime_convert(); + + $r = q("update app set app_sig = '%s', app_author = '%s', app_name = '%s', app_desc = '%s', app_url = '%s', app_photo = '%s', app_version = '%s', app_addr = '%s', app_price = '%s', app_page = '%s', app_requires = '%s', app_edited = '%s', app_system = %d, app_plugin = '%s', app_deleted = %d, app_options = %d where app_id = '%s' and app_channel = %d", + dbesc($darray['app_sig']), + dbesc($darray['app_author']), + dbesc($darray['app_name']), + dbesc($darray['app_desc']), + dbesc($darray['app_url']), + dbesc($darray['app_photo']), + dbesc($darray['app_version']), + dbesc($darray['app_addr']), + dbesc($darray['app_price']), + dbesc($darray['app_page']), + dbesc($darray['app_requires']), + dbesc($edited), + intval($darray['app_system']), + dbesc($darray['app_plugin']), + intval($darray['app_deleted']), + intval($darray['app_options']), + dbesc($darray['app_id']), + intval($darray['app_channel']) + ); + if ($r) { + $ret['success'] = true; + $ret['app_id'] = $darray['app_id']; + } + + $x = q("select id from app where app_id = '%s' and app_channel = %d limit 1", + dbesc($darray['app_id']), + intval($darray['app_channel']) + ); + + // if updating an embed app and we don't have a 0 channel_id don't mess with any existing categories + + if (array_key_exists('embed', $arr) && intval($arr['embed']) && (intval($darray['app_channel']))) + return $ret; + + if ($x) { + q("delete from term where otype = %d and oid = %d", + intval(TERM_OBJ_APP), + intval($x[0]['id']) + ); + if (isset($arr['categories']) && $arr['categories']) { + $y = explode(',', $arr['categories']); + if ($y) { + foreach ($y as $t) { + $t = trim($t); + if ($t) { + store_item_tag($darray['app_channel'], $x[0]['id'], TERM_OBJ_APP, TERM_CATEGORY, escape_tags($t), escape_tags(z_root() . '/apps/?f=&cat=' . escape_tags($t))); + } + } + } + } + } + + return $ret; + + } + + + public static function app_encode($app, $embed = false) + { + + $ret = []; + + $ret['type'] = 'personal'; + + if (isset($app['app_id']) && $app['app_id']) { + $ret['guid'] = $app['app_id']; + } + if (isset($app['app_sig']) && $app['app_sig']) { + $ret['sig'] = $app['app_sig']; + } + if (isset($app['app_author']) && $app['app_author']) { + $ret['author'] = $app['app_author']; + } + if (isset($app['app_name']) && $app['app_name']) { + $ret['name'] = $app['app_name']; + } + if (isset($app['app_desc']) && $app['app_desc']) { + $ret['desc'] = $app['app_desc']; + } + if (isset($app['app_url']) && $app['app_url']) { + $ret['url'] = $app['app_url']; + } + if (isset($app['app_photo']) && $app['app_photo']) { + $ret['photo'] = $app['app_photo']; + } + if (isset($app['app_icon']) && $app['app_icon']) { + $ret['icon'] = $app['app_icon']; + } + if (isset($app['app_version']) && $app['app_version']) { + $ret['version'] = $app['app_version']; + } + if (isset($app['app_addr']) && $app['app_addr']) { + $ret['addr'] = $app['app_addr']; + } + if (isset($app['app_price']) && $app['app_price']) { + $ret['price'] = $app['app_price']; + } + if (isset($app['app_page']) && $app['app_page']) { + $ret['page'] = $app['app_page']; + } + if (isset($app['app_requires']) && $app['app_requires']) { + $ret['requires'] = $app['app_requires']; + } + if (isset($app['app_system']) && $app['app_system']) { + $ret['system'] = $app['app_system']; + } + if (isset($app['app_options']) && $app['app_options']) { + $ret['options'] = $app['app_options']; + } + if (isset($app['app_plugin']) && $app['app_plugin']) { + $ret['plugin'] = trim($app['app_plugin']); + } + if (isset($app['app_deleted']) && $app['app_deleted']) { + $ret['deleted'] = $app['app_deleted']; + } + if (isset($app['term']) && $app['term']) { + $ret['categories'] = array_elm_to_str($app['term'], 'term'); + } + + + if (!$embed) { + return $ret; + } + $ret['embed'] = true; + + if (array_key_exists('categories', $ret)) { + unset($ret['categories']); + } + + $j = json_encode($ret); + return '[app]' . chunk_split(base64_encode($j), 72, "\n") . '[/app]'; + + } + + + public static function papp_encode($papp) + { + return chunk_split(base64_encode(json_encode($papp)), 72, "\n"); + } } diff --git a/Zotlabs/Lib/Chatroom.php b/Zotlabs/Lib/Chatroom.php index 34853b6ab..e20874093 100644 --- a/Zotlabs/Lib/Chatroom.php +++ b/Zotlabs/Lib/Chatroom.php @@ -6,272 +6,280 @@ use Zotlabs\Lib\Libsync; /** * @brief A class with chatroom related static methods. */ -class Chatroom { - /** - * @brief Creates a chatroom. - * - * @param array $channel - * @param array $arr - * @return array An associative array containing: - * * \e boolean \b success - A boolean success status - * * \e string \b message - (optional) A string - */ - static public function create($channel, $arr) { +class Chatroom +{ + /** + * @brief Creates a chatroom. + * + * @param array $channel + * @param array $arr + * @return array An associative array containing: + * * \e boolean \b success - A boolean success status + * * \e string \b message - (optional) A string + */ + public static function create($channel, $arr) + { - $ret = array('success' => false); + $ret = array('success' => false); - $name = trim($arr['name']); - if(! $name) { - $ret['message'] = t('Missing room name'); - return $ret; - } + $name = trim($arr['name']); + if (!$name) { + $ret['message'] = t('Missing room name'); + return $ret; + } - $r = q("select cr_id from chatroom where cr_uid = %d and cr_name = '%s' limit 1", - intval($channel['channel_id']), - dbesc($name) - ); - if($r) { - $ret['message'] = t('Duplicate room name'); - return $ret; - } + $r = q("select cr_id from chatroom where cr_uid = %d and cr_name = '%s' limit 1", + intval($channel['channel_id']), + dbesc($name) + ); + if ($r) { + $ret['message'] = t('Duplicate room name'); + return $ret; + } - $r = q("select count(cr_id) as total from chatroom where cr_aid = %d", - intval($channel['channel_account_id']) - ); - if($r) - $limit = service_class_fetch($channel['channel_id'], 'chatrooms'); + $r = q("select count(cr_id) as total from chatroom where cr_aid = %d", + intval($channel['channel_account_id']) + ); + if ($r) + $limit = service_class_fetch($channel['channel_id'], 'chatrooms'); - if(($r) && ($limit !== false) && ($r[0]['total'] >= $limit)) { - $ret['message'] = upgrade_message(); - return $ret; - } + if (($r) && ($limit !== false) && ($r[0]['total'] >= $limit)) { + $ret['message'] = upgrade_message(); + return $ret; + } - if(! array_key_exists('expire', $arr)) - $arr['expire'] = 120; // minutes, e.g. 2 hours + if (!array_key_exists('expire', $arr)) + $arr['expire'] = 120; // minutes, e.g. 2 hours - $created = datetime_convert(); + $created = datetime_convert(); - $x = q("insert into chatroom ( cr_aid, cr_uid, cr_name, cr_created, cr_edited, cr_expire, allow_cid, allow_gid, deny_cid, deny_gid ) + $x = q("insert into chatroom ( cr_aid, cr_uid, cr_name, cr_created, cr_edited, cr_expire, allow_cid, allow_gid, deny_cid, deny_gid ) values ( %d, %d , '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s' ) ", - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc($name), - dbesc($created), - dbesc($created), - intval($arr['expire']), - dbesc($arr['allow_cid']), - dbesc($arr['allow_gid']), - dbesc($arr['deny_cid']), - dbesc($arr['deny_gid']) - ); + intval($channel['channel_account_id']), + intval($channel['channel_id']), + dbesc($name), + dbesc($created), + dbesc($created), + intval($arr['expire']), + dbesc($arr['allow_cid']), + dbesc($arr['allow_gid']), + dbesc($arr['deny_cid']), + dbesc($arr['deny_gid']) + ); - if($x) - $ret['success'] = true; + if ($x) + $ret['success'] = true; - return $ret; - } + return $ret; + } - static public function destroy($channel,$arr) { + public static function destroy($channel, $arr) + { - $ret = array('success' => false); + $ret = array('success' => false); - if(intval($arr['cr_id'])) - $sql_extra = " and cr_id = " . intval($arr['cr_id']) . " "; - elseif(trim($arr['cr_name'])) - $sql_extra = " and cr_name = '" . protect_sprintf(dbesc(trim($arr['cr_name']))) . "' "; - else { - $ret['message'] = t('Invalid room specifier.'); - return $ret; - } + if (intval($arr['cr_id'])) + $sql_extra = " and cr_id = " . intval($arr['cr_id']) . " "; + elseif (trim($arr['cr_name'])) + $sql_extra = " and cr_name = '" . protect_sprintf(dbesc(trim($arr['cr_name']))) . "' "; + else { + $ret['message'] = t('Invalid room specifier.'); + return $ret; + } - $r = q("select * from chatroom where cr_uid = %d $sql_extra limit 1", - intval($channel['channel_id']) - ); - if(! $r) { - $ret['message'] = t('Invalid room specifier.'); - return $ret; - } + $r = q("select * from chatroom where cr_uid = %d $sql_extra limit 1", + intval($channel['channel_id']) + ); + if (!$r) { + $ret['message'] = t('Invalid room specifier.'); + return $ret; + } - Libsync::build_sync_packet($channel['channel_id'],array('chatroom' => $r)); + Libsync::build_sync_packet($channel['channel_id'], array('chatroom' => $r)); - q("delete from chatroom where cr_id = %d", - intval($r[0]['cr_id']) - ); - if($r[0]['cr_id']) { - q("delete from chatpresence where cp_room = %d", - intval($r[0]['cr_id']) - ); - q("delete from chat where chat_room = %d", - intval($r[0]['cr_id']) - ); - } + q("delete from chatroom where cr_id = %d", + intval($r[0]['cr_id']) + ); + if ($r[0]['cr_id']) { + q("delete from chatpresence where cp_room = %d", + intval($r[0]['cr_id']) + ); + q("delete from chat where chat_room = %d", + intval($r[0]['cr_id']) + ); + } - $ret['success'] = true; - return $ret; - } + $ret['success'] = true; + return $ret; + } - static public function enter($observer_xchan, $room_id, $status, $client) { + public static function enter($observer_xchan, $room_id, $status, $client) + { - if(! $room_id || ! $observer_xchan) - return; + if (!$room_id || !$observer_xchan) + return; - $r = q("select * from chatroom where cr_id = %d limit 1", - intval($room_id) - ); - if(! $r) { - notice( t('Room not found.') . EOL); - return false; - } - require_once('include/security.php'); - $sql_extra = permissions_sql($r[0]['cr_uid']); + $r = q("select * from chatroom where cr_id = %d limit 1", + intval($room_id) + ); + if (!$r) { + notice(t('Room not found.') . EOL); + return false; + } + require_once('include/security.php'); + $sql_extra = permissions_sql($r[0]['cr_uid']); - $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", - intval($room_id), - intval($r[0]['cr_uid']) - ); - if(! $x) { - notice( t('Permission denied.') . EOL); - return false; - } + $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", + intval($room_id), + intval($r[0]['cr_uid']) + ); + if (!$x) { + notice(t('Permission denied.') . EOL); + return false; + } - $limit = service_class_fetch($r[0]['cr_uid'], 'chatters_inroom'); - if($limit !== false) { - $y = q("select count(*) as total from chatpresence where cp_room = %d", - intval($room_id) - ); - if($y && $y[0]['total'] > $limit) { - notice( t('Room is full') . EOL); - return false; - } - } + $limit = service_class_fetch($r[0]['cr_uid'], 'chatters_inroom'); + if ($limit !== false) { + $y = q("select count(*) as total from chatpresence where cp_room = %d", + intval($room_id) + ); + if ($y && $y[0]['total'] > $limit) { + notice(t('Room is full') . EOL); + return false; + } + } - if(intval($x[0]['cr_expire'])) { - $r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d", - db_utcnow(), - db_quoteinterval( intval($x[0]['cr_expire']) . ' MINUTE' ), - intval($x[0]['cr_id']) - ); - } + if (intval($x[0]['cr_expire'])) { + $r = q("delete from chat where created < %s - INTERVAL %s and chat_room = %d", + db_utcnow(), + db_quoteinterval(intval($x[0]['cr_expire']) . ' MINUTE'), + intval($x[0]['cr_id']) + ); + } - $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d limit 1", - dbesc($observer_xchan), - intval($room_id) - ); - if($r) { - q("update chatpresence set cp_last = '%s' where cp_id = %d and cp_client = '%s'", - dbesc(datetime_convert()), - intval($r[0]['cp_id']), - dbesc($client) - ); - return true; - } + $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d limit 1", + dbesc($observer_xchan), + intval($room_id) + ); + if ($r) { + q("update chatpresence set cp_last = '%s' where cp_id = %d and cp_client = '%s'", + dbesc(datetime_convert()), + intval($r[0]['cp_id']), + dbesc($client) + ); + return true; + } - $r = q("insert into chatpresence ( cp_room, cp_xchan, cp_last, cp_status, cp_client ) + $r = q("insert into chatpresence ( cp_room, cp_xchan, cp_last, cp_status, cp_client ) values ( %d, '%s', '%s', '%s', '%s' )", - intval($room_id), - dbesc($observer_xchan), - dbesc(datetime_convert()), - dbesc($status), - dbesc($client) - ); + intval($room_id), + dbesc($observer_xchan), + dbesc(datetime_convert()), + dbesc($status), + dbesc($client) + ); - return $r; - } + return $r; + } - function leave($observer_xchan, $room_id, $client) { - if(! $room_id || ! $observer_xchan) - return; + public function leave($observer_xchan, $room_id, $client) + { + if (!$room_id || !$observer_xchan) + return; - $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d and cp_client = '%s' limit 1", - dbesc($observer_xchan), - intval($room_id), - dbesc($client) - ); - if($r) { - q("delete from chatpresence where cp_id = %d", - intval($r[0]['cp_id']) - ); - } + $r = q("select * from chatpresence where cp_xchan = '%s' and cp_room = %d and cp_client = '%s' limit 1", + dbesc($observer_xchan), + intval($room_id), + dbesc($client) + ); + if ($r) { + q("delete from chatpresence where cp_id = %d", + intval($r[0]['cp_id']) + ); + } - return true; - } + return true; + } - static public function roomlist($uid) { - require_once('include/security.php'); - $sql_extra = permissions_sql($uid); + public static function roomlist($uid) + { + require_once('include/security.php'); + $sql_extra = permissions_sql($uid); - $r = q("select allow_cid, allow_gid, deny_cid, deny_gid, cr_name, cr_expire, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name", - intval($uid) - ); + $r = q("select allow_cid, allow_gid, deny_cid, deny_gid, cr_name, cr_expire, cr_id, count(cp_id) as cr_inroom from chatroom left join chatpresence on cr_id = cp_room where cr_uid = %d $sql_extra group by cr_name, cr_id order by cr_name", + intval($uid) + ); - return $r; - } + return $r; + } - static public function list_count($uid) { - require_once('include/security.php'); - $sql_extra = permissions_sql($uid); + public static function list_count($uid) + { + require_once('include/security.php'); + $sql_extra = permissions_sql($uid); - $r = q("select count(*) as total from chatroom where cr_uid = %d $sql_extra", - intval($uid) - ); + $r = q("select count(*) as total from chatroom where cr_uid = %d $sql_extra", + intval($uid) + ); - return $r[0]['total']; - } + return $r[0]['total']; + } - /** - * @brief Create a chat message via API. - * - * It is the caller's responsibility to enter the room. - * - * @param int $uid - * @param int $room_id - * @param string $xchan - * @param string $text - * @return array - */ - static public function message($uid, $room_id, $xchan, $text) { + /** + * @brief Create a chat message via API. + * + * It is the caller's responsibility to enter the room. + * + * @param int $uid + * @param int $room_id + * @param string $xchan + * @param string $text + * @return array + */ + public static function message($uid, $room_id, $xchan, $text) + { - $ret = array('success' => false); + $ret = array('success' => false); - if(! $text) - return; + if (!$text) + return; - $sql_extra = permissions_sql($uid); + $sql_extra = permissions_sql($uid); - $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", - intval($uid), - intval($room_id) - ); - if(! $r) - return $ret; + $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", + intval($uid), + intval($room_id) + ); + if (!$r) + return $ret; - $arr = [ - 'chat_room' => $room_id, - 'chat_xchan' => $xchan, - 'chat_text' => $text - ]; - /** - * @hooks chat_message - * Called to create a chat message. - * * \e int \b chat_room - * * \e string \b chat_xchan - * * \e string \b chat_text - */ - call_hooks('chat_message', $arr); + $arr = [ + 'chat_room' => $room_id, + 'chat_xchan' => $xchan, + 'chat_text' => $text + ]; + /** + * @hooks chat_message + * Called to create a chat message. + * * \e int \b chat_room + * * \e string \b chat_xchan + * * \e string \b chat_text + */ + call_hooks('chat_message', $arr); - $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text ) + $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text ) values( %d, '%s', '%s', '%s' )", - intval($room_id), - dbesc($xchan), - dbesc(datetime_convert()), - dbesc(str_rot47(base64url_encode($arr['chat_text']))) - ); + intval($room_id), + dbesc($xchan), + dbesc(datetime_convert()), + dbesc(str_rot47(base64url_encode($arr['chat_text']))) + ); - $ret['success'] = true; - return $ret; - } + $ret['success'] = true; + return $ret; + } } diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php index 4f5346e52..5997968cc 100644 --- a/Zotlabs/Lib/Config.php +++ b/Zotlabs/Lib/Config.php @@ -16,7 +16,7 @@ class Config { * @param string $family * The category of the configuration value */ - static public function Load($family) { + public static function Load($family) { if(! array_key_exists($family, App::$config)) App::$config[$family] = []; @@ -48,7 +48,7 @@ class Config { * @return mixed * Return the set value, or false if the database update failed */ - static public function Set($family, $key, $value) { + public static function Set($family, $key, $value) { // manage array value $dbvalue = ((is_array($value)) ? serialise($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); @@ -98,7 +98,7 @@ class Config { * @param string $default (optional) default false * @return mixed Return value or false on error or if not set */ - static public function Get($family, $key, $default = false) { + public static function Get($family, $key, $default = false) { if((! array_key_exists($family, App::$config)) || (! array_key_exists('config_loaded', App::$config[$family]))) self::Load($family); @@ -124,7 +124,7 @@ class Config { * The configuration key to delete * @return mixed */ - static public function Delete($family, $key) { + public static function Delete($family, $key) { $ret = false; @@ -152,7 +152,7 @@ class Config { * The configuration key to query * @return mixed */ - static private function get_from_storage($family,$key) { + private static function get_from_storage($family, $key) { $ret = q("SELECT * FROM config WHERE cat = '%s' AND k = '%s' LIMIT 1", dbesc($family), dbesc($key) diff --git a/Zotlabs/Lib/Connect.php b/Zotlabs/Lib/Connect.php index 67aab0f1d..a855afdd4 100644 --- a/Zotlabs/Lib/Connect.php +++ b/Zotlabs/Lib/Connect.php @@ -7,302 +7,302 @@ use Zotlabs\Access\Permissions; use Zotlabs\Daemon\Run; +class Connect +{ -class Connect { + /** + * Takes a $channel and a $url/handle and adds a new connection + * + * Returns array + * $return['success'] boolean true if successful + * $return['abook'] Address book entry joined with xchan if successful + * $return['message'] error text if success is false. + * + * This function does NOT send sync packets to clones. The caller is responsible for doing this + */ - /** - * Takes a $channel and a $url/handle and adds a new connection - * - * Returns array - * $return['success'] boolean true if successful - * $return['abook'] Address book entry joined with xchan if successful - * $return['message'] error text if success is false. - * - * This function does NOT send sync packets to clones. The caller is responsible for doing this - */ + public static function connect($channel, $url, $sub_channel = false) + { - static function connect($channel, $url, $sub_channel = false) { + $uid = $channel['channel_id']; - $uid = $channel['channel_id']; + if (strpos($url, '@') === false && strpos($url, '/') === false) { + $url = $url . '@' . App::get_hostname(); + } - if (strpos($url,'@') === false && strpos($url,'/') === false) { - $url = $url . '@' . App::get_hostname(); - } + $result = ['success' => false, 'message' => '']; - $result = [ 'success' => false, 'message' => '' ]; + $my_perms = false; + $protocol = ''; - $my_perms = false; - $protocol = ''; + $ap_allowed = get_config('system', 'activitypub', ACTIVITYPUB_ENABLED) && get_pconfig($uid, 'system', 'activitypub', ACTIVITYPUB_ENABLED); - $ap_allowed = get_config('system','activitypub', ACTIVITYPUB_ENABLED) && get_pconfig($uid,'system','activitypub', ACTIVITYPUB_ENABLED); + if (substr($url, 0, 1) === '[') { + $x = strpos($url, ']'); + if ($x) { + $protocol = substr($url, 1, $x - 1); + $url = substr($url, $x + 1); + } + } - if (substr($url,0,1) === '[') { - $x = strpos($url,']'); - if ($x) { - $protocol = substr($url,1,$x-1); - $url = substr($url,$x+1); - } - } + if (!check_siteallowed($url)) { + $result['message'] = t('Channel is blocked on this site.'); + return $result; + } - if (! check_siteallowed($url)) { - $result['message'] = t('Channel is blocked on this site.'); - return $result; - } + if (!$url) { + $result['message'] = t('Channel location missing.'); + return $result; + } - if (! $url) { - $result['message'] = t('Channel location missing.'); - return $result; - } + // check service class limits - // check service class limits + $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ", + intval($uid) + ); + if ($r) { + $total_channels = $r[0]['total']; + } - $r = q("select count(*) as total from abook where abook_channel = %d and abook_self = 0 ", - intval($uid) - ); - if ($r) { - $total_channels = $r[0]['total']; - } + if (!service_class_allows($uid, 'total_channels', $total_channels)) { + $result['message'] = upgrade_message(); + return $result; + } - if (! service_class_allows($uid,'total_channels',$total_channels)) { - $result['message'] = upgrade_message(); - return $result; - } + $xchan_hash = ''; + $sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : ''); - $xchan_hash = ''; - $sql_options = (($protocol) ? " and xchan_network = '" . dbesc($protocol) . "' " : ''); + $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ", + dbesc($url), + dbesc($url), + dbesc($url) + ); - $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s') $sql_options ", - dbesc($url), - dbesc($url), - dbesc($url) - ); + if ($r) { - if ($r) { + // reset results to the best record or the first if we don't have the best + // note: this returns a single record and not an array of records - // reset results to the best record or the first if we don't have the best - // note: this returns a single record and not an array of records + $r = Libzot::zot_record_preferred($r, 'xchan_network'); - $r = Libzot::zot_record_preferred($r,'xchan_network'); + // ensure there's a valid hubloc for this xchan before proceeding - you cannot connect without it - // ensure there's a valid hubloc for this xchan before proceeding - you cannot connect without it - - if (in_array($r['xchan_network'], [ 'zot6','activitypub' ])) { - $h = q("select * from hubloc where hubloc_hash = '%s'", - dbesc($r['xchan_hash']) - ); - if (! $h) { - $r = null; - } - } + if (in_array($r['xchan_network'], ['zot6', 'activitypub'])) { + $h = q("select * from hubloc where hubloc_hash = '%s'", + dbesc($r['xchan_hash']) + ); + if (!$h) { + $r = null; + } + } - // we may have nulled out this record so check again - - if ($r) { + // we may have nulled out this record so check again - // Check the site table to see if we should have a zot6 hubloc, - // If so, clear the xchan and start fresh + if ($r) { - if ($r['xchan_network'] === 'activitypub') { - $m = parse_url($r['xchan_hash']); - unset($m['path']); - $h = unparse_url($m); - $s = q("select * from site where site_url = '%s'", - dbesc($h) - ); - if (intval($s['site_type']) === SITE_TYPE_ZOT) { - logger('got zot - ignore activitypub entry'); - $r = null; - } - } - } - } + // Check the site table to see if we should have a zot6 hubloc, + // If so, clear the xchan and start fresh + + if ($r['xchan_network'] === 'activitypub') { + $m = parse_url($r['xchan_hash']); + unset($m['path']); + $h = unparse_url($m); + $s = q("select * from site where site_url = '%s'", + dbesc($h) + ); + if (intval($s['site_type']) === SITE_TYPE_ZOT) { + logger('got zot - ignore activitypub entry'); + $r = null; + } + } + } + } - $singleton = false; + $singleton = false; - if (! $r) { + if (!$r) { - // not in cache - try discovery + // not in cache - try discovery - $wf = discover_by_webbie($url,$protocol,false); + $wf = discover_by_webbie($url, $protocol, false); - if (! $wf) { - $result['message'] = t('Remote channel or protocol unavailable.'); - return $result; - } - } + if (!$wf) { + $result['message'] = t('Remote channel or protocol unavailable.'); + return $result; + } + } - if ($wf) { + if ($wf) { - // something was discovered - find the record which was just created. + // something was discovered - find the record which was just created. - $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options", - dbesc(($wf) ? $wf : $url), - dbesc($url), - dbesc($url) - ); + $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' ) $sql_options", + dbesc(($wf) ? $wf : $url), + dbesc($url), + dbesc($url) + ); - // convert to a single record (once again preferring a zot solution in the case of multiples) + // convert to a single record (once again preferring a zot solution in the case of multiples) - if ($r) { - $r = Libzot::zot_record_preferred($r,'xchan_network'); - } - } + if ($r) { + $r = Libzot::zot_record_preferred($r, 'xchan_network'); + } + } - // if discovery was a success or the channel was already cached we should have an xchan record in $r + // if discovery was a success or the channel was already cached we should have an xchan record in $r - if ($r) { - $xchan = $r; - $xchan_hash = $r['xchan_hash']; - $their_perms = EMPTY_STR; - } + if ($r) { + $xchan = $r; + $xchan_hash = $r['xchan_hash']; + $their_perms = EMPTY_STR; + } - // failure case + // failure case - if (! $xchan_hash) { - $result['message'] = t('Channel discovery failed.'); - logger('follow: ' . $result['message']); - return $result; - } + if (!$xchan_hash) { + $result['message'] = t('Channel discovery failed.'); + logger('follow: ' . $result['message']); + return $result; + } - if (! check_channelallowed($xchan_hash)) { - $result['message'] = t('Channel is blocked on this site.'); - logger('follow: ' . $result['message']); - return $result; + if (!check_channelallowed($xchan_hash)) { + $result['message'] = t('Channel is blocked on this site.'); + logger('follow: ' . $result['message']); + return $result; - } + } - - if ($r['xchan_network'] === 'activitypub') { - if (! $ap_allowed) { - $result['message'] = t('Protocol not supported'); - return $result; - } - $singleton = true; - } - // Now start processing the new connection + if ($r['xchan_network'] === 'activitypub') { + if (!$ap_allowed) { + $result['message'] = t('Protocol not supported'); + return $result; + } + $singleton = true; + } - $aid = $channel['channel_account_id']; - $hash = $channel['channel_hash']; - $default_group = $channel['channel_default_group']; + // Now start processing the new connection - if ($hash === $xchan_hash) { - $result['message'] = t('Cannot connect to yourself.'); - return $result; - } + $aid = $channel['channel_account_id']; + $hash = $channel['channel_hash']; + $default_group = $channel['channel_default_group']; - $p = Permissions::connect_perms($uid); + if ($hash === $xchan_hash) { + $result['message'] = t('Cannot connect to yourself.'); + return $result; + } - // parent channels have unencumbered write permission + $p = Permissions::connect_perms($uid); - if ($sub_channel) { - $p['perms']['post_wall'] = 1; - $p['perms']['post_comments'] = 1; - $p['perms']['write_storage'] = 1; - $p['perms']['post_like'] = 1; - $p['perms']['delegate'] = 0; - $p['perms']['moderated'] = 0; - } + // parent channels have unencumbered write permission - $my_perms = Permissions::serialise($p['perms']); - - $profile_assign = get_pconfig($uid,'system','profile_assign',''); + if ($sub_channel) { + $p['perms']['post_wall'] = 1; + $p['perms']['post_comments'] = 1; + $p['perms']['write_storage'] = 1; + $p['perms']['post_like'] = 1; + $p['perms']['delegate'] = 0; + $p['perms']['moderated'] = 0; + } - // See if we are already connected by virtue of having an abook record + $my_perms = Permissions::serialise($p['perms']); - $r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook + $profile_assign = get_pconfig($uid, 'system', 'profile_assign', ''); + + // See if we are already connected by virtue of having an abook record + + $r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($xchan_hash), - intval($uid) - ); + dbesc($xchan_hash), + intval($uid) + ); - if ($r) { + if ($r) { - $abook_instance = $r[0]['abook_instance']; + $abook_instance = $r[0]['abook_instance']; - // If they are on a non-nomadic network, add them to this location + // If they are on a non-nomadic network, add them to this location - if (($singleton) && strpos($abook_instance,z_root()) === false) { - if ($abook_instance) { - $abook_instance .= ','; - } - $abook_instance .= z_root(); + if (($singleton) && strpos($abook_instance, z_root()) === false) { + if ($abook_instance) { + $abook_instance .= ','; + } + $abook_instance .= z_root(); - $x = q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d", - dbesc($abook_instance), - intval($r[0]['abook_id']) - ); - } + $x = q("update abook set abook_instance = '%s', abook_not_here = 0 where abook_id = %d", + dbesc($abook_instance), + intval($r[0]['abook_id']) + ); + } - // if they have a pending connection, we just followed them so approve the connection request + // if they have a pending connection, we just followed them so approve the connection request - if (intval($r[0]['abook_pending'])) { - $x = q("update abook set abook_pending = 0 where abook_id = %d", - intval($r[0]['abook_id']) - ); - } - } - else { + if (intval($r[0]['abook_pending'])) { + $x = q("update abook set abook_pending = 0 where abook_id = %d", + intval($r[0]['abook_id']) + ); + } + } else { - // create a new abook record + // create a new abook record - $closeness = get_pconfig($uid,'system','new_abook_closeness',80); + $closeness = get_pconfig($uid, 'system', 'new_abook_closeness', 80); - $r = abook_store_lowlevel( - [ - 'abook_account' => intval($aid), - 'abook_channel' => intval($uid), - 'abook_closeness' => intval($closeness), - 'abook_xchan' => $xchan_hash, - 'abook_profile' => $profile_assign, - 'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0), - 'abook_created' => datetime_convert(), - 'abook_updated' => datetime_convert(), - 'abook_instance' => (($singleton) ? z_root() : '') - ] - ); - } + $r = abook_store_lowlevel( + [ + 'abook_account' => intval($aid), + 'abook_channel' => intval($uid), + 'abook_closeness' => intval($closeness), + 'abook_xchan' => $xchan_hash, + 'abook_profile' => $profile_assign, + 'abook_feed' => intval(($xchan['xchan_network'] === 'rss') ? 1 : 0), + 'abook_created' => datetime_convert(), + 'abook_updated' => datetime_convert(), + 'abook_instance' => (($singleton) ? z_root() : '') + ] + ); + } - if (! $r) { - logger('abook creation failed'); - $result['message'] = t('error saving data'); - return $result; - } + if (!$r) { + logger('abook creation failed'); + $result['message'] = t('error saving data'); + return $result; + } - // Set suitable permissions to the connection + // Set suitable permissions to the connection - if ($my_perms) { - set_abconfig($uid,$xchan_hash,'system','my_perms',$my_perms); - } + if ($my_perms) { + set_abconfig($uid, $xchan_hash, 'system', 'my_perms', $my_perms); + } - // fetch the entire record + // fetch the entire record - $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash + $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($xchan_hash), - intval($uid) - ); + dbesc($xchan_hash), + intval($uid) + ); - if ($r) { - $result['abook'] = array_shift($r); - Run::Summon([ 'Notifier', 'permissions_create', $result['abook']['abook_id'] ]); - } + if ($r) { + $result['abook'] = array_shift($r); + Run::Summon(['Notifier', 'permissions_create', $result['abook']['abook_id']]); + } - $arr = [ 'channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook'] ]; + $arr = ['channel_id' => $uid, 'channel' => $channel, 'abook' => $result['abook']]; - call_hooks('follow', $arr); + call_hooks('follow', $arr); - /** If there is a default group for this channel, add this connection to it */ + /** If there is a default group for this channel, add this connection to it */ - if ($default_group) { - $g = AccessList::rec_byhash($uid,$default_group); - if ($g) { - AccessList::member_add($uid,'',$xchan_hash,$g['id']); - } - } + if ($default_group) { + $g = AccessList::rec_byhash($uid, $default_group); + if ($g) { + AccessList::member_add($uid, '', $xchan_hash, $g['id']); + } + } - $result['success'] = true; - return $result; - } + $result['success'] = true; + return $result; + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Crypto.php b/Zotlabs/Lib/Crypto.php index bf4de8a91..ac09ab8ac 100644 --- a/Zotlabs/Lib/Crypto.php +++ b/Zotlabs/Lib/Crypto.php @@ -5,7 +5,7 @@ use Exception; class Crypto { - static public $openssl_algorithms = [ + public static $openssl_algorithms = [ // zot6 nickname, opensslname, keylength, ivlength @@ -16,7 +16,7 @@ class Crypto { ]; - static public function methods() { + public static function methods() { $ret = []; foreach(self::$openssl_algorithms as $ossl) { @@ -28,7 +28,7 @@ class Crypto { } - static public function signing_methods() { + public static function signing_methods() { $ret = [ 'sha256' ]; call_hooks('signing_methods',$ret); @@ -37,7 +37,7 @@ class Crypto { } - static public function new_keypair($bits) { + public static function new_keypair($bits) { $openssl_options = [ 'digest_alg' => 'sha1', @@ -72,7 +72,7 @@ class Crypto { } - static public function sign($data,$key,$alg = 'sha256') { + public static function sign($data, $key, $alg = 'sha256') { if (! $key) { return false; @@ -84,7 +84,7 @@ class Crypto { } - static public function verify($data,$sig,$key,$alg = 'sha256') { + public static function verify($data, $sig, $key, $alg = 'sha256') { if (! $key) { return false; @@ -107,7 +107,7 @@ class Crypto { return (($verify > 0) ? true : false); } - static public function encapsulate($data,$pubkey,$alg) { + public static function encapsulate($data, $pubkey, $alg) { if (! ($alg && $pubkey)) { return $data; @@ -164,7 +164,7 @@ class Crypto { } } - static public function unencapsulate($data,$prvkey) { + public static function unencapsulate($data, $prvkey) { if (! (is_array($data) && array_key_exists('encrypted',$data) && array_key_exists('alg',$data) && $data['alg'])) { logger('not encrypted'); diff --git a/Zotlabs/Lib/DB_Upgrade.php b/Zotlabs/Lib/DB_Upgrade.php index 78e1eeb59..692ca98fb 100644 --- a/Zotlabs/Lib/DB_Upgrade.php +++ b/Zotlabs/Lib/DB_Upgrade.php @@ -5,112 +5,112 @@ namespace Zotlabs\Lib; use App; -class DB_Upgrade { +class DB_Upgrade +{ - public $config_name = ''; - public $func_prefix = ''; + public $config_name = ''; + public $func_prefix = ''; - function __construct($db_revision) { + public function __construct($db_revision) + { - $this->config_name = 'db_version'; - $this->func_prefix = '_'; + $this->config_name = 'db_version'; + $this->func_prefix = '_'; - $build = get_config('system', 'db_version', 0); - if(! intval($build)) - $build = set_config('system', 'db_version', $db_revision); + $build = get_config('system', 'db_version', 0); + if (!intval($build)) + $build = set_config('system', 'db_version', $db_revision); - if($build == $db_revision) { - // Nothing to be done. - return; - } - else { - $stored = intval($build); - if(! $stored) { - logger('Critical: check_config unable to determine database schema version'); - return; - } - - $current = intval($db_revision); + if ($build == $db_revision) { + // Nothing to be done. + return; + } else { + $stored = intval($build); + if (!$stored) { + logger('Critical: check_config unable to determine database schema version'); + return; + } - if($stored < $current) { + $current = intval($db_revision); - // The last update we performed was $stored. - // Start at $stored + 1 and continue until we have completed $current + if ($stored < $current) { - for($x = $stored + 1; $x <= $current; $x ++) { - $s = '_' . $x; - $cls = '\\Zotlabs\Update\\' . $s ; - if(! class_exists($cls)) { - return; - } + // The last update we performed was $stored. + // Start at $stored + 1 and continue until we have completed $current - // There could be a lot of processes running or about to run. - // We want exactly one process to run the update command. - // So store the fact that we're taking responsibility - // after first checking to see if somebody else already has. + for ($x = $stored + 1; $x <= $current; $x++) { + $s = '_' . $x; + $cls = '\\Zotlabs\Update\\' . $s; + if (!class_exists($cls)) { + return; + } - // If the update fails or times-out completely you may need to - // delete the config entry to try again. + // There could be a lot of processes running or about to run. + // We want exactly one process to run the update command. + // So store the fact that we're taking responsibility + // after first checking to see if somebody else already has. - Config::Load('database'); + // If the update fails or times-out completely you may need to + // delete the config entry to try again. - if(get_config('database', $s)) - break; - set_config('database',$s, '1'); - + Config::Load('database'); - $c = new $cls(); - - $retval = $c->run(); - - if($retval != UPDATE_SUCCESS) { + if (get_config('database', $s)) + break; + set_config('database', $s, '1'); - $source = t('Source code of failed update: ') . "\n\n" . @file_get_contents('Zotlabs/Update/' . $s . '.php'); - + $c = new $cls(); - // Prevent sending hundreds of thousands of emails by creating - // a lockfile. + $retval = $c->run(); - $lockfile = 'cache/mailsent'; + if ($retval != UPDATE_SUCCESS) { - if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 86400))) - return; - @unlink($lockfile); - //send the administrator an e-mail - file_put_contents($lockfile, $x); - - $r = q("select account_language from account where account_email = '%s' limit 1", - dbesc(App::$config['system']['admin_email']) - ); - push_lang(($r) ? $r[0]['account_language'] : 'en'); - z_mail( - [ - 'toEmail' => App::$config['system']['admin_email'], - 'messageSubject' => sprintf( t('Update Error at %s'), z_root()), - 'textVersion' => replace_macros(get_intltext_template('update_fail_eml.tpl'), - [ - '$sitename' => App::$config['system']['sitename'], - '$siteurl' => z_root(), - '$update' => $x, - '$error' => sprintf( t('Update %s failed. See error logs.'), $x), - '$baseurl' => z_root(), - '$source' => $source - ] - ) - ] - ); - //try the logger - logger('CRITICAL: Update Failed: ' . $x); - pop_lang(); - } - else { - set_config('database',$s, 'success'); - } - } - } - set_config('system', 'db_version', $db_revision); - } - } + $source = t('Source code of failed update: ') . "\n\n" . @file_get_contents('Zotlabs/Update/' . $s . '.php'); + + + // Prevent sending hundreds of thousands of emails by creating + // a lockfile. + + $lockfile = 'cache/mailsent'; + + if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 86400))) + return; + @unlink($lockfile); + //send the administrator an e-mail + file_put_contents($lockfile, $x); + + $r = q("select account_language from account where account_email = '%s' limit 1", + dbesc(App::$config['system']['admin_email']) + ); + push_lang(($r) ? $r[0]['account_language'] : 'en'); + z_mail( + [ + 'toEmail' => App::$config['system']['admin_email'], + 'messageSubject' => sprintf(t('Update Error at %s'), z_root()), + 'textVersion' => replace_macros(get_intltext_template('update_fail_eml.tpl'), + [ + '$sitename' => App::$config['system']['sitename'], + '$siteurl' => z_root(), + '$update' => $x, + '$error' => sprintf(t('Update %s failed. See error logs.'), $x), + '$baseurl' => z_root(), + '$source' => $source + ] + ) + ] + ); + + //try the logger + logger('CRITICAL: Update Failed: ' . $x); + pop_lang(); + } else { + set_config('database', $s, 'success'); + } + } + } + set_config('system', 'db_version', $db_revision); + } + } } \ No newline at end of file diff --git a/Zotlabs/Lib/DReport.php b/Zotlabs/Lib/DReport.php index 7a2cb062f..b023fc7fd 100644 --- a/Zotlabs/Lib/DReport.php +++ b/Zotlabs/Lib/DReport.php @@ -1,135 +1,143 @@ location = $location; - $this->sender = $sender; - $this->recipient = $recipient; - $this->name = EMPTY_STR; - $this->message_id = $message_id; - $this->status = $status; - $this->date = datetime_convert(); - } + public function __construct($location, $sender, $recipient, $message_id, $status = 'deliver') + { + $this->location = $location; + $this->sender = $sender; + $this->recipient = $recipient; + $this->name = EMPTY_STR; + $this->message_id = $message_id; + $this->status = $status; + $this->date = datetime_convert(); + } - function update($status) { - $this->status = $status; - $this->date = datetime_convert(); - } + public function update($status) + { + $this->status = $status; + $this->date = datetime_convert(); + } - function set_name($name) { - $this->name = $name; - } + public function set_name($name) + { + $this->name = $name; + } - function addto_update($status) { - $this->status = $this->status . ' ' . $status; - } + public function addto_update($status) + { + $this->status = $this->status . ' ' . $status; + } - function set($arr) { - $this->location = $arr['location']; - $this->sender = $arr['sender']; - $this->recipient = $arr['recipient']; - $this->name = $arr['name']; - $this->message_id = $arr['message_id']; - $this->status = $arr['status']; - $this->date = $arr['date']; - } + public function set($arr) + { + $this->location = $arr['location']; + $this->sender = $arr['sender']; + $this->recipient = $arr['recipient']; + $this->name = $arr['name']; + $this->message_id = $arr['message_id']; + $this->status = $arr['status']; + $this->date = $arr['date']; + } - function get() { - return array( - 'location' => $this->location, - 'sender' => $this->sender, - 'recipient' => $this->recipient, - 'name' => $this->name, - 'message_id' => $this->message_id, - 'status' => $this->status, - 'date' => $this->date - ); - } + public function get() + { + return array( + 'location' => $this->location, + 'sender' => $this->sender, + 'recipient' => $this->recipient, + 'name' => $this->name, + 'message_id' => $this->message_id, + 'status' => $this->status, + 'date' => $this->date + ); + } - /** - * @brief decide whether to store a returned delivery report - * - * @param array $dr - * @return boolean - */ + /** + * @brief decide whether to store a returned delivery report + * + * @param array $dr + * @return bool + */ - static function is_storable($dr) { + public static function is_storable($dr) + { - if(get_config('system', 'disable_dreport')) - return false; + if (get_config('system', 'disable_dreport')) + return false; - /** - * @hooks dreport_is_storable - * Called before storing a dreport record to determine whether to store it. - * * \e array - */ + /** + * @hooks dreport_is_storable + * Called before storing a dreport record to determine whether to store it. + * * \e array + */ - call_hooks('dreport_is_storable', $dr); + call_hooks('dreport_is_storable', $dr); - // let plugins accept or reject - if neither, continue on - if(array_key_exists('accept',$dr) && intval($dr['accept'])) - return true; - if(array_key_exists('reject',$dr) && intval($dr['reject'])) - return false; + // let plugins accept or reject - if neither, continue on + if (array_key_exists('accept', $dr) && intval($dr['accept'])) + return true; + if (array_key_exists('reject', $dr) && intval($dr['reject'])) + return false; - if(! ($dr['sender'])) - return false; + if (!($dr['sender'])) + return false; - // Is the sender one of our channels? + // Is the sender one of our channels? - $c = q("select channel_id from channel where channel_hash = '%s' limit 1", - dbesc($dr['sender']) - ); - if(! $c) - return false; + $c = q("select channel_id from channel where channel_hash = '%s' limit 1", + dbesc($dr['sender']) + ); + if (!$c) + return false; - // is the recipient one of our connections, or do we want to store every report? + // is the recipient one of our connections, or do we want to store every report? - $rxchan = $dr['recipient']; - $pcf = get_pconfig($c[0]['channel_id'],'system','dreport_store_all'); - if($pcf) - return true; + $rxchan = $dr['recipient']; + $pcf = get_pconfig($c[0]['channel_id'], 'system', 'dreport_store_all'); + if ($pcf) + return true; - // We always add ourself as a recipient to private and relayed posts - // So if a remote site says they can't find us, that's no big surprise - // and just creates a lot of extra report noise + // We always add ourself as a recipient to private and relayed posts + // So if a remote site says they can't find us, that's no big surprise + // and just creates a lot of extra report noise - if(($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient not found')) - return false; + if (($dr['location'] !== z_root()) && ($dr['sender'] === $rxchan) && ($dr['status'] === 'recipient not found')) + return false; - // If you have a private post with a recipient list, every single site is going to report - // back a failed delivery for anybody on that list that isn't local to them. We're only - // concerned about this if we have a local hubloc record which says we expected them to - // have a channel on that site. + // If you have a private post with a recipient list, every single site is going to report + // back a failed delivery for anybody on that list that isn't local to them. We're only + // concerned about this if we have a local hubloc record which says we expected them to + // have a channel on that site. - $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'", - dbesc($rxchan), - dbesc($dr['location']) - ); - if((! $r) && ($dr['status'] === 'recipient not found')) - return false; + $r = q("select hubloc_id from hubloc where hubloc_hash = '%s' and hubloc_url = '%s'", + dbesc($rxchan), + dbesc($dr['location']) + ); + if ((!$r) && ($dr['status'] === 'recipient not found')) + return false; - $r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($rxchan), - intval($c[0]['channel_id']) - ); - if($r) - return true; + $r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($rxchan), + intval($c[0]['channel_id']) + ); + if ($r) + return true; - return false; - } + return false; + } } diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index 5c32b5e86..b3fd8ecb0 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -29,7 +29,7 @@ class Enotify { */ - static public function submit($params) { + public static function submit($params) { logger('notification: entry', LOGGER_DEBUG); @@ -807,7 +807,7 @@ class Enotify { * * \e string \b textVersion text only version of the message * * \e string \b additionalMailHeader additions to the smtp mail header */ - static public function send($params) { + public static function send($params) { $params['sent'] = false; $params['result'] = false; @@ -862,7 +862,7 @@ class Enotify { return $res; } - static public function format($item) { + public static function format($item) { $ret = ''; diff --git a/Zotlabs/Lib/Hashpath.php b/Zotlabs/Lib/Hashpath.php index e27838ced..1e8c9502f 100644 --- a/Zotlabs/Lib/Hashpath.php +++ b/Zotlabs/Lib/Hashpath.php @@ -27,30 +27,31 @@ namespace Zotlabs\Lib; * see also: boot.php:os_mkdir() - here we provide the equivalent of mkdir -p with permissions of 770. * */ - -class Hashpath { - static function path($url, $prefix = '.', $depth = 1, $mkdir = true) { - $hash = hash('sha256', $url); - $start = 0; - $slice = 2; - if ($depth < 1) { - $depth = 1; - } - $sluglen = $depth * $slice; +class Hashpath +{ - do { - $slug = substr($hash,$start,$slice); - $prefix .= '/' . $slug; - $start += $slice; - $sluglen -= $slice; - } - while ($sluglen); + public static function path($url, $prefix = '.', $depth = 1, $mkdir = true) + { + $hash = hash('sha256', $url); + $start = 0; + $slice = 2; + if ($depth < 1) { + $depth = 1; + } + $sluglen = $depth * $slice; - if ($mkdir) { - os_mkdir($prefix, STORAGE_DEFAULT_PERMISSIONS, true); - } - - return $prefix . '/' . $hash; - } + do { + $slug = substr($hash, $start, $slice); + $prefix .= '/' . $slug; + $start += $slice; + $sluglen -= $slice; + } while ($sluglen); + + if ($mkdir) { + os_mkdir($prefix, STORAGE_DEFAULT_PERMISSIONS, true); + } + + return $prefix . '/' . $hash; + } } diff --git a/Zotlabs/Lib/IConfig.php b/Zotlabs/Lib/IConfig.php index 9e329c080..c05c17c70 100644 --- a/Zotlabs/Lib/IConfig.php +++ b/Zotlabs/Lib/IConfig.php @@ -6,11 +6,11 @@ namespace Zotlabs\Lib; class IConfig { - static public function Load(&$item) { + public static function Load(&$item) { return; } - static public function Get(&$item, $family, $key, $default = false) { + public static function Get(&$item, $family, $key, $default = false) { $is_item = false; @@ -76,7 +76,7 @@ class IConfig { */ - static public function Set(&$item, $family, $key, $value, $sharing = false) { + public static function Set(&$item, $family, $key, $value, $sharing = false) { $dbvalue = ((is_array($value)) ? serialise($value) : $value); $dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue); @@ -137,7 +137,7 @@ class IConfig { - static public function Delete(&$item, $family, $key) { + public static function Delete(&$item, $family, $key) { $is_item = false; diff --git a/Zotlabs/Lib/Img_cache.php b/Zotlabs/Lib/Img_cache.php index 5391538ad..fe58c6eab 100644 --- a/Zotlabs/Lib/Img_cache.php +++ b/Zotlabs/Lib/Img_cache.php @@ -4,78 +4,81 @@ namespace Zotlabs\Lib; use Zotlabs\Lib\Hashpath; use Zotlabs\Daemon\Run; -class Img_cache { +class Img_cache +{ - static $cache_life = 18600 * 7; - - static function get_filename($url, $prefix = '.') { - return Hashpath::path($url,$prefix); - } + static public $cache_life = 18600 * 7; - // Check to see if we have this url in our cache - // If we have it return true. - // If we do not, or the cache file is empty or expired, return false - // but attempt to fetch the entry in the background - - static function check($url, $prefix = '.') { + public static function get_filename($url, $prefix = '.') + { + return Hashpath::path($url, $prefix); + } - if (strpos($url,z_root()) !== false) { - return false; - } + // Check to see if we have this url in our cache + // If we have it return true. + // If we do not, or the cache file is empty or expired, return false + // but attempt to fetch the entry in the background - $path = self::get_filename($url,$prefix); - if (file_exists($path)) { - $t = filemtime($path); - if ($t && time() - $t >= self::$cache_life) { - Run::Summon( [ 'Cache_image', $url, $path ] ); - return false; - } - else { - return ((filesize($path)) ? true : false); - } - } - - // Cache_image invokes url_to_cache() as a background task - - Run::Summon( [ 'Cache_image', $url, $path ] ); - return false; - } + public static function check($url, $prefix = '.') + { - static function url_to_cache($url,$file) { + if (strpos($url, z_root()) !== false) { + return false; + } - $fp = fopen($file,'wb'); + $path = self::get_filename($url, $prefix); + if (file_exists($path)) { + $t = filemtime($path); + if ($t && time() - $t >= self::$cache_life) { + Run::Summon(['Cache_image', $url, $path]); + return false; + } else { + return ((filesize($path)) ? true : false); + } + } - if (! $fp) { - logger('failed to open storage file: ' . $file,LOGGER_NORMAL,LOG_ERR); - return false; - } + // Cache_image invokes url_to_cache() as a background task - // don't check certs, and since we're running in the background, - // allow a two-minute timeout rather than the default one minute. - // This is a compromise. We want to cache all the slow sites we can, - // but don't want to rack up too many processes doing so. - - $redirects = 0; - $x = z_fetch_url($url,true,$redirects,[ 'filep' => $fp, 'novalidate' => true, 'timeout' => 120 ]); + Run::Summon(['Cache_image', $url, $path]); + return false; + } - fclose($fp); - - if ($x['success'] && file_exists($file)) { - $i = @getimagesize($file); - if ($i && $i[2]) { // looking for non-zero imagetype - Run::Summon( [ 'CacheThumb' , basename($file) ] ); - return true; - } - } + public static function url_to_cache($url, $file) + { - // We could not cache the image for some reason. Leave an empty file here - // to provide a record of the attempt. We'll use this as a flag to avoid - // doing it again repeatedly. + $fp = fopen($file, 'wb'); - file_put_contents($file, EMPTY_STR); - logger('cache failed from ' . $url); - return false; - } + if (!$fp) { + logger('failed to open storage file: ' . $file, LOGGER_NORMAL, LOG_ERR); + return false; + } + + // don't check certs, and since we're running in the background, + // allow a two-minute timeout rather than the default one minute. + // This is a compromise. We want to cache all the slow sites we can, + // but don't want to rack up too many processes doing so. + + $redirects = 0; + $x = z_fetch_url($url, true, $redirects, ['filep' => $fp, 'novalidate' => true, 'timeout' => 120]); + + fclose($fp); + + if ($x['success'] && file_exists($file)) { + $i = @getimagesize($file); + if ($i && $i[2]) { // looking for non-zero imagetype + Run::Summon(['CacheThumb', basename($file)]); + return true; + } + } + + // We could not cache the image for some reason. Leave an empty file here + // to provide a record of the attempt. We'll use this as a flag to avoid + // doing it again repeatedly. + + file_put_contents($file, EMPTY_STR); + logger('cache failed from ' . $url); + return false; + } } diff --git a/Zotlabs/Lib/Img_filesize.php b/Zotlabs/Lib/Img_filesize.php index 196697733..99ed0a63c 100644 --- a/Zotlabs/Lib/Img_filesize.php +++ b/Zotlabs/Lib/Img_filesize.php @@ -2,50 +2,54 @@ namespace Zotlabs\Lib; -class Img_filesize { +class Img_filesize +{ - private $url; + private $url; - function __construct($url) { - $this->url = $url; - } + public function __construct($url) + { + $this->url = $url; + } - function getSize() { - $size = null; + public function getSize() + { + $size = null; - if(stripos($this->url,z_root() . '/photo') !== false) { - $size = self::getLocalFileSize($this->url); - } - if(! $size) { - $size = getRemoteFileSize($this->url); - } + if (stripos($this->url, z_root() . '/photo') !== false) { + $size = self::getLocalFileSize($this->url); + } + if (!$size) { + $size = getRemoteFileSize($this->url); + } - return $size; - } + return $size; + } - static function getLocalFileSize($url) { - - $fname = basename($url); - $resolution = 0; - - if(strpos($fname,'.') !== false) - $fname = substr($fname,0,strpos($fname,'.')); - - if(substr($fname,-2,1) == '-') { - $resolution = intval(substr($fname,-1,1)); - $fname = substr($fname,0,-2); - } - - $r = q("SELECT filesize FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", - dbesc($fname), - intval($resolution) - ); - if($r) { - return $r[0]['filesize']; - } - return null; - } + public static function getLocalFileSize($url) + { + + $fname = basename($url); + $resolution = 0; + + if (strpos($fname, '.') !== false) + $fname = substr($fname, 0, strpos($fname, '.')); + + if (substr($fname, -2, 1) == '-') { + $resolution = intval(substr($fname, -1, 1)); + $fname = substr($fname, 0, -2); + } + + $r = q("SELECT filesize FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", + dbesc($fname), + intval($resolution) + ); + if ($r) { + return $r[0]['filesize']; + } + return null; + } } diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php index d95fe7295..36ff7ee00 100644 --- a/Zotlabs/Lib/JSalmon.php +++ b/Zotlabs/Lib/JSalmon.php @@ -4,69 +4,73 @@ namespace Zotlabs\Lib; use Zotlabs\Web\HTTPSig; -class JSalmon { +class JSalmon +{ - static function sign($data,$key_id,$key,$data_type = 'application/x-zot+json') { + public static function sign($data, $key_id, $key, $data_type = 'application/x-zot+json') + { - $data = base64url_encode(json_encode($data,true),true); // strip padding - $encoding = 'base64url'; - $algorithm = 'RSA-SHA256'; + $data = base64url_encode(json_encode($data, true), true); // strip padding + $encoding = 'base64url'; + $algorithm = 'RSA-SHA256'; - $data = preg_replace('/\s+/','',$data); + $data = preg_replace('/\s+/', '', $data); - // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods + // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods - $precomputed = '.' . base64url_encode($data_type,true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng'; + $precomputed = '.' . base64url_encode($data_type, true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng'; - $signature = base64url_encode(Crypto::sign($data . $precomputed, $key), true); + $signature = base64url_encode(Crypto::sign($data . $precomputed, $key), true); - return ([ - 'signed' => true, - 'data' => $data, - 'data_type' => $data_type, - 'encoding' => $encoding, - 'alg' => $algorithm, - 'sigs' => [ - 'value' => $signature, - 'key_id' => base64url_encode($key_id, true) - ] - ]); + return ([ + 'signed' => true, + 'data' => $data, + 'data_type' => $data_type, + 'encoding' => $encoding, + 'alg' => $algorithm, + 'sigs' => [ + 'value' => $signature, + 'key_id' => base64url_encode($key_id, true) + ] + ]); - } + } - static function verify($x) { + public static function verify($x) + { - logger('verify'); - $ret = [ 'results' => [] ]; + logger('verify'); + $ret = ['results' => []]; - if(! is_array($x)) { - return false; - } - if(! ( array_key_exists('signed',$x) && $x['signed'])) { - return false; - } + if (!is_array($x)) { + return false; + } + if (!(array_key_exists('signed', $x) && $x['signed'])) { + return false; + } - $signed_data = preg_replace('/\s+/','',$x['data']) . '.' - . base64url_encode($x['data_type'],true) . '.' - . base64url_encode($x['encoding'],true) . '.' - . base64url_encode($x['alg'],true); + $signed_data = preg_replace('/\s+/', '', $x['data']) . '.' + . base64url_encode($x['data_type'], true) . '.' + . base64url_encode($x['encoding'], true) . '.' + . base64url_encode($x['alg'], true); - $key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id'])); - logger('key: ' . print_r($key,true)); - if($key['portable_id'] && $key['public_key']) { - if(Crypto::verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) { - logger('verified'); - $ret = [ 'success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc'] ]; - } - } + $key = HTTPSig::get_key(EMPTY_STR, 'zot6', base64url_decode($x['sigs']['key_id'])); + logger('key: ' . print_r($key, true)); + if ($key['portable_id'] && $key['public_key']) { + if (Crypto::verify($signed_data, base64url_decode($x['sigs']['value']), $key['public_key'])) { + logger('verified'); + $ret = ['success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc']]; + } + } - return $ret; + return $ret; - } + } - static function unpack($data) { - return json_decode(base64url_decode($data),true); - } + public static function unpack($data) + { + return json_decode(base64url_decode($data), true); + } } \ No newline at end of file diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php index 85d3dfd7f..737b2b199 100644 --- a/Zotlabs/Lib/LDSignatures.php +++ b/Zotlabs/Lib/LDSignatures.php @@ -7,127 +7,134 @@ use Zotlabs\Lib\Activity; require_once('library/jsonld/jsonld.php'); -class LDSignatures { +class LDSignatures +{ - static function verify($data,$pubkey) { + public static function verify($data, $pubkey) + { - $ohash = self::hash(self::signable_options($data['signature'])); - $dhash = self::hash(self::signable_data($data)); + $ohash = self::hash(self::signable_options($data['signature'])); + $dhash = self::hash(self::signable_data($data)); - $x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey); - logger('LD-verify: ' . intval($x)); + $x = Crypto::verify($ohash . $dhash, base64_decode($data['signature']['signatureValue']), $pubkey); + logger('LD-verify: ' . intval($x)); - return $x; - } + return $x; + } - static function dopplesign(&$data,$channel) { - // remove for the time being - performance issues - // $data['magicEnv'] = self::salmon_sign($data,$channel); - return self::sign($data,$channel); - } + public static function dopplesign(&$data, $channel) + { + // remove for the time being - performance issues + // $data['magicEnv'] = self::salmon_sign($data,$channel); + return self::sign($data, $channel); + } - static function sign($data,$channel) { + public static function sign($data, $channel) + { - $options = [ - 'type' => 'RsaSignature2017', - 'nonce' => random_string(64), - 'creator' => channel_url($channel), - 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\TH:i:s\Z') - ]; + $options = [ + 'type' => 'RsaSignature2017', + 'nonce' => random_string(64), + 'creator' => channel_url($channel), + 'created' => datetime_convert('UTC', 'UTC', 'now', 'Y-m-d\TH:i:s\Z') + ]; - $ohash = self::hash(self::signable_options($options)); - $dhash = self::hash(self::signable_data($data)); - $options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash,$channel['channel_prvkey'])); + $ohash = self::hash(self::signable_options($options)); + $dhash = self::hash(self::signable_data($data)); + $options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash, $channel['channel_prvkey'])); - return $options; - } + return $options; + } - static function signable_data($data) { + public static function signable_data($data) + { - $newdata = []; - if($data) { - foreach($data as $k => $v) { - if(! in_array($k,[ 'signature' ])) { - $newdata[$k] = $v; - } - } - } - return json_encode($newdata,JSON_UNESCAPED_SLASHES); - } + $newdata = []; + if ($data) { + foreach ($data as $k => $v) { + if (!in_array($k, ['signature'])) { + $newdata[$k] = $v; + } + } + } + return json_encode($newdata, JSON_UNESCAPED_SLASHES); + } - static function signable_options($options) { + public static function signable_options($options) + { - $newopts = [ '@context' => 'https://w3id.org/identity/v1' ]; - if($options) { - foreach($options as $k => $v) { - if(! in_array($k,[ 'type','id','signatureValue' ])) { - $newopts[$k] = $v; - } - } - } - return json_encode($newopts,JSON_UNESCAPED_SLASHES); - } + $newopts = ['@context' => 'https://w3id.org/identity/v1']; + if ($options) { + foreach ($options as $k => $v) { + if (!in_array($k, ['type', 'id', 'signatureValue'])) { + $newopts[$k] = $v; + } + } + } + return json_encode($newopts, JSON_UNESCAPED_SLASHES); + } - static function hash($obj) { + public static function hash($obj) + { - return hash('sha256',self::normalise($obj)); - } + return hash('sha256', self::normalise($obj)); + } - static function normalise($data) { - if(is_string($data)) { - $data = json_decode($data); - } + public static function normalise($data) + { + if (is_string($data)) { + $data = json_decode($data); + } - if(! is_object($data)) - return ''; + if (!is_object($data)) + return ''; - jsonld_set_document_loader('jsonld_document_loader'); - - try { - $d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); - } - catch (Exception $e) { - // Don't log the exception - this can exhaust memory - // logger('normalise error:' . print_r($e,true)); - logger('normalise error: ' . print_r($data,true)); - } + jsonld_set_document_loader('jsonld_document_loader'); - return $d; - } + try { + $d = jsonld_normalize($data, ['algorithm' => 'URDNA2015', 'format' => 'application/nquads']); + } catch (Exception $e) { + // Don't log the exception - this can exhaust memory + // logger('normalise error:' . print_r($e,true)); + logger('normalise error: ' . print_r($data, true)); + } - static function salmon_sign($data,$channel) { + return $d; + } - $arr = $data; - $data = json_encode($data,JSON_UNESCAPED_SLASHES); - $data = base64url_encode($data, false); // do not strip padding - $data_type = 'application/activity+json'; - $encoding = 'base64url'; - $algorithm = 'RSA-SHA256'; - $keyhash = base64url_encode(channel_url($channel)); + public static function salmon_sign($data, $channel) + { - $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$data); + $arr = $data; + $data = json_encode($data, JSON_UNESCAPED_SLASHES); + $data = base64url_encode($data, false); // do not strip padding + $data_type = 'application/activity+json'; + $encoding = 'base64url'; + $algorithm = 'RSA-SHA256'; + $keyhash = base64url_encode(channel_url($channel)); - // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods + $data = str_replace(array(" ", "\t", "\r", "\n"), array("", "", "", ""), $data); - $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng=='; + // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods - $signature = base64url_encode(Crypto::sign($data . $precomputed,$channel['channel_prvkey'])); + $precomputed = '.' . base64url_encode($data_type, false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng=='; - return ([ - 'id' => $arr['id'], - 'meData' => $data, - 'meDataType' => $data_type, - 'meEncoding' => $encoding, - 'meAlgorithm' => $algorithm, - 'meCreator' => channel_url($channel), - 'meSignatureValue' => $signature - ]); + $signature = base64url_encode(Crypto::sign($data . $precomputed, $channel['channel_prvkey'])); - } + return ([ + 'id' => $arr['id'], + 'meData' => $data, + 'meDataType' => $data_type, + 'meEncoding' => $encoding, + 'meAlgorithm' => $algorithm, + 'meCreator' => channel_url($channel), + 'meSignatureValue' => $signature + ]); + } } \ No newline at end of file diff --git a/Zotlabs/Lib/LibBlock.php b/Zotlabs/Lib/LibBlock.php index 21509eb96..25948ddb8 100644 --- a/Zotlabs/Lib/LibBlock.php +++ b/Zotlabs/Lib/LibBlock.php @@ -3,108 +3,114 @@ namespace Zotlabs\Lib; -class LibBlock { +class LibBlock +{ - static $cache = []; - static $empty = []; + static public $cache = []; + static public $empty = []; - // This limits the number of DB queries for fetch_by_entity to once per page load. - - static function fetch_from_cache($channel_id,$entity) { - if (! isset(self::$cache[$channel_id])) { - if (! isset(self::$empty[$channel_id])) { - self::$cache[$channel_id] = self::fetch($channel_id); - if (! self::$cache[$channel_id]) { - self::$empty[$channel_id] = true; - } - } - } - if (isset(self::$cache[$channel_id]) && self::$cache[$channel_id] && is_array(self::$cache[$channel_id])) { - foreach (self::$cache[$channel_id] as $entry) { - if (is_array($entry) && strcasecmp($entry['block_entity'],$entity) === 0) { - return $entry; - } - } - } - return false; - } + // This limits the number of DB queries for fetch_by_entity to once per page load. + + public static function fetch_from_cache($channel_id, $entity) + { + if (!isset(self::$cache[$channel_id])) { + if (!isset(self::$empty[$channel_id])) { + self::$cache[$channel_id] = self::fetch($channel_id); + if (!self::$cache[$channel_id]) { + self::$empty[$channel_id] = true; + } + } + } + if (isset(self::$cache[$channel_id]) && self::$cache[$channel_id] && is_array(self::$cache[$channel_id])) { + foreach (self::$cache[$channel_id] as $entry) { + if (is_array($entry) && strcasecmp($entry['block_entity'], $entity) === 0) { + return $entry; + } + } + } + return false; + } - static function store($arr) { + public static function store($arr) + { - $arr['block_entity'] = trim($arr['block_entity']); + $arr['block_entity'] = trim($arr['block_entity']); - if (! $arr['block_entity']) { - return false; - } - - $arr['block_channel_id'] = ((array_key_exists('block_channel_id',$arr)) ? intval($arr['block_channel_id']) : 0); - $arr['block_type'] = ((array_key_exists('block_type',$arr)) ? intval($arr['block_type']) : BLOCKTYPE_CHANNEL ); - $arr['block_comment'] = ((array_key_exists('block_comment',$arr)) ? escape_tags(trim($arr['block_comment'])) : EMPTY_STR); + if (!$arr['block_entity']) { + return false; + } - if (! intval($arr['block_id'])) { - $r = q("select * from block where block_channel_id = %d and block_entity = '%s' and block_type = %d limit 1", - intval($arr['block_channel_id']), - dbesc($arr['block_entity']), - intval($arr['block_type']) - ); - if ($r) { - $arr['block_id'] = $r[0]['block_id']; - } - } + $arr['block_channel_id'] = ((array_key_exists('block_channel_id', $arr)) ? intval($arr['block_channel_id']) : 0); + $arr['block_type'] = ((array_key_exists('block_type', $arr)) ? intval($arr['block_type']) : BLOCKTYPE_CHANNEL); + $arr['block_comment'] = ((array_key_exists('block_comment', $arr)) ? escape_tags(trim($arr['block_comment'])) : EMPTY_STR); - if (intval($arr['block_id'])) { - return q("UPDATE block set block_channel_id = %d, block_entity = '%s', block_type = %d, block_comment = '%s' where block_id = %d", - intval($arr['block_channel_id']), - dbesc($arr['block_entity']), - intval($arr['block_type']), - dbesc($arr['block_comment']), - intval($arr['block_id']) - ); - } - else { - return create_table_from_array('block',$arr); - } - } + if (!intval($arr['block_id'])) { + $r = q("select * from block where block_channel_id = %d and block_entity = '%s' and block_type = %d limit 1", + intval($arr['block_channel_id']), + dbesc($arr['block_entity']), + intval($arr['block_type']) + ); + if ($r) { + $arr['block_id'] = $r[0]['block_id']; + } + } - static function remove($channel_id,$entity) { - return q("delete from block where block_channel_id = %d and block_entity = '%s'", - intval($channel_id), - dbesc($entity) - ); - } + if (intval($arr['block_id'])) { + return q("UPDATE block set block_channel_id = %d, block_entity = '%s', block_type = %d, block_comment = '%s' where block_id = %d", + intval($arr['block_channel_id']), + dbesc($arr['block_entity']), + intval($arr['block_type']), + dbesc($arr['block_comment']), + intval($arr['block_id']) + ); + } else { + return create_table_from_array('block', $arr); + } + } - static function fetch_by_id($channel_id,$id) { - if (! intval($channel_id)) { - return false; - } - $r = q("select * from block where block_channel_id = %d and block_id = %d ", - intval($channel_id) - ); - return (($r) ? array_shift($r) : $r); - } + public static function remove($channel_id, $entity) + { + return q("delete from block where block_channel_id = %d and block_entity = '%s'", + intval($channel_id), + dbesc($entity) + ); + } + + public static function fetch_by_id($channel_id, $id) + { + if (!intval($channel_id)) { + return false; + } + $r = q("select * from block where block_channel_id = %d and block_id = %d ", + intval($channel_id) + ); + return (($r) ? array_shift($r) : $r); + } - static function fetch_by_entity($channel_id,$entity) { - if (! intval($channel_id)) { - return false; - } + public static function fetch_by_entity($channel_id, $entity) + { + if (!intval($channel_id)) { + return false; + } - return self::fetch_from_cache($channel_id,$entity); - - } + return self::fetch_from_cache($channel_id, $entity); - static function fetch($channel_id,$type = false) { - if (! intval($channel_id)) { - return []; - } + } - $sql_extra = (($type === false) ? EMPTY_STR : " and block_type = " . intval($type)); - - $r = q("select * from block where block_channel_id = %d $sql_extra", - intval($channel_id) - ); - return $r; - } + public static function fetch($channel_id, $type = false) + { + if (!intval($channel_id)) { + return []; + } + + $sql_extra = (($type === false) ? EMPTY_STR : " and block_type = " . intval($type)); + + $r = q("select * from block where block_channel_id = %d $sql_extra", + intval($channel_id) + ); + return $r; + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Libprofile.php b/Zotlabs/Lib/Libprofile.php index 622345901..27611f13c 100644 --- a/Zotlabs/Lib/Libprofile.php +++ b/Zotlabs/Lib/Libprofile.php @@ -4,454 +4,459 @@ namespace Zotlabs\Lib; use App; -class Libprofile { +class Libprofile +{ + /** + * @brief Loads a profile into the App structure. + * + * The function requires the nickname of a valid channel. + * + * Permissions of the current observer are checked. If a restricted profile is available + * to the current observer, that will be loaded instead of the channel default profile. + * + * The channel owner can set $profile to a valid profile_guid to preview that profile. + * + * The channel default theme is also selected for use, unless over-riden elsewhere. + * + * @param string $nickname + * @param string $profile_guid + */ - /** - * @brief Loads a profile into the App structure. - * - * The function requires the nickname of a valid channel. - * - * Permissions of the current observer are checked. If a restricted profile is available - * to the current observer, that will be loaded instead of the channel default profile. - * - * The channel owner can set $profile to a valid profile_guid to preview that profile. - * - * The channel default theme is also selected for use, unless over-riden elsewhere. - * - * @param string $nickname - * @param string $profile_guid - */ + public static function load($nickname, $profile = '') + { - static function load($nickname, $profile = '') { + // logger('Libprofile::load: ' . $nickname . (($profile) ? ' profile: ' . $profile : '')); - // logger('Libprofile::load: ' . $nickname . (($profile) ? ' profile: ' . $profile : '')); + $channel = channelx_by_nick($nickname); - $channel = channelx_by_nick($nickname); - - if (! $channel) { - logger('profile error: ' . App::$query_string, LOGGER_DEBUG); - notice( t('Requested channel is not available.') . EOL ); - App::$error = 404; - return; - } + if (!$channel) { + logger('profile error: ' . App::$query_string, LOGGER_DEBUG); + notice(t('Requested channel is not available.') . EOL); + App::$error = 404; + return; + } - // get the current observer - $observer = App::get_observer(); + // get the current observer + $observer = App::get_observer(); - $can_view_profile = true; + $can_view_profile = true; - // Can the observer see our profile? - require_once('include/permissions.php'); - if (! perm_is_allowed($channel['channel_id'],(($observer) ? $observer['xchan_hash'] : ''),'view_profile')) { - $can_view_profile = false; - } + // Can the observer see our profile? + require_once('include/permissions.php'); + if (!perm_is_allowed($channel['channel_id'], (($observer) ? $observer['xchan_hash'] : ''), 'view_profile')) { + $can_view_profile = false; + } - if (! $profile) { - $r = q("SELECT abook_profile FROM abook WHERE abook_xchan = '%s' and abook_channel = '%d' limit 1", - dbesc(($observer) ? $observer['xchan_hash'] : ''), - intval($channel['channel_id']) - ); - if ($r) - $profile = $r[0]['abook_profile']; - } + if (!$profile) { + $r = q("SELECT abook_profile FROM abook WHERE abook_xchan = '%s' and abook_channel = '%d' limit 1", + dbesc(($observer) ? $observer['xchan_hash'] : ''), + intval($channel['channel_id']) + ); + if ($r) + $profile = $r[0]['abook_profile']; + } - $p = null; + $p = null; - if ($profile) { - $p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile + if ($profile) { + $p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile LEFT JOIN channel ON profile.uid = channel.channel_id WHERE channel.channel_address = '%s' AND profile.profile_guid = '%s' LIMIT 1", - dbesc($nickname), - dbesc($profile) - ); - if (! $p) { - $p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile + dbesc($nickname), + dbesc($profile) + ); + if (!$p) { + $p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile LEFT JOIN channel ON profile.uid = channel.channel_id WHERE channel.channel_address = '%s' AND profile.id = %d LIMIT 1", - dbesc($nickname), - intval($profile) - ); - } - } + dbesc($nickname), + intval($profile) + ); + } + } - if (! $p) { - $p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile + if (!$p) { + $p = q("SELECT profile.uid AS profile_uid, profile.*, channel.* FROM profile LEFT JOIN channel ON profile.uid = channel.channel_id WHERE channel.channel_address = '%s' and channel_removed = 0 AND profile.is_default = 1 LIMIT 1", - dbesc($nickname) - ); - } - - if (! $p) { - logger('profile error: ' . App::$query_string, LOGGER_DEBUG); - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } - - $q = q("select * from profext where hash = '%s' and channel_id = %d", - dbesc($p[0]['profile_guid']), - intval($p[0]['profile_uid']) - ); - if ($q) { - - $extra_fields = []; - - $profile_fields_basic = get_profile_fields_basic(); - $profile_fields_advanced = get_profile_fields_advanced(); - - $advanced = ((feature_enabled(local_channel(),'advanced_profiles')) ? true : false); - if ($advanced) - $fields = $profile_fields_advanced; - else - $fields = $profile_fields_basic; - - foreach ($q as $qq) { - foreach ($fields as $k => $f) { - if ($k == $qq['k']) { - $p[0][$k] = $qq['v']; - $extra_fields[] = $k; - break; - } - } - } - } - - $p[0]['extra_fields'] = ((isset($extra_fields)) ? $extra_fields : []); - - $z = q("select xchan_photo_date, xchan_addr from xchan where xchan_hash = '%s' limit 1", - dbesc($p[0]['channel_hash']) - ); - if ($z) { - $p[0]['picdate'] = $z[0]['xchan_photo_date']; - $p[0]['reddress'] = str_replace('@','@',unpunify($z[0]['xchan_addr'])); - } - - // fetch user tags if this isn't the default profile - - if (! $p[0]['is_default']) { - $x = q("select keywords from profile where uid = %d and is_default = 1 limit 1", - intval($p[0]['profile_uid']) - ); - if ($x && $can_view_profile) - $p[0]['keywords'] = $x[0]['keywords']; - } - - if ($p[0]['keywords']) { - $keywords = str_replace(array('#',',',' ',',,'),array('',' ',',',','),$p[0]['keywords']); - if (strlen($keywords) && $can_view_profile) { - if (! isset(App::$page['htmlhead'])) { - App::$page['htmlhead'] = EMPTY_STR; - } - App::$page['htmlhead'] .= '' . "\r\n" ; - } - } - - App::$profile = $p[0]; - App::$profile_uid = $p[0]['profile_uid']; - App::$page['title'] = App::$profile['channel_name'] . " - " . unpunify(channel_reddress(App::$profile)); - - App::$profile['permission_to_view'] = $can_view_profile; - - if ($can_view_profile) { - $online = get_online_status($nickname); - App::$profile['online_status'] = $online['result']; - } - - if (local_channel()) { - App::$profile['channel_mobile_theme'] = get_pconfig(local_channel(),'system', 'mobile_theme'); - $_SESSION['mobile_theme'] = App::$profile['channel_mobile_theme']; - } - - /* - * load/reload current theme info - */ - - // $_SESSION['theme'] = $p[0]['channel_theme']; - - } - - static function edit_menu($uid) { - - $ret = []; - - $is_owner = (($uid == local_channel()) ? true : false); - - // show edit profile to profile owner - if ($is_owner) { - $ret['menu'] = array( - 'chg_photo' => t('Change profile photo'), - 'entries' => [], - ); - - $multi_profiles = feature_enabled(local_channel(), 'multi_profiles'); - if ($multi_profiles) { - $ret['multi'] = 1; - $ret['edit'] = [ z_root(). '/profiles', t('Edit Profiles'), '', t('Edit') ]; - $ret['menu']['cr_new'] = t('Create New Profile'); - } - else { - $ret['edit'] = [ z_root() . '/profiles/' . $uid, t('Edit Profile'), '', t('Edit') ]; - } - - $r = q("SELECT * FROM profile WHERE uid = %d", - local_channel() - ); - - if($r) { - foreach($r as $rr) { - if(!($multi_profiles || $rr['is_default'])) - continue; - - $ret['menu']['entries'][] = [ - 'photo' => $rr['thumb'], - 'id' => $rr['id'], - 'alt' => t('Profile Image'), - 'profile_name' => $rr['profile_name'], - 'isdefault' => $rr['is_default'], - 'visible_to_everybody' => t('Visible to everybody'), - 'edit_visibility' => t('Edit visibility'), - ]; - } - } - } - - return $ret; - } - - /** - * @brief Formats a profile for display in the sidebar. - * - * It is very difficult to templatise the HTML completely - * because of all the conditional logic. - * - * @param array $profile - * @param int $block - * @param boolean $show_connect (optional) default true - * @param mixed $zcard (optional) default false - * - * @return HTML string suitable for sidebar inclusion - * Exceptions: Returns empty string if passed $profile is wrong type or not populated - */ - - static function widget($profile, $block = 0, $show_connect = true, $zcard = false) { - - $observer = App::get_observer(); - - $o = ''; - $location = false; - $pdesc = true; - $reddress = true; - - if(! perm_is_allowed($profile['uid'],((is_array($observer)) ? $observer['xchan_hash'] : ''),'view_profile')) { - $block = true; - } - - if((! is_array($profile)) && (! count($profile))) - return $o; - - head_set_icon($profile['thumb']); - - if(is_sys_channel($profile['uid'])) - $show_connect = false; - - $profile['picdate'] = urlencode($profile['picdate']); - - /** - * @hooks profile_sidebar_enter - * Called before generating the 'channel sidebar' or mini-profile. - */ - call_hooks('profile_sidebar_enter', $profile); - - if($show_connect) { - - // This will return an empty string if we're already connected. - - $connect_url = rconnect_url($profile['uid'],get_observer_hash()); - $connect = (($connect_url) ? t('Connect') : ''); - if($connect_url) - $connect_url = sprintf($connect_url,urlencode(channel_reddress($profile))); - - // premium channel - over-ride - - if($profile['channel_pageflags'] & PAGE_PREMIUM) - $connect_url = z_root() . '/connect/' . $profile['channel_address']; - } - - 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:'); - - $profile['homepage'] = linkify($profile['homepage'],true); - - $gender = ((x($profile,'gender') == 1) ? t('Gender:') : False); - $marital = ((x($profile,'marital') == 1) ? t('Status:') : False); - $homepage = ((x($profile,'homepage') == 1) ? t('Homepage:') : False); - $pronouns = ((x($profile,'pronouns') == 1) ? t('Pronouns:') : False); - - // zap/osada do not have a realtime chat system at this time so don't show online state - // $profile['online'] = (($profile['online_status'] === 'online') ? t('Online Now') : False); - // logger('online: ' . $profile['online']); - - $profile['online'] = false; - - if(($profile['hidewall'] && (! local_channel()) && (! remote_channel())) || $block ) { - $location = $reddress = $pdesc = $gender = $marital = $homepage = False; - } - - if($profile['gender']) { - $profile['gender_icon'] = self::gender_icon($profile['gender']); - } - - if($profile['pronouns']) { - $profile['pronouns_icon'] = self::pronouns_icon($profile['pronouns']); - } - - $firstname = ((strpos($profile['channel_name'],' ')) - ? trim(substr($profile['channel_name'],0,strpos($profile['channel_name'],' '))) : $profile['channel_name']); - $lastname = (($firstname === $profile['channel_name']) ? '' : trim(substr($profile['channel_name'],strlen($firstname)))); - - - $contact_block = contact_block(); - - $channel_menu = false; - $menu = get_pconfig($profile['uid'],'system','channel_menu'); - if($menu && ! $block) { - require_once('include/menu.php'); - $m = menu_fetch($menu,$profile['uid'],$observer['xchan_hash']); - if($m) - $channel_menu = menu_render($m); - } - $menublock = get_pconfig($profile['uid'],'system','channel_menublock'); - if ($menublock && (! $block)) { - $comanche = new Comanche(); - $channel_menu .= $comanche->block($menublock); - } - - if($zcard) - $tpl = get_markup_template('profile_vcard_short.tpl'); - else - $tpl = get_markup_template('profile_vcard.tpl'); - - $o .= replace_macros($tpl, array( - '$zcard' => $zcard, - '$profile' => $profile, - '$connect' => $connect, - '$connect_url' => $connect_url, - '$location' => $location, - '$gender' => $gender, - '$pronouns' => $pronouns, - '$pdesc' => $pdesc, - '$marital' => $marital, - '$homepage' => $homepage, - '$chanmenu' => $channel_menu, - '$reddress' => $reddress, - '$active' => t('Active'), - '$activewhen' => relative_date($profile['channel_lastpost']), - '$rating' => '', - '$contact_block' => $contact_block, - '$change_photo' => t('Change your profile photo'), - '$copyto' => t('Copy to clipboard'), - '$copied' => t('Address copied to clipboard'), - '$editmenu' => self::edit_menu($profile['uid']) - )); - - $arr = [ - 'profile' => $profile, - 'entry' => $o - ]; - - /** - * @hooks profile_sidebar - * Called when generating the 'channel sidebar' or mini-profile. - * * \e array \b profile - * * \e string \b entry - The parsed HTML template - */ - call_hooks('profile_sidebar', $arr); - - return $arr['entry']; - } - - static function gender_icon($gender) { - - // logger('gender: ' . $gender); - - // This can easily get throw off if the observer language is different - // than the channel owner language. - - if(strpos(strtolower($gender),strtolower(t('Female'))) !== false) - return 'venus'; - if(strpos(strtolower($gender),strtolower(t('Male'))) !== false) - return 'mars'; - if(strpos(strtolower($gender),strtolower(t('Trans'))) !== false) - return 'transgender'; - if(strpos(strtolower($gender),strtolower(t('Inter'))) !== false) - return 'transgender'; - if(strpos(strtolower($gender),strtolower(t('Neuter'))) !== false) - return 'neuter'; - if(strpos(strtolower($gender),strtolower(t('Non-specific'))) !== false) - return 'genderless'; - - return ''; - } - - static function pronouns_icon($pronouns) { - - - // This can easily get throw off if the observer language is different - // than the channel owner language. - - if(strpos(strtolower($pronouns),strtolower(t('She'))) !== false) - return 'venus'; - if(strpos(strtolower($pronouns),strtolower(t('Him'))) !== false) - return 'mars'; - if(strpos(strtolower($pronouns),strtolower(t('Them'))) !== false) - return 'users'; - - return ''; - } - - - static function advanced() { - - if(! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),'view_profile')) - return ''; - - if(App::$profile['fullname']) { - - $profile_fields_basic = get_profile_fields_basic(); - $profile_fields_advanced = get_profile_fields_advanced(); - - $advanced = ((feature_enabled(App::$profile['profile_uid'],'advanced_profiles')) ? true : false); - if($advanced) - $fields = $profile_fields_advanced; - else - $fields = $profile_fields_basic; - - $clean_fields = []; - if($fields) { - foreach($fields as $k => $v) { - $clean_fields[] = trim($k); - } - } + dbesc($nickname) + ); + } + + if (!$p) { + logger('profile error: ' . App::$query_string, LOGGER_DEBUG); + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } + + $q = q("select * from profext where hash = '%s' and channel_id = %d", + dbesc($p[0]['profile_guid']), + intval($p[0]['profile_uid']) + ); + if ($q) { + + $extra_fields = []; + + $profile_fields_basic = get_profile_fields_basic(); + $profile_fields_advanced = get_profile_fields_advanced(); + + $advanced = ((feature_enabled(local_channel(), 'advanced_profiles')) ? true : false); + if ($advanced) + $fields = $profile_fields_advanced; + else + $fields = $profile_fields_basic; + + foreach ($q as $qq) { + foreach ($fields as $k => $f) { + if ($k == $qq['k']) { + $p[0][$k] = $qq['v']; + $extra_fields[] = $k; + break; + } + } + } + } + + $p[0]['extra_fields'] = ((isset($extra_fields)) ? $extra_fields : []); + + $z = q("select xchan_photo_date, xchan_addr from xchan where xchan_hash = '%s' limit 1", + dbesc($p[0]['channel_hash']) + ); + if ($z) { + $p[0]['picdate'] = $z[0]['xchan_photo_date']; + $p[0]['reddress'] = str_replace('@', '@', unpunify($z[0]['xchan_addr'])); + } + + // fetch user tags if this isn't the default profile + + if (!$p[0]['is_default']) { + $x = q("select keywords from profile where uid = %d and is_default = 1 limit 1", + intval($p[0]['profile_uid']) + ); + if ($x && $can_view_profile) + $p[0]['keywords'] = $x[0]['keywords']; + } + + if ($p[0]['keywords']) { + $keywords = str_replace(array('#', ',', ' ', ',,'), array('', ' ', ',', ','), $p[0]['keywords']); + if (strlen($keywords) && $can_view_profile) { + if (!isset(App::$page['htmlhead'])) { + App::$page['htmlhead'] = EMPTY_STR; + } + App::$page['htmlhead'] .= '' . "\r\n"; + } + } + + App::$profile = $p[0]; + App::$profile_uid = $p[0]['profile_uid']; + App::$page['title'] = App::$profile['channel_name'] . " - " . unpunify(channel_reddress(App::$profile)); + + App::$profile['permission_to_view'] = $can_view_profile; + + if ($can_view_profile) { + $online = get_online_status($nickname); + App::$profile['online_status'] = $online['result']; + } + + if (local_channel()) { + App::$profile['channel_mobile_theme'] = get_pconfig(local_channel(), 'system', 'mobile_theme'); + $_SESSION['mobile_theme'] = App::$profile['channel_mobile_theme']; + } + + /* + * load/reload current theme info + */ + + // $_SESSION['theme'] = $p[0]['channel_theme']; + + } + + public static function edit_menu($uid) + { + + $ret = []; + + $is_owner = (($uid == local_channel()) ? true : false); + + // show edit profile to profile owner + if ($is_owner) { + $ret['menu'] = array( + 'chg_photo' => t('Change profile photo'), + 'entries' => [], + ); + + $multi_profiles = feature_enabled(local_channel(), 'multi_profiles'); + if ($multi_profiles) { + $ret['multi'] = 1; + $ret['edit'] = [z_root() . '/profiles', t('Edit Profiles'), '', t('Edit')]; + $ret['menu']['cr_new'] = t('Create New Profile'); + } else { + $ret['edit'] = [z_root() . '/profiles/' . $uid, t('Edit Profile'), '', t('Edit')]; + } + + $r = q("SELECT * FROM profile WHERE uid = %d", + local_channel() + ); + + if ($r) { + foreach ($r as $rr) { + if (!($multi_profiles || $rr['is_default'])) + continue; + + $ret['menu']['entries'][] = [ + 'photo' => $rr['thumb'], + 'id' => $rr['id'], + 'alt' => t('Profile Image'), + 'profile_name' => $rr['profile_name'], + 'isdefault' => $rr['is_default'], + 'visible_to_everybody' => t('Visible to everybody'), + 'edit_visibility' => t('Edit visibility'), + ]; + } + } + } + + return $ret; + } + + /** + * @brief Formats a profile for display in the sidebar. + * + * It is very difficult to templatise the HTML completely + * because of all the conditional logic. + * + * @param array $profile + * @param int $block + * @param bool $show_connect (optional) default true + * @param mixed $zcard (optional) default false + * + * @return HTML string suitable for sidebar inclusion + * Exceptions: Returns empty string if passed $profile is wrong type or not populated + */ + + public static function widget($profile, $block = 0, $show_connect = true, $zcard = false) + { + + $observer = App::get_observer(); + + $o = ''; + $location = false; + $pdesc = true; + $reddress = true; + + if (!perm_is_allowed($profile['uid'], ((is_array($observer)) ? $observer['xchan_hash'] : ''), 'view_profile')) { + $block = true; + } + + if ((!is_array($profile)) && (!count($profile))) + return $o; + + head_set_icon($profile['thumb']); + + if (is_sys_channel($profile['uid'])) + $show_connect = false; + + $profile['picdate'] = urlencode($profile['picdate']); + + /** + * @hooks profile_sidebar_enter + * Called before generating the 'channel sidebar' or mini-profile. + */ + call_hooks('profile_sidebar_enter', $profile); + + if ($show_connect) { + + // This will return an empty string if we're already connected. + + $connect_url = rconnect_url($profile['uid'], get_observer_hash()); + $connect = (($connect_url) ? t('Connect') : ''); + if ($connect_url) + $connect_url = sprintf($connect_url, urlencode(channel_reddress($profile))); + + // premium channel - over-ride + + if ($profile['channel_pageflags'] & PAGE_PREMIUM) + $connect_url = z_root() . '/connect/' . $profile['channel_address']; + } + + 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:'); + + $profile['homepage'] = linkify($profile['homepage'], true); + + $gender = ((x($profile, 'gender') == 1) ? t('Gender:') : False); + $marital = ((x($profile, 'marital') == 1) ? t('Status:') : False); + $homepage = ((x($profile, 'homepage') == 1) ? t('Homepage:') : False); + $pronouns = ((x($profile, 'pronouns') == 1) ? t('Pronouns:') : False); + + // zap/osada do not have a realtime chat system at this time so don't show online state + // $profile['online'] = (($profile['online_status'] === 'online') ? t('Online Now') : False); + // logger('online: ' . $profile['online']); + + $profile['online'] = false; + + if (($profile['hidewall'] && (!local_channel()) && (!remote_channel())) || $block) { + $location = $reddress = $pdesc = $gender = $marital = $homepage = False; + } + + if ($profile['gender']) { + $profile['gender_icon'] = self::gender_icon($profile['gender']); + } + + if ($profile['pronouns']) { + $profile['pronouns_icon'] = self::pronouns_icon($profile['pronouns']); + } + + $firstname = ((strpos($profile['channel_name'], ' ')) + ? trim(substr($profile['channel_name'], 0, strpos($profile['channel_name'], ' '))) : $profile['channel_name']); + $lastname = (($firstname === $profile['channel_name']) ? '' : trim(substr($profile['channel_name'], strlen($firstname)))); + + + $contact_block = contact_block(); + + $channel_menu = false; + $menu = get_pconfig($profile['uid'], 'system', 'channel_menu'); + if ($menu && !$block) { + require_once('include/menu.php'); + $m = menu_fetch($menu, $profile['uid'], $observer['xchan_hash']); + if ($m) + $channel_menu = menu_render($m); + } + $menublock = get_pconfig($profile['uid'], 'system', 'channel_menublock'); + if ($menublock && (!$block)) { + $comanche = new Comanche(); + $channel_menu .= $comanche->block($menublock); + } + + if ($zcard) + $tpl = get_markup_template('profile_vcard_short.tpl'); + else + $tpl = get_markup_template('profile_vcard.tpl'); + + $o .= replace_macros($tpl, array( + '$zcard' => $zcard, + '$profile' => $profile, + '$connect' => $connect, + '$connect_url' => $connect_url, + '$location' => $location, + '$gender' => $gender, + '$pronouns' => $pronouns, + '$pdesc' => $pdesc, + '$marital' => $marital, + '$homepage' => $homepage, + '$chanmenu' => $channel_menu, + '$reddress' => $reddress, + '$active' => t('Active'), + '$activewhen' => relative_date($profile['channel_lastpost']), + '$rating' => '', + '$contact_block' => $contact_block, + '$change_photo' => t('Change your profile photo'), + '$copyto' => t('Copy to clipboard'), + '$copied' => t('Address copied to clipboard'), + '$editmenu' => self::edit_menu($profile['uid']) + )); + + $arr = [ + 'profile' => $profile, + 'entry' => $o + ]; + + /** + * @hooks profile_sidebar + * Called when generating the 'channel sidebar' or mini-profile. + * * \e array \b profile + * * \e string \b entry - The parsed HTML template + */ + call_hooks('profile_sidebar', $arr); + + return $arr['entry']; + } + + public static function gender_icon($gender) + { + + // logger('gender: ' . $gender); + + // This can easily get throw off if the observer language is different + // than the channel owner language. + + if (strpos(strtolower($gender), strtolower(t('Female'))) !== false) + return 'venus'; + if (strpos(strtolower($gender), strtolower(t('Male'))) !== false) + return 'mars'; + if (strpos(strtolower($gender), strtolower(t('Trans'))) !== false) + return 'transgender'; + if (strpos(strtolower($gender), strtolower(t('Inter'))) !== false) + return 'transgender'; + if (strpos(strtolower($gender), strtolower(t('Neuter'))) !== false) + return 'neuter'; + if (strpos(strtolower($gender), strtolower(t('Non-specific'))) !== false) + return 'genderless'; + + return ''; + } + + public static function pronouns_icon($pronouns) + { + + + // This can easily get throw off if the observer language is different + // than the channel owner language. + + if (strpos(strtolower($pronouns), strtolower(t('She'))) !== false) + return 'venus'; + if (strpos(strtolower($pronouns), strtolower(t('Him'))) !== false) + return 'mars'; + if (strpos(strtolower($pronouns), strtolower(t('Them'))) !== false) + return 'users'; + + return ''; + } + + + public static function advanced() + { + + if (!perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_profile')) + return ''; + + if (App::$profile['fullname']) { + + $profile_fields_basic = get_profile_fields_basic(); + $profile_fields_advanced = get_profile_fields_advanced(); + + $advanced = ((feature_enabled(App::$profile['profile_uid'], 'advanced_profiles')) ? true : false); + if ($advanced) + $fields = $profile_fields_advanced; + else + $fields = $profile_fields_basic; + + $clean_fields = []; + if ($fields) { + foreach ($fields as $k => $v) { + $clean_fields[] = trim($k); + } + } + + $tpl = get_markup_template('profile_advanced.tpl'); - $tpl = get_markup_template('profile_advanced.tpl'); + $profile = []; - $profile = []; + $profile['fullname'] = array(t('Full Name:'), App::$profile['fullname']); - $profile['fullname'] = array( t('Full Name:'), App::$profile['fullname'] ) ; + if (App::$profile['gender']) $profile['gender'] = array(t('Gender:'), App::$profile['gender']); - if(App::$profile['gender']) $profile['gender'] = array( t('Gender:'), App::$profile['gender'] ); - - $ob_hash = get_observer_hash(); + $ob_hash = get_observer_hash(); // this may not work at all any more, but definitely won't work correctly if the liked profile belongs to a group // comment out until we are able to look at it much closer // if($ob_hash && perm_is_allowed(App::$profile['profile_uid'],$ob_hash,'post_like')) { @@ -474,138 +479,121 @@ class Libprofile { // $profile['likers'][] = array('name' => $l['xchan_name'],'photo' => zid($l['xchan_photo_s']), 'url' => zid($l['xchan_url'])); // } - if((App::$profile['dob']) && (App::$profile['dob'] != '0000-00-00')) { + if ((App::$profile['dob']) && (App::$profile['dob'] != '0000-00-00')) { - $val = ''; + $val = ''; - if((substr(App::$profile['dob'],5,2) === '00') || (substr(App::$profile['dob'],8,2) === '00')) - $val = substr(App::$profile['dob'],0,4); + if ((substr(App::$profile['dob'], 5, 2) === '00') || (substr(App::$profile['dob'], 8, 2) === '00')) + $val = substr(App::$profile['dob'], 0, 4); - $year_bd_format = t('j F, Y'); - $short_bd_format = t('j F'); + $year_bd_format = t('j F, Y'); + $short_bd_format = t('j F'); - if(! $val) { - $val = ((intval(App::$profile['dob'])) - ? day_translate(datetime_convert('UTC','UTC',App::$profile['dob'] . ' 00:00 +00:00',$year_bd_format)) - : day_translate(datetime_convert('UTC','UTC','2001-' . substr(App::$profile['dob'],5) . ' 00:00 +00:00',$short_bd_format))); - } - $profile['birthday'] = array( t('Birthday:'), $val); - } + if (!$val) { + $val = ((intval(App::$profile['dob'])) + ? day_translate(datetime_convert('UTC', 'UTC', App::$profile['dob'] . ' 00:00 +00:00', $year_bd_format)) + : day_translate(datetime_convert('UTC', 'UTC', '2001-' . substr(App::$profile['dob'], 5) . ' 00:00 +00:00', $short_bd_format))); + } + $profile['birthday'] = array(t('Birthday:'), $val); + } - if($age = age(App::$profile['dob'],App::$profile['timezone'],'')) - $profile['age'] = array( t('Age:'), $age ); + if ($age = age(App::$profile['dob'], App::$profile['timezone'], '')) + $profile['age'] = array(t('Age:'), $age); - if(App::$profile['marital']) - $profile['marital'] = array( t('Status:'), App::$profile['marital']); + if (App::$profile['marital']) + $profile['marital'] = array(t('Status:'), App::$profile['marital']); - if(App::$profile['partner']) - $profile['marital']['partner'] = zidify_links(bbcode(App::$profile['partner'])); + if (App::$profile['partner']) + $profile['marital']['partner'] = zidify_links(bbcode(App::$profile['partner'])); - if(strlen(App::$profile['howlong']) && App::$profile['howlong'] > NULL_DATE) { - $profile['howlong'] = relative_date(App::$profile['howlong'], t('for %1$d %2$s')); - } + if (strlen(App::$profile['howlong']) && App::$profile['howlong'] > NULL_DATE) { + $profile['howlong'] = relative_date(App::$profile['howlong'], t('for %1$d %2$s')); + } - if(App::$profile['keywords']) { - $keywords = str_replace(',',' ', App::$profile['keywords']); - $keywords = str_replace(' ',' ', $keywords); - $karr = explode(' ', $keywords); - if($karr) { - for($cnt = 0; $cnt < count($karr); $cnt ++) { - $karr[$cnt] = '' . $karr[$cnt] . ''; - } - } - $profile['keywords'] = array( t('Tags:'), implode(' ', $karr)); - } + if (App::$profile['keywords']) { + $keywords = str_replace(',', ' ', App::$profile['keywords']); + $keywords = str_replace(' ', ' ', $keywords); + $karr = explode(' ', $keywords); + if ($karr) { + for ($cnt = 0; $cnt < count($karr); $cnt++) { + $karr[$cnt] = '' . $karr[$cnt] . ''; + } + } + $profile['keywords'] = array(t('Tags:'), implode(' ', $karr)); + } - if(App::$profile['sexual']) $profile['sexual'] = array( t('Sexual Preference:'), App::$profile['sexual'] ); + if (App::$profile['sexual']) $profile['sexual'] = array(t('Sexual Preference:'), App::$profile['sexual']); - if(App::$profile['pronouns']) $profile['pronouns'] = array( t('Pronouns:'), App::$profile['pronouns'] ); + if (App::$profile['pronouns']) $profile['pronouns'] = array(t('Pronouns:'), App::$profile['pronouns']); - if(App::$profile['homepage']) $profile['homepage'] = array( t('Homepage:'), linkify(App::$profile['homepage']) ); + if (App::$profile['homepage']) $profile['homepage'] = array(t('Homepage:'), linkify(App::$profile['homepage'])); - if(App::$profile['hometown']) $profile['hometown'] = array( t('Hometown:'), linkify(App::$profile['hometown']) ); + if (App::$profile['hometown']) $profile['hometown'] = array(t('Hometown:'), linkify(App::$profile['hometown'])); - if(App::$profile['politic']) $profile['politic'] = array( t('Political Views:'), App::$profile['politic']); + if (App::$profile['politic']) $profile['politic'] = array(t('Political Views:'), App::$profile['politic']); - if(App::$profile['religion']) $profile['religion'] = array( t('Religion:'), App::$profile['religion']); + if (App::$profile['religion']) $profile['religion'] = array(t('Religion:'), App::$profile['religion']); - if($txt = prepare_text(App::$profile['about'])) $profile['about'] = array( t('About:'), $txt ); + if ($txt = prepare_text(App::$profile['about'])) $profile['about'] = array(t('About:'), $txt); - if($txt = prepare_text(App::$profile['interest'])) $profile['interest'] = array( t('Hobbies/Interests:'), $txt); + if ($txt = prepare_text(App::$profile['interest'])) $profile['interest'] = array(t('Hobbies/Interests:'), $txt); - if($txt = prepare_text(App::$profile['likes'])) $profile['likes'] = array( t('Likes:'), $txt); - - if($txt = prepare_text(App::$profile['dislikes'])) $profile['dislikes'] = array( t('Dislikes:'), $txt); - - if($txt = prepare_text(App::$profile['contact'])) $profile['contact'] = array( t('Contact information and Social Networks:'), $txt); - - if($txt = prepare_text(App::$profile['channels'])) $profile['channels'] = array( t('My other channels:'), $txt); - - if($txt = prepare_text(App::$profile['music'])) $profile['music'] = array( t('Musical interests:'), $txt); - - if($txt = prepare_text(App::$profile['book'])) $profile['book'] = array( t('Books, literature:'), $txt); - - if($txt = prepare_text(App::$profile['tv'])) $profile['tv'] = array( t('Television:'), $txt); - - if($txt = prepare_text(App::$profile['film'])) $profile['film'] = array( t('Film/dance/culture/entertainment:'), $txt); - - if($txt = prepare_text(App::$profile['romance'])) $profile['romance'] = array( t('Love/Romance:'), $txt); - - if($txt = prepare_text(App::$profile['employment'])) $profile['employment'] = array( t('Work/employment:'), $txt); - - if($txt = prepare_text(App::$profile['education'])) $profile['education'] = array( t('School/education:'), $txt ); - - if(App::$profile['extra_fields']) { - foreach(App::$profile['extra_fields'] as $f) { - $x = q("select * from profdef where field_name = '%s' limit 1", - dbesc($f) - ); - if($x && $txt = prepare_text(App::$profile[$f])) - $profile[$f] = array( $x[0]['field_desc'] . ':',$txt); - } - $profile['extra_fields'] = App::$profile['extra_fields']; - } - - $things = get_things(App::$profile['profile_guid'],App::$profile['profile_uid']); - - - // logger('mod_profile: things: ' . print_r($things,true), LOGGER_DATA); - - // $exportlink = ((App::$profile['profile_vcard']) ? zid(z_root() . '/profile/' . App::$profile['channel_address'] . '/vcard') : ''); - - return replace_macros($tpl, array( - '$title' => t('Profile'), - '$canlike' => (($profile['canlike'])? true : false), - '$likethis' => t('Like this thing'), - '$export' => t('Export'), - '$exportlink' => '', // $exportlink, - '$profile' => $profile, - '$fields' => $clean_fields, - '$editmenu' => self::edit_menu(App::$profile['profile_uid']), - '$things' => $things - )); - } - - return ''; - } + if ($txt = prepare_text(App::$profile['likes'])) $profile['likes'] = array(t('Likes:'), $txt); + if ($txt = prepare_text(App::$profile['dislikes'])) $profile['dislikes'] = array(t('Dislikes:'), $txt); + if ($txt = prepare_text(App::$profile['contact'])) $profile['contact'] = array(t('Contact information and Social Networks:'), $txt); + if ($txt = prepare_text(App::$profile['channels'])) $profile['channels'] = array(t('My other channels:'), $txt); + if ($txt = prepare_text(App::$profile['music'])) $profile['music'] = array(t('Musical interests:'), $txt); + if ($txt = prepare_text(App::$profile['book'])) $profile['book'] = array(t('Books, literature:'), $txt); + if ($txt = prepare_text(App::$profile['tv'])) $profile['tv'] = array(t('Television:'), $txt); + if ($txt = prepare_text(App::$profile['film'])) $profile['film'] = array(t('Film/dance/culture/entertainment:'), $txt); + if ($txt = prepare_text(App::$profile['romance'])) $profile['romance'] = array(t('Love/Romance:'), $txt); + if ($txt = prepare_text(App::$profile['employment'])) $profile['employment'] = array(t('Work/employment:'), $txt); + if ($txt = prepare_text(App::$profile['education'])) $profile['education'] = array(t('School/education:'), $txt); + if (App::$profile['extra_fields']) { + foreach (App::$profile['extra_fields'] as $f) { + $x = q("select * from profdef where field_name = '%s' limit 1", + dbesc($f) + ); + if ($x && $txt = prepare_text(App::$profile[$f])) + $profile[$f] = array($x[0]['field_desc'] . ':', $txt); + } + $profile['extra_fields'] = App::$profile['extra_fields']; + } + $things = get_things(App::$profile['profile_guid'], App::$profile['profile_uid']); + // logger('mod_profile: things: ' . print_r($things,true), LOGGER_DATA); + // $exportlink = ((App::$profile['profile_vcard']) ? zid(z_root() . '/profile/' . App::$profile['channel_address'] . '/vcard') : ''); + return replace_macros($tpl, array( + '$title' => t('Profile'), + '$canlike' => (($profile['canlike']) ? true : false), + '$likethis' => t('Like this thing'), + '$export' => t('Export'), + '$exportlink' => '', // $exportlink, + '$profile' => $profile, + '$fields' => $clean_fields, + '$editmenu' => self::edit_menu(App::$profile['profile_uid']), + '$things' => $things + )); + } + return ''; + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php index 912090d43..5a1efe312 100644 --- a/Zotlabs/Lib/Libsync.php +++ b/Zotlabs/Lib/Libsync.php @@ -9,1238 +9,1232 @@ use Zotlabs\Lib\Connect; use Zotlabs\Lib\DReport; use Zotlabs\Daemon\Run; -class Libsync { +class Libsync +{ - /** - * @brief Builds and sends a sync packet. - * - * Send a zot packet to all hubs where this channel is duplicated, refreshing - * such things as personal settings, channel permissions, address book updates, etc. - * - * By default, sync the channel and any pconfig changes which were made in the current process - * AccessLists (aka privacy groups) will also be included if $groups_changed is true. - * To include other data sources, provide them as $packet. - * - * @param int $uid (optional) default 0 - * @param array $packet (optional) default null - * @param boolean $groups_changed (optional) default false - */ + /** + * @brief Builds and sends a sync packet. + * + * Send a zot packet to all hubs where this channel is duplicated, refreshing + * such things as personal settings, channel permissions, address book updates, etc. + * + * By default, sync the channel and any pconfig changes which were made in the current process + * AccessLists (aka privacy groups) will also be included if $groups_changed is true. + * To include other data sources, provide them as $packet. + * + * @param int $uid (optional) default 0 + * @param array $packet (optional) default null + * @param bool $groups_changed (optional) default false + */ - static function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) { + public static function build_sync_packet($uid = 0, $packet = null, $groups_changed = false) + { - //logger('build_sync_packet'); + //logger('build_sync_packet'); - $keychange = (($packet && array_key_exists('keychange',$packet)) ? true : false); - if ($keychange) { - logger('keychange sync'); - } + $keychange = (($packet && array_key_exists('keychange', $packet)) ? true : false); + if ($keychange) { + logger('keychange sync'); + } - if (! $uid) { - $uid = local_channel(); - } - - if (! $uid) { - return; - } + if (!$uid) { + $uid = local_channel(); + } - $channel = channelx_by_n($uid); - if (! $channel) { - return; - } + if (!$uid) { + return; + } - // don't provide these in the export + $channel = channelx_by_n($uid); + if (!$channel) { + return; + } - unset($channel['channel_active']); - unset($channel['channel_password']); - unset($channel['channel_salt']); + // don't provide these in the export - $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url + unset($channel['channel_active']); + unset($channel['channel_password']); + unset($channel['channel_salt']); + + $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash = '%s' and hubloc_network = 'zot6' and hubloc_deleted = 0", - dbesc(($keychange) ? $packet['keychange']['old_hash'] : $channel['channel_hash']) - ); + dbesc(($keychange) ? $packet['keychange']['old_hash'] : $channel['channel_hash']) + ); - if (! $h) { - return; - } + if (!$h) { + return; + } - $synchubs = []; + $synchubs = []; - foreach ($h as $x) { - if ($x['hubloc_host'] == App::get_hostname()) { - continue; - } + foreach ($h as $x) { + if ($x['hubloc_host'] == App::get_hostname()) { + continue; + } - $y = q("select site_dead from site where site_url = '%s' limit 1", - dbesc($x['hubloc_url']) - ); + $y = q("select site_dead from site where site_url = '%s' limit 1", + dbesc($x['hubloc_url']) + ); - if ((! $y) || ($y[0]['site_dead'] == 0)) { - $synchubs[] = $x; - } - } + if ((!$y) || ($y[0]['site_dead'] == 0)) { + $synchubs[] = $x; + } + } - if (! $synchubs) { - return; - } + if (!$synchubs) { + return; + } - $env_recips = [ $channel['channel_hash'] ]; + $env_recips = [$channel['channel_hash']]; - if ($packet) { - logger('packet: ' . print_r($packet, true),LOGGER_DATA, LOG_DEBUG); - } - - $info = (($packet) ? $packet : [] ); - $info['type'] = 'sync'; - $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific - $info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root() ]; + if ($packet) { + logger('packet: ' . print_r($packet, true), LOGGER_DATA, LOG_DEBUG); + } - if (array_key_exists($uid, App::$config) && array_key_exists('transient', App::$config[$uid])) { - $settings = App::$config[$uid]['transient']; - if ($settings) { - $info['config'] = $settings; - } - } + $info = (($packet) ? $packet : []); + $info['type'] = 'sync'; + $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific + $info['relocate'] = ['channel_address' => $channel['channel_address'], 'url' => z_root()]; - if ($channel) { - $info['channel'] = []; - foreach ($channel as $k => $v) { + if (array_key_exists($uid, App::$config) && array_key_exists('transient', App::$config[$uid])) { + $settings = App::$config[$uid]['transient']; + if ($settings) { + $info['config'] = $settings; + } + } - // filter out any joined tables like xchan + if ($channel) { + $info['channel'] = []; + foreach ($channel as $k => $v) { - if (strpos($k,'channel_') !== 0) { - continue; - } + // filter out any joined tables like xchan - // don't pass these elements, they should not be synchronised + if (strpos($k, 'channel_') !== 0) { + continue; + } + + // don't pass these elements, they should not be synchronised - $disallowed = [ 'channel_id','channel_account_id','channel_primary','channel_address', - 'channel_deleted','channel_removed','channel_system' ]; + $disallowed = ['channel_id', 'channel_account_id', 'channel_primary', 'channel_address', + 'channel_deleted', 'channel_removed', 'channel_system']; - if (! $keychange) { - $disallowed[] = 'channel_prvkey'; - } + if (!$keychange) { + $disallowed[] = 'channel_prvkey'; + } - if (in_array($k,$disallowed)) { - continue; - } + if (in_array($k, $disallowed)) { + continue; + } - $info['channel'][$k] = $v; - } - } + $info['channel'][$k] = $v; + } + } - if ($groups_changed) { - $r = q("select hash as collection, visible, deleted, rule, gname as name from pgrp where uid = %d ", - intval($uid) - ); - if ($r) { - $info['collections'] = $r; - } + if ($groups_changed) { + $r = q("select hash as collection, visible, deleted, rule, gname as name from pgrp where uid = %d ", + intval($uid) + ); + if ($r) { + $info['collections'] = $r; + } - $r = q("select pgrp.hash as collection, pgrp_member.xchan as member from pgrp left join pgrp_member on pgrp.id = pgrp_member.gid + $r = q("select pgrp.hash as collection, pgrp_member.xchan as member from pgrp left join pgrp_member on pgrp.id = pgrp_member.gid where pgrp_member.uid = %d ", - intval($uid) - ); - if ($r) { - $info['collection_members'] = $r; - } - } + intval($uid) + ); + if ($r) { + $info['collection_members'] = $r; + } + } - $interval = get_config('system','delivery_interval', 2); + $interval = get_config('system', 'delivery_interval', 2); - logger('Packet: ' . print_r($info,true), LOGGER_DATA, LOG_DEBUG); + logger('Packet: ' . print_r($info, true), LOGGER_DATA, LOG_DEBUG); - $total = count($synchubs); - - foreach ($synchubs as $hub) { - $hash = random_string(); - $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'red',$hub['hubloc_sitekey'],$hub['site_crypto']); - Queue::insert([ - 'hash' => $hash, - 'account_id' => $channel['channel_account_id'], - 'channel_id' => $channel['channel_id'], - 'posturl' => $hub['hubloc_callback'], - 'notify' => $n, - 'msg' => EMPTY_STR - ]); + $total = count($synchubs); + foreach ($synchubs as $hub) { + $hash = random_string(); + $n = Libzot::build_packet($channel, 'sync', $env_recips, json_encode($info), 'red', $hub['hubloc_sitekey'], $hub['site_crypto']); + Queue::insert([ + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $hub['hubloc_callback'], + 'notify' => $n, + 'msg' => EMPTY_STR + ]); - $x = q("select count(outq_hash) as total from outq where outq_delivered = 0"); - if (intval($x[0]['total']) > intval(get_config('system','force_queue_threshold',3000))) { - logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO); - Queue::update($hash); - continue; - } + $x = q("select count(outq_hash) as total from outq where outq_delivered = 0"); + if (intval($x[0]['total']) > intval(get_config('system', 'force_queue_threshold', 3000))) { + logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO); + Queue::update($hash); + continue; + } - Run::Summon([ 'Deliver', $hash ]); - $total = $total - 1; - - if ($interval && $total) { - @time_sleep_until(microtime(true) + (float) $interval); - } - } - } - - - static function build_link_packet($uid = 0, $packet = null) { - // logger('build_link_packet'); + Run::Summon(['Deliver', $hash]); + $total = $total - 1; - if (! $uid) { - $uid = local_channel(); - } - - if (! $uid) { - return; - } + if ($interval && $total) { + @time_sleep_until(microtime(true) + (float)$interval); + } + } + } - $channel = channelx_by_n($uid); - if (! $channel) { - return; - } - $l = q("select link from linkid where ident = '%s' and sigtype = 2", - dbesc($channel['channel_hash']) - ); + public static function build_link_packet($uid = 0, $packet = null) + { - if (! $l) { - return; - } - - $hashes = ids_to_querystr($l,'link',true); - - $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf($hashes) . ") and hubloc_network = 'zot6' and hubloc_deleted = 0"); - - if (! $h) { - return; - } - - $interval = get_config('system','delivery_interval',2); + // logger('build_link_packet'); + if (!$uid) { + $uid = local_channel(); + } - foreach ($h as $x) { - if ($x['hubloc_host'] == App::get_hostname()) { - continue; - } - - $y = q("select site_dead from site where site_url = '%s' limit 1", - dbesc($x['hubloc_url']) - ); - - if (($y) && (intval($y[0]['site_dead']) == 1)) { - $continue; - } - - $env_recips = [ $x['hubloc_hash'] ]; - - if ($packet) { - logger('packet: ' . print_r($packet, true),LOGGER_DATA, LOG_DEBUG); - } - - $info = (($packet) ? $packet : []); - $info['type'] = 'sync'; - $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific - - logger('Packet: ' . print_r($info,true), LOGGER_DATA, LOG_DEBUG); + if (!$uid) { + return; + } + $channel = channelx_by_n($uid); + if (!$channel) { + return; + } - $hash = random_string(); - $n = Libzot::build_packet($channel,'sync',$env_recips,json_encode($info),'red',$x['hubloc_sitekey'],$x['site_crypto']); - Queue::insert([ - 'hash' => $hash, - 'account_id' => $channel['channel_account_id'], - 'channel_id' => $channel['channel_id'], - 'posturl' => $x['hubloc_callback'], - 'notify' => $n, - 'msg' => EMPTY_STR - ]); - - $y = q("select count(outq_hash) as total from outq where outq_delivered = 0"); - if (intval($y[0]['total']) > intval(get_config('system','force_queue_threshold',3000))) { - logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO); - Queue::update($hash); - continue; - } - - Run::Summon([ 'Deliver', $hash ]); - - if ($interval && count($h) > 1) { - @time_sleep_until(microtime(true) + (float) $interval); - } - } - } - + $l = q("select link from linkid where ident = '%s' and sigtype = 2", + dbesc($channel['channel_hash']) + ); - /** - * @brief - * - * @param array $sender - * @param array $arr - * @param array $deliveries - * @return array - */ - - static function process_channel_sync_delivery($sender, $arr, $deliveries) { - - require_once('include/import.php'); - - $result = []; - - $keychange = ((array_key_exists('keychange',$arr)) ? true : false); - - foreach ($deliveries as $d) { - $linked_channel = false; - - $r = q("select * from channel where channel_hash = '%s' limit 1", - dbesc($sender) - ); - - $DR = new DReport(z_root(),$sender,$d,'sync'); - - if (! $r) { - $l = q("select ident from linkid where link = '%s' and sigtype = 2 limit 1", - dbesc($sender) - ); - if ($l) { - $linked_channel = true; - $r = q("select * from channel where channel_hash = '%s' limit 1", - dbesc($l[0]['ident']) - ); - } - } - - if (! $r) { - $DR->update('recipient not found'); - $result[] = $DR->get(); - continue; - } - - $channel = $r[0]; - - $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); - - $max_friends = service_class_fetch($channel['channel_id'],'total_channels'); - $max_feeds = account_service_class_fetch($channel['channel_account_id'],'total_feeds'); - - if ($channel['channel_hash'] != $sender && (! $linked_channel)) { - logger('Possible forgery. Sender ' . $sender . ' is not ' . $channel['channel_hash']); - $DR->update('channel mismatch'); - $result[] = $DR->get(); - continue; - } - - if ($keychange) { - self::keychange($channel,$arr); - continue; - } - - // if the clone is active, so are we - - if (substr($channel['channel_active'],0,10) !== substr(datetime_convert(),0,10)) { - q("UPDATE channel set channel_active = '%s' where channel_id = %d", - dbesc(datetime_convert()), - intval($channel['channel_id']) - ); - } - - if (array_key_exists('config',$arr) && is_array($arr['config']) && count($arr['config'])) { - foreach ($arr['config'] as $cat => $k) { - foreach ($arr['config'][$cat] as $k => $v) { - set_pconfig($channel['channel_id'],$cat,$k,$v); - } - } - } - - if (array_key_exists('atoken',$arr) && $arr['atoken']) { - sync_atoken($channel,$arr['atoken']); - } - - if (array_key_exists('xign',$arr) && $arr['xign']) { - sync_xign($channel,$arr['xign']); - } - - if (array_key_exists('block',$arr) && $arr['block']) { - sync_block($channel,$arr['block']); - } - - if (array_key_exists('obj',$arr) && $arr['obj']) { - sync_objs($channel,$arr['obj']); - } - - if (array_key_exists('likes',$arr) && $arr['likes']) { - import_likes($channel,$arr['likes']); - } - - if (array_key_exists('app',$arr) && $arr['app']) { - sync_apps($channel,$arr['app']); - } - - if (array_key_exists('sysapp',$arr) && $arr['sysapp']) { - sync_sysapps($channel,$arr['sysapp']); - } - - if (array_key_exists('chatroom',$arr) && $arr['chatroom']) { - sync_chatrooms($channel,$arr['chatroom']); - } - - if (array_key_exists('conv',$arr) && $arr['conv']) { - import_conv($channel,$arr['conv']); - } - - if (array_key_exists('mail',$arr) && $arr['mail']) { - sync_mail($channel,$arr['mail']); - } - - if (array_key_exists('event',$arr) && $arr['event']) { - sync_events($channel,$arr['event']); - } - - if (array_key_exists('event_item',$arr) && $arr['event_item']) { - sync_items($channel,$arr['event_item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null)); - } - - if (array_key_exists('item',$arr) && $arr['item']) { - sync_items($channel,$arr['item'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null)); - } - - if (array_key_exists('menu',$arr) && $arr['menu']) { - sync_menus($channel,$arr['menu']); - } - - if (array_key_exists('file',$arr) && $arr['file']) { - sync_files($channel,$arr['file']); - } - - if (array_key_exists('wiki',$arr) && $arr['wiki']) { - sync_items($channel,$arr['wiki'],((array_key_exists('relocate',$arr)) ? $arr['relocate'] : null)); - } - - if(array_key_exists('channel',$arr) && is_array($arr['channel']) && count($arr['channel'])) { - - $remote_channel = $arr['channel']; - $remote_channel['channel_id'] = $channel['channel_id']; - - if (array_key_exists('channel_pageflags',$arr['channel']) && intval($arr['channel']['channel_pageflags'])) { - - // Several pageflags are site-specific and cannot be sync'd. - // Only allow those bits which are shareable from the remote and then - // logically OR with the local flags - - $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] & (PAGE_HIDDEN|PAGE_AUTOCONNECT|PAGE_APPLICATION|PAGE_PREMIUM|PAGE_ADULT); - $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] | $channel['channel_pageflags']; - - } - - $columns = db_columns('channel'); - - $disallowed = [ - 'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', - 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', - 'channel_system', 'channel_r_stream', 'channel_r_profile', 'channel_r_abook', - 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', - 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', - 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', - 'channel_a_delegate', 'channel_moved' - ]; - - foreach($arr['channel'] as $k => $v) { - if (in_array($k,$disallowed)) { - continue; - } - if (! in_array($k,$columns)) { - continue; - } - $r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) - . "' where channel_id = " . intval($channel['channel_id']) ); - } - } - - if (array_key_exists('abook',$arr) && is_array($arr['abook']) && count($arr['abook'])) { - - $total_friends = 0; - $total_feeds = 0; - - $r = q("select abook_id, abook_feed from abook where abook_channel = %d", - intval($channel['channel_id']) - ); - if ($r) { - // don't count yourself - $total_friends = ((count($r) > 0) ? count($r) - 1 : 0); - foreach ($r as $rr) { - if (intval($rr['abook_feed'])) { - $total_feeds ++; - } - } - } - - - $disallowed = [ 'abook_id', 'abook_account', 'abook_channel', 'abook_rating', 'abook_rating_text', 'abook_not_here' ]; - - $fields = db_columns('abook'); - - foreach ($arr['abook'] as $abook) { - - // this is here for debugging so we can find the issue source - - if (! is_array($abook)) { - btlogger('abook is not an array'); - continue; - } - - $abconfig = null; - - if (array_key_exists('abconfig',$abook) && is_array($abook['abconfig']) && count($abook['abconfig'])) { - $abconfig = $abook['abconfig']; - } - - $clean = []; - - if ($abook['abook_xchan'] && $abook['entry_deleted']) { - logger('Removing abook entry for ' . $abook['abook_xchan']); - - $r = q("select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", - dbesc($abook['abook_xchan']), - intval($channel['channel_id']) - ); - if ($r) { - contact_remove($channel['channel_id'],$r[0]['abook_id']); - if ($total_friends) { - $total_friends --; - } - if (intval($r[0]['abook_feed'])) { - $total_feeds --; - } - } - continue; - } - - // Perform discovery if the referenced xchan hasn't ever been seen on this hub. - // This relies on the undocumented behaviour that red sites send xchan info with the abook - // and import_author_xchan will look them up on all federated networks - - $found = false; - if ($abook['abook_xchan'] && $abook['xchan_addr'] && (! in_array($abook['xchan_network'], [ 'token', 'unknown' ]))) { - $h = Libzot::get_hublocs($abook['abook_xchan']); - if ($h) { - $found = true; - } - else { - $xhash = import_author_xchan(encode_item_xchan($abook)); - if ($xhash) { - $found = true; - } - else { - logger('Import of ' . $abook['xchan_addr'] . ' failed.'); - } - } - } - - if ((! $found) && (! in_array($abook['xchan_network'], [ 'zot6', 'activitypub' ]))) { - // just import the record. - $xc = []; - foreach ($abook as $k => $v) { - if (strpos($k,'xchan_') === 0) { - $xc[$k] = $v; - } - } - $r = q("select * from xchan where xchan_hash = '%s'", - dbesc($xc['xchan_hash']) - ); - if (! $r) { - xchan_store_lowlevel($xc); - } - } - - foreach ($abook as $k => $v) { - if (in_array($k,$disallowed) || (strpos($k,'abook_') !== 0)) { - continue; - } - if (! in_array($k,$fields)) { - continue; - } - $clean[$k] = $v; - } - - if (! array_key_exists('abook_xchan',$clean)) { - continue; - } - - $reconnect = false; - if (array_key_exists('abook_instance',$clean) && $clean['abook_instance'] && strpos($clean['abook_instance'],z_root()) === false) { - // guest pass or access token - don't try to probe since it is one-way - // we are relying on the undocumented behaviour that the abook record also contains the xchan - if ($abook['xchan_network'] === 'token') { - $clean['abook_instance'] .= ','; - $clean['abook_instance'] .= z_root(); - $clean['abook_not_here'] = 0; - } - else { - $clean['abook_not_here'] = 1; - if (! ($abook['abook_pending'] || $abook['abook_blocked'])) { - $reconnect = true; - } - } - } - - $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($clean['abook_xchan']), - intval($channel['channel_id']) - ); - - // make sure we have an abook entry for this xchan on this system - - if (! $r) { - if ($max_friends !== false && $total_friends > $max_friends) { - logger('total_channels service class limit exceeded'); - continue; - } - if ($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) { - logger('total_feeds service class limit exceeded'); - continue; - } - abook_store_lowlevel( - [ - 'abook_xchan' => $clean['abook_xchan'], - 'abook_account' => $channel['channel_account_id'], - 'abook_channel' => $channel['channel_id'] - ] - ); - $total_friends ++; - if (intval($clean['abook_feed'])) { - $total_feeds ++; - } - } - - if (count($clean)) { - foreach ($clean as $k => $v) { - if ($k == 'abook_dob') { - $v = dbescdate($v); - } - - $r = dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v) - . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])); - - } - } - - // This will set abconfig vars if the sender is using old-style fixed permissions - // using the raw abook record as passed to us. New-style permissions will fall through - // and be set using abconfig - - // translate_abook_perms_inbound($channel,$abook); - - if ($abconfig) { - /// @fixme does not handle sync of del_abconfig - foreach ($abconfig as $abc) { - set_abconfig($channel['channel_id'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']); - } - } - if ($reconnect) { - Connect::connect($channel,$abook['abook_xchan']); - } - } - } - - // sync collections (privacy groups) oh joy... - - if (array_key_exists('collections',$arr) && is_array($arr['collections']) && count($arr['collections'])) { - $x = q("select * from pgrp where uid = %d ", - intval($channel['channel_id']) - ); - foreach ($arr['collections'] as $cl) { - $found = false; - if ($x) { - foreach ($x as $y) { - if ($cl['collection'] == $y['hash']) { - $found = true; - break; - } - } - if ($found) { - if (($y['gname'] != $cl['name']) - || ($y['visible'] != $cl['visible']) - || ($y['deleted'] != $cl['deleted'])) { - q("update pgrp set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", - dbesc($cl['name']), - intval($cl['visible']), - intval($cl['deleted']), - dbesc($cl['collection']), - intval($channel['channel_id']) - ); - } - if (intval($cl['deleted']) && (! intval($y['deleted']))) { - q("delete from pgrp_member where gid = %d", - intval($y['id']) - ); - } - } - } - if (! $found) { - $r = q("INSERT INTO pgrp ( hash, uid, visible, deleted, gname, rule ) + if (!$l) { + return; + } + + $hashes = ids_to_querystr($l, 'link', true); + + $h = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf($hashes) . ") and hubloc_network = 'zot6' and hubloc_deleted = 0"); + + if (!$h) { + return; + } + + $interval = get_config('system', 'delivery_interval', 2); + + + foreach ($h as $x) { + if ($x['hubloc_host'] == App::get_hostname()) { + continue; + } + + $y = q("select site_dead from site where site_url = '%s' limit 1", + dbesc($x['hubloc_url']) + ); + + if (($y) && (intval($y[0]['site_dead']) == 1)) { + $continue; + } + + $env_recips = [$x['hubloc_hash']]; + + if ($packet) { + logger('packet: ' . print_r($packet, true), LOGGER_DATA, LOG_DEBUG); + } + + $info = (($packet) ? $packet : []); + $info['type'] = 'sync'; + $info['encoding'] = 'red'; // note: not zot, this packet is very platform specific + + logger('Packet: ' . print_r($info, true), LOGGER_DATA, LOG_DEBUG); + + + $hash = random_string(); + $n = Libzot::build_packet($channel, 'sync', $env_recips, json_encode($info), 'red', $x['hubloc_sitekey'], $x['site_crypto']); + Queue::insert([ + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $x['hubloc_callback'], + 'notify' => $n, + 'msg' => EMPTY_STR + ]); + + $y = q("select count(outq_hash) as total from outq where outq_delivered = 0"); + if (intval($y[0]['total']) > intval(get_config('system', 'force_queue_threshold', 3000))) { + logger('immediate delivery deferred.', LOGGER_DEBUG, LOG_INFO); + Queue::update($hash); + continue; + } + + Run::Summon(['Deliver', $hash]); + + if ($interval && count($h) > 1) { + @time_sleep_until(microtime(true) + (float)$interval); + } + } + } + + + /** + * @brief + * + * @param array $sender + * @param array $arr + * @param array $deliveries + * @return array + */ + + public static function process_channel_sync_delivery($sender, $arr, $deliveries) + { + + require_once('include/import.php'); + + $result = []; + + $keychange = ((array_key_exists('keychange', $arr)) ? true : false); + + foreach ($deliveries as $d) { + $linked_channel = false; + + $r = q("select * from channel where channel_hash = '%s' limit 1", + dbesc($sender) + ); + + $DR = new DReport(z_root(), $sender, $d, 'sync'); + + if (!$r) { + $l = q("select ident from linkid where link = '%s' and sigtype = 2 limit 1", + dbesc($sender) + ); + if ($l) { + $linked_channel = true; + $r = q("select * from channel where channel_hash = '%s' limit 1", + dbesc($l[0]['ident']) + ); + } + } + + if (!$r) { + $DR->update('recipient not found'); + $result[] = $DR->get(); + continue; + } + + $channel = $r[0]; + + $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); + + $max_friends = service_class_fetch($channel['channel_id'], 'total_channels'); + $max_feeds = account_service_class_fetch($channel['channel_account_id'], 'total_feeds'); + + if ($channel['channel_hash'] != $sender && (!$linked_channel)) { + logger('Possible forgery. Sender ' . $sender . ' is not ' . $channel['channel_hash']); + $DR->update('channel mismatch'); + $result[] = $DR->get(); + continue; + } + + if ($keychange) { + self::keychange($channel, $arr); + continue; + } + + // if the clone is active, so are we + + if (substr($channel['channel_active'], 0, 10) !== substr(datetime_convert(), 0, 10)) { + q("UPDATE channel set channel_active = '%s' where channel_id = %d", + dbesc(datetime_convert()), + intval($channel['channel_id']) + ); + } + + if (array_key_exists('config', $arr) && is_array($arr['config']) && count($arr['config'])) { + foreach ($arr['config'] as $cat => $k) { + foreach ($arr['config'][$cat] as $k => $v) { + set_pconfig($channel['channel_id'], $cat, $k, $v); + } + } + } + + if (array_key_exists('atoken', $arr) && $arr['atoken']) { + sync_atoken($channel, $arr['atoken']); + } + + if (array_key_exists('xign', $arr) && $arr['xign']) { + sync_xign($channel, $arr['xign']); + } + + if (array_key_exists('block', $arr) && $arr['block']) { + sync_block($channel, $arr['block']); + } + + if (array_key_exists('obj', $arr) && $arr['obj']) { + sync_objs($channel, $arr['obj']); + } + + if (array_key_exists('likes', $arr) && $arr['likes']) { + import_likes($channel, $arr['likes']); + } + + if (array_key_exists('app', $arr) && $arr['app']) { + sync_apps($channel, $arr['app']); + } + + if (array_key_exists('sysapp', $arr) && $arr['sysapp']) { + sync_sysapps($channel, $arr['sysapp']); + } + + if (array_key_exists('chatroom', $arr) && $arr['chatroom']) { + sync_chatrooms($channel, $arr['chatroom']); + } + + if (array_key_exists('conv', $arr) && $arr['conv']) { + import_conv($channel, $arr['conv']); + } + + if (array_key_exists('mail', $arr) && $arr['mail']) { + sync_mail($channel, $arr['mail']); + } + + if (array_key_exists('event', $arr) && $arr['event']) { + sync_events($channel, $arr['event']); + } + + if (array_key_exists('event_item', $arr) && $arr['event_item']) { + sync_items($channel, $arr['event_item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null)); + } + + if (array_key_exists('item', $arr) && $arr['item']) { + sync_items($channel, $arr['item'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null)); + } + + if (array_key_exists('menu', $arr) && $arr['menu']) { + sync_menus($channel, $arr['menu']); + } + + if (array_key_exists('file', $arr) && $arr['file']) { + sync_files($channel, $arr['file']); + } + + if (array_key_exists('wiki', $arr) && $arr['wiki']) { + sync_items($channel, $arr['wiki'], ((array_key_exists('relocate', $arr)) ? $arr['relocate'] : null)); + } + + if (array_key_exists('channel', $arr) && is_array($arr['channel']) && count($arr['channel'])) { + + $remote_channel = $arr['channel']; + $remote_channel['channel_id'] = $channel['channel_id']; + + if (array_key_exists('channel_pageflags', $arr['channel']) && intval($arr['channel']['channel_pageflags'])) { + + // Several pageflags are site-specific and cannot be sync'd. + // Only allow those bits which are shareable from the remote and then + // logically OR with the local flags + + $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] & (PAGE_HIDDEN | PAGE_AUTOCONNECT | PAGE_APPLICATION | PAGE_PREMIUM | PAGE_ADULT); + $arr['channel']['channel_pageflags'] = $arr['channel']['channel_pageflags'] | $channel['channel_pageflags']; + + } + + $columns = db_columns('channel'); + + $disallowed = [ + 'channel_id', 'channel_account_id', 'channel_primary', 'channel_prvkey', + 'channel_address', 'channel_notifyflags', 'channel_removed', 'channel_deleted', + 'channel_system', 'channel_r_stream', 'channel_r_profile', 'channel_r_abook', + 'channel_r_storage', 'channel_r_pages', 'channel_w_stream', 'channel_w_wall', + 'channel_w_comment', 'channel_w_mail', 'channel_w_like', 'channel_w_tagwall', + 'channel_w_chat', 'channel_w_storage', 'channel_w_pages', 'channel_a_republish', + 'channel_a_delegate', 'channel_moved' + ]; + + foreach ($arr['channel'] as $k => $v) { + if (in_array($k, $disallowed)) { + continue; + } + if (!in_array($k, $columns)) { + continue; + } + $r = dbq("UPDATE channel set " . dbesc($k) . " = '" . dbesc($v) + . "' where channel_id = " . intval($channel['channel_id'])); + } + } + + if (array_key_exists('abook', $arr) && is_array($arr['abook']) && count($arr['abook'])) { + + $total_friends = 0; + $total_feeds = 0; + + $r = q("select abook_id, abook_feed from abook where abook_channel = %d", + intval($channel['channel_id']) + ); + if ($r) { + // don't count yourself + $total_friends = ((count($r) > 0) ? count($r) - 1 : 0); + foreach ($r as $rr) { + if (intval($rr['abook_feed'])) { + $total_feeds++; + } + } + } + + + $disallowed = ['abook_id', 'abook_account', 'abook_channel', 'abook_rating', 'abook_rating_text', 'abook_not_here']; + + $fields = db_columns('abook'); + + foreach ($arr['abook'] as $abook) { + + // this is here for debugging so we can find the issue source + + if (!is_array($abook)) { + btlogger('abook is not an array'); + continue; + } + + $abconfig = null; + + if (array_key_exists('abconfig', $abook) && is_array($abook['abconfig']) && count($abook['abconfig'])) { + $abconfig = $abook['abconfig']; + } + + $clean = []; + + if ($abook['abook_xchan'] && $abook['entry_deleted']) { + logger('Removing abook entry for ' . $abook['abook_xchan']); + + $r = q("select abook_id, abook_feed from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", + dbesc($abook['abook_xchan']), + intval($channel['channel_id']) + ); + if ($r) { + contact_remove($channel['channel_id'], $r[0]['abook_id']); + if ($total_friends) { + $total_friends--; + } + if (intval($r[0]['abook_feed'])) { + $total_feeds--; + } + } + continue; + } + + // Perform discovery if the referenced xchan hasn't ever been seen on this hub. + // This relies on the undocumented behaviour that red sites send xchan info with the abook + // and import_author_xchan will look them up on all federated networks + + $found = false; + if ($abook['abook_xchan'] && $abook['xchan_addr'] && (!in_array($abook['xchan_network'], ['token', 'unknown']))) { + $h = Libzot::get_hublocs($abook['abook_xchan']); + if ($h) { + $found = true; + } else { + $xhash = import_author_xchan(encode_item_xchan($abook)); + if ($xhash) { + $found = true; + } else { + logger('Import of ' . $abook['xchan_addr'] . ' failed.'); + } + } + } + + if ((!$found) && (!in_array($abook['xchan_network'], ['zot6', 'activitypub']))) { + // just import the record. + $xc = []; + foreach ($abook as $k => $v) { + if (strpos($k, 'xchan_') === 0) { + $xc[$k] = $v; + } + } + $r = q("select * from xchan where xchan_hash = '%s'", + dbesc($xc['xchan_hash']) + ); + if (!$r) { + xchan_store_lowlevel($xc); + } + } + + foreach ($abook as $k => $v) { + if (in_array($k, $disallowed) || (strpos($k, 'abook_') !== 0)) { + continue; + } + if (!in_array($k, $fields)) { + continue; + } + $clean[$k] = $v; + } + + if (!array_key_exists('abook_xchan', $clean)) { + continue; + } + + $reconnect = false; + if (array_key_exists('abook_instance', $clean) && $clean['abook_instance'] && strpos($clean['abook_instance'], z_root()) === false) { + // guest pass or access token - don't try to probe since it is one-way + // we are relying on the undocumented behaviour that the abook record also contains the xchan + if ($abook['xchan_network'] === 'token') { + $clean['abook_instance'] .= ','; + $clean['abook_instance'] .= z_root(); + $clean['abook_not_here'] = 0; + } else { + $clean['abook_not_here'] = 1; + if (!($abook['abook_pending'] || $abook['abook_blocked'])) { + $reconnect = true; + } + } + } + + $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($clean['abook_xchan']), + intval($channel['channel_id']) + ); + + // make sure we have an abook entry for this xchan on this system + + if (!$r) { + if ($max_friends !== false && $total_friends > $max_friends) { + logger('total_channels service class limit exceeded'); + continue; + } + if ($max_feeds !== false && intval($clean['abook_feed']) && $total_feeds > $max_feeds) { + logger('total_feeds service class limit exceeded'); + continue; + } + abook_store_lowlevel( + [ + 'abook_xchan' => $clean['abook_xchan'], + 'abook_account' => $channel['channel_account_id'], + 'abook_channel' => $channel['channel_id'] + ] + ); + $total_friends++; + if (intval($clean['abook_feed'])) { + $total_feeds++; + } + } + + if (count($clean)) { + foreach ($clean as $k => $v) { + if ($k == 'abook_dob') { + $v = dbescdate($v); + } + + $r = dbq("UPDATE abook set " . dbesc($k) . " = '" . dbesc($v) + . "' where abook_xchan = '" . dbesc($clean['abook_xchan']) . "' and abook_channel = " . intval($channel['channel_id'])); + + } + } + + // This will set abconfig vars if the sender is using old-style fixed permissions + // using the raw abook record as passed to us. New-style permissions will fall through + // and be set using abconfig + + // translate_abook_perms_inbound($channel,$abook); + + if ($abconfig) { + /// @fixme does not handle sync of del_abconfig + foreach ($abconfig as $abc) { + set_abconfig($channel['channel_id'], $abc['xchan'], $abc['cat'], $abc['k'], $abc['v']); + } + } + if ($reconnect) { + Connect::connect($channel, $abook['abook_xchan']); + } + } + } + + // sync collections (privacy groups) oh joy... + + if (array_key_exists('collections', $arr) && is_array($arr['collections']) && count($arr['collections'])) { + $x = q("select * from pgrp where uid = %d ", + intval($channel['channel_id']) + ); + foreach ($arr['collections'] as $cl) { + $found = false; + if ($x) { + foreach ($x as $y) { + if ($cl['collection'] == $y['hash']) { + $found = true; + break; + } + } + if ($found) { + if (($y['gname'] != $cl['name']) + || ($y['visible'] != $cl['visible']) + || ($y['deleted'] != $cl['deleted'])) { + q("update pgrp set gname = '%s', visible = %d, deleted = %d where hash = '%s' and uid = %d", + dbesc($cl['name']), + intval($cl['visible']), + intval($cl['deleted']), + dbesc($cl['collection']), + intval($channel['channel_id']) + ); + } + if (intval($cl['deleted']) && (!intval($y['deleted']))) { + q("delete from pgrp_member where gid = %d", + intval($y['id']) + ); + } + } + } + if (!$found) { + $r = q("INSERT INTO pgrp ( hash, uid, visible, deleted, gname, rule ) VALUES( '%s', %d, %d, %d, '%s', '%s' ) ", - dbesc($cl['collection']), - intval($channel['channel_id']), - intval($cl['visible']), - intval($cl['deleted']), - dbesc($cl['name']), - dbesc($cl['rule']) - ); - } + dbesc($cl['collection']), + intval($channel['channel_id']), + intval($cl['visible']), + intval($cl['deleted']), + dbesc($cl['name']), + dbesc($cl['rule']) + ); + } - // now look for any collections locally which weren't in the list we just received. - // They need to be removed by marking deleted and removing the members. - // This shouldn't happen except for clones created before this function was written. + // now look for any collections locally which weren't in the list we just received. + // They need to be removed by marking deleted and removing the members. + // This shouldn't happen except for clones created before this function was written. - if ($x) { - $found_local = false; - foreach ($x as $y) { - foreach ($arr['collections'] as $cl) { - if ($cl['collection'] == $y['hash']) { - $found_local = true; - break; - } - } - if (! $found_local) { - q("delete from pgrp_member where gid = %d", - intval($y['id']) - ); - q("update pgrp set deleted = 1 where id = %d and uid = %d", - intval($y['id']), - intval($channel['channel_id']) - ); - } - } - } - } + if ($x) { + $found_local = false; + foreach ($x as $y) { + foreach ($arr['collections'] as $cl) { + if ($cl['collection'] == $y['hash']) { + $found_local = true; + break; + } + } + if (!$found_local) { + q("delete from pgrp_member where gid = %d", + intval($y['id']) + ); + q("update pgrp set deleted = 1 where id = %d and uid = %d", + intval($y['id']), + intval($channel['channel_id']) + ); + } + } + } + } - // reload the group list with any updates - $x = q("select * from pgrp where uid = %d", - intval($channel['channel_id']) - ); + // reload the group list with any updates + $x = q("select * from pgrp where uid = %d", + intval($channel['channel_id']) + ); - // now sync the members + // now sync the members - if (array_key_exists('collection_members', $arr) - && is_array($arr['collection_members']) - && count($arr['collection_members'])) { + if (array_key_exists('collection_members', $arr) + && is_array($arr['collection_members']) + && count($arr['collection_members'])) { - // first sort into groups keyed by the group hash - $members = []; - foreach ($arr['collection_members'] as $cm) { - if (! array_key_exists($cm['collection'],$members)) { - $members[$cm['collection']] = []; - } + // first sort into groups keyed by the group hash + $members = []; + foreach ($arr['collection_members'] as $cm) { + if (!array_key_exists($cm['collection'], $members)) { + $members[$cm['collection']] = []; + } - $members[$cm['collection']][] = $cm['member']; - } + $members[$cm['collection']][] = $cm['member']; + } - // our group list is already synchronised - if ($x) { - foreach ($x as $y) { - - // for each group, loop on members list we just received - if (isset($y['hash']) && isset($members[$y['hash']])) { - foreach ($members[$y['hash']] as $member) { - $found = false; - $z = q("select xchan from pgrp_member where gid = %d and uid = %d and xchan = '%s' limit 1", - intval($y['id']), - intval($channel['channel_id']), - dbesc($member) - ); - if ($z) { - $found = true; - } - - // if somebody is in the group that wasn't before - add them - - if (! $found) { - q("INSERT INTO pgrp_member (uid, gid, xchan) + // our group list is already synchronised + if ($x) { + foreach ($x as $y) { + + // for each group, loop on members list we just received + if (isset($y['hash']) && isset($members[$y['hash']])) { + foreach ($members[$y['hash']] as $member) { + $found = false; + $z = q("select xchan from pgrp_member where gid = %d and uid = %d and xchan = '%s' limit 1", + intval($y['id']), + intval($channel['channel_id']), + dbesc($member) + ); + if ($z) { + $found = true; + } + + // if somebody is in the group that wasn't before - add them + + if (!$found) { + q("INSERT INTO pgrp_member (uid, gid, xchan) VALUES( %d, %d, '%s' ) ", - intval($channel['channel_id']), - intval($y['id']), - dbesc($member) - ); - } - } - } - - // now retrieve a list of members we have on this site - $m = q("select xchan from pgrp_member where gid = %d and uid = %d", - intval($y['id']), - intval($channel['channel_id']) - ); - if ($m) { - foreach ($m as $mm) { - // if the local existing member isn't in the list we just received - remove them - if (! in_array($mm['xchan'],$members[$y['hash']])) { - q("delete from pgrp_member where xchan = '%s' and gid = %d and uid = %d", - dbesc($mm['xchan']), - intval($y['id']), - intval($channel['channel_id']) - ); - } - } - } - } - } - } - } + intval($channel['channel_id']), + intval($y['id']), + dbesc($member) + ); + } + } + } - if (array_key_exists('profile',$arr) && is_array($arr['profile']) && count($arr['profile'])) { + // now retrieve a list of members we have on this site + $m = q("select xchan from pgrp_member where gid = %d and uid = %d", + intval($y['id']), + intval($channel['channel_id']) + ); + if ($m) { + foreach ($m as $mm) { + // if the local existing member isn't in the list we just received - remove them + if (!in_array($mm['xchan'], $members[$y['hash']])) { + q("delete from pgrp_member where xchan = '%s' and gid = %d and uid = %d", + dbesc($mm['xchan']), + intval($y['id']), + intval($channel['channel_id']) + ); + } + } + } + } + } + } + } - $disallowed = array('id','aid','uid','guid'); + if (array_key_exists('profile', $arr) && is_array($arr['profile']) && count($arr['profile'])) { - foreach ($arr['profile'] as $profile) { - - $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", - dbesc($profile['profile_guid']), - intval($channel['channel_id']) - ); - if (! $x) { - profile_store_lowlevel( - [ - 'aid' => $channel['channel_account_id'], - 'uid' => $channel['channel_id'], - 'profile_guid' => $profile['profile_guid'], - ] - ); - - $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", - dbesc($profile['profile_guid']), - intval($channel['channel_id']) - ); - if (! $x) { - continue; - } - } - $clean = []; - foreach ($profile as $k => $v) { - if (in_array($k,$disallowed)) { - continue; - } + $disallowed = array('id', 'aid', 'uid', 'guid'); - if ($profile['is_default'] && in_array($k,['photo','thumb'])) { - continue; - } + foreach ($arr['profile'] as $profile) { - if ($k === 'name') { - $clean['fullname'] = $v; - } - elseif ($k === 'with') { - $clean['partner'] = $v; - } - elseif ($k === 'work') { - $clean['employment'] = $v; - } - elseif (array_key_exists($k,$x[0])) { - $clean[$k] = $v; - } + $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", + dbesc($profile['profile_guid']), + intval($channel['channel_id']) + ); + if (!$x) { + profile_store_lowlevel( + [ + 'aid' => $channel['channel_account_id'], + 'uid' => $channel['channel_id'], + 'profile_guid' => $profile['profile_guid'], + ] + ); - /** - * @TODO - * We also need to import local photos if a custom photo is selected - */ + $x = q("select * from profile where profile_guid = '%s' and uid = %d limit 1", + dbesc($profile['profile_guid']), + intval($channel['channel_id']) + ); + if (!$x) { + continue; + } + } + $clean = []; + foreach ($profile as $k => $v) { + if (in_array($k, $disallowed)) { + continue; + } - if ((strpos($profile['thumb'],'/photo/profile/l/') !== false) || intval($profile['is_default'])) { - $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id']; - $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id']; - } - else { - $profile['photo'] = z_root() . '/photo/' . basename($profile['photo']); - $profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']); - } - } + if ($profile['is_default'] && in_array($k, ['photo', 'thumb'])) { + continue; + } - if (count($clean)) { - foreach ($clean as $k => $v) { - $r = dbq("UPDATE profile set " . TQUOT . dbesc($k) . TQUOT . " = '" . dbesc($v) - . "' where profile_guid = '" . dbesc($profile['profile_guid']) - . "' and uid = " . intval($channel['channel_id'])); - } - } - } - } + if ($k === 'name') { + $clean['fullname'] = $v; + } elseif ($k === 'with') { + $clean['partner'] = $v; + } elseif ($k === 'work') { + $clean['employment'] = $v; + } elseif (array_key_exists($k, $x[0])) { + $clean[$k] = $v; + } - $addon = [ 'channel' => $channel, 'data' => $arr ]; - /** - * @hooks process_channel_sync_delivery - * Called when accepting delivery of a 'sync packet' containing structure and table updates from a channel clone. - * * \e array \b channel - * * \e array \b data - */ - call_hooks('process_channel_sync_delivery', $addon); + /** + * @TODO + * We also need to import local photos if a custom photo is selected + */ - $DR = new DReport(z_root(),$d,$d,'sync','channel sync delivered'); + if ((strpos($profile['thumb'], '/photo/profile/l/') !== false) || intval($profile['is_default'])) { + $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id']; + $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id']; + } else { + $profile['photo'] = z_root() . '/photo/' . basename($profile['photo']); + $profile['thumb'] = z_root() . '/photo/' . basename($profile['thumb']); + } + } - $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); + if (count($clean)) { + foreach ($clean as $k => $v) { + $r = dbq("UPDATE profile set " . TQUOT . dbesc($k) . TQUOT . " = '" . dbesc($v) + . "' where profile_guid = '" . dbesc($profile['profile_guid']) + . "' and uid = " . intval($channel['channel_id'])); + } + } + } + } - $result[] = $DR->get(); - } + $addon = ['channel' => $channel, 'data' => $arr]; + /** + * @hooks process_channel_sync_delivery + * Called when accepting delivery of a 'sync packet' containing structure and table updates from a channel clone. + * * \e array \b channel + * * \e array \b data + */ + call_hooks('process_channel_sync_delivery', $addon); - return $result; - } + $DR = new DReport(z_root(), $d, $d, 'sync', 'channel sync delivered'); - /** - * @brief Synchronises locations. - * - * @param array $sender - * @param array $arr - * @param boolean $absolute (optional) default false - * @return array - */ + $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); - static function sync_locations($sender, $arr, $absolute = false) { + $result[] = $DR->get(); + } - $ret = []; - $what = EMPTY_STR; - $changed = false; + return $result; + } - // If a sender reports that the channel has been deleted, delete its hubloc + /** + * @brief Synchronises locations. + * + * @param array $sender + * @param array $arr + * @param bool $absolute (optional) default false + * @return array + */ - if (isset($arr['deleted_locally']) && intval($arr['deleted_locally'])) { - q("UPDATE hubloc SET hubloc_deleted = 1, hubloc_updated = '%s' WHERE hubloc_hash = '%s' AND hubloc_url = '%s'", - dbesc(datetime_convert()), - dbesc($sender['hash']), - dbesc($sender['site']['url']) - ); - } + public static function sync_locations($sender, $arr, $absolute = false) + { - if($arr['locations']) { + $ret = []; + $what = EMPTY_STR; + $changed = false; - $x = q("select * from xchan where xchan_hash = '%s'", - dbesc($sender['hash']) - ); - if ($x) { - $xchan = array_shift($x); - } + // If a sender reports that the channel has been deleted, delete its hubloc - if ($absolute) { - Libzot::check_location_move($sender['hash'],$arr['locations']); - } - - $xisting = q("select * from hubloc where hubloc_hash = '%s'", - dbesc($sender['hash']) - ); + if (isset($arr['deleted_locally']) && intval($arr['deleted_locally'])) { + q("UPDATE hubloc SET hubloc_deleted = 1, hubloc_updated = '%s' WHERE hubloc_hash = '%s' AND hubloc_url = '%s'", + dbesc(datetime_convert()), + dbesc($sender['hash']), + dbesc($sender['site']['url']) + ); + } - if (! $xisting) { - $xisting = []; - } - - // See if a primary is specified + if ($arr['locations']) { - $has_primary = false; - foreach($arr['locations'] as $location) { - if($location['primary']) { - $has_primary = true; - break; - } - } + $x = q("select * from xchan where xchan_hash = '%s'", + dbesc($sender['hash']) + ); + if ($x) { + $xchan = array_shift($x); + } - // Ensure that they have one primary hub + if ($absolute) { + Libzot::check_location_move($sender['hash'], $arr['locations']); + } - if(! $has_primary) - $arr['locations'][0]['primary'] = true; + $xisting = q("select * from hubloc where hubloc_hash = '%s'", + dbesc($sender['hash']) + ); - foreach($arr['locations'] as $location) { - if(! Libzot::verify($location['url'],$location['url_sig'],$sender['public_key'])) { - logger('Unable to verify site signature for ' . $location['url']); - $ret['message'] .= sprintf( t('Unable to verify site signature for %s'), $location['url']) . EOL; - continue; - } + if (!$xisting) { + $xisting = []; + } - for($x = 0; $x < count($xisting); $x ++) { - if(($xisting[$x]['hubloc_url'] === $location['url']) - && ($xisting[$x]['hubloc_sitekey'] === $location['sitekey'])) { - $xisting[$x]['updated'] = true; - } - } + // See if a primary is specified - if(! $location['sitekey']) { - logger('Empty hubloc sitekey. ' . print_r($location,true)); - continue; - } + $has_primary = false; + foreach ($arr['locations'] as $location) { + if ($location['primary']) { + $has_primary = true; + break; + } + } - // match as many fields as possible in case anything at all changed. + // Ensure that they have one primary hub - $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_id_url = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ", - dbesc($sender['hash']), - dbesc($sender['id']), - dbesc($sender['id_sig']), - dbesc($location['id_url']), - dbesc($location['url']), - dbesc($location['url_sig']), - dbesc($location['host']), - dbesc($location['address']), - dbesc($location['callback']), - dbesc($location['sitekey']) - ); - if($r) { - logger('Hub exists: ' . $location['url'], LOGGER_DEBUG); + if (!$has_primary) + $arr['locations'][0]['primary'] = true; - // generate a new hubloc_site_id if it's wrong due to historical bugs 2021-11-30 - - if ($r[0]['hubloc_site_id'] !== $location['site_id']) { - q("update hubloc set hubloc_site_id = '%s' where hubloc_id = %d", - dbesc(Libzot::make_xchan_hash($location['url'],$location['sitekey'])), - intval($r[0]['hubloc_id']) - ); - } - - // update connection timestamp if this is the site we're talking to - // This only happens when called from import_xchan + foreach ($arr['locations'] as $location) { + if (!Libzot::verify($location['url'], $location['url_sig'], $sender['public_key'])) { + logger('Unable to verify site signature for ' . $location['url']); + $ret['message'] .= sprintf(t('Unable to verify site signature for %s'), $location['url']) . EOL; + continue; + } - $current_site = false; + for ($x = 0; $x < count($xisting); $x++) { + if (($xisting[$x]['hubloc_url'] === $location['url']) + && ($xisting[$x]['hubloc_sitekey'] === $location['sitekey'])) { + $xisting[$x]['updated'] = true; + } + } - $t = datetime_convert('UTC','UTC','now - 15 minutes'); - - if(array_key_exists('site',$arr) && $location['url'] == $arr['site']['url']) { - q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_updated < '%s'", - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']), - dbesc($t) - ); - $current_site = true; - } + if (!$location['sitekey']) { + logger('Empty hubloc sitekey. ' . print_r($location, true)); + continue; + } - if($current_site && (intval($r[0]['hubloc_error']) || intval($r[0]['hubloc_deleted']))) { - q("update hubloc set hubloc_error = 0, hubloc_deleted = 0 where hubloc_id = %d", - intval($r[0]['hubloc_id']) - ); - if(intval($r[0]['hubloc_orphancheck'])) { - q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d", - intval($r[0]['hubloc_id']) - ); - } - q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", - dbesc($sender['hash']) - ); - } + // match as many fields as possible in case anything at all changed. - // Remove pure duplicates - if(count($r) > 1) { - for($h = 1; $h < count($r); $h ++) { - q("delete from hubloc where hubloc_id = %d", - intval($r[$h]['hubloc_id']) - ); - $what .= 'duplicate_hubloc_removed '; - $changed = true; - } - } + $r = q("select * from hubloc where hubloc_hash = '%s' and hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_id_url = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_host = '%s' and hubloc_addr = '%s' and hubloc_callback = '%s' and hubloc_sitekey = '%s' ", + dbesc($sender['hash']), + dbesc($sender['id']), + dbesc($sender['id_sig']), + dbesc($location['id_url']), + dbesc($location['url']), + dbesc($location['url_sig']), + dbesc($location['host']), + dbesc($location['address']), + dbesc($location['callback']), + dbesc($location['sitekey']) + ); + if ($r) { + logger('Hub exists: ' . $location['url'], LOGGER_DEBUG); - if(intval($r[0]['hubloc_primary']) && (! $location['primary'])) { - $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d", - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) - ); - $r[0]['hubloc_primary'] = intval($location['primary']); - hubloc_change_primary($r[0]); - $what .= 'primary_hub '; - $changed = true; - } - elseif((! intval($r[0]['hubloc_primary'])) && ($location['primary'])) { - $m = q("update hubloc set hubloc_primary = 1, hubloc_updated = '%s' where hubloc_id = %d", - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) - ); - // make sure hubloc_change_primary() has current data - $r[0]['hubloc_primary'] = intval($location['primary']); - hubloc_change_primary($r[0]); - $what .= 'primary_hub '; - $changed = true; - } - elseif($absolute) { - // Absolute sync - make sure the current primary is correctly reflected in the xchan - $pr = hubloc_change_primary($r[0]); - if($pr) { - $what .= 'xchan_primary '; - $changed = true; - } - } - elseif(intval($r[0]['hubloc_primary']) && $xchan && $xchan['xchan_url'] !== $r[0]['hubloc_id_url']) { - $pr = hubloc_change_primary($r[0]); - if($pr) { - $what .= 'xchan_primary '; - $changed = true; - } - } + // generate a new hubloc_site_id if it's wrong due to historical bugs 2021-11-30 - if(intval($r[0]['hubloc_deleted']) && (! intval($location['deleted']))) { - $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d", - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) - ); - $what .= 'undelete_hub '; - $changed = true; - } - elseif((! intval($r[0]['hubloc_deleted'])) && (intval($location['deleted']))) { - logger('deleting hubloc: ' . $r[0]['hubloc_addr']); - $n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", - dbesc(datetime_convert()), - intval($r[0]['hubloc_id']) - ); - $what .= 'delete_hub '; - $changed = true; - } - continue; - } + if ($r[0]['hubloc_site_id'] !== $location['site_id']) { + q("update hubloc set hubloc_site_id = '%s' where hubloc_id = %d", + dbesc(Libzot::make_xchan_hash($location['url'], $location['sitekey'])), + intval($r[0]['hubloc_id']) + ); + } - // Existing hubs are dealt with. Now let's process any new ones. - // New hub claiming to be primary. Make it so by removing any existing primaries. + // update connection timestamp if this is the site we're talking to + // This only happens when called from import_xchan - if(intval($location['primary'])) { - $r = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_hash = '%s' and hubloc_primary = 1", - dbesc(datetime_convert()), - dbesc($sender['hash']) - ); - } + $current_site = false; - logger('New hub: ' . $location['url']); + $t = datetime_convert('UTC', 'UTC', 'now - 15 minutes'); - $r = hubloc_store_lowlevel( - [ - 'hubloc_guid' => $sender['id'], - 'hubloc_guid_sig' => $sender['id_sig'], - 'hubloc_id_url' => $location['id_url'], - 'hubloc_hash' => $sender['hash'], - 'hubloc_addr' => $location['address'], - 'hubloc_network' => 'zot6', - 'hubloc_primary' => intval($location['primary']), - 'hubloc_url' => $location['url'], - 'hubloc_url_sig' => $location['url_sig'], - 'hubloc_site_id' => Libzot::make_xchan_hash($location['url'],$location['sitekey']), - 'hubloc_host' => $location['host'], - 'hubloc_callback' => $location['callback'], - 'hubloc_sitekey' => $location['sitekey'], - 'hubloc_updated' => datetime_convert(), - 'hubloc_connected' => datetime_convert() - ] - ); + if (array_key_exists('site', $arr) && $location['url'] == $arr['site']['url']) { + q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_updated < '%s'", + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']), + dbesc($t) + ); + $current_site = true; + } - $what .= 'newhub '; - $changed = true; + if ($current_site && (intval($r[0]['hubloc_error']) || intval($r[0]['hubloc_deleted']))) { + q("update hubloc set hubloc_error = 0, hubloc_deleted = 0 where hubloc_id = %d", + intval($r[0]['hubloc_id']) + ); + if (intval($r[0]['hubloc_orphancheck'])) { + q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d", + intval($r[0]['hubloc_id']) + ); + } + q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", + dbesc($sender['hash']) + ); + } - if($location['primary']) { - $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s' limit 1", - dbesc($location['address']), - dbesc($location['sitekey']) - ); - if($r) - hubloc_change_primary($r[0]); - } - } + // Remove pure duplicates + if (count($r) > 1) { + for ($h = 1; $h < count($r); $h++) { + q("delete from hubloc where hubloc_id = %d", + intval($r[$h]['hubloc_id']) + ); + $what .= 'duplicate_hubloc_removed '; + $changed = true; + } + } - // get rid of any hubs we have for this channel which weren't reported. + if (intval($r[0]['hubloc_primary']) && (!$location['primary'])) { + $m = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_id = %d", + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + $r[0]['hubloc_primary'] = intval($location['primary']); + hubloc_change_primary($r[0]); + $what .= 'primary_hub '; + $changed = true; + } elseif ((!intval($r[0]['hubloc_primary'])) && ($location['primary'])) { + $m = q("update hubloc set hubloc_primary = 1, hubloc_updated = '%s' where hubloc_id = %d", + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + // make sure hubloc_change_primary() has current data + $r[0]['hubloc_primary'] = intval($location['primary']); + hubloc_change_primary($r[0]); + $what .= 'primary_hub '; + $changed = true; + } elseif ($absolute) { + // Absolute sync - make sure the current primary is correctly reflected in the xchan + $pr = hubloc_change_primary($r[0]); + if ($pr) { + $what .= 'xchan_primary '; + $changed = true; + } + } elseif (intval($r[0]['hubloc_primary']) && $xchan && $xchan['xchan_url'] !== $r[0]['hubloc_id_url']) { + $pr = hubloc_change_primary($r[0]); + if ($pr) { + $what .= 'xchan_primary '; + $changed = true; + } + } - if($absolute && $xisting) { - foreach($xisting as $x) { - if(! array_key_exists('updated',$x)) { - logger('Deleting unreferenced hub location ' . $x['hubloc_addr']); - $r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", - dbesc(datetime_convert()), - intval($x['hubloc_id']) - ); - $what .= 'removed_hub '; - $changed = true; - } - } - } - } - else { - logger('No locations to sync!'); - } + if (intval($r[0]['hubloc_deleted']) && (!intval($location['deleted']))) { + $n = q("update hubloc set hubloc_deleted = 0, hubloc_updated = '%s' where hubloc_id = %d", + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + $what .= 'undelete_hub '; + $changed = true; + } elseif ((!intval($r[0]['hubloc_deleted'])) && (intval($location['deleted']))) { + logger('deleting hubloc: ' . $r[0]['hubloc_addr']); + $n = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", + dbesc(datetime_convert()), + intval($r[0]['hubloc_id']) + ); + $what .= 'delete_hub '; + $changed = true; + } + continue; + } - $ret['change_message'] = $what; - $ret['changed'] = $changed; + // Existing hubs are dealt with. Now let's process any new ones. + // New hub claiming to be primary. Make it so by removing any existing primaries. - return $ret; - } + if (intval($location['primary'])) { + $r = q("update hubloc set hubloc_primary = 0, hubloc_updated = '%s' where hubloc_hash = '%s' and hubloc_primary = 1", + dbesc(datetime_convert()), + dbesc($sender['hash']) + ); + } + + logger('New hub: ' . $location['url']); + + $r = hubloc_store_lowlevel( + [ + 'hubloc_guid' => $sender['id'], + 'hubloc_guid_sig' => $sender['id_sig'], + 'hubloc_id_url' => $location['id_url'], + 'hubloc_hash' => $sender['hash'], + 'hubloc_addr' => $location['address'], + 'hubloc_network' => 'zot6', + 'hubloc_primary' => intval($location['primary']), + 'hubloc_url' => $location['url'], + 'hubloc_url_sig' => $location['url_sig'], + 'hubloc_site_id' => Libzot::make_xchan_hash($location['url'], $location['sitekey']), + 'hubloc_host' => $location['host'], + 'hubloc_callback' => $location['callback'], + 'hubloc_sitekey' => $location['sitekey'], + 'hubloc_updated' => datetime_convert(), + 'hubloc_connected' => datetime_convert() + ] + ); + + $what .= 'newhub '; + $changed = true; + + if ($location['primary']) { + $r = q("select * from hubloc where hubloc_addr = '%s' and hubloc_sitekey = '%s' limit 1", + dbesc($location['address']), + dbesc($location['sitekey']) + ); + if ($r) + hubloc_change_primary($r[0]); + } + } + + // get rid of any hubs we have for this channel which weren't reported. + + if ($absolute && $xisting) { + foreach ($xisting as $x) { + if (!array_key_exists('updated', $x)) { + logger('Deleting unreferenced hub location ' . $x['hubloc_addr']); + $r = q("update hubloc set hubloc_deleted = 1, hubloc_updated = '%s' where hubloc_id = %d", + dbesc(datetime_convert()), + intval($x['hubloc_id']) + ); + $what .= 'removed_hub '; + $changed = true; + } + } + } + } else { + logger('No locations to sync!'); + } + + $ret['change_message'] = $what; + $ret['changed'] = $changed; + + return $ret; + } - static function keychange($channel,$arr) { + public static function keychange($channel, $arr) + { - // verify the keychange operation - if(! Libzot::verify($arr['channel']['channel_pubkey'],$arr['keychange']['new_sig'],$channel['channel_prvkey'])) { - logger('sync keychange: verification failed'); - return; - } + // verify the keychange operation + if (!Libzot::verify($arr['channel']['channel_pubkey'], $arr['keychange']['new_sig'], $channel['channel_prvkey'])) { + logger('sync keychange: verification failed'); + return; + } - $sig = Libzot::sign($channel['channel_guid'],$arr['channel']['channel_prvkey']); - $hash = Libzot::make_xchan_hash($channel['channel_guid'],$arr['channel']['channel_pubkey']); + $sig = Libzot::sign($channel['channel_guid'], $arr['channel']['channel_prvkey']); + $hash = Libzot::make_xchan_hash($channel['channel_guid'], $arr['channel']['channel_pubkey']); - $r = q("update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s', + $r = q("update channel set channel_prvkey = '%s', channel_pubkey = '%s', channel_guid_sig = '%s', channel_hash = '%s' where channel_id = %d", - dbesc($arr['channel']['channel_prvkey']), - dbesc($arr['channel']['channel_pubkey']), - dbesc($sig), - dbesc($hash), - intval($channel['channel_id']) - ); - if(! $r) { - logger('keychange sync: channel update failed'); - return; - } + dbesc($arr['channel']['channel_prvkey']), + dbesc($arr['channel']['channel_pubkey']), + dbesc($sig), + dbesc($hash), + intval($channel['channel_id']) + ); + if (!$r) { + logger('keychange sync: channel update failed'); + return; + } - $r = q("select * from channel where channel_id = %d", - intval($channel['channel_id']) - ); + $r = q("select * from channel where channel_id = %d", + intval($channel['channel_id']) + ); - if(! $r) { - logger('keychange sync: channel retrieve failed'); - return; - } + if (!$r) { + logger('keychange sync: channel retrieve failed'); + return; + } - $channel = $r[0]; + $channel = $r[0]; - $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' ", - dbesc($arr['keychange']['old_hash']), - dbesc(z_root()) - ); + $h = q("select * from hubloc where hubloc_hash = '%s' and hubloc_url = '%s' ", + dbesc($arr['keychange']['old_hash']), + dbesc(z_root()) + ); - if($h) { - foreach($h as $hv) { - $hv['hubloc_guid_sig'] = $sig; - $hv['hubloc_hash'] = $hash; - $hv['hubloc_url_sig'] = Libzot::sign(z_root(),$channel['channel_prvkey']); - hubloc_store_lowlevel($hv); - } - } + if ($h) { + foreach ($h as $hv) { + $hv['hubloc_guid_sig'] = $sig; + $hv['hubloc_hash'] = $hash; + $hv['hubloc_url_sig'] = Libzot::sign(z_root(), $channel['channel_prvkey']); + hubloc_store_lowlevel($hv); + } + } - $x = q("select * from xchan where xchan_hash = '%s' ", - dbesc($arr['keychange']['old_hash']) - ); + $x = q("select * from xchan where xchan_hash = '%s' ", + dbesc($arr['keychange']['old_hash']) + ); - $check = q("select * from xchan where xchan_hash = '%s'", - dbesc($hash) - ); + $check = q("select * from xchan where xchan_hash = '%s'", + dbesc($hash) + ); - if(($x) && (! $check)) { - $oldxchan = $x[0]; - foreach($x as $xv) { - $xv['xchan_guid_sig'] = $sig; - $xv['xchan_hash'] = $hash; - $xv['xchan_pubkey'] = $channel['channel_pubkey']; - $xv['xchan_updated'] = datetime_convert(); - xchan_store_lowlevel($xv); - $newxchan = $xv; - } - } + if (($x) && (!$check)) { + $oldxchan = $x[0]; + foreach ($x as $xv) { + $xv['xchan_guid_sig'] = $sig; + $xv['xchan_hash'] = $hash; + $xv['xchan_pubkey'] = $channel['channel_pubkey']; + $xv['xchan_updated'] = datetime_convert(); + xchan_store_lowlevel($xv); + $newxchan = $xv; + } + } - $a = q("select * from abook where abook_xchan = '%s' and abook_self = 1", - dbesc($arr['keychange']['old_hash']) - ); + $a = q("select * from abook where abook_xchan = '%s' and abook_self = 1", + dbesc($arr['keychange']['old_hash']) + ); - if($a) { - q("update abook set abook_xchan = '%s' where abook_id = %d", - dbesc($hash), - intval($a[0]['abook_id']) - ); - } + if ($a) { + q("update abook set abook_xchan = '%s' where abook_id = %d", + dbesc($hash), + intval($a[0]['abook_id']) + ); + } - xchan_change_key($oldxchan,$newxchan,$arr['keychange']); + xchan_change_key($oldxchan, $newxchan, $arr['keychange']); - } + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php index 8c6db171d..630fd82a4 100644 --- a/Zotlabs/Lib/Libzot.php +++ b/Zotlabs/Lib/Libzot.php @@ -20,1019 +20,1012 @@ use Zotlabs\Daemon\Run; require_once('include/html2bbcode.php'); -class Libzot { +class Libzot +{ - /** - * @brief Generates a unique string for use as a zot guid. - * - * Generates a unique string for use as a zot guid using our DNS-based url, the - * channel nickname and some entropy. - * The entropy ensures uniqueness against re-installs where the same URL and - * nickname are chosen. - * - * @note zot doesn't require this to be unique. Internally we use a whirlpool - * hash of this guid and the signature of this guid signed with the channel - * private key. This can be verified and should make the probability of - * collision of the verified result negligible within the constraints of our - * immediate universe. - * - * @param string $channel_nick a unique nickname of controlling entity - * @returns string - */ + /** + * @brief Generates a unique string for use as a zot guid. + * + * Generates a unique string for use as a zot guid using our DNS-based url, the + * channel nickname and some entropy. + * The entropy ensures uniqueness against re-installs where the same URL and + * nickname are chosen. + * + * @note zot doesn't require this to be unique. Internally we use a whirlpool + * hash of this guid and the signature of this guid signed with the channel + * private key. This can be verified and should make the probability of + * collision of the verified result negligible within the constraints of our + * immediate universe. + * + * @param string $channel_nick a unique nickname of controlling entity + * @returns string + */ - static function new_uid($channel_nick) { - $rawstr = z_root() . '/' . $channel_nick . '.' . mt_rand(); - return(base64url_encode(hash('whirlpool', $rawstr, true), true)); - } + public static function new_uid($channel_nick) + { + $rawstr = z_root() . '/' . $channel_nick . '.' . mt_rand(); + return (base64url_encode(hash('whirlpool', $rawstr, true), true)); + } - /** - * @brief Generates a portable hash identifier for a channel. - * - * Generates a portable hash identifier for the channel identified by $guid and - * $pubkey. - * - * @note This ID is portable across the network but MUST be calculated locally - * by verifying the signature and can not be trusted as an identity. - * - * @param string $guid - * @param string $pubkey - */ + /** + * @brief Generates a portable hash identifier for a channel. + * + * Generates a portable hash identifier for the channel identified by $guid and + * $pubkey. + * + * @note This ID is portable across the network but MUST be calculated locally + * by verifying the signature and can not be trusted as an identity. + * + * @param string $guid + * @param string $pubkey + */ - static function make_xchan_hash($guid, $pubkey) { - return base64url_encode(hash('whirlpool', $guid . $pubkey, true)); - } + public static function make_xchan_hash($guid, $pubkey) + { + return base64url_encode(hash('whirlpool', $guid . $pubkey, true)); + } - /** - * @brief Given a zot hash, return all distinct hubs. - * - * This function is used in building the zot discovery packet and therefore - * should only be used by channels which are defined on this hub. - * - * @param string $hash - xchan_hash - * @returns array of hubloc (hub location structures) - * - */ + /** + * @brief Given a zot hash, return all distinct hubs. + * + * This function is used in building the zot discovery packet and therefore + * should only be used by channels which are defined on this hub. + * + * @param string $hash - xchan_hash + * @returns array of hubloc (hub location structures) + * + */ - static function get_hublocs($hash) { + public static function get_hublocs($hash) + { - /* Only search for active hublocs - e.g. those that haven't been marked deleted */ + /* Only search for active hublocs - e.g. those that haven't been marked deleted */ - $ret = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 order by hubloc_url ", - dbesc($hash) - ); + $ret = q("select * from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 order by hubloc_url ", + dbesc($hash) + ); - return $ret; - } + return $ret; + } - /** - * @brief Builds a zot6 notification packet. - * - * Builds a zot6 notification packet that you can either store in the queue with - * a message array or call zot_zot to immediately zot it to the other side. - * - * @param array $channel - * sender channel structure - * @param string $type - * packet type: one of 'activity', 'response', 'sync', 'purge', 'refresh', 'force_refresh', 'rekey' - * @param array $recipients - * envelope recipients, array of portable_id's; empty for public posts - * @param string msg - * optional message - * @param string $remote_key - * optional public site key of target hub used to encrypt entire packet - * @param string $methods - * optional comma separated list of encryption methods @ref self::best_algorithm() - * @returns string json encoded zot packet - */ + /** + * @brief Builds a zot6 notification packet. + * + * Builds a zot6 notification packet that you can either store in the queue with + * a message array or call zot_zot to immediately zot it to the other side. + * + * @param array $channel + * sender channel structure + * @param string $type + * packet type: one of 'activity', 'response', 'sync', 'purge', 'refresh', 'force_refresh', 'rekey' + * @param array $recipients + * envelope recipients, array of portable_id's; empty for public posts + * @param string msg + * optional message + * @param string $remote_key + * optional public site key of target hub used to encrypt entire packet + * @param string $methods + * optional comma separated list of encryption methods @ref self::best_algorithm() + * @returns string json encoded zot packet + */ - static function build_packet($channel, $type = 'activity', $recipients = null, $msg = '', $encoding = 'activitystreams', $remote_key = null, $methods = '') { + public static function build_packet($channel, $type = 'activity', $recipients = null, $msg = '', $encoding = 'activitystreams', $remote_key = null, $methods = '') + { - $data = [ - 'type' => $type, - 'encoding' => $encoding, - 'sender' => $channel['channel_hash'], - 'site_id' => self::make_xchan_hash(z_root(), get_config('system','pubkey')), - 'version' => System::get_zot_revision(), - ]; + $data = [ + 'type' => $type, + 'encoding' => $encoding, + 'sender' => $channel['channel_hash'], + 'site_id' => self::make_xchan_hash(z_root(), get_config('system', 'pubkey')), + 'version' => System::get_zot_revision(), + ]; - if ($recipients) { - $data['recipients'] = $recipients; - } + if ($recipients) { + $data['recipients'] = $recipients; + } - if ($msg) { - $actor = channel_url($channel); - if ($encoding === 'activitystreams' && array_key_exists('actor',$msg) && is_string($msg['actor']) && $actor === $msg['actor']) { - $msg = JSalmon::sign($msg,$actor,$channel['channel_prvkey']); - } - $data['data'] = $msg; - } - else { - unset($data['encoding']); - } + if ($msg) { + $actor = channel_url($channel); + if ($encoding === 'activitystreams' && array_key_exists('actor', $msg) && is_string($msg['actor']) && $actor === $msg['actor']) { + $msg = JSalmon::sign($msg, $actor, $channel['channel_prvkey']); + } + $data['data'] = $msg; + } else { + unset($data['encoding']); + } - logger('packet: ' . print_r($data,true), LOGGER_DATA, LOG_DEBUG); + logger('packet: ' . print_r($data, true), LOGGER_DATA, LOG_DEBUG); - if ($remote_key) { - $algorithm = self::best_algorithm($methods); - if ($algorithm) { - $data = Crypto::encapsulate(json_encode($data),$remote_key, $algorithm); - } - } + if ($remote_key) { + $algorithm = self::best_algorithm($methods); + if ($algorithm) { + $data = Crypto::encapsulate(json_encode($data), $remote_key, $algorithm); + } + } - return json_encode($data); - } + return json_encode($data); + } - /** - * @brief Choose best encryption function from those available on both sites. - * - * @param string $methods - * comma separated list of encryption methods - * @return string first match from our site method preferences crypto_methods() array - * of a method which is common to both sites; or an empty string if no matches are found. - * - * Failure to find a common algorithm is not an issue as our communications - * take place primarily over https, so this is just redundant encryption in many cases. - * - * In any case, the receiver is free to reject unencrypted private content if they have - * reason to distrust https. - * - * We are not using array_intersect() here because the specification for that function - * does not guarantee the order of results. It probably returns entries in the correct - * order for our needs and would simplify this function dramatically, but we cannot be - * certain that it will always do so on all operating systems. - * - */ + /** + * @brief Choose best encryption function from those available on both sites. + * + * @param string $methods + * comma separated list of encryption methods + * @return string first match from our site method preferences crypto_methods() array + * of a method which is common to both sites; or an empty string if no matches are found. + * + * Failure to find a common algorithm is not an issue as our communications + * take place primarily over https, so this is just redundant encryption in many cases. + * + * In any case, the receiver is free to reject unencrypted private content if they have + * reason to distrust https. + * + * We are not using array_intersect() here because the specification for that function + * does not guarantee the order of results. It probably returns entries in the correct + * order for our needs and would simplify this function dramatically, but we cannot be + * certain that it will always do so on all operating systems. + * + */ - static function best_algorithm($methods) { + public static function best_algorithm($methods) + { - $x = [ - 'methods' => $methods, - 'result' => '' - ]; + $x = [ + 'methods' => $methods, + 'result' => '' + ]; - /** - * @hooks zot_best_algorithm - * Called when negotiating crypto algorithms with remote sites. - * * \e string \b methods - comma separated list of encryption methods - * * \e string \b result - the algorithm to return - */ - - call_hooks('zot_best_algorithm', $x); + /** + * @hooks zot_best_algorithm + * Called when negotiating crypto algorithms with remote sites. + * * \e string \b methods - comma separated list of encryption methods + * * \e string \b result - the algorithm to return + */ - if ($x['result']) { - return $x['result']; - } + call_hooks('zot_best_algorithm', $x); - if ($methods) { - // $x = their methods as an array - $x = explode(',', $methods); - if ($x) { - // $y = our methods as an array - $y = Crypto::methods(); - if ($y) { - foreach ($y as $yv) { - $yv = trim($yv); - if (in_array($yv, $x)) { - return($yv); - } - } - } - } - } + if ($x['result']) { + return $x['result']; + } - return EMPTY_STR; - } + if ($methods) { + // $x = their methods as an array + $x = explode(',', $methods); + if ($x) { + // $y = our methods as an array + $y = Crypto::methods(); + if ($y) { + foreach ($y as $yv) { + $yv = trim($yv); + if (in_array($yv, $x)) { + return ($yv); + } + } + } + } + } + + return EMPTY_STR; + } - /** - * @brief send a zot message - * - * @see z_post_url() - * - * @param string $url - * @param array $data - * @param array $channel (required if using zot6 delivery) - * @param array $crypto (required if encrypted httpsig, requires hubloc_sitekey and site_crypto elements) - * @return array see z_post_url() for returned data format - */ + /** + * @brief send a zot message + * + * @param string $url + * @param array $data + * @param array $channel (required if using zot6 delivery) + * @param array $crypto (required if encrypted httpsig, requires hubloc_sitekey and site_crypto elements) + * @return array see z_post_url() for returned data format + * @see z_post_url() + * + */ - static function zot($url, $data, $channel = null,$crypto = null) { + public static function zot($url, $data, $channel = null, $crypto = null) + { - if ($channel) { - $headers = [ - 'X-Zot-Token' => random_string(), - 'Digest' => HTTPSig::generate_digest_header($data), - 'Content-type' => 'application/x-zot+json', - '(request-target)' => 'post ' . get_request_string($url) - ]; + if ($channel) { + $headers = [ + 'X-Zot-Token' => random_string(), + 'Digest' => HTTPSig::generate_digest_header($data), + 'Content-type' => 'application/x-zot+json', + '(request-target)' => 'post ' . get_request_string($url) + ]; - $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false,'sha512', - (($crypto) ? [ 'key' => $crypto['hubloc_sitekey'], 'algorithm' => self::best_algorithm($crypto['site_crypto']) ] : false)); - } - else { - $h = []; - } + $h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), false, 'sha512', + (($crypto) ? ['key' => $crypto['hubloc_sitekey'], 'algorithm' => self::best_algorithm($crypto['site_crypto'])] : false)); + } else { + $h = []; + } - $redirects = 0; + $redirects = 0; - return z_post_url($url,$data,$redirects,((empty($h)) ? [] : [ 'headers' => $h ])); - } + return z_post_url($url, $data, $redirects, ((empty($h)) ? [] : ['headers' => $h])); + } - /** - * @brief Refreshes after permission changed or friending, etc. - * - * - * refresh is typically invoked when somebody has changed permissions of a channel and they are notified - * to fetch new permissions via a finger/discovery operation. This may result in a new connection - * (abook entry) being added to a local channel and it may result in auto-permissions being granted. - * - * Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a - * permission change has been made by the sender which affects the target channel. The hub controlling - * the target channel does targeted discovery (in which a zot discovery request contains permissions for - * the sender which were set by the local channel). These are decoded here, and if necessary an abook - * structure (addressbook) is created to store the permissions assigned to this channel. - * - * Initially these abook structures are created with a 'pending' flag, so that no reverse permissions are - * implied until this is approved by the owner channel. A channel can also auto-populate permissions in - * return and send back a refresh packet of its own. This is used by forum and group communication channels - * so that friending and membership in the channel's "club" is automatic. - * - * If $force is set when calling this function, this operation will be attempted even if our records indicate - * the remote site is permanently down. - * - * @param array $them => xchan structure of sender - * @param array $channel => local channel structure of target recipient, required for "friending" operations - * @param array $force (optional) default false - * - * @return boolean - * * \b true if successful - * * otherwise \b false - */ + /** + * @brief Refreshes after permission changed or friending, etc. + * + * + * refresh is typically invoked when somebody has changed permissions of a channel and they are notified + * to fetch new permissions via a finger/discovery operation. This may result in a new connection + * (abook entry) being added to a local channel and it may result in auto-permissions being granted. + * + * Friending in zot is accomplished by sending a refresh packet to a specific channel which indicates a + * permission change has been made by the sender which affects the target channel. The hub controlling + * the target channel does targeted discovery (in which a zot discovery request contains permissions for + * the sender which were set by the local channel). These are decoded here, and if necessary an abook + * structure (addressbook) is created to store the permissions assigned to this channel. + * + * Initially these abook structures are created with a 'pending' flag, so that no reverse permissions are + * implied until this is approved by the owner channel. A channel can also auto-populate permissions in + * return and send back a refresh packet of its own. This is used by forum and group communication channels + * so that friending and membership in the channel's "club" is automatic. + * + * If $force is set when calling this function, this operation will be attempted even if our records indicate + * the remote site is permanently down. + * + * @param array $them => xchan structure of sender + * @param array $channel => local channel structure of target recipient, required for "friending" operations + * @param array $force (optional) default false + * + * @return boolean + * * \b true if successful + * * otherwise \b false + */ - static function refresh($them, $channel = null, $force = false) { + public static function refresh($them, $channel = null, $force = false) + { - $hsig_valid = false; + $hsig_valid = false; - logger('them: ' . print_r($them,true), LOGGER_DATA, LOG_DEBUG); - if ($channel) { - logger('channel: ' . print_r($channel,true), LOGGER_DATA, LOG_DEBUG); - } + logger('them: ' . print_r($them, true), LOGGER_DATA, LOG_DEBUG); + if ($channel) { + logger('channel: ' . print_r($channel, true), LOGGER_DATA, LOG_DEBUG); + } - $url = null; + $url = null; - if ($them['hubloc_id_url']) { - $url = $them['hubloc_id_url']; - } - else { - $r = null; - - // if they re-installed the server we could end up with the wrong record - pointing to a hash generated by the old install. - // We'll order by reverse id to try and pick off the most recently created ones first and hopefully end up with the correct hubloc. - // We are looking for the most recently created primary hub, and the most recently created if for some reason we do not have a primary. - // hubloc_id_url is set to the channel home, which corresponds to an ActivityStreams actor id. - - $r = q("select hubloc_id_url, hubloc_primary from hubloc where hubloc_hash = '%s' and hubloc_network = 'zot6' order by hubloc_id desc", - dbesc($them['xchan_hash']) - ); + if ($them['hubloc_id_url']) { + $url = $them['hubloc_id_url']; + } else { + $r = null; - if ($r) { - foreach ($r as $rr) { - if (intval($rr['hubloc_primary'])) { - $url = $rr['hubloc_id_url']; - break; - } - } - if (! $url) { - $url = $r[0]['hubloc_id_url']; - } - } - } - - if (! $url) { - logger('zot_refresh: no url'); - return false; - } + // if they re-installed the server we could end up with the wrong record - pointing to a hash generated by the old install. + // We'll order by reverse id to try and pick off the most recently created ones first and hopefully end up with the correct hubloc. + // We are looking for the most recently created primary hub, and the most recently created if for some reason we do not have a primary. + // hubloc_id_url is set to the channel home, which corresponds to an ActivityStreams actor id. - $m = parse_url($url); - $site_url = unparse_url([ 'scheme' => $m['scheme'], 'host' => $m['host'] ]); + $r = q("select hubloc_id_url, hubloc_primary from hubloc where hubloc_hash = '%s' and hubloc_network = 'zot6' order by hubloc_id desc", + dbesc($them['xchan_hash']) + ); + + if ($r) { + foreach ($r as $rr) { + if (intval($rr['hubloc_primary'])) { + $url = $rr['hubloc_id_url']; + break; + } + } + if (!$url) { + $url = $r[0]['hubloc_id_url']; + } + } + } + + if (!$url) { + logger('zot_refresh: no url'); + return false; + } + + $m = parse_url($url); + $site_url = unparse_url(['scheme' => $m['scheme'], 'host' => $m['host']]); - $s = q("select site_dead from site where site_url = '%s' limit 1", - dbesc($site_url) - ); + $s = q("select site_dead from site where site_url = '%s' limit 1", + dbesc($site_url) + ); - if ($s && intval($s[0]['site_dead']) && (! $force)) { - logger('zot_refresh: site ' . $site_url . ' is marked dead and force flag is not set. Cancelling operation.'); - return false; - } + if ($s && intval($s[0]['site_dead']) && (!$force)) { + logger('zot_refresh: site ' . $site_url . ' is marked dead and force flag is not set. Cancelling operation.'); + return false; + } - $record = Zotfinger::exec($url,$channel); + $record = Zotfinger::exec($url, $channel); - // Check the HTTP signature + // Check the HTTP signature - $hsig = $record['signature']; - if ($hsig && $hsig['signer'] === $url && $hsig['header_valid'] === true && $hsig['content_valid'] === true) { - $hsig_valid = true; - } + $hsig = $record['signature']; + if ($hsig && $hsig['signer'] === $url && $hsig['header_valid'] === true && $hsig['content_valid'] === true) { + $hsig_valid = true; + } - if (! $hsig_valid) { - logger('http signature not valid: ' . (($record['data']) ? print_r($hsig,true) : 'fetch failed')); - return false; - } + if (!$hsig_valid) { + logger('http signature not valid: ' . (($record['data']) ? print_r($hsig, true) : 'fetch failed')); + return false; + } - // If we reach this point, the signature is valid and we can trust the channel discovery data, so try and store - // the generic information in the returned discovery packet. + // If we reach this point, the signature is valid and we can trust the channel discovery data, so try and store + // the generic information in the returned discovery packet. - logger('zot-info: ' . print_r($record,true), LOGGER_DATA, LOG_DEBUG); + logger('zot-info: ' . print_r($record, true), LOGGER_DATA, LOG_DEBUG); - $x = self::import_xchan($record['data'], (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); + $x = self::import_xchan($record['data'], (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); - if (! $x['success']) { - return false; - } + if (!$x['success']) { + return false; + } - // Here we handle discovery packets that return targeted permissions and require an abook (either an existing connection - // or a new one) - - if ($channel && $record['data']['permissions']) { - $old_read_stream_perm = their_perms_contains($channel['channel_id'],$x['hash'],'view_stream'); - set_abconfig($channel['channel_id'],$x['hash'],'system','their_perms',$record['data']['permissions']); + // Here we handle discovery packets that return targeted permissions and require an abook (either an existing connection + // or a new one) - if (array_key_exists('profile',$record['data']) && array_key_exists('next_birthday',$record['data']['profile'])) { - $next_birthday = datetime_convert('UTC','UTC',$record['data']['profile']['next_birthday']); - } - else { - $next_birthday = NULL_DATE; - } + if ($channel && $record['data']['permissions']) { + $old_read_stream_perm = their_perms_contains($channel['channel_id'], $x['hash'], 'view_stream'); + set_abconfig($channel['channel_id'], $x['hash'], 'system', 'their_perms', $record['data']['permissions']); - $profile_assign = get_pconfig($channel['channel_id'],'system','profile_assign',''); + if (array_key_exists('profile', $record['data']) && array_key_exists('next_birthday', $record['data']['profile'])) { + $next_birthday = datetime_convert('UTC', 'UTC', $record['data']['profile']['next_birthday']); + } else { + $next_birthday = NULL_DATE; + } - // Keep original perms to check if we need to notify them - $previous_perms = get_all_perms($channel['channel_id'],$x['hash']); + $profile_assign = get_pconfig($channel['channel_id'], 'system', 'profile_assign', ''); - $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", - dbesc($x['hash']), - intval($channel['channel_id']) - ); + // Keep original perms to check if we need to notify them + $previous_perms = get_all_perms($channel['channel_id'], $x['hash']); - if ($r) { + $r = q("select * from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", + dbesc($x['hash']), + intval($channel['channel_id']) + ); - // connection exists + if ($r) { - // if the dob is the same as what we have stored (disregarding the year), keep the one - // we have as we may have updated the year after sending a notification; and resetting - // to the one we just received would cause us to create duplicated events. + // connection exists - if (substr($r[0]['abook_dob'],5) == substr($next_birthday,5)) - $next_birthday = $r[0]['abook_dob']; + // if the dob is the same as what we have stored (disregarding the year), keep the one + // we have as we may have updated the year after sending a notification; and resetting + // to the one we just received would cause us to create duplicated events. - $y = q("update abook set abook_dob = '%s' + if (substr($r[0]['abook_dob'], 5) == substr($next_birthday, 5)) + $next_birthday = $r[0]['abook_dob']; + + $y = q("update abook set abook_dob = '%s' where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 ", - dbescdate($next_birthday), - dbesc($x['hash']), - intval($channel['channel_id']) - ); + dbescdate($next_birthday), + dbesc($x['hash']), + intval($channel['channel_id']) + ); - if (! $y) { - logger('abook update failed'); - } - else { - // if we were just granted read stream permission and didn't have it before, try to pull in some posts - if ((! $old_read_stream_perm) && (intval($permissions['view_stream']))) - Run::Summon([ 'Onepoll', $r[0]['abook_id'] ]); - } - } - else { + if (!$y) { + logger('abook update failed'); + } else { + // if we were just granted read stream permission and didn't have it before, try to pull in some posts + if ((!$old_read_stream_perm) && (intval($permissions['view_stream']))) + Run::Summon(['Onepoll', $r[0]['abook_id']]); + } + } else { - // limit the ability to do connection spamming, this limit is per channel - $lim = intval(get_config('system','max_connections_per_day',50)); - if ($lim) { - $n = q("select count(abook_id) as total from abook where abook_channel = %d and abook_created > '%s'", - intval($channel['channel_id']), - dbesc(datetime_convert('UTC','UTC','now - 24 hours')) - ); - if ($n && intval($n['total']) > $lim) { - logger('channel: ' . $channel['channel_id'] . ' too many new connections per day. This one from ' . $hsig['signer'], LOGGER_NORMAL, LOG_WARNING); - return false; - } - } + // limit the ability to do connection spamming, this limit is per channel + $lim = intval(get_config('system', 'max_connections_per_day', 50)); + if ($lim) { + $n = q("select count(abook_id) as total from abook where abook_channel = %d and abook_created > '%s'", + intval($channel['channel_id']), + dbesc(datetime_convert('UTC', 'UTC', 'now - 24 hours')) + ); + if ($n && intval($n['total']) > $lim) { + logger('channel: ' . $channel['channel_id'] . ' too many new connections per day. This one from ' . $hsig['signer'], LOGGER_NORMAL, LOG_WARNING); + return false; + } + } - // check personal blocklists - - $blocked = LibBlock::fetch($channel['channel_id'],BLOCKTYPE_SERVER); - if ($blocked) { - foreach($blocked as $b) { - if (strpos($url,$b['block_entity']) !== false) { - logger('siteblock - follower denied'); - return; - } - } - } - if (LibBlock::fetch_by_entity($channel['channel_id'],$x['hash'])) { - logger('actorblock - follower denied'); - return; - } + // check personal blocklists - $p = Permissions::connect_perms($channel['channel_id']); - $my_perms = Permissions::serialise($p['perms']); + $blocked = LibBlock::fetch($channel['channel_id'], BLOCKTYPE_SERVER); + if ($blocked) { + foreach ($blocked as $b) { + if (strpos($url, $b['block_entity']) !== false) { + logger('siteblock - follower denied'); + return; + } + } + } + if (LibBlock::fetch_by_entity($channel['channel_id'], $x['hash'])) { + logger('actorblock - follower denied'); + return; + } - $automatic = $p['automatic']; + $p = Permissions::connect_perms($channel['channel_id']); + $my_perms = Permissions::serialise($p['perms']); - // new connection + $automatic = $p['automatic']; - if ($my_perms) { - set_abconfig($channel['channel_id'],$x['hash'],'system','my_perms',$my_perms); - } + // new connection - $closeness = get_pconfig($channel['channel_id'],'system','new_abook_closeness',80); + if ($my_perms) { + set_abconfig($channel['channel_id'], $x['hash'], 'system', 'my_perms', $my_perms); + } - // check if it is a sub-channel (collection) and auto-friend if it is + $closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness', 80); - $is_collection = false; + // check if it is a sub-channel (collection) and auto-friend if it is - $cl = q("select channel_id from channel where channel_hash = '%s' and channel_parent = '%s' and channel_account_id = %d limit 1", - dbesc($x['hash']), - dbesc($channel['channel_hash']), - intval($channel['channel_account_id']) - ); - if ($cl) { - $is_collection = true; - $automatic = true; - $closeness = 10; - } + $is_collection = false; - $y = abook_store_lowlevel( - [ - 'abook_account' => intval($channel['channel_account_id']), - 'abook_channel' => intval($channel['channel_id']), - 'abook_closeness' => intval($closeness), - 'abook_xchan' => $x['hash'], - 'abook_profile' => $profile_assign, - 'abook_created' => datetime_convert(), - 'abook_updated' => datetime_convert(), - 'abook_dob' => $next_birthday, - 'abook_pending' => intval(($automatic) ? 0 : 1) - ] - ); + $cl = q("select channel_id from channel where channel_hash = '%s' and channel_parent = '%s' and channel_account_id = %d limit 1", + dbesc($x['hash']), + dbesc($channel['channel_hash']), + intval($channel['channel_account_id']) + ); + if ($cl) { + $is_collection = true; + $automatic = true; + $closeness = 10; + } - if ($y) { - logger("New introduction received for {$channel['channel_name']}"); - $new_perms = get_all_perms($channel['channel_id'],$x['hash']); - - // Send a clone sync packet and a permissions update if permissions have changed + $y = abook_store_lowlevel( + [ + 'abook_account' => intval($channel['channel_account_id']), + 'abook_channel' => intval($channel['channel_id']), + 'abook_closeness' => intval($closeness), + 'abook_xchan' => $x['hash'], + 'abook_profile' => $profile_assign, + 'abook_created' => datetime_convert(), + 'abook_updated' => datetime_convert(), + 'abook_dob' => $next_birthday, + 'abook_pending' => intval(($automatic) ? 0 : 1) + ] + ); - $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 order by abook_created desc limit 1", - dbesc($x['hash']), - intval($channel['channel_id']) - ); + if ($y) { + logger("New introduction received for {$channel['channel_name']}"); + $new_perms = get_all_perms($channel['channel_id'], $x['hash']); - if ($new_connection) { - if (! Permissions::PermsCompare($new_perms,$previous_perms)) { - Run::Summon([ 'Notifier', 'permissions_create', $new_connection[0]['abook_id'] ]); - } + // Send a clone sync packet and a permissions update if permissions have changed - if (! $is_collection) { - Enotify::submit( - [ - 'type' => NOTIFY_INTRO, - 'from_xchan' => $x['hash'], - 'to_xchan' => $channel['channel_hash'], - 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'] - ] - ); - } + $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 order by abook_created desc limit 1", + dbesc($x['hash']), + intval($channel['channel_id']) + ); - if (intval($permissions['view_stream'])) { - if (intval(get_pconfig($channel['channel_id'],'perm_limits','send_stream') & PERMS_PENDING) - || (! intval($new_connection[0]['abook_pending']))) - Run::Summon([ 'Onepoll', $new_connection[0]['abook_id'] ]); - } + if ($new_connection) { + if (!Permissions::PermsCompare($new_perms, $previous_perms)) { + Run::Summon(['Notifier', 'permissions_create', $new_connection[0]['abook_id']]); + } + + if (!$is_collection) { + Enotify::submit( + [ + 'type' => NOTIFY_INTRO, + 'from_xchan' => $x['hash'], + 'to_xchan' => $channel['channel_hash'], + 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'] + ] + ); + } + + if (intval($permissions['view_stream'])) { + if (intval(get_pconfig($channel['channel_id'], 'perm_limits', 'send_stream') & PERMS_PENDING) + || (!intval($new_connection[0]['abook_pending']))) + Run::Summon(['Onepoll', $new_connection[0]['abook_id']]); + } - // If there is a default group for this channel, add this connection to it - // for pending connections this will happens at acceptance time. + // If there is a default group for this channel, add this connection to it + // for pending connections this will happens at acceptance time. - if (! intval($new_connection[0]['abook_pending'])) { - $default_group = $channel['channel_default_group']; - if ($default_group) { - $g = AccessList::rec_byhash($channel['channel_id'],$default_group); - if ($g) { - AccessList::member_add($channel['channel_id'],'',$x['hash'],$g['id']); - } - } - } + if (!intval($new_connection[0]['abook_pending'])) { + $default_group = $channel['channel_default_group']; + if ($default_group) { + $g = AccessList::rec_byhash($channel['channel_id'], $default_group); + if ($g) { + AccessList::member_add($channel['channel_id'], '', $x['hash'], $g['id']); + } + } + } - unset($new_connection[0]['abook_id']); - unset($new_connection[0]['abook_account']); - unset($new_connection[0]['abook_channel']); - $abconfig = load_abconfig($channel['channel_id'],$new_connection[0]['abook_xchan']); - if ($abconfig) { - $new_connection[0]['abconfig'] = $abconfig; - } - Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => $new_connection ]); - } - } + unset($new_connection[0]['abook_id']); + unset($new_connection[0]['abook_account']); + unset($new_connection[0]['abook_channel']); + $abconfig = load_abconfig($channel['channel_id'], $new_connection[0]['abook_xchan']); + if ($abconfig) { + $new_connection[0]['abconfig'] = $abconfig; + } + Libsync::build_sync_packet($channel['channel_id'], ['abook' => $new_connection]); + } + } - } - return true; - } - else { - return true; - } - return false; - } + } + return true; + } else { + return true; + } + return false; + } - /** - * @brief Look up if channel is known and previously verified. - * - * A guid and a url, both signed by the sender, distinguish a known sender at a - * known location. - * This function looks these up to see if the channel is known and therefore - * previously verified. If not, we will need to verify it. - * - * @param array $arr an associative array which must contain: - * * \e string \b id => id of conversant - * * \e string \b id_sig => id signed with conversant's private key - * * \e string \b location => URL of the origination hub of this communication - * * \e string \b location_sig => URL signed with conversant's private key - * @param boolean $multiple (optional) default false - * - * @return array|null - * * null if site is denied or not found - * * otherwise an array with an hubloc record - */ + /** + * @brief Look up if channel is known and previously verified. + * + * A guid and a url, both signed by the sender, distinguish a known sender at a + * known location. + * This function looks these up to see if the channel is known and therefore + * previously verified. If not, we will need to verify it. + * + * @param array $arr an associative array which must contain: + * * \e string \b id => id of conversant + * * \e string \b id_sig => id signed with conversant's private key + * * \e string \b location => URL of the origination hub of this communication + * * \e string \b location_sig => URL signed with conversant's private key + * @param boolean $multiple (optional) default false + * + * @return array|null + * * null if site is denied or not found + * * otherwise an array with an hubloc record + */ - static function gethub($arr, $multiple = false) { + public static function gethub($arr, $multiple = false) + { - if ($arr['id'] && $arr['id_sig'] && $arr['location'] && $arr['location_sig']) { + if ($arr['id'] && $arr['id_sig'] && $arr['location'] && $arr['location_sig']) { - if (! check_siteallowed($arr['location'])) { - logger('denied site: ' . $arr['location']); - return null; - } + if (!check_siteallowed($arr['location'])) { + logger('denied site: ' . $arr['location']); + return null; + } - $limit = (($multiple) ? '' : ' limit 1 '); + $limit = (($multiple) ? '' : ' limit 1 '); - $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url + $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_url = '%s' and hubloc_url_sig = '%s' and hubloc_site_id = '%s' and hubloc_network = 'zot6' $limit", - dbesc($arr['id']), - dbesc($arr['id_sig']), - dbesc($arr['location']), - dbesc($arr['location_sig']), - dbesc($arr['site_id']) - ); - if ($r) { - logger('Found', LOGGER_DEBUG); - return (($multiple) ? $r : $r[0]); - } - } - logger('Not found: ' . print_r($arr,true), LOGGER_DEBUG); + dbesc($arr['id']), + dbesc($arr['id_sig']), + dbesc($arr['location']), + dbesc($arr['location_sig']), + dbesc($arr['site_id']) + ); + if ($r) { + logger('Found', LOGGER_DEBUG); + return (($multiple) ? $r : $r[0]); + } + } + logger('Not found: ' . print_r($arr, true), LOGGER_DEBUG); - return false; - } + return false; + } + public static function valid_hub($sender, $site_id) + { + + $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_site_id = '%s' limit 1", + dbesc($sender), + dbesc($site_id) + ); + if (!$r) { + return null; + } + + if (!check_siteallowed($r[0]['hubloc_url'])) { + logger('denied site: ' . $r[0]['hubloc_url']); + return null; + } + + if (!check_channelallowed($r[0]['hubloc_hash'])) { + logger('denied channel: ' . $r[0]['hubloc_hash']); + return null; + } + + return $r[0]; + } + + /** + * @brief Registers an unknown hub. + * + * A communication has been received which has an unknown (to us) sender. + * Perform discovery based on our calculated hash of the sender at the + * origination address. This will fetch the discovery packet of the sender, + * which contains the public key we need to verify our guid and url signatures. + * + * @param array $arr an associative array which must contain: + * * \e string \b guid => guid of conversant + * * \e string \b guid_sig => guid signed with conversant's private key + * * \e string \b url => URL of the origination hub of this communication + * * \e string \b url_sig => URL signed with conversant's private key + * + * @return array An associative array with + * * \b success boolean true or false + * * \b message (optional) error string only if success is false + */ + + public static function register_hub($id) + { + + $id_hash = false; + $valid = false; + $hsig_valid = false; + + $result = ['success' => false]; + + if (!$id) { + return $result; + } + + $record = Zotfinger::exec($id); + + // Check the HTTP signature + + $hsig = $record['signature']; + if ($hsig['signer'] === $id && $hsig['header_valid'] === true && $hsig['content_valid'] === true) { + $hsig_valid = true; + } + if (!$hsig_valid) { + logger('http signature not valid: ' . print_r($hsig, true)); + return $result; + } + + $c = self::import_xchan($record['data']); + if ($c['success']) { + $result['success'] = true; + } else { + logger('Failure to verify zot packet'); + } + + return $result; + } + + /** + * @brief Takes an associative array of a fetch discovery packet and updates + * all internal data structures which need to be updated as a result. + * + * @param array $arr => json_decoded discovery packet + * @param int $ud_flags + * Determines whether to create a directory update record if any changes occur, default is UPDATE_FLAGS_UPDATED + * $ud_flags = UPDATE_FLAGS_FORCED indicates a forced refresh where we unconditionally create a directory update record + * this typically occurs once a month for each channel as part of a scheduled ping to notify the directory + * that the channel still exists + * @param array $ud_arr + * If set [typically by update_directory_entry()] indicates a specific update table row and more particularly + * contains a particular address (ud_addr) which needs to be updated in that table. + * + * @return array An associative array with: + * * \e boolean \b success boolean true or false + * * \e string \b message (optional) error string only if success is false + */ + + public static function import_xchan($arr, $ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) + { + + /** + * @hooks import_xchan + * Called when processing the result of zot_finger() to store the result + * * \e array + */ + call_hooks('import_xchan', $arr); + + $ret = array('success' => false); + $dirmode = intval(get_config('system', 'directory_mode')); + + $changed = false; + $what = ''; + + if (!is_array($arr)) { + logger('Not an array: ' . print_r($arr, true), LOGGER_DEBUG); + return $ret; + } + + if (!($arr['id'] && $arr['id_sig'])) { + logger('No identity information provided. ' . print_r($arr, true)); + return $ret; + } + + $xchan_hash = self::make_xchan_hash($arr['id'], $arr['public_key']); + $arr['hash'] = $xchan_hash; + + $import_photos = false; + + $sig_methods = ((array_key_exists('signing', $arr) && is_array($arr['signing'])) ? $arr['signing'] : ['sha256']); + $verified = false; + + if (!self::verify($arr['id'], $arr['id_sig'], $arr['public_key'])) { + logger('Unable to verify channel signature for ' . $arr['address']); + return $ret; + } else { + $verified = true; + } + + if (!$verified) { + $ret['message'] = t('Unable to verify channel signature'); + return $ret; + } + + logger('import_xchan: ' . $xchan_hash, LOGGER_DEBUG); + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($xchan_hash) + ); + + if (!array_key_exists('connect_url', $arr)) { + $arr['connect_url'] = ''; + } + + if ($r) { + if ($arr['photo'] && array_key_exists('updated', $arr['photo']) && $arr['photo']['updated'] > $r[0]['xchan_photo_date']) { + $import_photos = true; + } + + // if we import an entry from a site that's not ours and either or both of us is off the grid - hide the entry. + /** @TODO: check if we're the same directory realm, which would mean we are allowed to see it */ + + $dirmode = get_config('system', 'directory_mode'); + + if ((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) && ($arr['site']['url'] != z_root())) { + $arr['searchable'] = false; + } + + $hidden = (1 - intval($arr['searchable'])); + + $hidden_changed = $adult_changed = $deleted_changed = $type_changed = 0; + + if (intval($r[0]['xchan_hidden']) != (1 - intval($arr['searchable']))) { + $hidden_changed = 1; + } + if (intval($r[0]['xchan_selfcensored']) != intval($arr['adult_content'])) { + $adult_changed = 1; + } + if (isset($arr['deleted']) && intval($r[0]['xchan_deleted']) != intval($arr['deleted'])) { + $deleted_changed = 1; + } + + if ($arr['channel_type'] === 'collection') { + $px = 2; + } elseif ($arr['channel_type'] === 'group') { + $px = 1; + } else { + $px = 0; + } + if (array_key_exists('public_forum', $arr) && intval($arr['public_forum'])) { + $px = 1; + } + + if (intval($r[0]['xchan_type']) !== $px) { + $type_changed = true; + } + + if ($arr['protocols']) { + $protocols = implode(',', $arr['protocols']); + if ($protocols !== 'zot6') { + set_xconfig($xchan_hash, 'system', 'protocols', $protocols); + } else { + del_xconfig($xchan_hash, 'system', 'protocols'); + } + } + $collections = []; + if (isset($arr['primary_location']['following'])) { + $collections['following'] = $arr['primary_location']['following']; + } + if (isset($arr['primary_location']['followers'])) { + $collections['followers'] = $arr['primary_location']['followers']; + } + if (isset($arr['primary_location']['wall'])) { + $collections['wall'] = $arr['primary_location']['wall']; + } + if ($collections) { + set_xconfig($xchan_hash, 'activitypub', 'collections', $collections); + } + + if (isset($arr['cover_photo']) && isset($arr['cover_photo']['url']) && strlen($arr['cover_photo']['url'])) { + set_xconfig($xchan_hash, 'system', 'cover_photo', $arr['cover_photo']['url']); + } + + if (isset($arr['signing_algorithm']) && strlen($arr['signing_algorithm'])) { + set_xconfig($xchan_hash, 'system', 'signing_algorithm', $arr['signing_algorithm']); + } - static function valid_hub($sender,$site_id) { - - $r = q("select hubloc.*, site.site_crypto from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and hubloc_site_id = '%s' limit 1", - dbesc($sender), - dbesc($site_id) - ); - if (! $r) { - return null; - } - - if (! check_siteallowed($r[0]['hubloc_url'])) { - logger('denied site: ' . $r[0]['hubloc_url']); - return null; - } - - if (! check_channelallowed($r[0]['hubloc_hash'])) { - logger('denied channel: ' . $r[0]['hubloc_hash']); - return null; - } - - return $r[0]; - } - - /** - * @brief Registers an unknown hub. - * - * A communication has been received which has an unknown (to us) sender. - * Perform discovery based on our calculated hash of the sender at the - * origination address. This will fetch the discovery packet of the sender, - * which contains the public key we need to verify our guid and url signatures. - * - * @param array $arr an associative array which must contain: - * * \e string \b guid => guid of conversant - * * \e string \b guid_sig => guid signed with conversant's private key - * * \e string \b url => URL of the origination hub of this communication - * * \e string \b url_sig => URL signed with conversant's private key - * - * @return array An associative array with - * * \b success boolean true or false - * * \b message (optional) error string only if success is false - */ - - static function register_hub($id) { - - $id_hash = false; - $valid = false; - $hsig_valid = false; - - $result = [ 'success' => false ]; - - if (! $id) { - return $result; - } - - $record = Zotfinger::exec($id); - - // Check the HTTP signature - - $hsig = $record['signature']; - if ($hsig['signer'] === $id && $hsig['header_valid'] === true && $hsig['content_valid'] === true) { - $hsig_valid = true; - } - if (! $hsig_valid) { - logger('http signature not valid: ' . print_r($hsig,true)); - return $result; - } - - $c = self::import_xchan($record['data']); - if ($c['success']) { - $result['success'] = true; - } - else { - logger('Failure to verify zot packet'); - } - - return $result; - } - - /** - * @brief Takes an associative array of a fetch discovery packet and updates - * all internal data structures which need to be updated as a result. - * - * @param array $arr => json_decoded discovery packet - * @param int $ud_flags - * Determines whether to create a directory update record if any changes occur, default is UPDATE_FLAGS_UPDATED - * $ud_flags = UPDATE_FLAGS_FORCED indicates a forced refresh where we unconditionally create a directory update record - * this typically occurs once a month for each channel as part of a scheduled ping to notify the directory - * that the channel still exists - * @param array $ud_arr - * If set [typically by update_directory_entry()] indicates a specific update table row and more particularly - * contains a particular address (ud_addr) which needs to be updated in that table. - * - * @return array An associative array with: - * * \e boolean \b success boolean true or false - * * \e string \b message (optional) error string only if success is false - */ - - static function import_xchan($arr, $ud_flags = UPDATE_FLAGS_UPDATED, $ud_arr = null) { - - /** - * @hooks import_xchan - * Called when processing the result of zot_finger() to store the result - * * \e array - */ - call_hooks('import_xchan', $arr); - - $ret = array('success' => false); - $dirmode = intval(get_config('system','directory_mode')); - - $changed = false; - $what = ''; - - if (! is_array($arr)) { - logger('Not an array: ' . print_r($arr,true), LOGGER_DEBUG); - return $ret; - } - - if (! ($arr['id'] && $arr['id_sig'])) { - logger('No identity information provided. ' . print_r($arr,true)); - return $ret; - } - - $xchan_hash = self::make_xchan_hash($arr['id'],$arr['public_key']); - $arr['hash'] = $xchan_hash; - - $import_photos = false; - - $sig_methods = ((array_key_exists('signing',$arr) && is_array($arr['signing'])) ? $arr['signing'] : [ 'sha256' ]); - $verified = false; - - if (! self::verify($arr['id'],$arr['id_sig'],$arr['public_key'])) { - logger('Unable to verify channel signature for ' . $arr['address']); - return $ret; - } - else { - $verified = true; - } - - if (! $verified) { - $ret['message'] = t('Unable to verify channel signature'); - return $ret; - } - - logger('import_xchan: ' . $xchan_hash, LOGGER_DEBUG); - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($xchan_hash) - ); - - if (! array_key_exists('connect_url', $arr)) { - $arr['connect_url'] = ''; - } - - if ($r) { - if ($arr['photo'] && array_key_exists('updated',$arr['photo']) && $arr['photo']['updated'] > $r[0]['xchan_photo_date']) { - $import_photos = true; - } - - // if we import an entry from a site that's not ours and either or both of us is off the grid - hide the entry. - /** @TODO: check if we're the same directory realm, which would mean we are allowed to see it */ - - $dirmode = get_config('system','directory_mode'); - - if ((($arr['site']['directory_mode'] === 'standalone') || ($dirmode & DIRECTORY_MODE_STANDALONE)) && ($arr['site']['url'] != z_root())) { - $arr['searchable'] = false; - } - - $hidden = (1 - intval($arr['searchable'])); - - $hidden_changed = $adult_changed = $deleted_changed = $type_changed = 0; - - if (intval($r[0]['xchan_hidden']) != (1 - intval($arr['searchable']))) { - $hidden_changed = 1; - } - if (intval($r[0]['xchan_selfcensored']) != intval($arr['adult_content'])) { - $adult_changed = 1; - } - if (isset($arr['deleted']) && intval($r[0]['xchan_deleted']) != intval($arr['deleted'])) { - $deleted_changed = 1; - } - - if ($arr['channel_type'] === 'collection') { - $px = 2; - } - elseif ($arr['channel_type'] === 'group') { - $px = 1; - } - else { - $px = 0; - } - if (array_key_exists('public_forum',$arr) && intval($arr['public_forum'])) { - $px = 1; - } - - if (intval($r[0]['xchan_type']) !== $px) { - $type_changed = true; - } - - if ($arr['protocols']) { - $protocols = implode(',',$arr['protocols']); - if ($protocols !== 'zot6') { - set_xconfig($xchan_hash,'system','protocols',$protocols); - } - else { - del_xconfig($xchan_hash,'system','protocols'); - } - } - $collections = []; - if (isset($arr['primary_location']['following'])) { - $collections['following'] = $arr['primary_location']['following']; - } - if (isset($arr['primary_location']['followers'])) { - $collections['followers'] = $arr['primary_location']['followers']; - } - if (isset($arr['primary_location']['wall'])) { - $collections['wall'] = $arr['primary_location']['wall']; - } - if ($collections) { - set_xconfig($xchan_hash,'activitypub','collections',$collections); - } - - if (isset($arr['cover_photo']) && isset($arr['cover_photo']['url']) && strlen($arr['cover_photo']['url'])) { - set_xconfig($xchan_hash,'system','cover_photo',$arr['cover_photo']['url']); - } - - if (isset($arr['signing_algorithm']) && strlen($arr['signing_algorithm'])) { - set_xconfig($xchan_hash,'system','signing_algorithm',$arr['signing_algorithm']); - } - - - if (($r[0]['xchan_name_date'] != $arr['name_updated']) - || ($r[0]['xchan_connurl'] != $arr['primary_location']['connections_url']) - || ($r[0]['xchan_addr'] != $arr['primary_location']['address']) - || ($r[0]['xchan_follow'] != $arr['primary_location']['follow_url']) - || ($r[0]['xchan_connpage'] != $arr['connect_url']) - || ($r[0]['xchan_url'] != $arr['primary_location']['url']) - || ($r[0]['xchan_updated'] < datetime_convert('UTC','UTC','now - 7 days')) - || $hidden_changed || $adult_changed || $deleted_changed || $type_changed ) { - $rup = q("update xchan set xchan_updated = '%s', xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', + if (($r[0]['xchan_name_date'] != $arr['name_updated']) + || ($r[0]['xchan_connurl'] != $arr['primary_location']['connections_url']) + || ($r[0]['xchan_addr'] != $arr['primary_location']['address']) + || ($r[0]['xchan_follow'] != $arr['primary_location']['follow_url']) + || ($r[0]['xchan_connpage'] != $arr['connect_url']) + || ($r[0]['xchan_url'] != $arr['primary_location']['url']) + || ($r[0]['xchan_updated'] < datetime_convert('UTC', 'UTC', 'now - 7 days')) + || $hidden_changed || $adult_changed || $deleted_changed || $type_changed) { + $rup = q("update xchan set xchan_updated = '%s', xchan_name = '%s', xchan_name_date = '%s', xchan_connurl = '%s', xchan_follow = '%s', xchan_connpage = '%s', xchan_hidden = %d, xchan_selfcensored = %d, xchan_deleted = %d, xchan_type = %d, xchan_addr = '%s', xchan_url = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc(($arr['name']) ? escape_tags($arr['name']) : '-'), - dbesc($arr['name_updated']), - dbesc($arr['primary_location']['connections_url']), - dbesc($arr['primary_location']['follow_url']), - dbesc($arr['primary_location']['connect_url']), - intval(1 - intval($arr['searchable'])), - intval($arr['adult_content']), - intval($arr['deleted']), - intval($px), - dbesc(escape_tags($arr['primary_location']['address'])), - dbesc(escape_tags($arr['primary_location']['url'])), - dbesc($xchan_hash) - ); + dbesc(datetime_convert()), + dbesc(($arr['name']) ? escape_tags($arr['name']) : '-'), + dbesc($arr['name_updated']), + dbesc($arr['primary_location']['connections_url']), + dbesc($arr['primary_location']['follow_url']), + dbesc($arr['primary_location']['connect_url']), + intval(1 - intval($arr['searchable'])), + intval($arr['adult_content']), + intval($arr['deleted']), + intval($px), + dbesc(escape_tags($arr['primary_location']['address'])), + dbesc(escape_tags($arr['primary_location']['url'])), + dbesc($xchan_hash) + ); - logger('Update: existing: ' . print_r($r[0],true), LOGGER_DATA, LOG_DEBUG); - logger('Update: new: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - $what .= 'xchan '; - $changed = true; - } - } - else { - $import_photos = true; + logger('Update: existing: ' . print_r($r[0], true), LOGGER_DATA, LOG_DEBUG); + logger('Update: new: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + $what .= 'xchan '; + $changed = true; + } + } else { + $import_photos = true; - if ((($arr['site']['directory_mode'] === 'standalone') - || ($dirmode & DIRECTORY_MODE_STANDALONE)) - && ($arr['site']['url'] != z_root())) { - $arr['searchable'] = false; - } + if ((($arr['site']['directory_mode'] === 'standalone') + || ($dirmode & DIRECTORY_MODE_STANDALONE)) + && ($arr['site']['url'] != z_root())) { + $arr['searchable'] = false; + } - if ($arr['channel_type'] === 'collection') { - $px = 2; - } - elseif ($arr['channel_type'] === 'group') { - $px = 1; - } - else { - $px = 0; - } + if ($arr['channel_type'] === 'collection') { + $px = 2; + } elseif ($arr['channel_type'] === 'group') { + $px = 1; + } else { + $px = 0; + } - if (array_key_exists('public_forum',$arr) && intval($arr['public_forum'])) { - $px = 1; - } + if (array_key_exists('public_forum', $arr) && intval($arr['public_forum'])) { + $px = 1; + } - $x = xchan_store_lowlevel( - [ - 'xchan_hash' => $xchan_hash, - 'xchan_guid' => $arr['id'], - 'xchan_guid_sig' => $arr['id_sig'], - 'xchan_pubkey' => $arr['public_key'], - 'xchan_photo_mimetype' => $arr['photo']['type'], - 'xchan_photo_l' => $arr['photo']['url'], - 'xchan_addr' => escape_tags($arr['primary_location']['address']), - 'xchan_url' => escape_tags($arr['primary_location']['url']), - 'xchan_connurl' => $arr['primary_location']['connections_url'], - 'xchan_follow' => $arr['primary_location']['follow_url'], - 'xchan_connpage' => $arr['connect_url'], - 'xchan_name' => (($arr['name']) ? escape_tags($arr['name']) : '-'), - 'xchan_network' => 'zot6', - 'xchan_updated' => datetime_convert(), - 'xchan_photo_date' => $arr['photo']['updated'], - 'xchan_name_date' => $arr['name_updated'], - 'xchan_hidden' => intval(1 - intval($arr['searchable'])), - 'xchan_selfcensored' => $arr['adult_content'], - 'xchan_deleted' => $arr['deleted'], - 'xchan_type' => $px - ] - ); + $x = xchan_store_lowlevel( + [ + 'xchan_hash' => $xchan_hash, + 'xchan_guid' => $arr['id'], + 'xchan_guid_sig' => $arr['id_sig'], + 'xchan_pubkey' => $arr['public_key'], + 'xchan_photo_mimetype' => $arr['photo']['type'], + 'xchan_photo_l' => $arr['photo']['url'], + 'xchan_addr' => escape_tags($arr['primary_location']['address']), + 'xchan_url' => escape_tags($arr['primary_location']['url']), + 'xchan_connurl' => $arr['primary_location']['connections_url'], + 'xchan_follow' => $arr['primary_location']['follow_url'], + 'xchan_connpage' => $arr['connect_url'], + 'xchan_name' => (($arr['name']) ? escape_tags($arr['name']) : '-'), + 'xchan_network' => 'zot6', + 'xchan_updated' => datetime_convert(), + 'xchan_photo_date' => $arr['photo']['updated'], + 'xchan_name_date' => $arr['name_updated'], + 'xchan_hidden' => intval(1 - intval($arr['searchable'])), + 'xchan_selfcensored' => $arr['adult_content'], + 'xchan_deleted' => $arr['deleted'], + 'xchan_type' => $px + ] + ); - $what .= 'new_xchan'; - $changed = true; - } + $what .= 'new_xchan'; + $changed = true; + } - if (isset($arr['cover_photo']) && isset($arr['cover_photo']['url']) && strlen($arr['cover_photo']['url'])) { - set_xconfig($xchan_hash,'system','cover_photo',$arr['cover_photo']['url']); - } + if (isset($arr['cover_photo']) && isset($arr['cover_photo']['url']) && strlen($arr['cover_photo']['url'])) { + set_xconfig($xchan_hash, 'system', 'cover_photo', $arr['cover_photo']['url']); + } - if ($import_photos) { + if ($import_photos) { - require_once('include/photo_factory.php'); + require_once('include/photo_factory.php'); - // see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections + // see if this is a channel clone that's hosted locally - which we treat different from other xchans/connections - $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1", - dbesc($xchan_hash) - ); - if ($local) { - $ph = false; - if (strpos($arr['photo']['url'], z_root()) === false) { - $ph = z_fetch_url($arr['photo']['url'], true); - } - if ($ph && $ph['success']) { - $hash = import_channel_photo($ph['body'], $arr['photo']['type'], $local[0]['channel_account_id'], $local[0]['channel_id']); + $local = q("select channel_account_id, channel_id from channel where channel_hash = '%s' limit 1", + dbesc($xchan_hash) + ); + if ($local) { + $ph = false; + if (strpos($arr['photo']['url'], z_root()) === false) { + $ph = z_fetch_url($arr['photo']['url'], true); + } + if ($ph && $ph['success']) { + $hash = import_channel_photo($ph['body'], $arr['photo']['type'], $local[0]['channel_account_id'], $local[0]['channel_id']); - if ($hash) { - // unless proven otherwise - $is_default_profile = 1; + if ($hash) { + // unless proven otherwise + $is_default_profile = 1; - $profile = q("select is_default from profile where aid = %d and uid = %d limit 1", - intval($local[0]['channel_account_id']), - intval($local[0]['channel_id']) - ); - if ($profile) { - if (! intval($profile[0]['is_default'])) { - $is_default_profile = 0; - } - } + $profile = q("select is_default from profile where aid = %d and uid = %d limit 1", + intval($local[0]['channel_account_id']), + intval($local[0]['channel_id']) + ); + if ($profile) { + if (!intval($profile[0]['is_default'])) { + $is_default_profile = 0; + } + } - // If setting for the default profile, unset the profile photo flag from any other photos I own - if ($is_default_profile) { - q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - dbesc($hash), - intval($local[0]['channel_account_id']), - intval($local[0]['channel_id']) - ); - } - } + // If setting for the default profile, unset the profile photo flag from any other photos I own + if ($is_default_profile) { + q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND aid = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($hash), + intval($local[0]['channel_account_id']), + intval($local[0]['channel_id']) + ); + } + } - // reset the names in case they got messed up when we had a bug in this function - $photos = array( - z_root() . '/photo/profile/l/' . $local[0]['channel_id'], - z_root() . '/photo/profile/m/' . $local[0]['channel_id'], - z_root() . '/photo/profile/s/' . $local[0]['channel_id'], - $arr['photo_mimetype'], - false - ); - } - } - else { - $photos = import_remote_xchan_photo($arr['photo']['url'], $xchan_hash); - } - if ($photos) { - if ($photos[4]) { - // importing the photo failed somehow. Leave the photo_date alone so we can try again at a later date. - // This often happens when somebody joins the matrix with a bad cert. - $r = q("update xchan set xchan_updated = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' + // reset the names in case they got messed up when we had a bug in this function + $photos = array( + z_root() . '/photo/profile/l/' . $local[0]['channel_id'], + z_root() . '/photo/profile/m/' . $local[0]['channel_id'], + z_root() . '/photo/profile/s/' . $local[0]['channel_id'], + $arr['photo_mimetype'], + false + ); + } + } else { + $photos = import_remote_xchan_photo($arr['photo']['url'], $xchan_hash); + } + if ($photos) { + if ($photos[4]) { + // importing the photo failed somehow. Leave the photo_date alone so we can try again at a later date. + // This often happens when somebody joins the matrix with a bad cert. + $r = q("update xchan set xchan_updated = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc($photos[3]), - dbesc($xchan_hash) - ); - } - else { - $r = q("update xchan set xchan_updated = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' + dbesc(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($xchan_hash) + ); + } else { + $r = q("update xchan set xchan_updated = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc(datetime_convert('UTC','UTC',((isset($arr['photo_updated'])) ? $arr['photo_updated'] : 'now'))), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc($photos[3]), - dbesc($xchan_hash) - ); - } - $what .= 'photo '; - $changed = true; - } - } + dbesc(datetime_convert()), + dbesc(datetime_convert('UTC', 'UTC', ((isset($arr['photo_updated'])) ? $arr['photo_updated'] : 'now'))), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($xchan_hash) + ); + } + $what .= 'photo '; + $changed = true; + } + } - // what we are missing for true hub independence is for any changes in the primary hub to - // get reflected not only in the hublocs, but also to update the URLs and addr in the appropriate xchan + // what we are missing for true hub independence is for any changes in the primary hub to + // get reflected not only in the hublocs, but also to update the URLs and addr in the appropriate xchan - $s = Libsync::sync_locations($arr, $arr); + $s = Libsync::sync_locations($arr, $arr); - if ($s) { - if (isset($s['change_message']) && $s['change_message']) { - $what .= $s['change_message']; - } - if (isset($s['changed']) && $s['changed']) { - $changed = $s['changed']; - } - if (isset($s['message']) && $s['message']) { - $ret['message'] .= $s['message']; - } - } + if ($s) { + if (isset($s['change_message']) && $s['change_message']) { + $what .= $s['change_message']; + } + if (isset($s['changed']) && $s['changed']) { + $changed = $s['changed']; + } + if (isset($s['message']) && $s['message']) { + $ret['message'] .= $s['message']; + } + } - // Which entries in the update table are we interested in updating? - $address = ((isset($arr['address']) && $arr['address']) ? $arr['address'] : EMPTY_STR); - if (isset($ud_arr) && isset($ud_arr['ud_addr'])) { - $address = $ud_arr['ud_addr']; - } + // Which entries in the update table are we interested in updating? + $address = ((isset($arr['address']) && $arr['address']) ? $arr['address'] : EMPTY_STR); + if (isset($ud_arr) && isset($ud_arr['ud_addr'])) { + $address = $ud_arr['ud_addr']; + } - // Are we a directory server of some kind? + // Are we a directory server of some kind? - $other_realm = false; + $other_realm = false; // $realm = get_directory_realm(); // if (array_key_exists('site',$arr) @@ -1043,666 +1036,661 @@ class Libzot { // if ($dirmode != DIRECTORY_MODE_NORMAL) { - // We're some kind of directory server. However we can only add directory information - // if the entry is in the same realm (or is a sub-realm). Sub-realms are denoted by - // including the parent realm in the name. e.g. 'RED_GLOBAL:foo' would allow an entry to - // be in directories for the local realm (foo) and also the RED_GLOBAL realm. + // We're some kind of directory server. However we can only add directory information + // if the entry is in the same realm (or is a sub-realm). Sub-realms are denoted by + // including the parent realm in the name. e.g. 'RED_GLOBAL:foo' would allow an entry to + // be in directories for the local realm (foo) and also the RED_GLOBAL realm. - if (array_key_exists('profile',$arr) && is_array($arr['profile']) && (! $other_realm)) { - $profile_changed = Libzotdir::import_directory_profile($xchan_hash,$arr['profile'],$address,$ud_flags, 1); - if ($profile_changed) { - $what .= 'profile '; - $changed = true; - } - } - else { - logger('Profile not available - hiding'); - // they may have made it private - $r = q("delete from xprof where xprof_hash = '%s'", - dbesc($xchan_hash) - ); - $r = q("delete from xtag where xtag_hash = '%s' and xtag_flags = 0", - dbesc($xchan_hash) - ); - } + if (array_key_exists('profile', $arr) && is_array($arr['profile']) && (!$other_realm)) { + $profile_changed = Libzotdir::import_directory_profile($xchan_hash, $arr['profile'], $address, $ud_flags, 1); + if ($profile_changed) { + $what .= 'profile '; + $changed = true; + } + } else { + logger('Profile not available - hiding'); + // they may have made it private + $r = q("delete from xprof where xprof_hash = '%s'", + dbesc($xchan_hash) + ); + $r = q("delete from xtag where xtag_hash = '%s' and xtag_flags = 0", + dbesc($xchan_hash) + ); + } // } - if (array_key_exists('site',$arr) && is_array($arr['site'])) { - $profile_changed = self::import_site($arr['site']); - if ($profile_changed) { - $what .= 'site '; - $changed = true; - } - } - - if (($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) { - $guid = random_string() . '@' . App::get_hostname(); - Libzotdir::update_modtime($xchan_hash,$guid,$address,$ud_flags); - logger('Changed: ' . $what,LOGGER_DEBUG); - } - elseif (! $ud_flags) { - // nothing changed but we still need to update the updates record - q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d) > 0 ", - intval(UPDATE_FLAGS_UPDATED), - dbesc($address), - intval(UPDATE_FLAGS_UPDATED) - ); - } - - if (! x($ret,'message')) { - $ret['success'] = true; - $ret['hash'] = $xchan_hash; - } - - logger('Result: ' . print_r($ret,true), LOGGER_DATA, LOG_DEBUG); - return $ret; - } - - /** - * @brief Called immediately after sending a zot message which is using queue processing. - * - * Updates the queue item according to the response result and logs any information - * returned to aid communications troubleshooting. - * - * @param string $hub - url of site we just contacted - * @param array $arr - output of z_post_url() - * @param array $outq - The queue structure attached to this request - */ - - static function process_response($hub, $arr, $outq) { - - logger('remote: ' . print_r($arr,true),LOGGER_DATA); - - if (! $arr['success']) { - logger('Failed: ' . $hub); - return; - } - - $x = json_decode($arr['body'], true); - - if (! $x) { - logger('No json from ' . $hub); - logger('Headers: ' . print_r($arr['header'], true), LOGGER_DATA, LOG_DEBUG); - } - - $x = Crypto::unencapsulate($x, get_config('system','prvkey')); - if (! is_array($x)) { - $x = json_decode($x,true); - } - - if (! is_array($x)) { - logger('no useful response: ' . $x); - } - - if ($x) { - if (! $x['success']) { - - // handle remote validation issues - - $b = q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", - dbesc(($x['message']) ? $x['message'] : 'unknown delivery error'), - dbesc(datetime_convert()), - dbesc($outq['outq_hash']) - ); - } - - if (is_array($x) && array_key_exists('delivery_report',$x) && is_array($x['delivery_report'])) { - foreach ($x['delivery_report'] as $xx) { - call_hooks('dreport_process',$xx); - if (is_array($xx) && array_key_exists('message_id',$xx) && DReport::is_storable($xx)) { - q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_log ) values ( '%s', '%s', '%s','%s','%s','%s','%s','%s' ) ", - dbesc($xx['message_id']), - dbesc($xx['location']), - dbesc($xx['recipient']), - dbesc($xx['name']), - dbesc($xx['status']), - dbesc(datetime_convert('UTC','UTC',$xx['date'])), - dbesc($xx['sender']), - dbesc(EMPTY_STR) - ); - } - } - - // we have a more descriptive delivery report, so discard the per hub 'queue' report. - - q("delete from dreport where dreport_queue = '%s' ", - dbesc($outq['outq_hash']) - ); - } - } - // update the timestamp for this site - - q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", - dbesc(datetime_convert()), - dbesc(dirname($hub)) - ); - - // synchronous message types are handled immediately - // async messages remain in the queue until processed. - - if (intval($outq['outq_async'])) { - Queue::remove($outq['outq_hash'],$outq['outq_channel']); - } - - logger('zot_process_response: ' . print_r($x,true), LOGGER_DEBUG); - } - - /** - * @brief - * - * We received a notification packet (in mod_post) that a message is waiting for us, and we've verified the sender. - * Check if the site is using zot6 delivery and includes a verified HTTP Signature, signed content, and a 'msg' field, - * and also that the signer and the sender match. - * If that happens, we do not need to fetch/pickup the message - we have it already and it is verified. - * Translate it into the form we need for zot_import() and import it. - * - * Otherwise send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site - * private key. - * The entire pickup message is encrypted with the remote site's public key. - * If everything checks out on the remote end, we will receive back a packet containing one or more messages, - * which will be processed and delivered before this function ultimately returns. - * - * @see zot_import() - * - * @param array $arr - * decrypted and json decoded notify packet from remote site - * @return array from zot_import() - */ - - static function fetch($arr,$hub = null) { - - logger('zot_fetch: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - - return self::import($arr,$hub); - - } - - /** - * @brief Process incoming messages. - * - * Process incoming messages and import, update, delete as directed - * - * The message types handled here are 'activity' (e.g. posts), and 'sync'. - * - * @param array $arr - * 'pickup' structure returned from remote site - * @param string $sender_url - * the url specified by the sender in the initial communication. - * We will verify the sender and url in each returned message structure and - * also verify that all the messages returned match the site url that we are - * currently processing. - * - * @returns array - * Suitable for logging remotely, enumerating the processing results of each message/recipient combination - * * [0] => \e string $channel_hash - * * [1] => \e string $delivery_status - * * [2] => \e string $address - */ - - static function import($arr,$hub = null) { - - $env = $arr; - $private = false; - $return = []; - - $result = null; - - logger('Notify: ' . print_r($env,true), LOGGER_DATA, LOG_DEBUG); - - if (! is_array($env)) { - logger('decode error'); - return; - } - - $message_request = false; - - $has_data = array_key_exists('data',$env) && $env['data']; - $data = (($has_data) ? $env['data'] : false); - - $AS = null; - - if ($env['encoding'] === 'activitystreams') { - - $AS = new ActivityStreams($data); - if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) - && array_key_exists('object',$AS->obj) && array_key_exists('actor',$AS->obj)) { - // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) - // Reparse the encapsulated Activity and use that instead - logger('relayed activity',LOGGER_DEBUG); - $AS = new ActivityStreams($AS->obj); - } - - if (! $AS->is_valid()) { - logger('Activity rejected: ' . print_r($data,true)); - return; - } - - // compatibility issue with like of Hubzilla "new friend" activities which is very difficult to fix - - if ($AS->implied_create && is_array($AS->obj) && array_key_exists('type',$AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { - logger('create/person activity rejected. ' . print_r($data,true)); - return false; - } - - if (is_array($AS->obj)) { - $arr = Activity::decode_note($AS); - } - else { - $arr = []; - } - - logger($AS->debug(), LOGGER_DATA); - } - - // There is nothing inherently wrong with getting a message-id which isn't a canonical URI/URL, but - // at the present time (2019/02) during the Hubzilla transition to zot6 it is likely to cause lots of duplicates for - // messages arriving from different protocols and sources with different message-id semantics. This - // restriction can be relaxed once most Hubzilla sites are upgraded to > 4.0. - // Don't check sync packets since they have a different encoding - - if ($arr && $env['type'] !== 'sync') { - if (strpos($arr['mid'],'http') === false && strpos($arr['mid'],'x-zot') === false) { - if (strpos($arr['mid'],'bear:') === false) { - logger('activity rejected: legacy message-id'); - return; - } - } - - if ($arr['verb'] === 'Create' && ActivityStreams::is_an_actor($arr['obj_type'])) { - logger('activity rejected: create actor'); - return; - } - - } - - $deliveries = null; - - if (array_key_exists('recipients',$env) && count($env['recipients'])) { - logger('specific recipients'); - logger('recipients: ' . print_r($env['recipients'],true),LOGGER_DEBUG); - - $recip_arr = []; - foreach ($env['recipients'] as $recip) { - $recip_arr[] = $recip; - } - - $r = false; - if ($recip_arr) { - stringify_array_elms($recip_arr,true); - $recips = implode(',',$recip_arr); - $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 "); - } - - if (! $r) { - logger('recips: no recipients on this site'); - return; - } - - // Response messages will inherit the privacy of the parent - - if ($env['type'] !== 'response') { - $private = true; - } - - $deliveries = ids_to_array($r,'hash'); - - // We found somebody on this site that's in the recipient list. - } - else { - - logger('public post'); - - - // Public post. look for any site members who are or may be accepting posts from this sender - // and who are allowed to see them based on the sender's permissions - // @fixme; - - $deliveries = self::public_recips($env,$AS); - } - - $deliveries = array_unique($deliveries); - - if (! $deliveries) { - logger('No deliveries on this site'); - return; - } - - if ($has_data) { - - if (in_array($env['type'],['activity','response'])) { - - if (! (is_array($AS->actor) && isset($AS->actor['id']))) { - logger('No author!'); - return; - } - - $r = q("select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_id_url = '%s'", - dbesc($AS->actor['id']) - ); - - if ($r) { - $r = self::zot_record_preferred($r); - $arr['author_xchan'] = $r['hubloc_hash']; - } - - if (! $arr['author_xchan']) { - logger('No author!'); - return; - } - - $s = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($env['sender']) - ); - - // in individual delivery, change owner if needed - if ($s) { - $arr['owner_xchan'] = $s[0]['hubloc_hash']; - } - else { - $arr['owner_xchan'] = $env['sender']; - } - - if ($private && (! intval($arr['item_private']))) { - $arr['item_private'] = 1; - } - if ($arr['mid'] === $arr['parent_mid']) { - if (is_array($AS->obj) && array_key_exists('commentPolicy',$AS->obj)) { - $p = strstr($AS->obj['commentPolicy'],'until='); - - // if until= is the same as the creation date, set the item_nocomment flag - // as comments were already closed before the post was even sent. - - if($p !== false) { - $comments_closed_at = datetime_convert('UTC','UTC',substr($p,6)); - if ($comments_closed_at === $arr['created']) { - $arr['item_nocomment'] = 1; - } - else { - $arr['comments_closed'] = $comments_closed_at; - $arr['comment_policy'] = trim(str_replace($p,'',$AS->obj['commentPolicy'])); - } - } - else { - $arr['comment_policy'] = $AS->obj['commentPolicy']; - } - } - } - if ($AS->data['hubloc']) { - $arr['item_verified'] = true; - - if (! array_key_exists('comment_policy',$arr)) { - // set comment policy depending on source hub. Unknown or osada is ActivityPub. - // Anything else we'll say is zot - which could have a range of project names - $s = q("select site_project from site where site_url = '%s' limit 1", - dbesc($r[0]['hubloc_url']) - ); - - if ((! $s) || (in_array($s[0]['site_project'],[ '', 'osada' ]))) { - $arr['comment_policy'] = 'authenticated'; - } - else { - $arr['comment_policy'] = 'contacts'; - } - } - } - if ($AS->data['signed_data']) { - IConfig::Set($arr,'activitypub','signed_data',$AS->data['signed_data'],false); - $j = json_decode($AS->data['signed_data'],true); - if ($j) { - IConfig::Set($arr,'activitypub','rawmsg',json_encode(JSalmon::unpack($j['data'])),true); - } - } - - logger('Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - logger('Activity recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG); - - $relay = (($env['type'] === 'response') ? true : false ); - - $result = self::process_delivery($env['sender'],$AS,$arr,$deliveries,$relay,false,$message_request); - } - elseif ($env['type'] === 'sync') { - - $arr = json_decode($data,true); - - logger('Channel sync received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - logger('Channel sync recipients: ' . print_r($deliveries,true), LOGGER_DATA, LOG_DEBUG); - - if ($env['encoding'] === 'red') { - $result = Libsync::process_channel_sync_delivery($env['sender'],$arr,$deliveries); - } - else { - logger('unsupported sync packet encoding ignored.'); - } - } - } - if ($result) { - $return = array_merge($return, $result); - } - return $return; - } - - - static function is_top_level($env,$act) { - if ($env['encoding'] === 'zot' && array_key_exists('flags',$env) && in_array('thread_parent', $env['flags'])) { - return true; - } - if ($act) { - if (in_array($act->type, ['Like','Dislike'])) { - return false; - } - $x = self::find_parent($env,$act); - if ($x === $act->id || (is_array($act->obj) && array_key_exists('id',$act->obj) && $x === $act->obj['id'])) { - return true; - } - } - return false; - } - - - static function find_parent($env,$act) { - if ($act) { - if (in_array($act->type, ['Like','Dislike']) && is_array($act->obj)) { - return $act->obj['id']; - } - if ($act->parent_id) { - return $act->parent_id; - } - } - return false; - } - - - /** - * @brief - * - * A public message with no listed recipients can be delivered to anybody who - * has PERMS_NETWORK for that type of post, PERMS_AUTHED (in-network senders are - * by definition authenticated) or PERMS_SITE and is one the same site, - * or PERMS_SPECIFIC and the sender is a contact who is granted permissions via - * their connection permissions in the address book. - * Here we take a given message and construct a list of hashes of everybody - * on the site that we should try and deliver to. - * Some of these will be rejected, but this gives us a place to start. - * - * @param array $msg - * @return NULL|array - */ - - static function public_recips($msg, $act) { - - $check_mentions = false; - $include_sys = false; - - if ($msg['type'] === 'activity') { - $public_stream_mode = intval(get_config('system','public_stream_mode',PUBLIC_STREAM_NONE)); - if ($public_stream_mode === PUBLIC_STREAM_FULL) { - $include_sys = true; - } - - $perm = 'send_stream'; - - if (self::is_top_level($msg,$act)) { - $check_mentions = true; - } - } - elseif ($msg['type'] === 'mail') { - $perm = 'post_mail'; - } - - // channels which we will deliver this post to - $r = []; - - $c = q("select channel_id, channel_hash from channel where channel_removed = 0"); - - if ($c) { - foreach ($c as $cc) { - - // top level activity sent to ourself: ignore. Clones will get a sync activity - // which is a true clone of the original item. Everything else is a duplicate. - - if ($check_mentions && $cc['channel_hash'] === $msg['sender']) { - continue; - } - - if (perm_is_allowed($cc['channel_id'],$msg['sender'],$perm)) { - $r[] = $cc['channel_hash']; - } - } - } - - if ($include_sys) { - $sys = get_sys_channel(); - if ($sys) { - $r[] = $sys['channel_hash']; - } - } - - // add channels that are following tags - // these will be enumerated and validated in tgroup_check() - - $ft = q("select channel_hash as hash from channel left join pconfig on pconfig.uid = channel_id where cat = 'system' and k = 'followed_tags' and channel_hash != '%s' and channel_removed = 0", - dbesc($msg['sender']) - ); - if ($ft ) { - foreach ($ft as $t) { - $r[] = $t['hash']; - } - } - - // look for any public mentions on this site - // They will get filtered by tgroup_check() so we don't need to check permissions now - - if ($check_mentions) { - // It's a top level post. Look at the tags. See if any of them are mentions and are on this hub. - if ($act && $act->obj) { - if (is_array($act->obj['tag']) && $act->obj['tag']) { - foreach ($act->obj['tag'] as $tag) { - if ($tag['type'] === 'Mention' && (strpos($tag['href'],z_root()) !== false)) { - $address = basename($tag['href']); - if ($address) { - $z = q("select channel_hash as hash from channel where channel_address = '%s' + if (array_key_exists('site', $arr) && is_array($arr['site'])) { + $profile_changed = self::import_site($arr['site']); + if ($profile_changed) { + $what .= 'site '; + $changed = true; + } + } + + if (($changed) || ($ud_flags == UPDATE_FLAGS_FORCED)) { + $guid = random_string() . '@' . App::get_hostname(); + Libzotdir::update_modtime($xchan_hash, $guid, $address, $ud_flags); + logger('Changed: ' . $what, LOGGER_DEBUG); + } elseif (!$ud_flags) { + // nothing changed but we still need to update the updates record + q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and not (ud_flags & %d) > 0 ", + intval(UPDATE_FLAGS_UPDATED), + dbesc($address), + intval(UPDATE_FLAGS_UPDATED) + ); + } + + if (!x($ret, 'message')) { + $ret['success'] = true; + $ret['hash'] = $xchan_hash; + } + + logger('Result: ' . print_r($ret, true), LOGGER_DATA, LOG_DEBUG); + return $ret; + } + + /** + * @brief Called immediately after sending a zot message which is using queue processing. + * + * Updates the queue item according to the response result and logs any information + * returned to aid communications troubleshooting. + * + * @param string $hub - url of site we just contacted + * @param array $arr - output of z_post_url() + * @param array $outq - The queue structure attached to this request + */ + + public static function process_response($hub, $arr, $outq) + { + + logger('remote: ' . print_r($arr, true), LOGGER_DATA); + + if (!$arr['success']) { + logger('Failed: ' . $hub); + return; + } + + $x = json_decode($arr['body'], true); + + if (!$x) { + logger('No json from ' . $hub); + logger('Headers: ' . print_r($arr['header'], true), LOGGER_DATA, LOG_DEBUG); + } + + $x = Crypto::unencapsulate($x, get_config('system', 'prvkey')); + if (!is_array($x)) { + $x = json_decode($x, true); + } + + if (!is_array($x)) { + logger('no useful response: ' . $x); + } + + if ($x) { + if (!$x['success']) { + + // handle remote validation issues + + $b = q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", + dbesc(($x['message']) ? $x['message'] : 'unknown delivery error'), + dbesc(datetime_convert()), + dbesc($outq['outq_hash']) + ); + } + + if (is_array($x) && array_key_exists('delivery_report', $x) && is_array($x['delivery_report'])) { + foreach ($x['delivery_report'] as $xx) { + call_hooks('dreport_process', $xx); + if (is_array($xx) && array_key_exists('message_id', $xx) && DReport::is_storable($xx)) { + q("insert into dreport ( dreport_mid, dreport_site, dreport_recip, dreport_name, dreport_result, dreport_time, dreport_xchan, dreport_log ) values ( '%s', '%s', '%s','%s','%s','%s','%s','%s' ) ", + dbesc($xx['message_id']), + dbesc($xx['location']), + dbesc($xx['recipient']), + dbesc($xx['name']), + dbesc($xx['status']), + dbesc(datetime_convert('UTC', 'UTC', $xx['date'])), + dbesc($xx['sender']), + dbesc(EMPTY_STR) + ); + } + } + + // we have a more descriptive delivery report, so discard the per hub 'queue' report. + + q("delete from dreport where dreport_queue = '%s' ", + dbesc($outq['outq_hash']) + ); + } + } + // update the timestamp for this site + + q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", + dbesc(datetime_convert()), + dbesc(dirname($hub)) + ); + + // synchronous message types are handled immediately + // async messages remain in the queue until processed. + + if (intval($outq['outq_async'])) { + Queue::remove($outq['outq_hash'], $outq['outq_channel']); + } + + logger('zot_process_response: ' . print_r($x, true), LOGGER_DEBUG); + } + + /** + * @brief + * + * We received a notification packet (in mod_post) that a message is waiting for us, and we've verified the sender. + * Check if the site is using zot6 delivery and includes a verified HTTP Signature, signed content, and a 'msg' field, + * and also that the signer and the sender match. + * If that happens, we do not need to fetch/pickup the message - we have it already and it is verified. + * Translate it into the form we need for zot_import() and import it. + * + * Otherwise send back a pickup message, using our message tracking ID ($arr['secret']), which we will sign with our site + * private key. + * The entire pickup message is encrypted with the remote site's public key. + * If everything checks out on the remote end, we will receive back a packet containing one or more messages, + * which will be processed and delivered before this function ultimately returns. + * + * @param array $arr + * decrypted and json decoded notify packet from remote site + * @return array from zot_import() + * @see zot_import() + * + */ + + public static function fetch($arr, $hub = null) + { + + logger('zot_fetch: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + + return self::import($arr, $hub); + + } + + /** + * @brief Process incoming messages. + * + * Process incoming messages and import, update, delete as directed + * + * The message types handled here are 'activity' (e.g. posts), and 'sync'. + * + * @param array $arr + * 'pickup' structure returned from remote site + * @param string $sender_url + * the url specified by the sender in the initial communication. + * We will verify the sender and url in each returned message structure and + * also verify that all the messages returned match the site url that we are + * currently processing. + * + * @returns array + * Suitable for logging remotely, enumerating the processing results of each message/recipient combination + * * [0] => \e string $channel_hash + * * [1] => \e string $delivery_status + * * [2] => \e string $address + */ + + public static function import($arr, $hub = null) + { + + $env = $arr; + $private = false; + $return = []; + + $result = null; + + logger('Notify: ' . print_r($env, true), LOGGER_DATA, LOG_DEBUG); + + if (!is_array($env)) { + logger('decode error'); + return; + } + + $message_request = false; + + $has_data = array_key_exists('data', $env) && $env['data']; + $data = (($has_data) ? $env['data'] : false); + + $AS = null; + + if ($env['encoding'] === 'activitystreams') { + + $AS = new ActivityStreams($data); + if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) + && array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $AS = new ActivityStreams($AS->obj); + } + + if (!$AS->is_valid()) { + logger('Activity rejected: ' . print_r($data, true)); + return; + } + + // compatibility issue with like of Hubzilla "new friend" activities which is very difficult to fix + + if ($AS->implied_create && is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { + logger('create/person activity rejected. ' . print_r($data, true)); + return false; + } + + if (is_array($AS->obj)) { + $arr = Activity::decode_note($AS); + } else { + $arr = []; + } + + logger($AS->debug(), LOGGER_DATA); + } + + // There is nothing inherently wrong with getting a message-id which isn't a canonical URI/URL, but + // at the present time (2019/02) during the Hubzilla transition to zot6 it is likely to cause lots of duplicates for + // messages arriving from different protocols and sources with different message-id semantics. This + // restriction can be relaxed once most Hubzilla sites are upgraded to > 4.0. + // Don't check sync packets since they have a different encoding + + if ($arr && $env['type'] !== 'sync') { + if (strpos($arr['mid'], 'http') === false && strpos($arr['mid'], 'x-zot') === false) { + if (strpos($arr['mid'], 'bear:') === false) { + logger('activity rejected: legacy message-id'); + return; + } + } + + if ($arr['verb'] === 'Create' && ActivityStreams::is_an_actor($arr['obj_type'])) { + logger('activity rejected: create actor'); + return; + } + + } + + $deliveries = null; + + if (array_key_exists('recipients', $env) && count($env['recipients'])) { + logger('specific recipients'); + logger('recipients: ' . print_r($env['recipients'], true), LOGGER_DEBUG); + + $recip_arr = []; + foreach ($env['recipients'] as $recip) { + $recip_arr[] = $recip; + } + + $r = false; + if ($recip_arr) { + stringify_array_elms($recip_arr, true); + $recips = implode(',', $recip_arr); + $r = q("select channel_hash as hash from channel where channel_hash in ( " . $recips . " ) and channel_removed = 0 "); + } + + if (!$r) { + logger('recips: no recipients on this site'); + return; + } + + // Response messages will inherit the privacy of the parent + + if ($env['type'] !== 'response') { + $private = true; + } + + $deliveries = ids_to_array($r, 'hash'); + + // We found somebody on this site that's in the recipient list. + } else { + + logger('public post'); + + + // Public post. look for any site members who are or may be accepting posts from this sender + // and who are allowed to see them based on the sender's permissions + // @fixme; + + $deliveries = self::public_recips($env, $AS); + } + + $deliveries = array_unique($deliveries); + + if (!$deliveries) { + logger('No deliveries on this site'); + return; + } + + if ($has_data) { + + if (in_array($env['type'], ['activity', 'response'])) { + + if (!(is_array($AS->actor) && isset($AS->actor['id']))) { + logger('No author!'); + return; + } + + $r = q("select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_id_url = '%s'", + dbesc($AS->actor['id']) + ); + + if ($r) { + $r = self::zot_record_preferred($r); + $arr['author_xchan'] = $r['hubloc_hash']; + } + + if (!$arr['author_xchan']) { + logger('No author!'); + return; + } + + $s = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($env['sender']) + ); + + // in individual delivery, change owner if needed + if ($s) { + $arr['owner_xchan'] = $s[0]['hubloc_hash']; + } else { + $arr['owner_xchan'] = $env['sender']; + } + + if ($private && (!intval($arr['item_private']))) { + $arr['item_private'] = 1; + } + if ($arr['mid'] === $arr['parent_mid']) { + if (is_array($AS->obj) && array_key_exists('commentPolicy', $AS->obj)) { + $p = strstr($AS->obj['commentPolicy'], 'until='); + + // if until= is the same as the creation date, set the item_nocomment flag + // as comments were already closed before the post was even sent. + + if ($p !== false) { + $comments_closed_at = datetime_convert('UTC', 'UTC', substr($p, 6)); + if ($comments_closed_at === $arr['created']) { + $arr['item_nocomment'] = 1; + } else { + $arr['comments_closed'] = $comments_closed_at; + $arr['comment_policy'] = trim(str_replace($p, '', $AS->obj['commentPolicy'])); + } + } else { + $arr['comment_policy'] = $AS->obj['commentPolicy']; + } + } + } + if ($AS->data['hubloc']) { + $arr['item_verified'] = true; + + if (!array_key_exists('comment_policy', $arr)) { + // set comment policy depending on source hub. Unknown or osada is ActivityPub. + // Anything else we'll say is zot - which could have a range of project names + $s = q("select site_project from site where site_url = '%s' limit 1", + dbesc($r[0]['hubloc_url']) + ); + + if ((!$s) || (in_array($s[0]['site_project'], ['', 'osada']))) { + $arr['comment_policy'] = 'authenticated'; + } else { + $arr['comment_policy'] = 'contacts'; + } + } + } + if ($AS->data['signed_data']) { + IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false); + $j = json_decode($AS->data['signed_data'], true); + if ($j) { + IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true); + } + } + + logger('Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + logger('Activity recipients: ' . print_r($deliveries, true), LOGGER_DATA, LOG_DEBUG); + + $relay = (($env['type'] === 'response') ? true : false); + + $result = self::process_delivery($env['sender'], $AS, $arr, $deliveries, $relay, false, $message_request); + } elseif ($env['type'] === 'sync') { + + $arr = json_decode($data, true); + + logger('Channel sync received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + logger('Channel sync recipients: ' . print_r($deliveries, true), LOGGER_DATA, LOG_DEBUG); + + if ($env['encoding'] === 'red') { + $result = Libsync::process_channel_sync_delivery($env['sender'], $arr, $deliveries); + } else { + logger('unsupported sync packet encoding ignored.'); + } + } + } + if ($result) { + $return = array_merge($return, $result); + } + return $return; + } + + + public static function is_top_level($env, $act) + { + if ($env['encoding'] === 'zot' && array_key_exists('flags', $env) && in_array('thread_parent', $env['flags'])) { + return true; + } + if ($act) { + if (in_array($act->type, ['Like', 'Dislike'])) { + return false; + } + $x = self::find_parent($env, $act); + if ($x === $act->id || (is_array($act->obj) && array_key_exists('id', $act->obj) && $x === $act->obj['id'])) { + return true; + } + } + return false; + } + + + public static function find_parent($env, $act) + { + if ($act) { + if (in_array($act->type, ['Like', 'Dislike']) && is_array($act->obj)) { + return $act->obj['id']; + } + if ($act->parent_id) { + return $act->parent_id; + } + } + return false; + } + + + /** + * @brief + * + * A public message with no listed recipients can be delivered to anybody who + * has PERMS_NETWORK for that type of post, PERMS_AUTHED (in-network senders are + * by definition authenticated) or PERMS_SITE and is one the same site, + * or PERMS_SPECIFIC and the sender is a contact who is granted permissions via + * their connection permissions in the address book. + * Here we take a given message and construct a list of hashes of everybody + * on the site that we should try and deliver to. + * Some of these will be rejected, but this gives us a place to start. + * + * @param array $msg + * @return NULL|array + */ + + public static function public_recips($msg, $act) + { + + $check_mentions = false; + $include_sys = false; + + if ($msg['type'] === 'activity') { + $public_stream_mode = intval(get_config('system', 'public_stream_mode', PUBLIC_STREAM_NONE)); + if ($public_stream_mode === PUBLIC_STREAM_FULL) { + $include_sys = true; + } + + $perm = 'send_stream'; + + if (self::is_top_level($msg, $act)) { + $check_mentions = true; + } + } elseif ($msg['type'] === 'mail') { + $perm = 'post_mail'; + } + + // channels which we will deliver this post to + $r = []; + + $c = q("select channel_id, channel_hash from channel where channel_removed = 0"); + + if ($c) { + foreach ($c as $cc) { + + // top level activity sent to ourself: ignore. Clones will get a sync activity + // which is a true clone of the original item. Everything else is a duplicate. + + if ($check_mentions && $cc['channel_hash'] === $msg['sender']) { + continue; + } + + if (perm_is_allowed($cc['channel_id'], $msg['sender'], $perm)) { + $r[] = $cc['channel_hash']; + } + } + } + + if ($include_sys) { + $sys = get_sys_channel(); + if ($sys) { + $r[] = $sys['channel_hash']; + } + } + + // add channels that are following tags + // these will be enumerated and validated in tgroup_check() + + $ft = q("select channel_hash as hash from channel left join pconfig on pconfig.uid = channel_id where cat = 'system' and k = 'followed_tags' and channel_hash != '%s' and channel_removed = 0", + dbesc($msg['sender']) + ); + if ($ft) { + foreach ($ft as $t) { + $r[] = $t['hash']; + } + } + + // look for any public mentions on this site + // They will get filtered by tgroup_check() so we don't need to check permissions now + + if ($check_mentions) { + // It's a top level post. Look at the tags. See if any of them are mentions and are on this hub. + if ($act && $act->obj) { + if (is_array($act->obj['tag']) && $act->obj['tag']) { + foreach ($act->obj['tag'] as $tag) { + if ($tag['type'] === 'Mention' && (strpos($tag['href'], z_root()) !== false)) { + $address = basename($tag['href']); + if ($address) { + $z = q("select channel_hash as hash from channel where channel_address = '%s' and channel_hash != '%s' and channel_removed = 0 limit 1", - dbesc($address), - dbesc($msg['sender']) - ); - if ($z) { - $r[] = $z[0]['hash']; - } - } - } - if ($tag['type'] === 'topicalCollection' && strpos($tag['name'],App::get_hostname())) { - $address = substr($tag['name'],0,strpos($tag['name'],'@')); - if ($address) { - $z = q("select channel_hash as hash from channel where channel_address = '%s' + dbesc($address), + dbesc($msg['sender']) + ); + if ($z) { + $r[] = $z[0]['hash']; + } + } + } + if ($tag['type'] === 'topicalCollection' && strpos($tag['name'], App::get_hostname())) { + $address = substr($tag['name'], 0, strpos($tag['name'], '@')); + if ($address) { + $z = q("select channel_hash as hash from channel where channel_address = '%s' and channel_hash != '%s' and channel_removed = 0 limit 1", - dbesc($address), - dbesc($msg['sender']) - ); - if ($z) { - $r[] = $z[0]['hash']; - } - } - } - } - } - } - } - else { - // This is a comment. We need to find any parent with ITEM_UPLINK set. But in fact, let's just return - // everybody that stored a copy of the parent. This way we know we're covered. We'll check the - // comment permissions when we deliver them. + dbesc($address), + dbesc($msg['sender']) + ); + if ($z) { + $r[] = $z[0]['hash']; + } + } + } + } + } + } + } else { + // This is a comment. We need to find any parent with ITEM_UPLINK set. But in fact, let's just return + // everybody that stored a copy of the parent. This way we know we're covered. We'll check the + // comment permissions when we deliver them. - $thread_parent = self::find_parent($msg,$act); + $thread_parent = self::find_parent($msg, $act); - if ($thread_parent) { - $z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ", - dbesc($thread_parent), - dbesc($thread_parent) - ); - if ($z) { - foreach ($z as $zv) { - $r[] = $zv['hash']; - } - } - } - } + if ($thread_parent) { + $z = q("select channel_hash as hash from channel left join item on channel.channel_id = item.uid where ( item.thr_parent = '%s' OR item.parent_mid = '%s' ) ", + dbesc($thread_parent), + dbesc($thread_parent) + ); + if ($z) { + foreach ($z as $zv) { + $r[] = $zv['hash']; + } + } + } + } - // There are probably a lot of duplicates in $r at this point. We need to filter those out. + // There are probably a lot of duplicates in $r at this point. We need to filter those out. - if ($r) { - $r = array_values(array_unique($r)); - } + if ($r) { + $r = array_values(array_unique($r)); + } - logger('public_recips: ' . print_r($r,true), LOGGER_DATA, LOG_DEBUG); - return $r; - } + logger('public_recips: ' . print_r($r, true), LOGGER_DATA, LOG_DEBUG); + return $r; + } - /** - * @brief - * - * @param array $sender - * @param ActivityStreams object $act - * @param array $msg_arr - * @param array $deliveries - * @param boolean $relay - * @param boolean $public (optional) default false - * @param boolean $request (optional) default false - * @return array - */ + /** + * @brief + * + * @param array $sender + * @param ActivityStreams object $act + * @param array $msg_arr + * @param array $deliveries + * @param boolean $relay + * @param boolean $public (optional) default false + * @param boolean $request (optional) default false + * @return array + */ - static function process_delivery($sender, $act, $msg_arr, $deliveries, $relay, $public = false, $request = false) { + public static function process_delivery($sender, $act, $msg_arr, $deliveries, $relay, $public = false, $request = false) + { - $result = []; + $result = []; - // logger('msg_arr: ' . print_r($msg_arr,true),LOGGER_ALL); + // logger('msg_arr: ' . print_r($msg_arr,true),LOGGER_ALL); - // If an upstream hop used ActivityPub, set the identities to zot6 nomadic identities where applicable - // else things could easily get confused + // If an upstream hop used ActivityPub, set the identities to zot6 nomadic identities where applicable + // else things could easily get confused - $msg_arr['author_xchan'] = Activity::find_best_identity($msg_arr['author_xchan']); - $msg_arr['owner_xchan'] = Activity::find_best_identity($msg_arr['owner_xchan']); + $msg_arr['author_xchan'] = Activity::find_best_identity($msg_arr['author_xchan']); + $msg_arr['owner_xchan'] = Activity::find_best_identity($msg_arr['owner_xchan']); - // We've validated the sender. Now make sure that the sender is the owner or author + // We've validated the sender. Now make sure that the sender is the owner or author - if (! $public) { - if ($sender != $msg_arr['owner_xchan'] && $sender != $msg_arr['author_xchan']) { - logger("Sender $sender is not owner {$msg_arr['owner_xchan']} or author {$msg_arr['author_xchan']} - mid {$msg_arr['mid']}"); - return; - } - } + if (!$public) { + if ($sender != $msg_arr['owner_xchan'] && $sender != $msg_arr['author_xchan']) { + logger("Sender $sender is not owner {$msg_arr['owner_xchan']} or author {$msg_arr['author_xchan']} - mid {$msg_arr['mid']}"); + return; + } + } - if ($act->implied_create) { - logger('implied create activity. Not delivering/storing.'); - return; - } + if ($act->implied_create) { + logger('implied create activity. Not delivering/storing.'); + return; + } - foreach ($deliveries as $d) { + foreach ($deliveries as $d) { - $local_public = $public; + $local_public = $public; - // if any further changes are to be made, change a copy and not the original - $arr = $msg_arr; + // if any further changes are to be made, change a copy and not the original + $arr = $msg_arr; // if (! $msg_arr['mid']) { // logger('no mid2: ' . print_r($msg_arr,true)); @@ -1710,17 +1698,17 @@ class Libzot { // } - $DR = new DReport(z_root(),$sender,$d,$arr['mid']); + $DR = new DReport(z_root(), $sender, $d, $arr['mid']); - $channel = channelx_by_hash($d); + $channel = channelx_by_hash($d); - if (! $channel) { - $DR->update('recipient not found'); - $result[] = $DR->get(); - continue; - } + if (!$channel) { + $DR->update('recipient not found'); + $result[] = $DR->get(); + continue; + } - $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); + $DR->set_name($channel['channel_name'] . ' <' . channel_reddress($channel) . '>'); // if ($act->type === 'Tombstone') { // $r = q("select * from item where mid in ( '%s', '%s' ) and uid = %d", @@ -1738,1841 +1726,1825 @@ class Libzot { // } // $DR->update('deleted item not found'); // $result[] = $DR->get(); -// continue; +// continue; // } - if (($act) && ($act->obj) && (! is_array($act->obj))) { - - // The initial object fetch failed using the sys channel credentials. - // Try again using the delivery channel credentials. - // We will also need to re-parse the $item array, - // but preserve any values that were set during anonymous parsing. - - $o = Activity::fetch($act->obj,$channel); - if ($o) { - $act->obj = $o; - $arr = array_merge(Activity::decode_note($act),$arr); - } - else { - $DR->update('Incomplete or corrupt activity'); - $result[] = $DR->get(); - continue; - } - } - - /** - * We need to block normal top-level message delivery from our clones, as the delivered - * message doesn't have ACL information in it as the cloned copy does. That copy - * will normally arrive first via sync delivery, but this isn't guaranteed. - * There's a chance the current delivery could take place before the cloned copy arrives - * hence the item could have the wrong ACL and *could* be used in subsequent deliveries or - * access checks. - */ - - if ($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && $arr['mid'] === $arr['parent_mid']) { - $DR->update('self delivery ignored'); - $result[] = $DR->get(); - continue; - } - - // allow public postings to the sys channel regardless of permissions, but not - // for comments travelling upstream. Wait and catch them on the way down. - // They may have been blocked by the owner. - - if (intval($channel['channel_system']) && (! $arr['item_private']) && (! $relay)) { - $local_public = true; - - if (! check_pubstream_channelallowed($sender)) { - $local_public = false; - continue; - } - - // don't allow pubstream posts if the sender even has a clone on a pubstream denied site - - $siteallowed = true; - $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", - dbesc($sender) - ); - if ($h) { - foreach ($h as $hub) { - if (! check_pubstream_siteallowed($hub['hubloc_url'])) { - $siteallowed = false; - break; - } - } - } - if (! $siteallowed) { - $local_public = false; - continue; - } - - $r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1", - dbesc($sender) - ); - // don't import sys channel posts from selfcensored authors - if ($r && (intval($r[0]['xchan_selfcensored']))) { - $local_public = false; - continue; - } - if (! MessageFilter::evaluate($arr,get_config('system','pubstream_incl'),get_config('system','pubstream_excl'))) { - $local_public = false; - continue; - } - } - - // perform pre-storage check to see if it's "likely" that this is a group or collection post - - $tag_delivery = tgroup_check($channel['channel_id'],$arr); - - $perm = 'send_stream'; - if (($arr['mid'] !== $arr['parent_mid']) && ($relay)) - $perm = 'post_comments'; - - // This is our own post, possibly coming from a channel clone - - if ($arr['owner_xchan'] == $d) { - $arr['item_wall'] = 1; - } - else { - $arr['item_wall'] = 0; - } - - $friendofriend = false; - - if ((! $tag_delivery) && (! $local_public)) { - $allowed = (perm_is_allowed($channel['channel_id'],$sender,$perm)); - - $blocked = LibBlock::fetch($channel['channel_id'],BLOCKTYPE_SERVER); - if ($blocked) { - $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", - dbesc($sender) - ); - if ($h) { - foreach ($h as $hub) { - foreach($blocked as $b) { - if (strpos($hub['hubloc_url'],$b['block_entity']) !== false) { - $allowed = false; - } - } - } - } - } - - $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system','permit_all_mentions') && i_am_mentioned($channel,$arr)); - - if (! $allowed) { - if ($perm === 'post_comments') { - $parent = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($arr['parent_mid']), - intval($channel['channel_id']) - ); - if ($parent) { - $allowed = can_comment_on_post($sender,$parent[0]); - } - if ((! $allowed) && $permit_mentions) { - if ($parent && $parent[0]['owner_xchan'] === $channel['channel_hash']) { - $allowed = false; - } - else { - $allowed = true; - } - } - if ($parent && absolutely_no_comments($parent[0])) { - $allowed = false; - } - - } - elseif ($permit_mentions) { - $allowed = true; - } - } - if ($request) { - - // Conversation fetches (e.g. $request == true) take place for - // a) new comments on expired posts - // b) hyperdrive (friend-of-friend) conversations - - - // over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations - // (if hyperdrive is enabled). - // If $allowed is already true, this is probably the conversation of a direct friend or a - // conversation fetch for a new comment on an expired post - // Comments of all these activities are allowed and will only be rejected (later) if the parent - // doesn't exist. - - if ($perm === 'send_stream') { - if (get_pconfig($channel['channel_id'],'system','hyperdrive',true)) { - $allowed = true; - } - } - else { - $allowed = true; - } - - $friendofriend = true; - } - - if (intval($arr['item_private']) === 2) { - if (! perm_is_allowed($channel['channel_id'],$sender,'post_mail')) { - $allowed = false; - } - } - - if (get_abconfig($channel['channel_id'],$sender,'system','block_announce', false)) { - if ($arr['verb'] === 'Announce' || strpos($arr['body'],'[/share]')) { - $allowed = false; - } - } - - if (! $allowed) { - logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); - $DR->update('permission denied'); - $result[] = $DR->get(); - continue; - } - } - - if ($arr['mid'] !== $arr['parent_mid']) { - - if (perm_is_allowed($channel['channel_id'],$sender,'moderated') && $relay) { - $arr['item_blocked'] = ITEM_MODERATED; - } - - // check source route. - // We are only going to accept comments from this sender if the comment has the same route as the top-level-post, - // this is so that permissions mismatches between senders apply to the entire conversation - // As a side effect we will also do a preliminary check that we have the top-level-post, otherwise - // processing it is pointless. - - // The original author won't have a token in their copy of the message - - $prnt = ((strpos($arr['parent_mid'],'token=') !== false) ? substr($arr['parent_mid'],0,strpos($arr['parent_mid'],'?')) : ''); - - $r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1", - dbesc($arr['parent_mid']), - intval($channel['channel_id']) - ); - if (! $r) { - $r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1", - dbesc($prnt), - intval($channel['channel_id']) - ); - } - - if ($r) { - // if this is a multi-threaded conversation, preserve the threading information - if ($r[0]['parent_mid'] !== $r[0]['mid']) { - $arr['thr_parent'] = $arr['parent_mid']; - $arr['parent_mid'] = $r[0]['parent_mid']; - if ($act->replyto) { - q("update item set replyto = '%s' where id = %d", - dbesc($act->replyto), - intval($r[0]['id']) - ); - } - } - - if ($r[0]['obj_type'] === 'Question') { - // route checking doesn't work correctly here because we've changed the privacy - $r[0]['route'] = EMPTY_STR; - // If this is a poll response, convert the obj_type to our (internal-only) "Answer" type - if ($arr['obj_type'] === 'Note' && $arr['title'] && (! $arr['content'])) { - $arr['obj_type'] = 'Answer'; - } - } - } - else { - - // We don't seem to have a copy of this conversation or at least the parent - // - so request a copy of the entire conversation to date. - // Don't do this if it's a relay post as we're the ones who are supposed to - // have the copy and we don't want the request to loop. - // Also don't do this if this comment came from a conversation request packet. - // It's possible that comments are allowed but posting isn't and that could - // cause a conversation fetch loop. - // We'll also check the send_stream permission - because if it isn't allowed, - // the top level post is unlikely to be imported and - // this is just an exercise in futility. - - if ((! $relay) && (! $request) && (! $local_public) - && perm_is_allowed($channel['channel_id'],$sender,'send_stream')) { - $reports = self::fetch_conversation($channel,$arr['mid']); - - // extract our delivery report from the fetched conversation - // if we can find it. - logger('fetch_report for ' . $arr['mid'], LOGGER_ALL); - logger('fetch_report: ' . print_r($reports,true), LOGGER_ALL); - - if ($reports && is_array($reports)) { - $found_report = false; - foreach ($reports as $report) { - if ($report['message_id'] === $arr['mid']) { - $found_report = true; - $DR->update($report['status']); - } - } - if (! $found_report) { - $DR->update('conversation fetch failed'); - } - } - else { - $DR->update('conversation fetch failed'); - } - } - else { - $DR->update('comment parent not found'); - } - $result[] = $DR->get(); - continue; - } - - - if ($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) { - // reset the route in case it travelled a great distance upstream - // use our parent's route so when we go back downstream we'll match - // with whatever route our parent has. - // Also friend-of-friend conversations may have been imported without a route, - // but we are now getting comments via listener delivery - // and if there is no privacy on this or the parent, we don't care about the route, - // so just set the owner and route accordingly. - $arr['route'] = $r[0]['route']; - $arr['owner_xchan'] = $r[0]['owner_xchan']; - } - else { - - // going downstream check that we have the same upstream provider that - // sent it to us originally. Ignore it if it came from another source - // (with potentially different permissions). - // only compare the last hop since it could have arrived at the last location any number of ways. - // Always accept empty routes and firehose items (route contains 'undefined') . - - $existing_route = explode(',', $r[0]['route']); - $routes = count($existing_route); - if ($routes) { - $last_hop = array_pop($existing_route); - $last_prior_route = implode(',',$existing_route); - } - else { - $last_hop = ''; - $last_prior_route = ''; - } - - if (in_array('undefined',$existing_route) || $last_hop == 'undefined' || $sender == 'undefined') { - $last_hop = ''; - } - - $current_route = (($arr['route']) ? $arr['route'] . ',' : '') . $sender; - - if ($last_hop && $last_hop != $sender) { - logger('comment route mismatch: parent route = ' . $r[0]['route'] . ' expected = ' . $current_route, LOGGER_DEBUG); - logger('comment route mismatch: parent msg = ' . $r[0]['id'],LOGGER_DEBUG); - $DR->update('comment route mismatch'); - $result[] = $DR->get(); - continue; - } - - // we'll add sender onto this when we deliver it. $last_prior_route now has the previously stored route - // *except* for the sender which would've been the last hop before it got to us. - - $arr['route'] = $last_prior_route; - } - } - - // This is used to fetch allow/deny rules if either the sender - // or owner is a connection. post_is_importable() evaluates all of them - $abook = q("select * from abook where abook_channel = %d and ( abook_xchan = '%s' OR abook_xchan = '%s' )", - intval($channel['channel_id']), - dbesc($arr['owner_xchan']), - dbesc($arr['author_xchan']) - ); - - if (isset($arr['item_deleted']) && intval($arr['item_deleted'])) { - - // set these just in case we need to store a fresh copy of the deleted post. - // This could happen if the delete got here before the original post did. - - $arr['aid'] = $channel['channel_account_id']; - $arr['uid'] = $channel['channel_id']; - - $item_id = self::delete_imported_item($sender,$act,$arr,$channel['channel_id'],$relay); - $DR->update(($item_id) ? 'deleted' : 'delete_failed'); - $result[] = $DR->get(); - - if ($relay && $item_id) { - logger('process_delivery: invoking relay'); - Run::Summon([ 'Notifier', 'relay', intval($item_id) ]); - $DR->update('relayed'); - $result[] = $DR->get(); - } - continue; - } - - // reactions such as like and dislike could have an mid with /activity/ in it. - // Check for both forms in order to prevent duplicates. - - $r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1", - dbesc($arr['mid']), - dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])), - intval($channel['channel_id']) - ); - - if ($r) { - // We already have this post. - $item_id = $r[0]['id']; - - if (intval($r[0]['item_deleted'])) { - // It was deleted locally. - $DR->update('update ignored'); - $result[] = $DR->get(); - - continue; - } - // Maybe it has been edited? - elseif ($arr['edited'] > $r[0]['edited']) { - $arr['id'] = $r[0]['id']; - $arr['uid'] = $channel['channel_id']; - if (post_is_importable($channel['channel_id'],$arr,$abook)) { - $item_result = self::update_imported_item($sender,$arr,$r[0],$channel['channel_id'],$tag_delivery); - $DR->update('updated'); - $result[] = $DR->get(); - if (! $relay) { - add_source_route($item_id,$sender); - } - } - else { - $DR->update('update ignored'); - $result[] = $DR->get(); - } - } - else { - $DR->update('update ignored'); - $result[] = $DR->get(); - - // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), - // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. - if (! intval($r[0]['item_origin'])) { - continue; - } - } - } - else { - $arr['aid'] = $channel['channel_account_id']; - $arr['uid'] = $channel['channel_id']; - - // if it's a sourced post, call the post_local hooks as if it were - // posted locally so that crosspost connectors will be triggered. - - if (check_item_source($arr['uid'], $arr)) { - /** - * @hooks post_local - * Called when an item has been posted on this machine via mod/item.php (also via API). - * * \e array with an item - */ - call_hooks('post_local', $arr); - } - - $item_id = 0; - - Activity::rewrite_mentions($arr); - - - $maxlen = get_max_import_size(); - - if($maxlen && mb_strlen($arr['body']) > $maxlen) { - $arr['body'] = mb_substr($arr['body'],0,$maxlen,'UTF-8'); - logger('message length exceeds max_import_size: truncated'); - } - - if($maxlen && mb_strlen($arr['summary']) > $maxlen) { - $arr['summary'] = mb_substr($arr['summary'],0,$maxlen,'UTF-8'); - logger('message summary length exceeds max_import_size: truncated'); - } - - if (post_is_importable($arr['uid'],$arr,$abook)) { - - // Strip old-style hubzilla bookmarks - if (strpos($arr['body'],"#^[") !== false) { - $arr['body'] = str_replace("#^[","[",$arr['body']); - } - - $item_result = item_store($arr); - if ($item_result['success']) { - $item_id = $item_result['item_id']; - $parr = [ - 'item_id' => $item_id, - 'item' => $arr, - 'sender' => $sender, - 'channel' => $channel - ]; - /** - * @hooks activity_received - * Called when an activity (post, comment, like, etc.) has been received from a zot source. - * * \e int \b item_id - * * \e array \b item - * * \e array \b sender - * * \e array \b channel - */ - call_hooks('activity_received', $parr); - // don't add a source route if it's a relay or later recipients will get a route mismatch - if (! $relay) { - add_source_route($item_id,$sender); - } - } - $DR->update(($item_id) ? 'posted' : 'storage failed: ' . $item_result['message']); - $result[] = $DR->get(); - } - else { - $DR->update('post ignored'); - $result[] = $DR->get(); - } - } - - // preserve conversations with which you are involved from expiration - - $stored = (($item_result && $item_result['item']) ? $item_result['item'] : false); - if ((is_array($stored)) && ($stored['id'] != $stored['parent']) - && ($stored['author_xchan'] === $channel['channel_hash'])) { - retain_item($stored['item']['parent']); - } - - if ($relay && $item_id) { - logger('Invoking relay'); - Run::Summon([ 'Notifier', 'relay', intval($item_id) ]); - $DR->addto_update('relayed'); - $result[] = $DR->get(); - } - } - - if (! $deliveries) { - $result[] = array('', 'no recipients', '', $arr['mid']); - } - - logger('Local results: ' . print_r($result, true), LOGGER_DEBUG); - - return $result; - } - - static public function hyperdrive_enabled($channel,$item) { - - if (get_pconfig($channel['channel_id'],'system','hyperdrive',true)) { - return true; - } - return false; - } - - static public function fetch_conversation($channel,$mid) { - - // Use Zotfinger to create a signed request - - logger('fetching conversation: ' . $mid, LOGGER_DEBUG); - - $a = Zotfinger::exec($mid,$channel); - - logger('received conversation: ' . print_r($a,true), LOGGER_DATA); - - if (! $a) { - return false; - } - - if ($a['data']['type'] !== 'OrderedCollection') { - return false; - } - - $obj = new ASCollection($a['data'],$channel); - $items = $obj->get(); - - if (! $items) { - return false; - } - - $ret = []; - - - $signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($a['signature']['signer']) - ); - - - foreach ($items as $activity) { - - $AS = new ActivityStreams($activity); - if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) - && array_key_exists('object',$AS->obj) && array_key_exists('actor',$AS->obj)) { - // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) - // Reparse the encapsulated Activity and use that instead - logger('relayed activity',LOGGER_DEBUG); - $AS = new ActivityStreams($AS->obj); - } - - if (! $AS->is_valid()) { - logger('FOF Activity rejected: ' . print_r($activity,true)); - continue; - } - $arr = Activity::decode_note($AS); - - // logger($AS->debug()); - - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", - dbesc($AS->actor['id']), - dbesc($AS->actor['id']) - ); - - if (! $r) { - $y = import_author_xchan([ 'url' => $AS->actor['id'] ]); - if ($y) { - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", - dbesc($AS->actor['id']), - dbesc($AS->actor['id']) - ); - } - if (! $r) { - logger('FOF Activity: no actor'); - continue; - } - } - - if ($AS->obj['actor'] && $AS->obj['actor']['id'] && $AS->obj['actor']['id'] !== $AS->actor['id']) { - $y = import_author_xchan([ 'url' => $AS->obj['actor']['id'] ]); - if (! $y) { - logger('FOF Activity: no object actor'); - continue; - } - } - - - if ($r) { - $arr['author_xchan'] = $r[0]['hubloc_hash']; - } - - if ($signer) { - $arr['owner_xchan'] = $signer[0]['hubloc_hash']; - } - else { - $arr['owner_xchan'] = $a['signature']['signer']; - } - - if ($AS->data['hubloc'] || $arr['author_xchan'] === $arr['owner_xchan']) { - $arr['item_verified'] = true; - } - - if ($AS->data['signed_data']) { - IConfig::Set($arr,'activitystreams','signed_data',$AS->data['signed_data'],false); - } - - logger('FOF Activity received: ' . print_r($arr,true), LOGGER_DATA, LOG_DEBUG); - logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG); - - $result = self::process_delivery($arr['owner_xchan'],$AS,$arr, [ $channel['channel_hash'] ],false,false,true); - if ($result) { - $ret = array_merge($ret, $result); - } - } - - return $ret; - } - - - /** - * @brief Remove community tag. - * - * @param array $sender an associative array with - * * \e string \b hash a xchan_hash - * @param array $arr an associative array - * * \e int \b verb - * * \e int \b obj_type - * * \e int \b mid - * @param int $uid - */ - - static function remove_community_tag($sender, $arr, $uid) { - - if (! (activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM))) - return; - - logger('remove_community_tag: invoked'); - - if (! get_pconfig($uid,'system','blocktags')) { - logger('Permission denied.'); - return; - } - - $r = q("select * from item where mid = '%s' and uid = %d limit 1", - dbesc($arr['mid']), - intval($uid) - ); - if (! $r) { - logger('No item'); - return; - } - - if (($sender != $r[0]['owner_xchan']) && ($sender != $r[0]['author_xchan'])) { - logger('Sender not authorised.'); - return; - } - - $i = $r[0]; - - if ($i['target']) { - $i['target'] = json_decode($i['target'],true); - } - if ($i['object']) { - $i['object'] = json_decode($i['object'],true); - } - if (! ($i['target'] && $i['object'])) { - logger('No target/object'); - return; - } - - $message_id = $i['target']['id']; - - $r = q("select id from item where mid = '%s' and uid = %d limit 1", - dbesc($message_id), - intval($uid) - ); - if (! $r) { - logger('No parent message'); - return; - } - - q("delete from term where uid = %d and oid = %d and otype = %d and ttype in ( %d, %d ) and term = '%s' and url = '%s'", - intval($uid), - intval($r[0]['id']), - intval(TERM_OBJ_POST), - intval(TERM_HASHTAG), - intval(TERM_COMMUNITYTAG), - dbesc($i['object']['title']), - dbesc(get_rel_link($i['object']['link'],'alternate')) - ); - } - - /** - * @brief Updates an imported item. - * - * @see item_store_update() - * - * @param array $sender - * @param array $item - * @param array $orig - * @param int $uid - * @param boolean $tag_delivery - */ - - static function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) { - - // If this is a comment being updated, remove any privacy information - // so that item_store_update will set it from the original. - - if ($item['mid'] !== $item['parent_mid']) { - unset($item['allow_cid']); - unset($item['allow_gid']); - unset($item['deny_cid']); - unset($item['deny_gid']); - unset($item['item_private']); - } - - // we need the tag_delivery check for downstream flowing posts as the stored post - // may have a different owner than the one being transmitted. - - if (($sender != $orig['owner_xchan'] && $sender != $orig['author_xchan']) && (! $tag_delivery)) { - logger('sender is not owner or author'); - return; - } - - - $x = item_store_update($item); - - // If we're updating an event that we've saved locally, we store the item info first - // because event_addtocal will parse the body to get the 'new' event details - - if ($orig['resource_type'] === 'event') { - $res = event_addtocal($orig['id'], $uid); - if (! $res) { - logger('update event: failed'); - } - } - - if (! $x['item_id']) { - logger('update_imported_item: failed: ' . $x['message']); - } - else { - logger('update_imported_item'); - } - - return $x; - } - - /** - * @brief Deletes an imported item. - * - * @param array $sender - * * \e string \b hash a xchan_hash - * @param array $item - * @param int $uid - * @param boolean $relay - * @return boolean|int post_id - */ - - static function delete_imported_item($sender, $act, $item, $uid, $relay) { - - logger('invoked', LOGGER_DEBUG); - - $ownership_valid = false; - $item_found = false; - $post_id = 0; - - if ($item['verb'] === 'Tombstone') { - // The id of the deleted thing is the item mid (activity id) - $mid = $item['mid']; - } - else { - // The id is the object id if the type is Undo or Delete - $mid = ((is_array($act->obj)) ? $act->obj['id'] : $act->obj); - } - - // we may have stored either the object id or the activity id if it was a response activity (like, dislike, etc.) - - $r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' ) + if (($act) && ($act->obj) && (!is_array($act->obj))) { + + // The initial object fetch failed using the sys channel credentials. + // Try again using the delivery channel credentials. + // We will also need to re-parse the $item array, + // but preserve any values that were set during anonymous parsing. + + $o = Activity::fetch($act->obj, $channel); + if ($o) { + $act->obj = $o; + $arr = array_merge(Activity::decode_note($act), $arr); + } else { + $DR->update('Incomplete or corrupt activity'); + $result[] = $DR->get(); + continue; + } + } + + /** + * We need to block normal top-level message delivery from our clones, as the delivered + * message doesn't have ACL information in it as the cloned copy does. That copy + * will normally arrive first via sync delivery, but this isn't guaranteed. + * There's a chance the current delivery could take place before the cloned copy arrives + * hence the item could have the wrong ACL and *could* be used in subsequent deliveries or + * access checks. + */ + + if ($sender === $channel['channel_hash'] && $arr['author_xchan'] === $channel['channel_hash'] && $arr['mid'] === $arr['parent_mid']) { + $DR->update('self delivery ignored'); + $result[] = $DR->get(); + continue; + } + + // allow public postings to the sys channel regardless of permissions, but not + // for comments travelling upstream. Wait and catch them on the way down. + // They may have been blocked by the owner. + + if (intval($channel['channel_system']) && (!$arr['item_private']) && (!$relay)) { + $local_public = true; + + if (!check_pubstream_channelallowed($sender)) { + $local_public = false; + continue; + } + + // don't allow pubstream posts if the sender even has a clone on a pubstream denied site + + $siteallowed = true; + $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", + dbesc($sender) + ); + if ($h) { + foreach ($h as $hub) { + if (!check_pubstream_siteallowed($hub['hubloc_url'])) { + $siteallowed = false; + break; + } + } + } + if (!$siteallowed) { + $local_public = false; + continue; + } + + $r = q("select xchan_selfcensored from xchan where xchan_hash = '%s' limit 1", + dbesc($sender) + ); + // don't import sys channel posts from selfcensored authors + if ($r && (intval($r[0]['xchan_selfcensored']))) { + $local_public = false; + continue; + } + if (!MessageFilter::evaluate($arr, get_config('system', 'pubstream_incl'), get_config('system', 'pubstream_excl'))) { + $local_public = false; + continue; + } + } + + // perform pre-storage check to see if it's "likely" that this is a group or collection post + + $tag_delivery = tgroup_check($channel['channel_id'], $arr); + + $perm = 'send_stream'; + if (($arr['mid'] !== $arr['parent_mid']) && ($relay)) + $perm = 'post_comments'; + + // This is our own post, possibly coming from a channel clone + + if ($arr['owner_xchan'] == $d) { + $arr['item_wall'] = 1; + } else { + $arr['item_wall'] = 0; + } + + $friendofriend = false; + + if ((!$tag_delivery) && (!$local_public)) { + $allowed = (perm_is_allowed($channel['channel_id'], $sender, $perm)); + + $blocked = LibBlock::fetch($channel['channel_id'], BLOCKTYPE_SERVER); + if ($blocked) { + $h = q("select hubloc_url from hubloc where hubloc_hash = '%s'", + dbesc($sender) + ); + if ($h) { + foreach ($h as $hub) { + foreach ($blocked as $b) { + if (strpos($hub['hubloc_url'], $b['block_entity']) !== false) { + $allowed = false; + } + } + } + } + } + + $permit_mentions = intval(PConfig::Get($channel['channel_id'], 'system', 'permit_all_mentions') && i_am_mentioned($channel, $arr)); + + if (!$allowed) { + if ($perm === 'post_comments') { + $parent = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['parent_mid']), + intval($channel['channel_id']) + ); + if ($parent) { + $allowed = can_comment_on_post($sender, $parent[0]); + } + if ((!$allowed) && $permit_mentions) { + if ($parent && $parent[0]['owner_xchan'] === $channel['channel_hash']) { + $allowed = false; + } else { + $allowed = true; + } + } + if ($parent && absolutely_no_comments($parent[0])) { + $allowed = false; + } + + } elseif ($permit_mentions) { + $allowed = true; + } + } + if ($request) { + + // Conversation fetches (e.g. $request == true) take place for + // a) new comments on expired posts + // b) hyperdrive (friend-of-friend) conversations + + + // over-ride normal connection permissions for hyperdrive (friend-of-friend) conversations + // (if hyperdrive is enabled). + // If $allowed is already true, this is probably the conversation of a direct friend or a + // conversation fetch for a new comment on an expired post + // Comments of all these activities are allowed and will only be rejected (later) if the parent + // doesn't exist. + + if ($perm === 'send_stream') { + if (get_pconfig($channel['channel_id'], 'system', 'hyperdrive', true)) { + $allowed = true; + } + } else { + $allowed = true; + } + + $friendofriend = true; + } + + if (intval($arr['item_private']) === 2) { + if (!perm_is_allowed($channel['channel_id'], $sender, 'post_mail')) { + $allowed = false; + } + } + + if (get_abconfig($channel['channel_id'], $sender, 'system', 'block_announce', false)) { + if ($arr['verb'] === 'Announce' || strpos($arr['body'], '[/share]')) { + $allowed = false; + } + } + + if (!$allowed) { + logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); + $DR->update('permission denied'); + $result[] = $DR->get(); + continue; + } + } + + if ($arr['mid'] !== $arr['parent_mid']) { + + if (perm_is_allowed($channel['channel_id'], $sender, 'moderated') && $relay) { + $arr['item_blocked'] = ITEM_MODERATED; + } + + // check source route. + // We are only going to accept comments from this sender if the comment has the same route as the top-level-post, + // this is so that permissions mismatches between senders apply to the entire conversation + // As a side effect we will also do a preliminary check that we have the top-level-post, otherwise + // processing it is pointless. + + // The original author won't have a token in their copy of the message + + $prnt = ((strpos($arr['parent_mid'], 'token=') !== false) ? substr($arr['parent_mid'], 0, strpos($arr['parent_mid'], '?')) : ''); + + $r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['parent_mid']), + intval($channel['channel_id']) + ); + if (!$r) { + $r = q("select route, id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1", + dbesc($prnt), + intval($channel['channel_id']) + ); + } + + if ($r) { + // if this is a multi-threaded conversation, preserve the threading information + if ($r[0]['parent_mid'] !== $r[0]['mid']) { + $arr['thr_parent'] = $arr['parent_mid']; + $arr['parent_mid'] = $r[0]['parent_mid']; + if ($act->replyto) { + q("update item set replyto = '%s' where id = %d", + dbesc($act->replyto), + intval($r[0]['id']) + ); + } + } + + if ($r[0]['obj_type'] === 'Question') { + // route checking doesn't work correctly here because we've changed the privacy + $r[0]['route'] = EMPTY_STR; + // If this is a poll response, convert the obj_type to our (internal-only) "Answer" type + if ($arr['obj_type'] === 'Note' && $arr['title'] && (!$arr['content'])) { + $arr['obj_type'] = 'Answer'; + } + } + } else { + + // We don't seem to have a copy of this conversation or at least the parent + // - so request a copy of the entire conversation to date. + // Don't do this if it's a relay post as we're the ones who are supposed to + // have the copy and we don't want the request to loop. + // Also don't do this if this comment came from a conversation request packet. + // It's possible that comments are allowed but posting isn't and that could + // cause a conversation fetch loop. + // We'll also check the send_stream permission - because if it isn't allowed, + // the top level post is unlikely to be imported and + // this is just an exercise in futility. + + if ((!$relay) && (!$request) && (!$local_public) + && perm_is_allowed($channel['channel_id'], $sender, 'send_stream')) { + $reports = self::fetch_conversation($channel, $arr['mid']); + + // extract our delivery report from the fetched conversation + // if we can find it. + logger('fetch_report for ' . $arr['mid'], LOGGER_ALL); + logger('fetch_report: ' . print_r($reports, true), LOGGER_ALL); + + if ($reports && is_array($reports)) { + $found_report = false; + foreach ($reports as $report) { + if ($report['message_id'] === $arr['mid']) { + $found_report = true; + $DR->update($report['status']); + } + } + if (!$found_report) { + $DR->update('conversation fetch failed'); + } + } else { + $DR->update('conversation fetch failed'); + } + } else { + $DR->update('comment parent not found'); + } + $result[] = $DR->get(); + continue; + } + + + if ($relay || $friendofriend || (intval($r[0]['item_private']) === 0 && intval($arr['item_private']) === 0)) { + // reset the route in case it travelled a great distance upstream + // use our parent's route so when we go back downstream we'll match + // with whatever route our parent has. + // Also friend-of-friend conversations may have been imported without a route, + // but we are now getting comments via listener delivery + // and if there is no privacy on this or the parent, we don't care about the route, + // so just set the owner and route accordingly. + $arr['route'] = $r[0]['route']; + $arr['owner_xchan'] = $r[0]['owner_xchan']; + } else { + + // going downstream check that we have the same upstream provider that + // sent it to us originally. Ignore it if it came from another source + // (with potentially different permissions). + // only compare the last hop since it could have arrived at the last location any number of ways. + // Always accept empty routes and firehose items (route contains 'undefined') . + + $existing_route = explode(',', $r[0]['route']); + $routes = count($existing_route); + if ($routes) { + $last_hop = array_pop($existing_route); + $last_prior_route = implode(',', $existing_route); + } else { + $last_hop = ''; + $last_prior_route = ''; + } + + if (in_array('undefined', $existing_route) || $last_hop == 'undefined' || $sender == 'undefined') { + $last_hop = ''; + } + + $current_route = (($arr['route']) ? $arr['route'] . ',' : '') . $sender; + + if ($last_hop && $last_hop != $sender) { + logger('comment route mismatch: parent route = ' . $r[0]['route'] . ' expected = ' . $current_route, LOGGER_DEBUG); + logger('comment route mismatch: parent msg = ' . $r[0]['id'], LOGGER_DEBUG); + $DR->update('comment route mismatch'); + $result[] = $DR->get(); + continue; + } + + // we'll add sender onto this when we deliver it. $last_prior_route now has the previously stored route + // *except* for the sender which would've been the last hop before it got to us. + + $arr['route'] = $last_prior_route; + } + } + + // This is used to fetch allow/deny rules if either the sender + // or owner is a connection. post_is_importable() evaluates all of them + $abook = q("select * from abook where abook_channel = %d and ( abook_xchan = '%s' OR abook_xchan = '%s' )", + intval($channel['channel_id']), + dbesc($arr['owner_xchan']), + dbesc($arr['author_xchan']) + ); + + if (isset($arr['item_deleted']) && intval($arr['item_deleted'])) { + + // set these just in case we need to store a fresh copy of the deleted post. + // This could happen if the delete got here before the original post did. + + $arr['aid'] = $channel['channel_account_id']; + $arr['uid'] = $channel['channel_id']; + + $item_id = self::delete_imported_item($sender, $act, $arr, $channel['channel_id'], $relay); + $DR->update(($item_id) ? 'deleted' : 'delete_failed'); + $result[] = $DR->get(); + + if ($relay && $item_id) { + logger('process_delivery: invoking relay'); + Run::Summon(['Notifier', 'relay', intval($item_id)]); + $DR->update('relayed'); + $result[] = $DR->get(); + } + continue; + } + + // reactions such as like and dislike could have an mid with /activity/ in it. + // Check for both forms in order to prevent duplicates. + + $r = q("select * from item where mid in ('%s','%s') and uid = %d limit 1", + dbesc($arr['mid']), + dbesc(str_replace(z_root() . '/activity/', z_root() . '/item/', $arr['mid'])), + intval($channel['channel_id']) + ); + + if ($r) { + // We already have this post. + $item_id = $r[0]['id']; + + if (intval($r[0]['item_deleted'])) { + // It was deleted locally. + $DR->update('update ignored'); + $result[] = $DR->get(); + + continue; + } // Maybe it has been edited? + elseif ($arr['edited'] > $r[0]['edited']) { + $arr['id'] = $r[0]['id']; + $arr['uid'] = $channel['channel_id']; + if (post_is_importable($channel['channel_id'], $arr, $abook)) { + $item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery); + $DR->update('updated'); + $result[] = $DR->get(); + if (!$relay) { + add_source_route($item_id, $sender); + } + } else { + $DR->update('update ignored'); + $result[] = $DR->get(); + } + } else { + $DR->update('update ignored'); + $result[] = $DR->get(); + + // We need this line to ensure wall-to-wall comments are relayed (by falling through to the relay bit), + // and at the same time not relay any other relayable posts more than once, because to do so is very wasteful. + if (!intval($r[0]['item_origin'])) { + continue; + } + } + } else { + $arr['aid'] = $channel['channel_account_id']; + $arr['uid'] = $channel['channel_id']; + + // if it's a sourced post, call the post_local hooks as if it were + // posted locally so that crosspost connectors will be triggered. + + if (check_item_source($arr['uid'], $arr)) { + /** + * @hooks post_local + * Called when an item has been posted on this machine via mod/item.php (also via API). + * * \e array with an item + */ + call_hooks('post_local', $arr); + } + + $item_id = 0; + + Activity::rewrite_mentions($arr); + + + $maxlen = get_max_import_size(); + + if ($maxlen && mb_strlen($arr['body']) > $maxlen) { + $arr['body'] = mb_substr($arr['body'], 0, $maxlen, 'UTF-8'); + logger('message length exceeds max_import_size: truncated'); + } + + if ($maxlen && mb_strlen($arr['summary']) > $maxlen) { + $arr['summary'] = mb_substr($arr['summary'], 0, $maxlen, 'UTF-8'); + logger('message summary length exceeds max_import_size: truncated'); + } + + if (post_is_importable($arr['uid'], $arr, $abook)) { + + // Strip old-style hubzilla bookmarks + if (strpos($arr['body'], "#^[") !== false) { + $arr['body'] = str_replace("#^[", "[", $arr['body']); + } + + $item_result = item_store($arr); + if ($item_result['success']) { + $item_id = $item_result['item_id']; + $parr = [ + 'item_id' => $item_id, + 'item' => $arr, + 'sender' => $sender, + 'channel' => $channel + ]; + /** + * @hooks activity_received + * Called when an activity (post, comment, like, etc.) has been received from a zot source. + * * \e int \b item_id + * * \e array \b item + * * \e array \b sender + * * \e array \b channel + */ + call_hooks('activity_received', $parr); + // don't add a source route if it's a relay or later recipients will get a route mismatch + if (!$relay) { + add_source_route($item_id, $sender); + } + } + $DR->update(($item_id) ? 'posted' : 'storage failed: ' . $item_result['message']); + $result[] = $DR->get(); + } else { + $DR->update('post ignored'); + $result[] = $DR->get(); + } + } + + // preserve conversations with which you are involved from expiration + + $stored = (($item_result && $item_result['item']) ? $item_result['item'] : false); + if ((is_array($stored)) && ($stored['id'] != $stored['parent']) + && ($stored['author_xchan'] === $channel['channel_hash'])) { + retain_item($stored['item']['parent']); + } + + if ($relay && $item_id) { + logger('Invoking relay'); + Run::Summon(['Notifier', 'relay', intval($item_id)]); + $DR->addto_update('relayed'); + $result[] = $DR->get(); + } + } + + if (!$deliveries) { + $result[] = array('', 'no recipients', '', $arr['mid']); + } + + logger('Local results: ' . print_r($result, true), LOGGER_DEBUG); + + return $result; + } + + public static function hyperdrive_enabled($channel, $item) + { + + if (get_pconfig($channel['channel_id'], 'system', 'hyperdrive', true)) { + return true; + } + return false; + } + + public static function fetch_conversation($channel, $mid) + { + + // Use Zotfinger to create a signed request + + logger('fetching conversation: ' . $mid, LOGGER_DEBUG); + + $a = Zotfinger::exec($mid, $channel); + + logger('received conversation: ' . print_r($a, true), LOGGER_DATA); + + if (!$a) { + return false; + } + + if ($a['data']['type'] !== 'OrderedCollection') { + return false; + } + + $obj = new ASCollection($a['data'], $channel); + $items = $obj->get(); + + if (!$items) { + return false; + } + + $ret = []; + + + $signer = q("select hubloc_hash, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($a['signature']['signer']) + ); + + + foreach ($items as $activity) { + + $AS = new ActivityStreams($activity); + if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) + && array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $AS = new ActivityStreams($AS->obj); + } + + if (!$AS->is_valid()) { + logger('FOF Activity rejected: ' . print_r($activity, true)); + continue; + } + $arr = Activity::decode_note($AS); + + // logger($AS->debug()); + + $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", + dbesc($AS->actor['id']), + dbesc($AS->actor['id']) + ); + + if (!$r) { + $y = import_author_xchan(['url' => $AS->actor['id']]); + if ($y) { + $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_hash = '%s' limit 1", + dbesc($AS->actor['id']), + dbesc($AS->actor['id']) + ); + } + if (!$r) { + logger('FOF Activity: no actor'); + continue; + } + } + + if ($AS->obj['actor'] && $AS->obj['actor']['id'] && $AS->obj['actor']['id'] !== $AS->actor['id']) { + $y = import_author_xchan(['url' => $AS->obj['actor']['id']]); + if (!$y) { + logger('FOF Activity: no object actor'); + continue; + } + } + + + if ($r) { + $arr['author_xchan'] = $r[0]['hubloc_hash']; + } + + if ($signer) { + $arr['owner_xchan'] = $signer[0]['hubloc_hash']; + } else { + $arr['owner_xchan'] = $a['signature']['signer']; + } + + if ($AS->data['hubloc'] || $arr['author_xchan'] === $arr['owner_xchan']) { + $arr['item_verified'] = true; + } + + if ($AS->data['signed_data']) { + IConfig::Set($arr, 'activitystreams', 'signed_data', $AS->data['signed_data'], false); + } + + logger('FOF Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG); + logger('FOF Activity recipient: ' . $channel['channel_hash'], LOGGER_DATA, LOG_DEBUG); + + $result = self::process_delivery($arr['owner_xchan'], $AS, $arr, [$channel['channel_hash']], false, false, true); + if ($result) { + $ret = array_merge($ret, $result); + } + } + + return $ret; + } + + + /** + * @brief Remove community tag. + * + * @param array $sender an associative array with + * * \e string \b hash a xchan_hash + * @param array $arr an associative array + * * \e int \b verb + * * \e int \b obj_type + * * \e int \b mid + * @param int $uid + */ + + public static function remove_community_tag($sender, $arr, $uid) + { + + if (!(activity_match($arr['verb'], ACTIVITY_TAG) && ($arr['obj_type'] == ACTIVITY_OBJ_TAGTERM))) + return; + + logger('remove_community_tag: invoked'); + + if (!get_pconfig($uid, 'system', 'blocktags')) { + logger('Permission denied.'); + return; + } + + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['mid']), + intval($uid) + ); + if (!$r) { + logger('No item'); + return; + } + + if (($sender != $r[0]['owner_xchan']) && ($sender != $r[0]['author_xchan'])) { + logger('Sender not authorised.'); + return; + } + + $i = $r[0]; + + if ($i['target']) { + $i['target'] = json_decode($i['target'], true); + } + if ($i['object']) { + $i['object'] = json_decode($i['object'], true); + } + if (!($i['target'] && $i['object'])) { + logger('No target/object'); + return; + } + + $message_id = $i['target']['id']; + + $r = q("select id from item where mid = '%s' and uid = %d limit 1", + dbesc($message_id), + intval($uid) + ); + if (!$r) { + logger('No parent message'); + return; + } + + q("delete from term where uid = %d and oid = %d and otype = %d and ttype in ( %d, %d ) and term = '%s' and url = '%s'", + intval($uid), + intval($r[0]['id']), + intval(TERM_OBJ_POST), + intval(TERM_HASHTAG), + intval(TERM_COMMUNITYTAG), + dbesc($i['object']['title']), + dbesc(get_rel_link($i['object']['link'], 'alternate')) + ); + } + + /** + * @brief Updates an imported item. + * + * @param array $sender + * @param array $item + * @param array $orig + * @param int $uid + * @param boolean $tag_delivery + * @see item_store_update() + * + */ + + public static function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) + { + + // If this is a comment being updated, remove any privacy information + // so that item_store_update will set it from the original. + + if ($item['mid'] !== $item['parent_mid']) { + unset($item['allow_cid']); + unset($item['allow_gid']); + unset($item['deny_cid']); + unset($item['deny_gid']); + unset($item['item_private']); + } + + // we need the tag_delivery check for downstream flowing posts as the stored post + // may have a different owner than the one being transmitted. + + if (($sender != $orig['owner_xchan'] && $sender != $orig['author_xchan']) && (!$tag_delivery)) { + logger('sender is not owner or author'); + return; + } + + + $x = item_store_update($item); + + // If we're updating an event that we've saved locally, we store the item info first + // because event_addtocal will parse the body to get the 'new' event details + + if ($orig['resource_type'] === 'event') { + $res = event_addtocal($orig['id'], $uid); + if (!$res) { + logger('update event: failed'); + } + } + + if (!$x['item_id']) { + logger('update_imported_item: failed: ' . $x['message']); + } else { + logger('update_imported_item'); + } + + return $x; + } + + /** + * @brief Deletes an imported item. + * + * @param array $sender + * * \e string \b hash a xchan_hash + * @param array $item + * @param int $uid + * @param boolean $relay + * @return boolean|int post_id + */ + + public static function delete_imported_item($sender, $act, $item, $uid, $relay) + { + + logger('invoked', LOGGER_DEBUG); + + $ownership_valid = false; + $item_found = false; + $post_id = 0; + + if ($item['verb'] === 'Tombstone') { + // The id of the deleted thing is the item mid (activity id) + $mid = $item['mid']; + } else { + // The id is the object id if the type is Undo or Delete + $mid = ((is_array($act->obj)) ? $act->obj['id'] : $act->obj); + } + + // we may have stored either the object id or the activity id if it was a response activity (like, dislike, etc.) + + $r = q("select * from item where ( author_xchan = '%s' or owner_xchan = '%s' or source_xchan = '%s' ) and mid in ('%s','%s') and uid = %d limit 1", - dbesc($sender), - dbesc($sender), - dbesc($sender), - dbesc($mid), - dbesc(str_replace('/activity/','/item/',$mid)), - intval($uid) - ); + dbesc($sender), + dbesc($sender), + dbesc($sender), + dbesc($mid), + dbesc(str_replace('/activity/', '/item/', $mid)), + intval($uid) + ); - if ($r) { - $stored = $r[0]; - // we proved ownership in the sql query - $ownership_valid = true; + if ($r) { + $stored = $r[0]; + // we proved ownership in the sql query + $ownership_valid = true; - $post_id = $stored['id']; - $item_found = true; - } - else { - // this will fail with an ownership issue, so explain the real reason - logger('delete received for non-existent item or not owned by sender - ignoring.'); + $post_id = $stored['id']; + $item_found = true; + } else { + // this will fail with an ownership issue, so explain the real reason + logger('delete received for non-existent item or not owned by sender - ignoring.'); - } + } - if ($ownership_valid === false) { - logger('delete_imported_item: failed: ownership issue'); - return false; - } + if ($ownership_valid === false) { + logger('delete_imported_item: failed: ownership issue'); + return false; + } - if ($stored['resource_type'] === 'event') { - $i = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", - dbesc($stored['resource_id']), - intval($uid) - ); - if ($i) { - if ($i[0]['event_xchan'] === $sender) { - q("delete from event where event_hash = '%s' and uid = %d", - dbesc($stored['resource_id']), - intval($uid) - ); - } - else { - logger('delete linked event: not owner'); - return; - } - } - } - if ($item_found) { - if (intval($stored['item_deleted'])) { - logger('delete_imported_item: item was already deleted'); - if (! $relay) { - return false; - } - - // This is a bit hackish, but may have to suffice until the notification/delivery loop is optimised - // a bit further. We're going to strip the ITEM_ORIGIN on this item if it's a comment, because - // it was already deleted, and we're already relaying, and this ensures that no other process or - // code path downstream can relay it again (causing a loop). Since it's already gone it's not coming - // back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing - // this information from the metadata should have no other discernible impact. + if ($stored['resource_type'] === 'event') { + $i = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + dbesc($stored['resource_id']), + intval($uid) + ); + if ($i) { + if ($i[0]['event_xchan'] === $sender) { + q("delete from event where event_hash = '%s' and uid = %d", + dbesc($stored['resource_id']), + intval($uid) + ); + } else { + logger('delete linked event: not owner'); + return; + } + } + } + if ($item_found) { + if (intval($stored['item_deleted'])) { + logger('delete_imported_item: item was already deleted'); + if (!$relay) { + return false; + } - if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) { - q("update item set item_origin = 0 where id = %d and uid = %d", - intval($stored['id']), - intval($stored['uid']) - ); - } - } - else { - if ($stored['id'] !== $stored['parent']) { - q("update item set commented = '%s', changed = '%s' where id = %d", - dbesc(datetime_convert()), - dbesc(datetime_convert()), - intval($stored['parent']) - ); - } - } + // This is a bit hackish, but may have to suffice until the notification/delivery loop is optimised + // a bit further. We're going to strip the ITEM_ORIGIN on this item if it's a comment, because + // it was already deleted, and we're already relaying, and this ensures that no other process or + // code path downstream can relay it again (causing a loop). Since it's already gone it's not coming + // back, and we aren't going to (or shouldn't at any rate) delete it again in the future - so losing + // this information from the metadata should have no other discernible impact. - // Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels - // and then clean up after ourselves with a cron job after several days to do the delete_item_lowlevel() (DROPITEM_PHASE2). + if (($stored['id'] != $stored['parent']) && intval($stored['item_origin'])) { + q("update item set item_origin = 0 where id = %d and uid = %d", + intval($stored['id']), + intval($stored['uid']) + ); + } + } else { + if ($stored['id'] !== $stored['parent']) { + q("update item set commented = '%s', changed = '%s' where id = %d", + dbesc(datetime_convert()), + dbesc(datetime_convert()), + intval($stored['parent']) + ); + } + } - drop_item($post_id, false, DROPITEM_PHASE1); - tag_deliver($uid, $post_id); - } + // Use phased deletion to set the deleted flag, call both tag_deliver and the notifier to notify downstream channels + // and then clean up after ourselves with a cron job after several days to do the delete_item_lowlevel() (DROPITEM_PHASE2). - return $post_id; - } + drop_item($post_id, false, DROPITEM_PHASE1); + tag_deliver($uid, $post_id); + } + + return $post_id; + } - /** - * @brief Processes delivery of profile. - * - * @see import_directory_profile() - * @param array $sender an associative array - * * \e string \b hash a xchan_hash - * @param array $arr - * @param array $deliveries (unused) - */ + /** + * @brief Processes delivery of profile. + * + * @param array $sender an associative array + * * \e string \b hash a xchan_hash + * @param array $arr + * @param array $deliveries (unused) + * @see import_directory_profile() + */ - static function process_profile_delivery($sender, $arr, $deliveries) { + public static function process_profile_delivery($sender, $arr, $deliveries) + { - logger('process_profile_delivery', LOGGER_DEBUG); + logger('process_profile_delivery', LOGGER_DEBUG); - $r = q("select xchan_addr from xchan where xchan_hash = '%s' limit 1", - dbesc($sender['hash']) - ); - if ($r) { - Libzotdir::import_directory_profile($sender, $arr, $r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0); - } - } + $r = q("select xchan_addr from xchan where xchan_hash = '%s' limit 1", + dbesc($sender['hash']) + ); + if ($r) { + Libzotdir::import_directory_profile($sender, $arr, $r[0]['xchan_addr'], UPDATE_FLAGS_UPDATED, 0); + } + } - /** - * @brief - * - * @param array $sender an associative array - * * \e string \b hash a xchan_hash - * @param array $arr - * @param array $deliveries (unused) deliveries is irrelevant - */ - static function process_location_delivery($sender, $arr, $deliveries) { + /** + * @brief + * + * @param array $sender an associative array + * * \e string \b hash a xchan_hash + * @param array $arr + * @param array $deliveries (unused) deliveries is irrelevant + */ + public static function process_location_delivery($sender, $arr, $deliveries) + { - // deliveries is irrelevant - logger('process_location_delivery', LOGGER_DEBUG); + // deliveries is irrelevant + logger('process_location_delivery', LOGGER_DEBUG); - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($sender) - ); - if ($r) { - $xchan = [ 'id' => $r[0]['xchan_guid'], 'id_sig' => $r[0]['xchan_guid_sig'], - 'hash' => $r[0]['xchan_hash'], 'public_key' => $r[0]['xchan_pubkey'] ]; - } - if (array_key_exists('locations',$arr) && $arr['locations']) { - $x = Libsync::sync_locations($xchan,$arr,true); - logger('results: ' . print_r($x,true), LOGGER_DEBUG); - if ($x['changed']) { - $guid = random_string() . '@' . App::get_hostname(); - Libzotdir::update_modtime($sender,$r[0]['xchan_guid'],$arr['locations'][0]['address'],UPDATE_FLAGS_UPDATED); - } - } - } + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($sender) + ); + if ($r) { + $xchan = ['id' => $r[0]['xchan_guid'], 'id_sig' => $r[0]['xchan_guid_sig'], + 'hash' => $r[0]['xchan_hash'], 'public_key' => $r[0]['xchan_pubkey']]; + } + if (array_key_exists('locations', $arr) && $arr['locations']) { + $x = Libsync::sync_locations($xchan, $arr, true); + logger('results: ' . print_r($x, true), LOGGER_DEBUG); + if ($x['changed']) { + $guid = random_string() . '@' . App::get_hostname(); + Libzotdir::update_modtime($sender, $r[0]['xchan_guid'], $arr['locations'][0]['address'], UPDATE_FLAGS_UPDATED); + } + } + } - /** - * @brief Checks for a moved channel and sets the channel_moved flag. - * - * Currently the effect of this flag is to turn the channel into 'read-only' mode. - * New content will not be processed (there was still an issue with blocking the - * ability to post comments as of 10-Mar-2016). - * We do not physically remove the channel at this time. The hub admin may choose - * to do so, but is encouraged to allow a grace period of several days in case there - * are any issues migrating content. This packet will generally be received by the - * original site when the basic channel import has been processed. - * - * This will only be executed on the old location - * if a new location is reported and there is only one location record. - * The rest of the hubloc syncronisation will be handled within - * sync_locations - * - * @param string $sender_hash A channel hash - * @param array $locations - */ + /** + * @brief Checks for a moved channel and sets the channel_moved flag. + * + * Currently the effect of this flag is to turn the channel into 'read-only' mode. + * New content will not be processed (there was still an issue with blocking the + * ability to post comments as of 10-Mar-2016). + * We do not physically remove the channel at this time. The hub admin may choose + * to do so, but is encouraged to allow a grace period of several days in case there + * are any issues migrating content. This packet will generally be received by the + * original site when the basic channel import has been processed. + * + * This will only be executed on the old location + * if a new location is reported and there is only one location record. + * The rest of the hubloc syncronisation will be handled within + * sync_locations + * + * @param string $sender_hash A channel hash + * @param array $locations + */ - static function check_location_move($sender_hash, $locations) { + public static function check_location_move($sender_hash, $locations) + { - if (! $locations) { - return; - } + if (!$locations) { + return; + } - if (count($locations) != 1) { - return; - } + if (count($locations) != 1) { + return; + } - $loc = $locations[0]; + $loc = $locations[0]; - $r = q("select * from channel where channel_hash = '%s' limit 1", - dbesc($sender_hash) - ); + $r = q("select * from channel where channel_hash = '%s' limit 1", + dbesc($sender_hash) + ); - if (! $r) { - return; - } + if (!$r) { + return; + } - if ($loc['url'] !== z_root()) { - $x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1", - dbesc($loc['url']), - dbesc($sender_hash) - ); + if ($loc['url'] !== z_root()) { + $x = q("update channel set channel_moved = '%s' where channel_hash = '%s' limit 1", + dbesc($loc['url']), + dbesc($sender_hash) + ); - // federation plugins may wish to notify connections - // of the move on singleton networks + // federation plugins may wish to notify connections + // of the move on singleton networks - $arr = [ - 'channel' => $r[0], - 'locations' => $locations - ]; - /** - * @hooks location_move - * Called when a new location has been provided to a UNO channel (indicating a move rather than a clone). - * * \e array \b channel - * * \e array \b locations - */ - call_hooks('location_move', $arr); - } - } + $arr = [ + 'channel' => $r[0], + 'locations' => $locations + ]; + /** + * @hooks location_move + * Called when a new location has been provided to a UNO channel (indicating a move rather than a clone). + * * \e array \b channel + * * \e array \b locations + */ + call_hooks('location_move', $arr); + } + } + /** + * @brief Returns an array with all known distinct hubs for this channel. + * + * @param array $channel an associative array which must contain + * * \e string \b channel_hash the hash of the channel + * @return array an array with associative arrays + * @see self::get_hublocs() + */ - /** - * @brief Returns an array with all known distinct hubs for this channel. - * - * @see self::get_hublocs() - * @param array $channel an associative array which must contain - * * \e string \b channel_hash the hash of the channel - * @return array an array with associative arrays - */ + public static function encode_locations($channel) + { + $ret = []; - static function encode_locations($channel) { - $ret = []; + $x = self::get_hublocs($channel['channel_hash']); - $x = self::get_hublocs($channel['channel_hash']); + if ($x && count($x)) { + foreach ($x as $hub) { - if ($x && count($x)) { - foreach ($x as $hub) { + // if this is a local channel that has been deleted, the hubloc is no good + // - make sure it is marked deleted so that nobody tries to use it. - // if this is a local channel that has been deleted, the hubloc is no good - // - make sure it is marked deleted so that nobody tries to use it. + if (intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root()) { + $hub['hubloc_deleted'] = 1; + } - if (intval($channel['channel_removed']) && $hub['hubloc_url'] === z_root()) { - $hub['hubloc_deleted'] = 1; - } + $ret[] = [ + 'host' => $hub['hubloc_host'], + 'address' => $hub['hubloc_addr'], + 'id_url' => $hub['hubloc_id_url'], + 'primary' => (intval($hub['hubloc_primary']) ? true : false), + 'url' => $hub['hubloc_url'], + 'url_sig' => $hub['hubloc_url_sig'], + 'site_id' => $hub['hubloc_site_id'], + 'callback' => $hub['hubloc_callback'], + 'sitekey' => $hub['hubloc_sitekey'], + 'deleted' => (intval($hub['hubloc_deleted']) ? true : false) + ]; + } + } - $ret[] = [ - 'host' => $hub['hubloc_host'], - 'address' => $hub['hubloc_addr'], - 'id_url' => $hub['hubloc_id_url'], - 'primary' => (intval($hub['hubloc_primary']) ? true : false), - 'url' => $hub['hubloc_url'], - 'url_sig' => $hub['hubloc_url_sig'], - 'site_id' => $hub['hubloc_site_id'], - 'callback' => $hub['hubloc_callback'], - 'sitekey' => $hub['hubloc_sitekey'], - 'deleted' => (intval($hub['hubloc_deleted']) ? true : false) - ]; - } - } - - return $ret; - } + return $ret; + } - /** - * @brief - * - * @param array $arr - * @param string $pubkey - * @return boolean true if updated or inserted - */ - - static function import_site($arr) { + /** + * @brief + * + * @param array $arr + * @param string $pubkey + * @return boolean true if updated or inserted + */ - if ( (! is_array($arr)) || (! $arr['url']) || (! $arr['site_sig'])) { - return false; - } + public static function import_site($arr) + { - if (! self::verify($arr['url'], $arr['site_sig'], $arr['sitekey'])) { - logger('Bad url_sig'); - return false; - } + if ((!is_array($arr)) || (!$arr['url']) || (!$arr['site_sig'])) { + return false; + } - $update = false; - $exists = false; + if (!self::verify($arr['url'], $arr['site_sig'], $arr['sitekey'])) { + logger('Bad url_sig'); + return false; + } - $r = q("select * from site where site_url = '%s' limit 1", - dbesc($arr['url']) - ); - if ($r) { - $exists = true; - $siterecord = $r[0]; - } + $update = false; + $exists = false; - $site_directory = 0; - if ($arr['directory_mode'] == 'normal') { - $site_directory = DIRECTORY_MODE_NORMAL; - } - if ($arr['directory_mode'] == 'primary') { - $site_directory = DIRECTORY_MODE_PRIMARY; - } - if ($arr['directory_mode'] == 'secondary') { - $site_directory = DIRECTORY_MODE_SECONDARY; - } - if ($arr['directory_mode'] == 'standalone') { - $site_directory = DIRECTORY_MODE_STANDALONE; - } + $r = q("select * from site where site_url = '%s' limit 1", + dbesc($arr['url']) + ); + if ($r) { + $exists = true; + $siterecord = $r[0]; + } - $register_policy = 0; - if ($arr['register_policy'] == 'closed') { - $register_policy = REGISTER_CLOSED; - } - if ($arr['register_policy'] == 'open') { - $register_policy = REGISTER_OPEN; - } - if ($arr['register_policy'] == 'approve') { - $register_policy = REGISTER_APPROVE; - } + $site_directory = 0; + if ($arr['directory_mode'] == 'normal') { + $site_directory = DIRECTORY_MODE_NORMAL; + } + if ($arr['directory_mode'] == 'primary') { + $site_directory = DIRECTORY_MODE_PRIMARY; + } + if ($arr['directory_mode'] == 'secondary') { + $site_directory = DIRECTORY_MODE_SECONDARY; + } + if ($arr['directory_mode'] == 'standalone') { + $site_directory = DIRECTORY_MODE_STANDALONE; + } - $access_policy = 0; - if (array_key_exists('access_policy',$arr)) { - if ($arr['access_policy'] === 'private') { - $access_policy = ACCESS_PRIVATE; - } - if ($arr['access_policy'] === 'paid') { - $access_policy = ACCESS_PAID; - } - if ($arr['access_policy'] === 'free') { - $access_policy = ACCESS_FREE; - } - if ($arr['access_policy'] === 'tiered') { - $access_policy = ACCESS_TIERED; - } - } + $register_policy = 0; + if ($arr['register_policy'] == 'closed') { + $register_policy = REGISTER_CLOSED; + } + if ($arr['register_policy'] == 'open') { + $register_policy = REGISTER_OPEN; + } + if ($arr['register_policy'] == 'approve') { + $register_policy = REGISTER_APPROVE; + } - // don't let insecure sites register as public hubs + $access_policy = 0; + if (array_key_exists('access_policy', $arr)) { + if ($arr['access_policy'] === 'private') { + $access_policy = ACCESS_PRIVATE; + } + if ($arr['access_policy'] === 'paid') { + $access_policy = ACCESS_PAID; + } + if ($arr['access_policy'] === 'free') { + $access_policy = ACCESS_FREE; + } + if ($arr['access_policy'] === 'tiered') { + $access_policy = ACCESS_TIERED; + } + } - if (strpos($arr['url'],'https://') === false) { - $access_policy = ACCESS_PRIVATE; - } + // don't let insecure sites register as public hubs - if ($access_policy != ACCESS_PRIVATE) { - $x = z_fetch_url($arr['url'] . '/siteinfo.json'); - if (! $x['success']) - $access_policy = ACCESS_PRIVATE; - } + if (strpos($arr['url'], 'https://') === false) { + $access_policy = ACCESS_PRIVATE; + } - $site_about = EMPTY_STR; - $site_logo = EMPTY_STR; - $sitename = EMPTY_STR; + if ($access_policy != ACCESS_PRIVATE) { + $x = z_fetch_url($arr['url'] . '/siteinfo.json'); + if (!$x['success']) + $access_policy = ACCESS_PRIVATE; + } - $directory_url = htmlspecialchars(isset($arr['directory_url']) ? $arr['directory_url'] : EMPTY_STR,ENT_COMPAT,'UTF-8',false); - $url = htmlspecialchars(strtolower($arr['url']),ENT_COMPAT,'UTF-8',false); - $sellpage = htmlspecialchars($arr['sellpage'],ENT_COMPAT,'UTF-8',false); - $site_location = htmlspecialchars($arr['location'],ENT_COMPAT,'UTF-8',false); - $site_realm = htmlspecialchars($arr['realm'],ENT_COMPAT,'UTF-8',false); - $sitename = htmlspecialchars($arr['sitename'],ENT_COMPAT,'UTF-8',false); - $site_project = htmlspecialchars($arr['project'],ENT_COMPAT,'UTF-8',false); - $site_crypto = ((array_key_exists('encryption',$arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',',$arr['encryption']),ENT_COMPAT,'UTF-8',false) : ''); - $site_version = ((array_key_exists('version',$arr)) ? htmlspecialchars($arr['version'],ENT_COMPAT,'UTF-8',false) : ''); - if (array_key_exists('about',$arr) && $arr['about']) { - $site_about = html2bbcode(purify_html($arr['about'])); - } - if (array_key_exists('logo',$arr) && $arr['logo']) { - $site_logo = $arr['logo']; - } - elseif (file_exists('images/' . strtolower($site_project) . '.png')) { - $site_logo = z_root() . '/images/' . strtolower($site_project) . '.png'; - } - else { - $site_logo = z_root() . '/images/default_profile_photos/red_koala_trans/300.png'; - } - - set_sconfig($url,'system','about', $site_about); - set_sconfig($url,'system','logo', $site_logo); - set_sconfig($url,'system','sitename', $sitename); - - $site_flags = $site_directory; + $site_about = EMPTY_STR; + $site_logo = EMPTY_STR; + $sitename = EMPTY_STR; - if (array_key_exists('zot',$arr)) { - set_sconfig($arr['url'],'system','zot_version',$arr['zot']); - } + $directory_url = htmlspecialchars(isset($arr['directory_url']) ? $arr['directory_url'] : EMPTY_STR, ENT_COMPAT, 'UTF-8', false); + $url = htmlspecialchars(strtolower($arr['url']), ENT_COMPAT, 'UTF-8', false); + $sellpage = htmlspecialchars($arr['sellpage'], ENT_COMPAT, 'UTF-8', false); + $site_location = htmlspecialchars($arr['location'], ENT_COMPAT, 'UTF-8', false); + $site_realm = htmlspecialchars($arr['realm'], ENT_COMPAT, 'UTF-8', false); + $sitename = htmlspecialchars($arr['sitename'], ENT_COMPAT, 'UTF-8', false); + $site_project = htmlspecialchars($arr['project'], ENT_COMPAT, 'UTF-8', false); + $site_crypto = ((array_key_exists('encryption', $arr) && is_array($arr['encryption'])) ? htmlspecialchars(implode(',', $arr['encryption']), ENT_COMPAT, 'UTF-8', false) : ''); + $site_version = ((array_key_exists('version', $arr)) ? htmlspecialchars($arr['version'], ENT_COMPAT, 'UTF-8', false) : ''); + if (array_key_exists('about', $arr) && $arr['about']) { + $site_about = html2bbcode(purify_html($arr['about'])); + } + if (array_key_exists('logo', $arr) && $arr['logo']) { + $site_logo = $arr['logo']; + } elseif (file_exists('images/' . strtolower($site_project) . '.png')) { + $site_logo = z_root() . '/images/' . strtolower($site_project) . '.png'; + } else { + $site_logo = z_root() . '/images/default_profile_photos/red_koala_trans/300.png'; + } - if ($exists) { - if (($siterecord['site_flags'] != $site_flags) - || ($siterecord['site_access'] != $access_policy) - || ($siterecord['site_directory'] != $directory_url) - || ($siterecord['site_sellpage'] != $sellpage) - || ($siterecord['site_location'] != $site_location) - || ($siterecord['site_register'] != $register_policy) - || ($siterecord['site_project'] != $site_project) - || ($siterecord['site_realm'] != $site_realm) - || ($siterecord['site_crypto'] != $site_crypto) - || ($siterecord['site_version'] != $site_version) ) { + set_sconfig($url, 'system', 'about', $site_about); + set_sconfig($url, 'system', 'logo', $site_logo); + set_sconfig($url, 'system', 'sitename', $sitename); - $update = true; + $site_flags = $site_directory; - // logger('import_site: input: ' . print_r($arr,true)); - // logger('import_site: stored: ' . print_r($siterecord,true)); + if (array_key_exists('zot', $arr)) { + set_sconfig($arr['url'], 'system', 'zot_version', $arr['zot']); + } - $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s', site_crypto = '%s' + if ($exists) { + if (($siterecord['site_flags'] != $site_flags) + || ($siterecord['site_access'] != $access_policy) + || ($siterecord['site_directory'] != $directory_url) + || ($siterecord['site_sellpage'] != $sellpage) + || ($siterecord['site_location'] != $site_location) + || ($siterecord['site_register'] != $register_policy) + || ($siterecord['site_project'] != $site_project) + || ($siterecord['site_realm'] != $site_realm) + || ($siterecord['site_crypto'] != $site_crypto) + || ($siterecord['site_version'] != $site_version)) { + + $update = true; + + // logger('import_site: input: ' . print_r($arr,true)); + // logger('import_site: stored: ' . print_r($siterecord,true)); + + $r = q("update site set site_dead = 0, site_location = '%s', site_flags = %d, site_access = %d, site_directory = '%s', site_register = %d, site_update = '%s', site_sellpage = '%s', site_realm = '%s', site_type = %d, site_project = '%s', site_version = '%s', site_crypto = '%s' where site_url = '%s'", - dbesc($site_location), - intval($site_flags), - intval($access_policy), - dbesc($directory_url), - intval($register_policy), - dbesc(datetime_convert()), - dbesc($sellpage), - dbesc($site_realm), - intval(SITE_TYPE_ZOT), - dbesc($site_project), - dbesc($site_version), - dbesc($site_crypto), - dbesc($url) - ); - if (! $r) { - logger('Update failed. ' . print_r($arr,true)); - } - } - else { - // update the timestamp to indicate we communicated with this site - q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", - dbesc(datetime_convert()), - dbesc($url) - ); - } - } - else { - $update = true; + dbesc($site_location), + intval($site_flags), + intval($access_policy), + dbesc($directory_url), + intval($register_policy), + dbesc(datetime_convert()), + dbesc($sellpage), + dbesc($site_realm), + intval(SITE_TYPE_ZOT), + dbesc($site_project), + dbesc($site_version), + dbesc($site_crypto), + dbesc($url) + ); + if (!$r) { + logger('Update failed. ' . print_r($arr, true)); + } + } else { + // update the timestamp to indicate we communicated with this site + q("update site set site_dead = 0, site_update = '%s' where site_url = '%s'", + dbesc(datetime_convert()), + dbesc($url) + ); + } + } else { + $update = true; - $r = site_store_lowlevel( - [ - 'site_location' => $site_location, - 'site_url' => $url, - 'site_access' => intval($access_policy), - 'site_flags' => intval($site_flags), - 'site_update' => datetime_convert(), - 'site_directory' => $directory_url, - 'site_register' => intval($register_policy), - 'site_sellpage' => $sellpage, - 'site_realm' => $site_realm, - 'site_type' => intval(SITE_TYPE_ZOT), - 'site_project' => $site_project, - 'site_version' => $site_version, - 'site_crypto' => $site_crypto - ] - ); + $r = site_store_lowlevel( + [ + 'site_location' => $site_location, + 'site_url' => $url, + 'site_access' => intval($access_policy), + 'site_flags' => intval($site_flags), + 'site_update' => datetime_convert(), + 'site_directory' => $directory_url, + 'site_register' => intval($register_policy), + 'site_sellpage' => $sellpage, + 'site_realm' => $site_realm, + 'site_type' => intval(SITE_TYPE_ZOT), + 'site_project' => $site_project, + 'site_version' => $site_version, + 'site_crypto' => $site_crypto + ] + ); - if (! $r) { - logger('Record create failed. ' . print_r($arr,true)); - } - } + if (!$r) { + logger('Record create failed. ' . print_r($arr, true)); + } + } - return $update; - } + return $update; + } - /** - * @brief Returns path to /rpost - * - * @todo We probably should make rpost discoverable. - * - * @param array $observer - * * \e string \b xchan_url - * @return string - */ - static function get_rpost_path($observer) { - if (! $observer) { - return EMPTY_STR; - } + /** + * @brief Returns path to /rpost + * + * @param array $observer + * * \e string \b xchan_url + * @return string + * @todo We probably should make rpost discoverable. + * + */ + public static function get_rpost_path($observer) + { + if (!$observer) { + return EMPTY_STR; + } - $parsed = parse_url($observer['xchan_url']); + $parsed = parse_url($observer['xchan_url']); - return $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') . '/rpost?f='; - } + return $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') . '/rpost?f='; + } - /** - * @brief - * - * @param array $x - * @return boolean|string return false or a hash - */ + /** + * @brief + * + * @param array $x + * @return boolean|string return false or a hash + */ - static function import_author_zot($x) { + public static function import_author_zot($x) + { - // Check that we have both a hubloc and xchan record - as occasionally storage calls will fail and - // we may only end up with one; which results in posts with no author name or photo and are a bit - // of a hassle to repair. If either or both are missing, do a full discovery probe. + // Check that we have both a hubloc and xchan record - as occasionally storage calls will fail and + // we may only end up with one; which results in posts with no author name or photo and are a bit + // of a hassle to repair. If either or both are missing, do a full discovery probe. - if (! array_key_exists('id',$x)) { - return import_author_activitypub($x); - } + if (!array_key_exists('id', $x)) { + return import_author_activitypub($x); + } - $hash = self::make_xchan_hash($x['id'],$x['key']); + $hash = self::make_xchan_hash($x['id'], $x['key']); - $desturl = $x['url']; + $desturl = $x['url']; - $found_primary = false; + $found_primary = false; - $r1 = q("select hubloc_url, hubloc_updated, site_dead from hubloc left join site on + $r1 = q("select hubloc_url, hubloc_updated, site_dead from hubloc left join site on hubloc_url = site_url where hubloc_guid = '%s' and hubloc_guid_sig = '%s' and hubloc_primary = 1 limit 1", - dbesc($x['id']), - dbesc($x['id_sig']) - ); - if ($r1) { - $found_primary = true; - } + dbesc($x['id']), + dbesc($x['id_sig']) + ); + if ($r1) { + $found_primary = true; + } - $r2 = q("select xchan_hash from xchan where xchan_guid = '%s' and xchan_guid_sig = '%s' limit 1", - dbesc($x['id']), - dbesc($x['id_sig']) - ); + $r2 = q("select xchan_hash from xchan where xchan_guid = '%s' and xchan_guid_sig = '%s' limit 1", + dbesc($x['id']), + dbesc($x['id_sig']) + ); - $primary_dead = false; + $primary_dead = false; - if ($r1 && intval($r1[0]['site_dead'])) { - $primary_dead = true; - } + if ($r1 && intval($r1[0]['site_dead'])) { + $primary_dead = true; + } - // We have valid and somewhat fresh information. Always true if it is our own site. + // We have valid and somewhat fresh information. Always true if it is our own site. - if ($r1 && $r2 && ( $r1[0]['hubloc_updated'] > datetime_convert('UTC','UTC','now - 1 week') || $r1[0]['hubloc_url'] === z_root() ) ) { - logger('in cache', LOGGER_DEBUG); - return $hash; - } + if ($r1 && $r2 && ($r1[0]['hubloc_updated'] > datetime_convert('UTC', 'UTC', 'now - 1 week') || $r1[0]['hubloc_url'] === z_root())) { + logger('in cache', LOGGER_DEBUG); + return $hash; + } - logger('not in cache or cache stale - probing: ' . print_r($x,true), LOGGER_DEBUG,LOG_INFO); + logger('not in cache or cache stale - probing: ' . print_r($x, true), LOGGER_DEBUG, LOG_INFO); - // The primary hub may be dead. Try to find another one associated with this identity that is - // still alive. If we find one, use that url for the discovery/refresh probe. Otherwise, the dead site - // is all we have and there is no point probing it. Just return the hash indicating we have a - // cached entry and the identity is valid. It's just unreachable until they bring back their - // server from the grave or create another clone elsewhere. + // The primary hub may be dead. Try to find another one associated with this identity that is + // still alive. If we find one, use that url for the discovery/refresh probe. Otherwise, the dead site + // is all we have and there is no point probing it. Just return the hash indicating we have a + // cached entry and the identity is valid. It's just unreachable until they bring back their + // server from the grave or create another clone elsewhere. - if ($primary_dead || ! $found_primary) { - logger('dead or site - ignoring', LOGGER_DEBUG,LOG_INFO); + if ($primary_dead || !$found_primary) { + logger('dead or site - ignoring', LOGGER_DEBUG, LOG_INFO); - $r = q("select hubloc_id_url from hubloc left join site on hubloc_url = site_url + $r = q("select hubloc_id_url from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0", - dbesc($hash) - ); - if ($r) { - logger('found another site that is not dead: ' . $r[0]['hubloc_id_url'], LOGGER_DEBUG,LOG_INFO); - $desturl = $r[0]['hubloc_id_url']; - } - else { - return $hash; - } - } + dbesc($hash) + ); + if ($r) { + logger('found another site that is not dead: ' . $r[0]['hubloc_id_url'], LOGGER_DEBUG, LOG_INFO); + $desturl = $r[0]['hubloc_id_url']; + } else { + return $hash; + } + } - $them = [ 'hubloc_id_url' => $desturl ]; - if (self::refresh($them)) { - return $hash; - } + $them = ['hubloc_id_url' => $desturl]; + if (self::refresh($them)) { + return $hash; + } - return false; - } + return false; + } - static function zotinfo($arr) { + public static function zotinfo($arr) + { - $ret = []; + $ret = []; - $zhash = ((x($arr,'guid_hash')) ? $arr['guid_hash'] : ''); - $zguid = ((x($arr,'guid')) ? $arr['guid'] : ''); - $zguid_sig = ((x($arr,'guid_sig')) ? $arr['guid_sig'] : ''); - $zaddr = ((x($arr,'address')) ? $arr['address'] : ''); - $ztarget = ((x($arr,'target_url')) ? $arr['target_url'] : ''); - $zsig = ((x($arr,'target_sig')) ? $arr['target_sig'] : ''); - $zkey = ((x($arr,'key')) ? $arr['key'] : ''); - $mindate = ((x($arr,'mindate')) ? $arr['mindate'] : ''); - $token = ((x($arr,'token')) ? $arr['token'] : ''); - $feed = ((x($arr,'feed')) ? intval($arr['feed']) : 0); + $zhash = ((x($arr, 'guid_hash')) ? $arr['guid_hash'] : ''); + $zguid = ((x($arr, 'guid')) ? $arr['guid'] : ''); + $zguid_sig = ((x($arr, 'guid_sig')) ? $arr['guid_sig'] : ''); + $zaddr = ((x($arr, 'address')) ? $arr['address'] : ''); + $ztarget = ((x($arr, 'target_url')) ? $arr['target_url'] : ''); + $zsig = ((x($arr, 'target_sig')) ? $arr['target_sig'] : ''); + $zkey = ((x($arr, 'key')) ? $arr['key'] : ''); + $mindate = ((x($arr, 'mindate')) ? $arr['mindate'] : ''); + $token = ((x($arr, 'token')) ? $arr['token'] : ''); + $feed = ((x($arr, 'feed')) ? intval($arr['feed']) : 0); - if ($ztarget) { - $t = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($ztarget) - ); - if ($t) { - $ztarget_hash = $t[0]['hubloc_hash']; - } - else { - - // should probably perform discovery of the requestor (target) but if they actually had - // permissions we would know about them and we only want to know who they are to - // enumerate their specific permissions - - $ztarget_hash = EMPTY_STR; - } - } + if ($ztarget) { + $t = q("select * from hubloc where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($ztarget) + ); + if ($t) { + $ztarget_hash = $t[0]['hubloc_hash']; + } else { - $r = null; + // should probably perform discovery of the requestor (target) but if they actually had + // permissions we would know about them and we only want to know who they are to + // enumerate their specific permissions - if (strlen($zhash)) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + $ztarget_hash = EMPTY_STR; + } + } + + $r = null; + + if (strlen($zhash)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1", - dbesc($zhash) - ); - } - elseif (strlen($zguid) && strlen($zguid_sig)) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + dbesc($zhash) + ); + } elseif (strlen($zguid) && strlen($zguid_sig)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", - dbesc($zguid), - dbesc($zguid_sig) - ); - } - elseif (strlen($zaddr)) { - if (strpos($zaddr,'[system]') === false) { /* normal address lookup */ - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + dbesc($zguid), + dbesc($zguid_sig) + ); + } elseif (strlen($zaddr)) { + if (strpos($zaddr, '[system]') === false) { /* normal address lookup */ + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", - dbesc($zaddr), - dbesc($zaddr) - ); - } - else { + dbesc($zaddr), + dbesc($zaddr) + ); + } else { - /** - * The special address '[system]' will return a system channel if one has been defined, - * Or the first valid channel we find if there are no system channels. - * - * This is used by magic-auth if we have no prior communications with this site - and - * returns an identity on this site which we can use to create a valid hub record so that - * we can exchange signed messages. The precise identity is irrelevant. It's the hub - * information that we really need at the other end - and this will return it. - * - */ + /** + * The special address '[system]' will return a system channel if one has been defined, + * Or the first valid channel we find if there are no system channels. + * + * This is used by magic-auth if we have no prior communications with this site - and + * returns an identity on this site which we can use to create a valid hub record so that + * we can exchange signed messages. The precise identity is irrelevant. It's the hub + * information that we really need at the other end - and this will return it. + * + */ - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash where channel_system = 1 order by channel_id limit 1"); - if (! $r) { - $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + if (!$r) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash where channel_removed = 0 order by channel_id limit 1"); - } - } - } - else { - $ret['message'] = 'Invalid request'; - return($ret); - } + } + } + } else { + $ret['message'] = 'Invalid request'; + return ($ret); + } - if (! $r) { - $ret['message'] = 'Item not found.'; - return($ret); - } + if (!$r) { + $ret['message'] = 'Item not found.'; + return ($ret); + } - $e = $r[0]; + $e = $r[0]; - $id = $e['channel_id']; + $id = $e['channel_id']; - $sys_channel = (intval($e['channel_system']) ? true : false); - $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); - $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); - $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); - $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); - $deleted = (intval($e['xchan_deleted']) ? true : false); + $sys_channel = (intval($e['channel_system']) ? true : false); + $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); + $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); + $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); + $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $deleted = (intval($e['xchan_deleted']) ? true : false); - if ($deleted || $censored || $sys_channel) { - $searchable = false; - } + if ($deleted || $censored || $sys_channel) { + $searchable = false; + } - // now all forums (public, restricted, and private) set the public_forum flag. So it really means "is a group" - // and has nothing to do with accessibility. + // now all forums (public, restricted, and private) set the public_forum flag. So it really means "is a group" + // and has nothing to do with accessibility. - $role = get_pconfig($e['channel_id'],'system','permissions_role'); - $rolesettings = PermissionRoles::role_perms($role); + $role = get_pconfig($e['channel_id'], 'system', 'permissions_role'); + $rolesettings = PermissionRoles::role_perms($role); - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; + $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; - // This is for birthdays and keywords, but must check access permissions - $p = q("select * from profile where uid = %d and is_default = 1", - intval($e['channel_id']) - ); + // This is for birthdays and keywords, but must check access permissions + $p = q("select * from profile where uid = %d and is_default = 1", + intval($e['channel_id']) + ); - $profile = []; + $profile = []; - if ($p) { + if ($p) { - if (! intval($p[0]['publish'])) - $searchable = false; + if (!intval($p[0]['publish'])) + $searchable = false; - $profile['description'] = $p[0]['pdesc']; - $profile['birthday'] = $p[0]['dob']; - if (($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) { - $profile['next_birthday'] = $bd; - } + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if (($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'], $e['channel_timezone'])) !== '')) { + $profile['next_birthday'] = $bd; + } - if ($age = age($p[0]['dob'],$e['channel_timezone'],'')) { - $profile['age'] = $age; - } - $profile['gender'] = $p[0]['gender']; - $profile['marital'] = $p[0]['marital']; - $profile['sexual'] = $p[0]['sexual']; - $profile['locale'] = $p[0]['locality']; - $profile['region'] = $p[0]['region']; - $profile['postcode'] = $p[0]['postal_code']; - $profile['country'] = $p[0]['country_name']; - $profile['about'] = ((is_sys_channel($e['channel_id'])) ? get_config('system','siteinfo') : $p[0]['about']); - $profile['homepage'] = $p[0]['homepage']; - $profile['hometown'] = $p[0]['hometown']; + if ($age = age($p[0]['dob'], $e['channel_timezone'], '')) { + $profile['age'] = $age; + } + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = ((is_sys_channel($e['channel_id'])) ? get_config('system', 'siteinfo') : $p[0]['about']); + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; - if ($p[0]['keywords']) { - $tags = []; - $k = explode(' ',$p[0]['keywords']); - if ($k) { - foreach ($k as $kk) { - if (trim($kk," \t\n\r\0\x0B,")) { - $tags[] = trim($kk," \t\n\r\0\x0B,"); - } - } - } - if ($tags) { - $profile['keywords'] = $tags; - } - } - } + if ($p[0]['keywords']) { + $tags = []; + $k = explode(' ', $p[0]['keywords']); + if ($k) { + foreach ($k as $kk) { + if (trim($kk, " \t\n\r\0\x0B,")) { + $tags[] = trim($kk, " \t\n\r\0\x0B,"); + } + } + } + if ($tags) { + $profile['keywords'] = $tags; + } + } + } - $cover_photo = get_cover_photo($e['channel_id'],'array'); - - // Communication details + $cover_photo = get_cover_photo($e['channel_id'], 'array'); - $ret['id'] = $e['xchan_guid']; - $ret['id_sig'] = self::sign($e['xchan_guid'], $e['channel_prvkey']); + // Communication details - $ret['primary_location'] = [ - 'address' => $e['xchan_addr'], - 'url' => $e['xchan_url'], - 'connections_url' => $e['xchan_connurl'], - 'follow_url' => $e['xchan_follow'], - 'wall' => z_root() . '/outbox/' . $e['channel_address'], - 'followers' => z_root() . '/followers/' . $e['channel_address'], - 'following' => z_root() . '/following/' . $e['channel_address'] - ]; + $ret['id'] = $e['xchan_guid']; + $ret['id_sig'] = self::sign($e['xchan_guid'], $e['channel_prvkey']); - $ret['public_key'] = $e['xchan_pubkey']; - $ret['signing_algorithm'] = 'rsa-sha256'; - $ret['username'] = $e['channel_address']; - $ret['name'] = $e['xchan_name']; - $ret['name_updated'] = $e['xchan_name_date']; - $ret['photo'] = [ - 'url' => $e['xchan_photo_l'], - 'type' => $e['xchan_photo_mimetype'], - 'updated' => $e['xchan_photo_date'] - ]; + $ret['primary_location'] = [ + 'address' => $e['xchan_addr'], + 'url' => $e['xchan_url'], + 'connections_url' => $e['xchan_connurl'], + 'follow_url' => $e['xchan_follow'], + 'wall' => z_root() . '/outbox/' . $e['channel_address'], + 'followers' => z_root() . '/followers/' . $e['channel_address'], + 'following' => z_root() . '/following/' . $e['channel_address'] + ]; - if ($cover_photo) { - $ret['cover_photo'] = [ - 'url' => $cover_photo['url'], - 'type' => $cover_photo['type'], - 'updated' => $cover_photo['updated'] - ]; - } + $ret['public_key'] = $e['xchan_pubkey']; + $ret['signing_algorithm'] = 'rsa-sha256'; + $ret['username'] = $e['channel_address']; + $ret['name'] = $e['xchan_name']; + $ret['name_updated'] = $e['xchan_name_date']; + $ret['photo'] = [ + 'url' => $e['xchan_photo_l'], + 'type' => $e['xchan_photo_mimetype'], + 'updated' => $e['xchan_photo_date'] + ]; - $ret['channel_role'] = get_pconfig($e['channel_id'],'system','permissions_role','custom'); - $ret['channel_type'] = $channel_type; - $ret['protocols'] = [ 'zot6' ]; - if (get_pconfig($e['channel_id'],'system','activitypub',get_config('system','activitypub', ACTIVITYPUB_ENABLED))) { - $ret['protocols'][] = 'activitypub'; - } - $ret['searchable'] = $searchable; - $ret['adult_content'] = $adult_channel; - - $ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'],'post_comments')); + if ($cover_photo) { + $ret['cover_photo'] = [ + 'url' => $cover_photo['url'], + 'type' => $cover_photo['type'], + 'updated' => $cover_photo['updated'] + ]; + } - if ($deleted) { - $ret['deleted'] = $deleted; - } + $ret['channel_role'] = get_pconfig($e['channel_id'], 'system', 'permissions_role', 'custom'); + $ret['channel_type'] = $channel_type; + $ret['protocols'] = ['zot6']; + if (get_pconfig($e['channel_id'], 'system', 'activitypub', get_config('system', 'activitypub', ACTIVITYPUB_ENABLED))) { + $ret['protocols'][] = 'activitypub'; + } + $ret['searchable'] = $searchable; + $ret['adult_content'] = $adult_channel; - if (intval($e['channel_removed'])) { - $ret['deleted_locally'] = true; - } + $ret['comments'] = map_scope(PermissionLimits::Get($e['channel_id'], 'post_comments')); - // premium or other channel desiring some contact with potential followers before connecting. - // This is a template - %s will be replaced with the follow_url we discover for the return channel. + if ($deleted) { + $ret['deleted'] = $deleted; + } - if ($special_channel) { - $ret['connect_url'] = (($e['xchan_connpage']) ? $e['xchan_connpage'] : z_root() . '/connect/' . $e['channel_address']); - } + if (intval($e['channel_removed'])) { + $ret['deleted_locally'] = true; + } - // This is a template for our follow url, %s will be replaced with a webbie - if (! isset($ret['follow_url'])) { - $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; - } + // premium or other channel desiring some contact with potential followers before connecting. + // This is a template - %s will be replaced with the follow_url we discover for the return channel. - $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); + if ($special_channel) { + $ret['connect_url'] = (($e['xchan_connpage']) ? $e['xchan_connpage'] : z_root() . '/connect/' . $e['channel_address']); + } - if ($ztarget_hash) { - $permissions['connected'] = false; - $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($ztarget_hash), - intval($e['channel_id']) - ); - if ($b) { - $permissions['connected'] = true; - } - } + // This is a template for our follow url, %s will be replaced with a webbie + if (!isset($ret['follow_url'])) { + $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; + } - if ($permissions['view_profile']) { - $ret['profile'] = $profile; - } + $permissions = get_all_perms($e['channel_id'], $ztarget_hash, false); + + if ($ztarget_hash) { + $permissions['connected'] = false; + $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($ztarget_hash), + intval($e['channel_id']) + ); + if ($b) { + $permissions['connected'] = true; + } + } + + if ($permissions['view_profile']) { + $ret['profile'] = $profile; + } - $concise_perms = []; - if ($permissions) { - foreach ($permissions as $k => $v) { - if ($v) { - $concise_perms[] = $k; - } - } - $permissions = implode(',',$concise_perms); - } + $concise_perms = []; + if ($permissions) { + foreach ($permissions as $k => $v) { + if ($v) { + $concise_perms[] = $k; + } + } + $permissions = implode(',', $concise_perms); + } - $ret['permissions'] = $permissions; - $ret['permissions_for'] = $ztarget; + $ret['permissions'] = $permissions; + $ret['permissions_for'] = $ztarget; - // array of (verified) hubs this channel uses + // array of (verified) hubs this channel uses - $x = self::encode_locations($e); - if ($x) { - $ret['locations'] = $x; - } - $ret['site'] = self::site_info(); + $x = self::encode_locations($e); + if ($x) { + $ret['locations'] = $x; + } + $ret['site'] = self::site_info(); - call_hooks('zotinfo',$ret); + call_hooks('zotinfo', $ret); - return($ret); + return ($ret); - } + } - static function site_info($force = false) { + public static function site_info($force = false) + { - $signing_key = get_config('system','prvkey'); - $sig_method = get_config('system','signature_algorithm','sha256'); + $signing_key = get_config('system', 'prvkey'); + $sig_method = get_config('system', 'signature_algorithm', 'sha256'); - $ret = []; - $ret['site'] = []; - $ret['site']['url'] = z_root(); - $ret['site']['site_sig'] = self::sign(z_root(), $signing_key); - $ret['site']['post'] = z_root() . '/zot'; - $ret['site']['openWebAuth'] = z_root() . '/owa'; - $ret['site']['authRedirect'] = z_root() . '/magic'; - $ret['site']['sitekey'] = get_config('system','pubkey'); + $ret = []; + $ret['site'] = []; + $ret['site']['url'] = z_root(); + $ret['site']['site_sig'] = self::sign(z_root(), $signing_key); + $ret['site']['post'] = z_root() . '/zot'; + $ret['site']['openWebAuth'] = z_root() . '/owa'; + $ret['site']['authRedirect'] = z_root() . '/magic'; + $ret['site']['sitekey'] = get_config('system', 'pubkey'); - $dirmode = get_config('system','directory_mode'); - if (($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) { - $ret['site']['directory_mode'] = 'normal'; - } + $dirmode = get_config('system', 'directory_mode'); + if (($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) { + $ret['site']['directory_mode'] = 'normal'; + } - if ($dirmode == DIRECTORY_MODE_PRIMARY) { - $ret['site']['directory_mode'] = 'primary'; - } - elseif ($dirmode == DIRECTORY_MODE_SECONDARY) { - $ret['site']['directory_mode'] = 'secondary'; - } - elseif ($dirmode == DIRECTORY_MODE_STANDALONE) { - $ret['site']['directory_mode'] = 'standalone'; - } - if ($dirmode != DIRECTORY_MODE_NORMAL) { - $ret['site']['directory_url'] = z_root() . '/dirsearch'; - } + if ($dirmode == DIRECTORY_MODE_PRIMARY) { + $ret['site']['directory_mode'] = 'primary'; + } elseif ($dirmode == DIRECTORY_MODE_SECONDARY) { + $ret['site']['directory_mode'] = 'secondary'; + } elseif ($dirmode == DIRECTORY_MODE_STANDALONE) { + $ret['site']['directory_mode'] = 'standalone'; + } + if ($dirmode != DIRECTORY_MODE_NORMAL) { + $ret['site']['directory_url'] = z_root() . '/dirsearch'; + } - $ret['site']['encryption'] = Crypto::methods(); - $ret['site']['zot'] = System::get_zot_revision(); + $ret['site']['encryption'] = Crypto::methods(); + $ret['site']['zot'] = System::get_zot_revision(); - // hide detailed site information if you're off the grid + // hide detailed site information if you're off the grid - if ($dirmode != DIRECTORY_MODE_STANDALONE || $force) { + if ($dirmode != DIRECTORY_MODE_STANDALONE || $force) { - $register_policy = intval(get_config('system','register_policy')); - - if ($register_policy == REGISTER_CLOSED) { - $ret['site']['register_policy'] = 'closed'; - } - if ($register_policy == REGISTER_APPROVE) { - $ret['site']['register_policy'] = 'approve'; - } - if ($register_policy == REGISTER_OPEN) { - $ret['site']['register_policy'] = 'open'; - } + $register_policy = intval(get_config('system', 'register_policy')); - $access_policy = intval(get_config('system','access_policy')); + if ($register_policy == REGISTER_CLOSED) { + $ret['site']['register_policy'] = 'closed'; + } + if ($register_policy == REGISTER_APPROVE) { + $ret['site']['register_policy'] = 'approve'; + } + if ($register_policy == REGISTER_OPEN) { + $ret['site']['register_policy'] = 'open'; + } - if ($access_policy == ACCESS_PRIVATE) { - $ret['site']['access_policy'] = 'private'; - } - if ($access_policy == ACCESS_PAID) { - $ret['site']['access_policy'] = 'paid'; - } - if ($access_policy == ACCESS_FREE) { - $ret['site']['access_policy'] = 'free'; - } - if ($access_policy == ACCESS_TIERED) { - $ret['site']['access_policy'] = 'tiered'; - } + $access_policy = intval(get_config('system', 'access_policy')); - $ret['site']['admin'] = get_config('system','admin_email'); + if ($access_policy == ACCESS_PRIVATE) { + $ret['site']['access_policy'] = 'private'; + } + if ($access_policy == ACCESS_PAID) { + $ret['site']['access_policy'] = 'paid'; + } + if ($access_policy == ACCESS_FREE) { + $ret['site']['access_policy'] = 'free'; + } + if ($access_policy == ACCESS_TIERED) { + $ret['site']['access_policy'] = 'tiered'; + } - $visible_plugins = []; - if (is_array(App::$plugins) && count(App::$plugins)) { - $r = q("select * from addon where hidden = 0"); - if ($r) { - foreach ($r as $rr) { - $visible_plugins[] = $rr['aname']; - } - } - } - - $ret['site']['about'] = bbcode(get_config('system','siteinfo'), [ 'export' => true ]); - $ret['site']['plugins'] = $visible_plugins; - $ret['site']['sitehash'] = get_config('system','location_hash'); - $ret['site']['sellpage'] = get_config('system','sellpage'); - $ret['site']['location'] = get_config('system','site_location'); - $ret['site']['realm'] = get_directory_realm(); - $ret['site']['sitename'] = System::get_site_name(); - $ret['site']['logo'] = System::get_site_icon(); - $ret['site']['project'] = System::get_platform_name(); - $ret['site']['version'] = System::get_project_version(); - } + $ret['site']['admin'] = get_config('system', 'admin_email'); - return $ret['site']; + $visible_plugins = []; + if (is_array(App::$plugins) && count(App::$plugins)) { + $r = q("select * from addon where hidden = 0"); + if ($r) { + foreach ($r as $rr) { + $visible_plugins[] = $rr['aname']; + } + } + } - } + $ret['site']['about'] = bbcode(get_config('system', 'siteinfo'), ['export' => true]); + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system', 'location_hash'); + $ret['site']['sellpage'] = get_config('system', 'sellpage'); + $ret['site']['location'] = get_config('system', 'site_location'); + $ret['site']['realm'] = get_directory_realm(); + $ret['site']['sitename'] = System::get_site_name(); + $ret['site']['logo'] = System::get_site_icon(); + $ret['site']['project'] = System::get_platform_name(); + $ret['site']['version'] = System::get_project_version(); + } - /** - * @brief - * - * @param array $hub - * @param string $sitekey (optional, default empty) - * - * @return string hubloc_url - */ + return $ret['site']; - static function update_hub_connected($hub, $site_id = '') { + } - if ($site_id) { + /** + * @brief + * + * @param array $hub + * @param string $sitekey (optional, default empty) + * + * @return string hubloc_url + */ - /* + public static function update_hub_connected($hub, $site_id = '') + { + + if ($site_id) { + + /* * This hub has now been proven to be valid. * Any hub with the same URL and a different sitekey cannot be valid. * Get rid of them (mark them deleted). There's a good chance they were re-installs. */ - q("update hubloc set hubloc_deleted = 1, hubloc_error = 1 where hubloc_hash = '%s' and hubloc_url = '%s' and hubloc_site_id != '%s' ", - dbesc($hub['hubloc_hash']), - dbesc($hub['hubloc_url']), - dbesc($site_id) - ); + q("update hubloc set hubloc_deleted = 1, hubloc_error = 1 where hubloc_hash = '%s' and hubloc_url = '%s' and hubloc_site_id != '%s' ", + dbesc($hub['hubloc_hash']), + dbesc($hub['hubloc_url']), + dbesc($site_id) + ); - } - else { - $site_id = $hub['hubloc_site_id']; - } + } else { + $site_id = $hub['hubloc_site_id']; + } - // $sender['sitekey'] is a new addition to the protocol to distinguish - // hublocs coming from re-installed sites. Older sites will not provide - // this field and we have to still mark them valid, since we can't tell - // if this hubloc has the same sitekey as the packet we received. - // Update our DB to show when we last communicated successfully with this hub - // This will allow us to prune dead hubs from using up resources + // $sender['sitekey'] is a new addition to the protocol to distinguish + // hublocs coming from re-installed sites. Older sites will not provide + // this field and we have to still mark them valid, since we can't tell + // if this hubloc has the same sitekey as the packet we received. + // Update our DB to show when we last communicated successfully with this hub + // This will allow us to prune dead hubs from using up resources - $t = datetime_convert('UTC', 'UTC', 'now - 15 minutes'); + $t = datetime_convert('UTC', 'UTC', 'now - 15 minutes'); - $r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d and hubloc_site_id = '%s' and hubloc_connected < '%s' ", - dbesc(datetime_convert()), - intval($hub['hubloc_id']), - dbesc($site_id), - dbesc($t) - ); + $r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d and hubloc_site_id = '%s' and hubloc_connected < '%s' ", + dbesc(datetime_convert()), + intval($hub['hubloc_id']), + dbesc($site_id), + dbesc($t) + ); - // a dead hub came back to life - reset any tombstones we might have + // a dead hub came back to life - reset any tombstones we might have - if (intval($hub['hubloc_error']) || intval($hub['hubloc_deleted'])) { - q("update hubloc set hubloc_error = 0, hubloc_deleted = 0 where hubloc_id = %d and hubloc_site_id = '%s' ", - intval($hub['hubloc_id']), - dbesc($site_id) - ); - if (intval($hub['hubloc_orphancheck'])) { - q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d and hubloc_site_id = '%s' ", - intval($hub['hubloc_id']), - dbesc($site_id) - ); - } - q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", - dbesc($hub['hubloc_hash']) - ); - } + if (intval($hub['hubloc_error']) || intval($hub['hubloc_deleted'])) { + q("update hubloc set hubloc_error = 0, hubloc_deleted = 0 where hubloc_id = %d and hubloc_site_id = '%s' ", + intval($hub['hubloc_id']), + dbesc($site_id) + ); + if (intval($hub['hubloc_orphancheck'])) { + q("update hubloc set hubloc_orphancheck = 0 where hubloc_id = %d and hubloc_site_id = '%s' ", + intval($hub['hubloc_id']), + dbesc($site_id) + ); + } + q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", + dbesc($hub['hubloc_hash']) + ); + } - // this site obviously isn't dead because they are trying to communicate with us. - q("update site set site_dead = 0 where site_dead = 1 and site_url = '%s' ", - dbesc($hub['hubloc_url']) - ); + // this site obviously isn't dead because they are trying to communicate with us. + q("update site set site_dead = 0 where site_dead = 1 and site_url = '%s' ", + dbesc($hub['hubloc_url']) + ); - return $hub['hubloc_url']; - } + return $hub['hubloc_url']; + } - static function sign($data,$key,$alg = 'sha256') { - if (! $key) { - return 'no key'; - } - $sig = ''; - openssl_sign($data,$sig,$key,$alg); - return $alg . '.' . base64url_encode($sig); - } + public static function sign($data, $key, $alg = 'sha256') + { + if (!$key) { + return 'no key'; + } + $sig = ''; + openssl_sign($data, $sig, $key, $alg); + return $alg . '.' . base64url_encode($sig); + } - static function verify($data,$sig,$key) { + public static function verify($data, $sig, $key) + { - $verify = 0; + $verify = 0; - $x = explode('.',$sig,2); + $x = explode('.', $sig, 2); - if ($key && count($x) === 2) { - $alg = $x[0]; - $signature = base64url_decode($x[1]); - - $verify = @openssl_verify($data,$signature,$key,$alg); + if ($key && count($x) === 2) { + $alg = $x[0]; + $signature = base64url_decode($x[1]); - if ($verify === (-1)) { - while ($msg = openssl_error_string()) { - logger('openssl_verify: ' . $msg,LOGGER_NORMAL,LOG_ERR); - } - btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR); - } - } - return(($verify > 0) ? true : false); - } + $verify = @openssl_verify($data, $signature, $key, $alg); + + if ($verify === (-1)) { + while ($msg = openssl_error_string()) { + logger('openssl_verify: ' . $msg, LOGGER_NORMAL, LOG_ERR); + } + btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR); + } + } + return (($verify > 0) ? true : false); + } + public static function is_zot_request() + { - static function is_zot_request() { - - $x = getBestSupportedMimeType([ 'application/x-zot+json', 'application/x-nomad' ]); - return(($x) ? true : false); - } + $x = getBestSupportedMimeType(['application/x-zot+json', 'application/x-nomad']); + return (($x) ? true : false); + } - static public function zot_record_preferred($arr, $check = 'hubloc_network') { + public static function zot_record_preferred($arr, $check = 'hubloc_network') + { - if (! $arr) { - return $arr; - } + if (!$arr) { + return $arr; + } - foreach ($arr as $v) { - if($v[$check] === 'zot6') { - return $v; - } - } - return $arr[0]; - } + foreach ($arr as $v) { + if ($v[$check] === 'zot6') { + return $v; + } + } + return $arr[0]; + } - static function update_cached_hubloc($hubloc) { - if ($hubloc['hubloc_updated'] > datetime_convert('UTC','UTC','now - 1 week') || $hubloc['hubloc_url'] === z_root()) { - return; - } - self::refresh( [ 'hubloc_id_url' => $hubloc['hubloc_id_url'] ] ); - } + public static function update_cached_hubloc($hubloc) + { + if ($hubloc['hubloc_updated'] > datetime_convert('UTC', 'UTC', 'now - 1 week') || $hubloc['hubloc_url'] === z_root()) { + return; + } + self::refresh(['hubloc_id_url' => $hubloc['hubloc_id_url']]); + } } diff --git a/Zotlabs/Lib/Libzotdir.php b/Zotlabs/Lib/Libzotdir.php index 79cb8da86..e9d9eff8a 100644 --- a/Zotlabs/Lib/Libzotdir.php +++ b/Zotlabs/Lib/Libzotdir.php @@ -10,332 +10,336 @@ use Zotlabs\Lib\Zotfinger; require_once('include/permissions.php'); -class Libzotdir { +class Libzotdir +{ - /** - * Directories may come and go over time. We will need to check that our - * directory server is still valid occasionally, and reset to something that - * is if our directory has gone offline for any reason - */ + /** + * Directories may come and go over time. We will need to check that our + * directory server is still valid occasionally, and reset to something that + * is if our directory has gone offline for any reason + */ - static function check_upstream_directory() { + public static function check_upstream_directory() + { - $directory = get_config('system', 'directory_server'); + $directory = get_config('system', 'directory_server'); - // it's possible there is no directory server configured and the local hub is being used. - // If so, default to preserving the absence of a specific server setting. + // it's possible there is no directory server configured and the local hub is being used. + // If so, default to preserving the absence of a specific server setting. - $isadir = true; + $isadir = true; - if ($directory) { - $j = Zotfinger::exec($directory); - if (array_path_exists('data/directory_mode',$j)) { - if ($j['data']['directory_mode'] === 'normal') { - $isadir = false; - } - } - } + if ($directory) { + $j = Zotfinger::exec($directory); + if (array_path_exists('data/directory_mode', $j)) { + if ($j['data']['directory_mode'] === 'normal') { + $isadir = false; + } + } + } - if (! $isadir) - set_config('system', 'directory_server', ''); - } + if (!$isadir) + set_config('system', 'directory_server', ''); + } - static function get_directory_setting($observer, $setting) { + public static function get_directory_setting($observer, $setting) + { - if ($observer) - $ret = get_xconfig($observer, 'directory', $setting); - else - $ret = ((array_key_exists($setting,$_SESSION)) ? intval($_SESSION[$setting]) : false); + if ($observer) + $ret = get_xconfig($observer, 'directory', $setting); + else + $ret = ((array_key_exists($setting, $_SESSION)) ? intval($_SESSION[$setting]) : false); - if($ret === false) { - $ret = get_config('directory', $setting); - if($ret === false) { - $ret = (in_array($setting,[ 'globaldir','safemode', 'activedir' ]) ? 1 : 0); - } - } + if ($ret === false) { + $ret = get_config('directory', $setting); + if ($ret === false) { + $ret = (in_array($setting, ['globaldir', 'safemode', 'activedir']) ? 1 : 0); + } + } - if($setting === 'globaldir' && intval(get_config('system','localdir_hide'))) - $ret = 1; + if ($setting === 'globaldir' && intval(get_config('system', 'localdir_hide'))) + $ret = 1; - return $ret; - } + return $ret; + } - /** - * @brief Called by the directory_sort widget. - */ - static function dir_sort_links() { + /** + * @brief Called by the directory_sort widget. + */ + public static function dir_sort_links() + { - $safe_mode = 1; + $safe_mode = 1; - $observer = get_observer_hash(); + $observer = get_observer_hash(); - $safe_mode = self::get_directory_setting($observer, 'safemode'); - $globaldir = self::get_directory_setting($observer, 'globaldir'); - $pubforums = self::get_directory_setting($observer, 'chantype'); - $activedir = self::get_directory_setting($observer, 'activedir'); + $safe_mode = self::get_directory_setting($observer, 'safemode'); + $globaldir = self::get_directory_setting($observer, 'globaldir'); + $pubforums = self::get_directory_setting($observer, 'chantype'); + $activedir = self::get_directory_setting($observer, 'activedir'); - $hide_local = intval(get_config('system','localdir_hide')); - if ($hide_local) { - $globaldir = 1; - } + $hide_local = intval(get_config('system', 'localdir_hide')); + if ($hide_local) { + $globaldir = 1; + } - // Build urls without order and pubforums so it's easy to tack on the changed value - // Probably there's an easier way to do this + // Build urls without order and pubforums so it's easy to tack on the changed value + // Probably there's an easier way to do this - $directory_sort_order = get_config('system','directory_sort_order'); - if (! $directory_sort_order) { - $directory_sort_order = 'date'; - } + $directory_sort_order = get_config('system', 'directory_sort_order'); + if (!$directory_sort_order) { + $directory_sort_order = 'date'; + } - $current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order); - $suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : ''); + $current_order = (($_REQUEST['order']) ? $_REQUEST['order'] : $directory_sort_order); + $suggest = (($_REQUEST['suggest']) ? '&suggest=' . $_REQUEST['suggest'] : ''); - $url = 'directory?f='; + $url = 'directory?f='; - $tmp = array_merge($_GET,$_POST); - unset($tmp['suggest']); - unset($tmp['pubforums']); - unset($tmp['type']); - unset($tmp['global']); - unset($tmp['safe']); - unset($tmp['active']); - unset($tmp['req']); - unset($tmp['f']); - $q = http_build_query($tmp); - $forumsurl = $url . (($q) ? '&' . $q : '') . $suggest; + $tmp = array_merge($_GET, $_POST); + unset($tmp['suggest']); + unset($tmp['pubforums']); + unset($tmp['type']); + unset($tmp['global']); + unset($tmp['safe']); + unset($tmp['active']); + unset($tmp['req']); + unset($tmp['f']); + $q = http_build_query($tmp); + $forumsurl = $url . (($q) ? '&' . $q : '') . $suggest; - $o = replace_macros(get_markup_template('dir_sort_links.tpl'), [ - '$header' => t('Directory Options'), - '$forumsurl' => $forumsurl, - '$safemode' => array('safemode', t('Safe Mode'),$safe_mode,'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&safe="+(this.checked ? 1 : 0)\''), - '$pubforums' => array('pubforums', t('Groups Only'),(($pubforums == 1) ? true : false),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 1 : 0)\''), + $o = replace_macros(get_markup_template('dir_sort_links.tpl'), [ + '$header' => t('Directory Options'), + '$forumsurl' => $forumsurl, + '$safemode' => array('safemode', t('Safe Mode'), $safe_mode, '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&safe="+(this.checked ? 1 : 0)\''), + '$pubforums' => array('pubforums', t('Groups Only'), (($pubforums == 1) ? true : false), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 1 : 0)\''), // '$collections' => array('collections', t('Collections Only'),(($pubforums == 2) ? true : false),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 2 : 0)\''), - '$hide_local' => $hide_local, - '$globaldir' => array('globaldir', t('This Website Only'), 1-intval($globaldir),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&global="+(this.checked ? 0 : 1)\''), - '$activedir' => array('activedir', t('Recently Updated'), intval($activedir),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&active="+(this.checked ? 1 : 0)\''), - ]); + '$hide_local' => $hide_local, + '$globaldir' => array('globaldir', t('This Website Only'), 1 - intval($globaldir), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&global="+(this.checked ? 0 : 1)\''), + '$activedir' => array('activedir', t('Recently Updated'), intval($activedir), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&active="+(this.checked ? 1 : 0)\''), + ]); - return $o; - } + return $o; + } - /** - * @brief - * - * Given an update record, probe the channel, grab a zot-info packet and refresh/sync the data. - * - * Ignore updating records marked as deleted. - * - * If successful, sets ud_last in the DB to the current datetime for this - * reddress/webbie. - * - * @param array $ud Entry from update table - */ + /** + * @brief + * + * Given an update record, probe the channel, grab a zot-info packet and refresh/sync the data. + * + * Ignore updating records marked as deleted. + * + * If successful, sets ud_last in the DB to the current datetime for this + * reddress/webbie. + * + * @param array $ud Entry from update table + */ - static function update_directory_entry($ud) { + public static function update_directory_entry($ud) + { - logger('update_directory_entry: ' . print_r($ud,true), LOGGER_DATA); + logger('update_directory_entry: ' . print_r($ud, true), LOGGER_DATA); - if ($ud['ud_addr'] && (! ($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) { - $success = false; + if ($ud['ud_addr'] && (!($ud['ud_flags'] & UPDATE_FLAGS_DELETED))) { + $success = false; - $href = Webfinger::zot_url(punify($ud['ud_addr'])); - if($href) { - $zf = Zotfinger::exec($href); - } - if(is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { - $xc = Libzot::import_xchan($zf['data'], 0, $ud); - } - else { - q("update updates set ud_last = '%s' where ud_addr = '%s'", - dbesc(datetime_convert()), - dbesc($ud['ud_addr']) - ); - } - } - } + $href = Webfinger::zot_url(punify($ud['ud_addr'])); + if ($href) { + $zf = Zotfinger::exec($href); + } + if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { + $xc = Libzot::import_xchan($zf['data'], 0, $ud); + } else { + q("update updates set ud_last = '%s' where ud_addr = '%s'", + dbesc(datetime_convert()), + dbesc($ud['ud_addr']) + ); + } + } + } - /** - * @brief Push local channel updates to a local directory server. - * - * This is called from Zotlabs/Daemon/Directory.php if a profile is to be pushed to the - * directory and the local hub in this case is any kind of directory server. - * - * @param int $uid - * @param boolean $force - */ + /** + * @brief Push local channel updates to a local directory server. + * + * This is called from Zotlabs/Daemon/Directory.php if a profile is to be pushed to the + * directory and the local hub in this case is any kind of directory server. + * + * @param int $uid + * @param bool $force + */ - static function local_dir_update($uid, $force) { - - - logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG); - - $p = q("select channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", - intval($uid) - ); - - $profile = []; - $profile['encoding'] = 'zot'; - - if ($p) { - $hash = $p[0]['channel_hash']; - - $profile['description'] = $p[0]['pdesc']; - $profile['birthday'] = $p[0]['dob']; - if ($age = age($p[0]['dob'],$p[0]['channel_timezone'],'')) - $profile['age'] = $age; - - $profile['gender'] = $p[0]['gender']; - $profile['marital'] = $p[0]['marital']; - $profile['sexual'] = $p[0]['sexual']; - $profile['locale'] = $p[0]['locality']; - $profile['region'] = $p[0]['region']; - $profile['postcode'] = $p[0]['postal_code']; - $profile['country'] = $p[0]['country_name']; - $profile['about'] = $p[0]['about']; - $profile['homepage'] = $p[0]['homepage']; - $profile['hometown'] = $p[0]['hometown']; - - if ($p[0]['keywords']) { - $tags = []; - $k = explode(' ', $p[0]['keywords']); - if ($k) - foreach ($k as $kk) - if (trim($kk)) - $tags[] = trim($kk); - - if ($tags) - $profile['keywords'] = $tags; - } - - $hidden = (1 - intval($p[0]['publish'])); - - // logger('hidden: ' . $hidden); - - $r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1", - dbesc($p[0]['channel_hash']) - ); - - if(intval($r[0]['xchan_hidden']) != $hidden) { - $r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'", - intval($hidden), - dbesc($p[0]['channel_hash']) - ); - } - - $arr = [ 'channel_id' => $uid, 'hash' => $hash, 'profile' => $profile ]; - call_hooks('local_dir_update', $arr); - - $address = channel_reddress($p[0]); - - if (perm_is_allowed($uid, '', 'view_profile')) { - self::import_directory_profile($hash, $arr['profile'], $address, 0); - } - else { - // they may have made it private - $r = q("delete from xprof where xprof_hash = '%s'", - dbesc($hash) - ); - $r = q("delete from xtag where xtag_hash = '%s'", - dbesc($hash) - ); - } - - } - - $ud_hash = random_string() . '@' . App::get_hostname(); - self::update_modtime($hash, $ud_hash, channel_reddress($p[0]),(($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); - } + public static function local_dir_update($uid, $force) + { + logger('local_dir_update: uid: ' . $uid, LOGGER_DEBUG); - /** - * @brief Imports a directory profile. - * - * @param string $hash - * @param array $profile - * @param string $addr - * @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED - * @param number $suppress_update (optional) default 0 - * @return boolean $updated if something changed - */ + $p = q("select channel_hash, channel_address, channel_timezone, profile.* from profile left join channel on channel_id = uid where uid = %d and is_default = 1", + intval($uid) + ); - static function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) { + $profile = []; + $profile['encoding'] = 'zot'; - logger('import_directory_profile', LOGGER_DEBUG); - if (! $hash) - return false; + if ($p) { + $hash = $p[0]['channel_hash']; + + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if ($age = age($p[0]['dob'], $p[0]['channel_timezone'], '')) + $profile['age'] = $age; + + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; + + if ($p[0]['keywords']) { + $tags = []; + $k = explode(' ', $p[0]['keywords']); + if ($k) + foreach ($k as $kk) + if (trim($kk)) + $tags[] = trim($kk); + + if ($tags) + $profile['keywords'] = $tags; + } + + $hidden = (1 - intval($p[0]['publish'])); + + // logger('hidden: ' . $hidden); + + $r = q("select xchan_hidden from xchan where xchan_hash = '%s' limit 1", + dbesc($p[0]['channel_hash']) + ); + + if (intval($r[0]['xchan_hidden']) != $hidden) { + $r = q("update xchan set xchan_hidden = %d where xchan_hash = '%s'", + intval($hidden), + dbesc($p[0]['channel_hash']) + ); + } + + $arr = ['channel_id' => $uid, 'hash' => $hash, 'profile' => $profile]; + call_hooks('local_dir_update', $arr); + + $address = channel_reddress($p[0]); + + if (perm_is_allowed($uid, '', 'view_profile')) { + self::import_directory_profile($hash, $arr['profile'], $address, 0); + } else { + // they may have made it private + $r = q("delete from xprof where xprof_hash = '%s'", + dbesc($hash) + ); + $r = q("delete from xtag where xtag_hash = '%s'", + dbesc($hash) + ); + } + + } + + $ud_hash = random_string() . '@' . App::get_hostname(); + self::update_modtime($hash, $ud_hash, channel_reddress($p[0]), (($force) ? UPDATE_FLAGS_FORCED : UPDATE_FLAGS_UPDATED)); + } - $maxlen = get_max_import_size(); + /** + * @brief Imports a directory profile. + * + * @param string $hash + * @param array $profile + * @param string $addr + * @param number $ud_flags (optional) UPDATE_FLAGS_UPDATED + * @param number $suppress_update (optional) default 0 + * @return bool $updated if something changed + */ - if($maxlen && mb_strlen($profile['about']) > $maxlen) { - $profile['about'] = mb_substr($profile['about'],0,$maxlen,'UTF-8'); - } + public static function import_directory_profile($hash, $profile, $addr, $ud_flags = UPDATE_FLAGS_UPDATED, $suppress_update = 0) + { - $arr = []; - - $arr['xprof_hash'] = $hash; - $arr['xprof_dob'] = ((isset($profile['birthday']) && $profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('','',$profile['birthday'],'Y-m-d')); // !!!! check this for 0000 year - $arr['xprof_age'] = (isset($profile['age']) ? intval($profile['age']) : 0); - $arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_marital'] = ((isset($profile['marital']) && $profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_sexual'] = ((isset($profile['sexual']) && $profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_locale'] = ((isset($profile['locale']) && $profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_region'] = ((isset($profile['region']) && $profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_postcode'] = ((isset($profile['postcode']) && $profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_country'] = ((isset($profile['country']) && $profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_about'] = ((isset($profile['about']) && $profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_pronouns'] = ((isset($profile['pronouns']) && $profile['pronouns']) ? htmlspecialchars($profile['pronouns'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_homepage'] = ((isset($profile['homepage']) && $profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['xprof_hometown'] = ((isset($profile['hometown']) && $profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT,'UTF-8',false) : ''); - - $clean = []; - if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) { - self::import_directory_keywords($hash,$profile['keywords']); - foreach ($profile['keywords'] as $kw) { - $kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false)); - $kw = trim($kw, ','); - $clean[] = $kw; - } - } - - $arr['xprof_keywords'] = implode(' ',$clean); - - // Self censored, make it so - // These are not translated, so the German "erwachsenen" keyword will not censor the directory profile. Only the English form - "adult". + logger('import_directory_profile', LOGGER_DEBUG); + if (!$hash) + return false; - if(in_arrayi('nsfw',$clean) || in_arrayi('adult',$clean)) { - q("update xchan set xchan_selfcensored = 1 where xchan_hash = '%s'", - dbesc($hash) - ); - } + $maxlen = get_max_import_size(); - $r = q("select * from xprof where xprof_hash = '%s' limit 1", - dbesc($hash) - ); + if ($maxlen && mb_strlen($profile['about']) > $maxlen) { + $profile['about'] = mb_substr($profile['about'], 0, $maxlen, 'UTF-8'); + } - if ($arr['xprof_age'] > 150) - $arr['xprof_age'] = 150; - if ($arr['xprof_age'] < 0) - $arr['xprof_age'] = 0; + $arr = []; - if ($r) { - $update = false; - foreach ($r[0] as $k => $v) { - if ((array_key_exists($k,$arr)) && ($arr[$k] != $v)) { - logger('import_directory_profile: update ' . $k . ' => ' . $arr[$k]); - $update = true; - break; - } - } - if ($update) { - q("update xprof set + $arr['xprof_hash'] = $hash; + $arr['xprof_dob'] = ((isset($profile['birthday']) && $profile['birthday'] === '0000-00-00') ? $profile['birthday'] : datetime_convert('', '', $profile['birthday'], 'Y-m-d')); // !!!! check this for 0000 year + $arr['xprof_age'] = (isset($profile['age']) ? intval($profile['age']) : 0); + $arr['xprof_desc'] = ((isset($profile['description']) && $profile['description']) ? htmlspecialchars($profile['description'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_gender'] = ((isset($profile['gender']) && $profile['gender']) ? htmlspecialchars($profile['gender'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_marital'] = ((isset($profile['marital']) && $profile['marital']) ? htmlspecialchars($profile['marital'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_sexual'] = ((isset($profile['sexual']) && $profile['sexual']) ? htmlspecialchars($profile['sexual'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_locale'] = ((isset($profile['locale']) && $profile['locale']) ? htmlspecialchars($profile['locale'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_region'] = ((isset($profile['region']) && $profile['region']) ? htmlspecialchars($profile['region'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_postcode'] = ((isset($profile['postcode']) && $profile['postcode']) ? htmlspecialchars($profile['postcode'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_country'] = ((isset($profile['country']) && $profile['country']) ? htmlspecialchars($profile['country'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_about'] = ((isset($profile['about']) && $profile['about']) ? htmlspecialchars($profile['about'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_pronouns'] = ((isset($profile['pronouns']) && $profile['pronouns']) ? htmlspecialchars($profile['pronouns'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_homepage'] = ((isset($profile['homepage']) && $profile['homepage']) ? htmlspecialchars($profile['homepage'], ENT_COMPAT, 'UTF-8', false) : ''); + $arr['xprof_hometown'] = ((isset($profile['hometown']) && $profile['hometown']) ? htmlspecialchars($profile['hometown'], ENT_COMPAT, 'UTF-8', false) : ''); + + $clean = []; + if (array_key_exists('keywords', $profile) and is_array($profile['keywords'])) { + self::import_directory_keywords($hash, $profile['keywords']); + foreach ($profile['keywords'] as $kw) { + $kw = trim(htmlspecialchars($kw, ENT_COMPAT, 'UTF-8', false)); + $kw = trim($kw, ','); + $clean[] = $kw; + } + } + + $arr['xprof_keywords'] = implode(' ', $clean); + + // Self censored, make it so + // These are not translated, so the German "erwachsenen" keyword will not censor the directory profile. Only the English form - "adult". + + + if (in_arrayi('nsfw', $clean) || in_arrayi('adult', $clean)) { + q("update xchan set xchan_selfcensored = 1 where xchan_hash = '%s'", + dbesc($hash) + ); + } + + $r = q("select * from xprof where xprof_hash = '%s' limit 1", + dbesc($hash) + ); + + if ($arr['xprof_age'] > 150) + $arr['xprof_age'] = 150; + if ($arr['xprof_age'] < 0) + $arr['xprof_age'] = 0; + + if ($r) { + $update = false; + foreach ($r[0] as $k => $v) { + if ((array_key_exists($k, $arr)) && ($arr[$k] != $v)) { + logger('import_directory_profile: update ' . $k . ' => ' . $arr[$k]); + $update = true; + break; + } + } + if ($update) { + q("update xprof set xprof_desc = '%s', xprof_dob = '%s', xprof_age = %d, @@ -352,156 +356,153 @@ class Libzotdir { xprof_keywords = '%s', xprof_pronouns = '%s' where xprof_hash = '%s'", - dbesc($arr['xprof_desc']), - dbesc($arr['xprof_dob']), - intval($arr['xprof_age']), - dbesc($arr['xprof_gender']), - dbesc($arr['xprof_marital']), - dbesc($arr['xprof_sexual']), - dbesc($arr['xprof_locale']), - dbesc($arr['xprof_region']), - dbesc($arr['xprof_postcode']), - dbesc($arr['xprof_country']), - dbesc($arr['xprof_about']), - dbesc($arr['xprof_homepage']), - dbesc($arr['xprof_hometown']), - dbesc($arr['xprof_keywords']), - dbesc($arr['xprof_pronouns']), - dbesc($arr['xprof_hash']) - ); - } - } else { - $update = true; - logger('New profile'); - q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_about, xprof_homepage, xprof_hometown, xprof_keywords, xprof_pronouns) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", - dbesc($arr['xprof_hash']), - dbesc($arr['xprof_desc']), - dbesc($arr['xprof_dob']), - intval($arr['xprof_age']), - dbesc($arr['xprof_gender']), - dbesc($arr['xprof_marital']), - dbesc($arr['xprof_sexual']), - dbesc($arr['xprof_locale']), - dbesc($arr['xprof_region']), - dbesc($arr['xprof_postcode']), - dbesc($arr['xprof_country']), - dbesc($arr['xprof_about']), - dbesc($arr['xprof_homepage']), - dbesc($arr['xprof_hometown']), - dbesc($arr['xprof_keywords']), - dbesc($arr['xprof_pronouns']) - ); - } + dbesc($arr['xprof_desc']), + dbesc($arr['xprof_dob']), + intval($arr['xprof_age']), + dbesc($arr['xprof_gender']), + dbesc($arr['xprof_marital']), + dbesc($arr['xprof_sexual']), + dbesc($arr['xprof_locale']), + dbesc($arr['xprof_region']), + dbesc($arr['xprof_postcode']), + dbesc($arr['xprof_country']), + dbesc($arr['xprof_about']), + dbesc($arr['xprof_homepage']), + dbesc($arr['xprof_hometown']), + dbesc($arr['xprof_keywords']), + dbesc($arr['xprof_pronouns']), + dbesc($arr['xprof_hash']) + ); + } + } else { + $update = true; + logger('New profile'); + q("insert into xprof (xprof_hash, xprof_desc, xprof_dob, xprof_age, xprof_gender, xprof_marital, xprof_sexual, xprof_locale, xprof_region, xprof_postcode, xprof_country, xprof_about, xprof_homepage, xprof_hometown, xprof_keywords, xprof_pronouns) values ('%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", + dbesc($arr['xprof_hash']), + dbesc($arr['xprof_desc']), + dbesc($arr['xprof_dob']), + intval($arr['xprof_age']), + dbesc($arr['xprof_gender']), + dbesc($arr['xprof_marital']), + dbesc($arr['xprof_sexual']), + dbesc($arr['xprof_locale']), + dbesc($arr['xprof_region']), + dbesc($arr['xprof_postcode']), + dbesc($arr['xprof_country']), + dbesc($arr['xprof_about']), + dbesc($arr['xprof_homepage']), + dbesc($arr['xprof_hometown']), + dbesc($arr['xprof_keywords']), + dbesc($arr['xprof_pronouns']) + ); + } - $d = [ - 'xprof' => $arr, - 'profile' => $profile, - 'update' => $update - ]; + $d = [ + 'xprof' => $arr, + 'profile' => $profile, + 'update' => $update + ]; - /** - * @hooks import_directory_profile - * Called when processing delivery of a profile structure from an external source (usually for directory storage). - * * \e array \b xprof - * * \e array \b profile - * * \e boolean \b update - */ + /** + * @hooks import_directory_profile + * Called when processing delivery of a profile structure from an external source (usually for directory storage). + * * \e array \b xprof + * * \e array \b profile + * * \e boolean \b update + */ - call_hooks('import_directory_profile', $d); + call_hooks('import_directory_profile', $d); - if (($d['update']) && (! $suppress_update)) { - self::update_modtime($arr['xprof_hash'], new_uuid(), $addr, $ud_flags); - } + if (($d['update']) && (!$suppress_update)) { + self::update_modtime($arr['xprof_hash'], new_uuid(), $addr, $ud_flags); + } - q("update xchan set xchan_updated = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc($arr['xprof_hash']) - ); + q("update xchan set xchan_updated = '%s' where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($arr['xprof_hash']) + ); - return $d['update']; - } + return $d['update']; + } - /** - * @brief - * - * @param string $hash An xtag_hash - * @param array $keywords - */ + /** + * @brief + * + * @param string $hash An xtag_hash + * @param array $keywords + */ - static function import_directory_keywords($hash, $keywords) { + public static function import_directory_keywords($hash, $keywords) + { - $existing = []; - $r = q("select * from xtag where xtag_hash = '%s' and xtag_flags = 0", - dbesc($hash) - ); + $existing = []; + $r = q("select * from xtag where xtag_hash = '%s' and xtag_flags = 0", + dbesc($hash) + ); - if($r) { - foreach($r as $rr) - $existing[] = $rr['xtag_term']; - } + if ($r) { + foreach ($r as $rr) + $existing[] = $rr['xtag_term']; + } - $clean = []; - foreach($keywords as $kw) { - $kw = trim(htmlspecialchars($kw,ENT_COMPAT, 'UTF-8', false)); - $kw = trim($kw, ','); - $clean[] = $kw; - } + $clean = []; + foreach ($keywords as $kw) { + $kw = trim(htmlspecialchars($kw, ENT_COMPAT, 'UTF-8', false)); + $kw = trim($kw, ','); + $clean[] = $kw; + } - foreach($existing as $x) { - if(! in_array($x, $clean)) - $r = q("delete from xtag where xtag_hash = '%s' and xtag_term = '%s' and xtag_flags = 0", - dbesc($hash), - dbesc($x) - ); - } - foreach($clean as $x) { - if(! in_array($x, $existing)) { - $r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', 0 )", - dbesc($hash), - dbesc($x) - ); - } - } - } + foreach ($existing as $x) { + if (!in_array($x, $clean)) + $r = q("delete from xtag where xtag_hash = '%s' and xtag_term = '%s' and xtag_flags = 0", + dbesc($hash), + dbesc($x) + ); + } + foreach ($clean as $x) { + if (!in_array($x, $existing)) { + $r = q("insert into xtag ( xtag_hash, xtag_term, xtag_flags) values ( '%s' ,'%s', 0 )", + dbesc($hash), + dbesc($x) + ); + } + } + } - /** - * @brief - * - * @param string $hash - * @param string $guid - * @param string $addr - * @param int $flags (optional) default 0 - */ - - static function update_modtime($hash, $guid, $addr, $flags = 0) { - - $dirmode = intval(get_config('system', 'directory_mode')); - - if($dirmode == DIRECTORY_MODE_NORMAL) - return; - - if($flags) { - q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )", - dbesc($hash), - dbesc($guid), - dbesc(datetime_convert()), - intval($flags), - dbesc($addr) - ); - } - else { - q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and (ud_flags & %d) = 0 ", - intval(UPDATE_FLAGS_UPDATED), - dbesc($addr), - intval(UPDATE_FLAGS_UPDATED) - ); - } - } + /** + * @brief + * + * @param string $hash + * @param string $guid + * @param string $addr + * @param int $flags (optional) default 0 + */ + public static function update_modtime($hash, $guid, $addr, $flags = 0) + { + $dirmode = intval(get_config('system', 'directory_mode')); + if ($dirmode == DIRECTORY_MODE_NORMAL) + return; + if ($flags) { + q("insert into updates (ud_hash, ud_guid, ud_date, ud_flags, ud_addr ) values ( '%s', '%s', '%s', %d, '%s' )", + dbesc($hash), + dbesc($guid), + dbesc(datetime_convert()), + intval($flags), + dbesc($addr) + ); + } else { + q("update updates set ud_flags = ( ud_flags | %d ) where ud_addr = '%s' and (ud_flags & %d) = 0 ", + intval(UPDATE_FLAGS_UPDATED), + dbesc($addr), + intval(UPDATE_FLAGS_UPDATED) + ); + } + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Markdown.php b/Zotlabs/Lib/Markdown.php index 03ff41bd5..6aae98a66 100644 --- a/Zotlabs/Lib/Markdown.php +++ b/Zotlabs/Lib/Markdown.php @@ -18,308 +18,314 @@ require_once("include/html2bbcode.php"); require_once("include/bbcode.php"); -class Markdown { - - /** - * @brief Convert Markdown to bbcode. - * - * We don't want to support a bbcode specific markdown interpreter - * and the markdown library we have is pretty good, but provides HTML output. - * So we'll use that to convert to HTML, then convert the HTML back to bbcode, - * and then clean up a few Diaspora specific constructs. - * - * @param string $s The message as Markdown - * @param boolean $use_zrl default false - * @param array $options default empty - * @return string The message converted to bbcode - */ - - static public function to_bbcode($s, $use_zrl = false, $options = []) { - - if(is_array($s)) { - btlogger('markdown_to_bb called with array. ' . print_r($s, true), LOGGER_NORMAL, LOG_WARNING); - return ''; - } - - $s = str_replace(" ","\r",$s); - $s = str_replace(" \n>","",$s); - - $s = html_entity_decode($s,ENT_COMPAT,'UTF-8'); - - // if empty link text replace with the url - $s = preg_replace("/\[\]\((.*?)\)/ism",'[$1]($1)',$s); - - $x = [ - 'text' => $s, - 'zrl' => $use_zrl, - 'options' => $options - ]; - - /** - * @hooks markdown_to_bb_init - * * \e string \b text - The message as Markdown and what will get returned - * * \e boolean \b zrl - * * \e array \b options - */ - call_hooks('markdown_to_bb_init', $x); - - $s = $x['text']; - - // Escaping the hash tags - $s = preg_replace('/\#([^\s\#])/','#$1',$s); - - $s = MarkdownExtra::defaultTransform($s); - - if($options && $options['preserve_lf']) { - $s = str_replace(["\r","\n"],["",'
'],$s); - } - else { - $s = str_replace("\r","",$s); - } - - $s = str_replace('#','#',$s); - - $s = html2bbcode($s); - - // Convert everything that looks like a link to a link - if($use_zrl) { - if (strpos($s,'[/img]') !== false) { - $s = preg_replace_callback("/\[img\](.*?)\[\/img\]/ism", [ '\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img'], $s); - $s = preg_replace_callback("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", [ '\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img_x' ], $s); - } - $s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", [ '\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_link'] ,$s); - } - else { - $s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]',$s); - } - - // remove duplicate adjacent code tags - $s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism","[code]$2[/code]", $s); - - /** - * @hooks markdown_to_bb - * * \e string - The already converted message as bbcode - */ - call_hooks('markdown_to_bb', $s); - - return $s; - } - - static function use_zrl_cb_link($match) { - $res = ''; - $is_zid = is_matrix_url(trim($match[0])); - - if($is_zid) - $res = $match[1] . '[zrl=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/zrl]'; - else - $res = $match[1] . '[url=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/url]'; - - return $res; - } - - static function use_zrl_cb_img($match) { - $res = ''; - $is_zid = is_matrix_url(trim($match[1])); - - if($is_zid) - $res = '[zmg]' . $match[1] . '[/zmg]'; - else - $res = $match[0]; - - return $res; - } - - static function use_zrl_cb_img_x($match) { - $res = ''; - $is_zid = is_matrix_url(trim($match[3])); +class Markdown +{ + + /** + * @brief Convert Markdown to bbcode. + * + * We don't want to support a bbcode specific markdown interpreter + * and the markdown library we have is pretty good, but provides HTML output. + * So we'll use that to convert to HTML, then convert the HTML back to bbcode, + * and then clean up a few Diaspora specific constructs. + * + * @param string $s The message as Markdown + * @param bool $use_zrl default false + * @param array $options default empty + * @return string The message converted to bbcode + */ + + public static function to_bbcode($s, $use_zrl = false, $options = []) + { + + if (is_array($s)) { + btlogger('markdown_to_bb called with array. ' . print_r($s, true), LOGGER_NORMAL, LOG_WARNING); + return ''; + } + + $s = str_replace(" ", "\r", $s); + $s = str_replace(" \n>", "", $s); + + $s = html_entity_decode($s, ENT_COMPAT, 'UTF-8'); + + // if empty link text replace with the url + $s = preg_replace("/\[\]\((.*?)\)/ism", '[$1]($1)', $s); + + $x = [ + 'text' => $s, + 'zrl' => $use_zrl, + 'options' => $options + ]; + + /** + * @hooks markdown_to_bb_init + * * \e string \b text - The message as Markdown and what will get returned + * * \e boolean \b zrl + * * \e array \b options + */ + call_hooks('markdown_to_bb_init', $x); + + $s = $x['text']; + + // Escaping the hash tags + $s = preg_replace('/\#([^\s\#])/', '#$1', $s); + + $s = MarkdownExtra::defaultTransform($s); + + if ($options && $options['preserve_lf']) { + $s = str_replace(["\r", "\n"], ["", '
'], $s); + } else { + $s = str_replace("\r", "", $s); + } + + $s = str_replace('#', '#', $s); + + $s = html2bbcode($s); + + // Convert everything that looks like a link to a link + if ($use_zrl) { + if (strpos($s, '[/img]') !== false) { + $s = preg_replace_callback("/\[img\](.*?)\[\/img\]/ism", ['\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img'], $s); + $s = preg_replace_callback("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", ['\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_img_x'], $s); + } + $s = preg_replace_callback("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", ['\\Zotlabs\\Lib\\Markdown', 'use_zrl_cb_link'], $s); + } else { + $s = preg_replace("/([^\]\=\{\/]|^)(https?\:\/\/)([a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@\(\)]+)/ismu", '$1[url=$2$3]$2$3[/url]', $s); + } + + // remove duplicate adjacent code tags + $s = preg_replace("/(\[code\])+(.*?)(\[\/code\])+/ism", "[code]$2[/code]", $s); + + /** + * @hooks markdown_to_bb + * * \e string - The already converted message as bbcode + */ + call_hooks('markdown_to_bb', $s); + + return $s; + } + + public static function use_zrl_cb_link($match) + { + $res = ''; + $is_zid = is_matrix_url(trim($match[0])); + + if ($is_zid) + $res = $match[1] . '[zrl=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/zrl]'; + else + $res = $match[1] . '[url=' . $match[2] . $match[3] . ']' . $match[2] . $match[3] . '[/url]'; + + return $res; + } + + public static function use_zrl_cb_img($match) + { + $res = ''; + $is_zid = is_matrix_url(trim($match[1])); + + if ($is_zid) + $res = '[zmg]' . $match[1] . '[/zmg]'; + else + $res = $match[0]; + + return $res; + } + + public static function use_zrl_cb_img_x($match) + { + $res = ''; + $is_zid = is_matrix_url(trim($match[3])); - if($is_zid) - $res = '[zmg=' . $match[1] . 'x' . $match[2] . ']' . $match[3] . '[/zmg]'; - else - $res = $match[0]; + if ($is_zid) + $res = '[zmg=' . $match[1] . 'x' . $match[2] . ']' . $match[3] . '[/zmg]'; + else + $res = $match[0]; - return $res; - } + return $res; + } - /** - * @brief - * - * @param array $match - * @return string - */ + /** + * @brief + * + * @param array $match + * @return string + */ - static public function from_bbcode_share($match) { + public static function from_bbcode_share($match) + { - $matches = []; - $attributes = $match[1]; + $matches = []; + $attributes = $match[1]; - $author = ""; - preg_match("/author='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $author = urldecode($matches[1]); + $author = ""; + preg_match("/author='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $author = urldecode($matches[1]); - $link = ""; - preg_match("/link='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $link = $matches[1]; + $link = ""; + preg_match("/link='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $link = $matches[1]; - $avatar = ""; - preg_match("/avatar='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $avatar = $matches[1]; + $avatar = ""; + preg_match("/avatar='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $avatar = $matches[1]; - $profile = ""; - preg_match("/profile='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $profile = $matches[1]; + $profile = ""; + preg_match("/profile='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $profile = $matches[1]; - $posted = ""; - preg_match("/posted='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $posted = $matches[1]; + $posted = ""; + preg_match("/posted='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $posted = $matches[1]; - // message_id is never used, do we still need it? - $message_id = ""; - preg_match("/message_id='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $message_id = $matches[1]; - - if(! $message_id) { - preg_match("/guid='(.*?)'/ism", $attributes, $matches); - if ($matches[1] != "") - $message_id = $matches[1]; - } + // message_id is never used, do we still need it? + $message_id = ""; + preg_match("/message_id='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $message_id = $matches[1]; + if (!$message_id) { + preg_match("/guid='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $message_id = $matches[1]; + } - $reldate = datetime_convert('UTC', date_default_timezone_get(), $posted, 'r'); - $headline = ''; + $reldate = datetime_convert('UTC', date_default_timezone_get(), $posted, 'r'); - if ($avatar != "") - $headline .= '[url=' . zid($profile) . '][img]' . $avatar . '[/img][/url]'; + $headline = ''; - // Bob Smith wrote the following post 2 hours ago + if ($avatar != "") + $headline .= '[url=' . zid($profile) . '][img]' . $avatar . '[/img][/url]'; - $fmt = sprintf( t('%1$s wrote the following %2$s %3$s'), - '[url=' . zid($profile) . ']' . $author . '[/url]', - '[url=' . zid($link) . ']' . t('post') . '[/url]', - $reldate - ); + // Bob Smith wrote the following post 2 hours ago - $headline .= $fmt . "\n\n"; + $fmt = sprintf(t('%1$s wrote the following %2$s %3$s'), + '[url=' . zid($profile) . ']' . $author . '[/url]', + '[url=' . zid($link) . ']' . t('post') . '[/url]', + $reldate + ); - $text = $headline . trim($match[2]); + $headline .= $fmt . "\n\n"; - return $text; - } + $text = $headline . trim($match[2]); + return $text; + } - /** - * @brief Convert bbcode to Markdown. - * - * @param string $Text The message as bbcode - * @param array $options default empty - * @return string The message converted to Markdown - */ - static public function from_bbcode($Text, $options = []) { + /** + * @brief Convert bbcode to Markdown. + * + * @param string $Text The message as bbcode + * @param array $options default empty + * @return string The message converted to Markdown + */ - /* - * Transform #tags, strip off the [url] and replace spaces with underscore - */ + public static function from_bbcode($Text, $options = []) + { - $Text = preg_replace_callback('/#\[([zu])rl\=(.*?)\](.*?)\[\/[(zu)]rl\]/i', - create_function('$match', 'return \'#\'. str_replace(\' \', \'_\', $match[3]);'), $Text); + /* + * Transform #tags, strip off the [url] and replace spaces with underscore + */ - $Text = preg_replace('/#\^\[([zu])rl\=(.*?)\](.*?)\[\/([zu])rl\]/i', '[$1rl=$2]$3[/$4rl]', $Text); + $Text = preg_replace_callback('/#\[([zu])rl\=(.*?)\](.*?)\[\/[(zu)]rl\]/i', + create_function('$match', 'return \'#\'. str_replace(\' \', \'_\', $match[3]);'), $Text); - // Converting images with size parameters to simple images. Markdown doesn't know it. - $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $Text); + $Text = preg_replace('/#\^\[([zu])rl\=(.*?)\](.*?)\[\/([zu])rl\]/i', '[$1rl=$2]$3[/$4rl]', $Text); - $Text = preg_replace_callback("/\[share(.*?)\](.*?)\[\/share\]/ism", [ '\\Zotlabs\\Lib\\Markdown', 'from_bbcode_share'], $Text); + // Converting images with size parameters to simple images. Markdown doesn't know it. + $Text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $Text); - $x = [ 'bbcode' => $Text, 'options' => $options ]; + $Text = preg_replace_callback("/\[share(.*?)\](.*?)\[\/share\]/ism", ['\\Zotlabs\\Lib\\Markdown', 'from_bbcode_share'], $Text); - /** - * @hooks bb_to_markdown_bb - * * \e string \b bbcode - The message as bbcode and what will get returned - * * \e array \b options - */ - call_hooks('bb_to_markdown_bb', $x); + $x = ['bbcode' => $Text, 'options' => $options]; - $Text = $x['bbcode']; + /** + * @hooks bb_to_markdown_bb + * * \e string \b bbcode - The message as bbcode and what will get returned + * * \e array \b options + */ + call_hooks('bb_to_markdown_bb', $x); - // Convert it to HTML - don't try oembed - $Text = bbcode($Text, [ 'tryoembed' => false ]); + $Text = $x['bbcode']; - // Now convert HTML to Markdown + // Convert it to HTML - don't try oembed + $Text = bbcode($Text, ['tryoembed' => false]); - $Text = self::from_html($Text); + // Now convert HTML to Markdown - //html2markdown adds backslashes infront of hashes after a new line. remove them - $Text = str_replace("\n\#", "\n#", $Text); + $Text = self::from_html($Text); + //html2markdown adds backslashes infront of hashes after a new line. remove them + $Text = str_replace("\n\#", "\n#", $Text); - // If the text going into bbcode() has a plain URL in it, i.e. - // with no [url] tags around it, it will come out of parseString() - // looking like: , which gets removed by strip_tags(). - // So take off the angle brackets of any such URL - $Text = preg_replace("//is", "http$1", $Text); - // Remove empty zrl links - $Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text); + // If the text going into bbcode() has a plain URL in it, i.e. + // with no [url] tags around it, it will come out of parseString() + // looking like: , which gets removed by strip_tags(). + // So take off the angle brackets of any such URL + $Text = preg_replace("//is", "http$1", $Text); - $Text = trim($Text); + // Remove empty zrl links + $Text = preg_replace("/\[zrl\=\].*?\[\/zrl\]/is", "", $Text); - /** - * @hooks bb_to_markdown - * * \e string - The already converted message as bbcode and what will get returned - */ - call_hooks('bb_to_markdown', $Text); + $Text = trim($Text); - return $Text; - } + /** + * @hooks bb_to_markdown + * * \e string - The already converted message as bbcode and what will get returned + */ + call_hooks('bb_to_markdown', $Text); + return $Text; + } - /** - * @brief Convert a HTML text into Markdown. - * - * This function uses the library league/html-to-markdown for this task. - * - * If the HTML text can not get parsed it will return an empty string. - * - * @param string $html The HTML code to convert - * @return string Markdown representation of the given HTML text, empty on error - */ - static public function from_html($html,$options = []) { - $markdown = ''; + /** + * @brief Convert a HTML text into Markdown. + * + * This function uses the library league/html-to-markdown for this task. + * + * If the HTML text can not get parsed it will return an empty string. + * + * @param string $html The HTML code to convert + * @return string Markdown representation of the given HTML text, empty on error + */ - if(! $options) { - $options = [ - 'header_style' => 'setext', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2 - 'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML - 'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output. - 'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style - 'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style - 'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script' - 'hard_break' => false, // Set to true to turn
into `\n` instead of ` \n` - 'list_item_style' => '-', // Set the default character for each
  • in a
      . Can be '-', '*', or '+' - ]; - } - - $environment = Environment::createDefaultEnvironment($options); - $environment->addConverter(new TableConverter()); - $converter = new HtmlConverter($environment); + public static function from_html($html, $options = []) + { + $markdown = ''; - try { - $markdown = $converter->convert($html); - } catch (InvalidArgumentException $e) { - logger("Invalid HTML. HTMLToMarkdown library threw an exception."); - } + if (!$options) { + $options = [ + 'header_style' => 'setext', // Set to 'atx' to output H1 and H2 headers as # Header1 and ## Header2 + 'suppress_errors' => true, // Set to false to show warnings when loading malformed HTML + 'strip_tags' => false, // Set to true to strip tags that don't have markdown equivalents. N.B. Strips tags, not their content. Useful to clean MS Word HTML output. + 'bold_style' => '**', // DEPRECATED: Set to '__' if you prefer the underlined style + 'italic_style' => '*', // DEPRECATED: Set to '_' if you prefer the underlined style + 'remove_nodes' => '', // space-separated list of dom nodes that should be removed. example: 'meta style script' + 'hard_break' => false, // Set to true to turn
      into `\n` instead of ` \n` + 'list_item_style' => '-', // Set the default character for each
    • in a
        . Can be '-', '*', or '+' + ]; + } - return $markdown; - } + $environment = Environment::createDefaultEnvironment($options); + $environment->addConverter(new TableConverter()); + $converter = new HtmlConverter($environment); + + try { + $markdown = $converter->convert($html); + } catch (InvalidArgumentException $e) { + logger("Invalid HTML. HTMLToMarkdown library threw an exception."); + } + + return $markdown; + } } // Tables are not an official part of the markdown specification. diff --git a/Zotlabs/Lib/MarkdownSoap.php b/Zotlabs/Lib/MarkdownSoap.php index a58a5753a..a08ad6073 100644 --- a/Zotlabs/Lib/MarkdownSoap.php +++ b/Zotlabs/Lib/MarkdownSoap.php @@ -22,111 +22,123 @@ namespace Zotlabs\Lib; * $html = \Michelf\MarkdownExtra::DefaultTransform($markdown); * @endcode */ -class MarkdownSoap { +class MarkdownSoap +{ - /** - * @var string - */ - private $str; - /** - * @var string - */ - private $token; + /** + * @var string + */ + private $str; + /** + * @var string + */ + private $token; - function __construct($s) { - $this->str = $s; - $this->token = random_string(20); - } + public function __construct($s) + { + $this->str = $s; + $this->token = random_string(20); + } - function clean() { + public function clean() + { - $x = $this->extract_code($this->str); + $x = $this->extract_code($this->str); - $x = $this->purify($x); + $x = $this->purify($x); - $x = $this->putback_code($x); + $x = $this->putback_code($x); - $x = $this->escape($x); + $x = $this->escape($x); - return $x; - } + return $x; + } - /** - * @brief Extracts code blocks and privately escapes them from processing. - * - * @see encode_code() - * @see putback_code() - * - * @param string $s - * @return string - */ - function extract_code($s) { + /** + * @brief Extracts code blocks and privately escapes them from processing. + * + * @param string $s + * @return string + * @see encode_code() + * @see putback_code() + * + */ + public function extract_code($s) + { - $text = preg_replace_callback('{ + $text = preg_replace_callback('{ (?:\n\n|\A\n?) ( # $1 = the code block -- one or more lines, starting with a space/tab (?> - [ ]{'.'4'.'} # Lines must start with a tab or a tab-width of spaces + [ ]{' . '4' . '} # Lines must start with a tab or a tab-width of spaces .*\n+ )+ ) - ((?=^[ ]{0,'.'4'.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc + ((?=^[ ]{0,' . '4' . '}\S)|\Z) # Lookahead for non-space at line-start, or end of doc }xm', - [ $this , 'encode_code' ], $s); + [$this, 'encode_code'], $s); - return $text; - } + return $text; + } - function encode_code($matches) { - return $this->token . ';' . base64_encode($matches[0]) . ';' ; - } + public function encode_code($matches) + { + return $this->token . ';' . base64_encode($matches[0]) . ';'; + } - function decode_code($matches) { - return base64_decode($matches[1]); - } + public function decode_code($matches) + { + return base64_decode($matches[1]); + } - /** - * @brief Put back the code blocks. - * - * @see extract_code() - * @see decode_code() - * - * @param string $s - * @return string - */ - function putback_code($s) { - $text = preg_replace_callback('{' . $this->token . '\;(.*?)\;}xm', [ $this, 'decode_code' ], $s); - return $text; - } + /** + * @brief Put back the code blocks. + * + * @param string $s + * @return string + * @see extract_code() + * @see decode_code() + * + */ + public function putback_code($s) + { + $text = preg_replace_callback('{' . $this->token . '\;(.*?)\;}xm', [$this, 'decode_code'], $s); + return $text; + } - function purify($s) { - $s = $this->protect_autolinks($s); - $s = purify_html($s); - $s = $this->unprotect_autolinks($s); - return $s; - } + public function purify($s) + { + $s = $this->protect_autolinks($s); + $s = purify_html($s); + $s = $this->unprotect_autolinks($s); + return $s; + } - function protect_autolinks($s) { - $s = preg_replace('/\<(https?\:\/\/)(.*?)\>/', '[$1$2]($1$2)', $s); - return $s; - } + public function protect_autolinks($s) + { + $s = preg_replace('/\<(https?\:\/\/)(.*?)\>/', '[$1$2]($1$2)', $s); + return $s; + } - function unprotect_autolinks($s) { - return $s; - } + public function unprotect_autolinks($s) + { + return $s; + } - function escape($s) { - return htmlspecialchars($s, ENT_QUOTES, 'UTF-8', false); - } + public function escape($s) + { + return htmlspecialchars($s, ENT_QUOTES, 'UTF-8', false); + } - /** - * @brief Converts special HTML entities back to characters. - * - * @param string $s - * @return string - */ - static public function unescape($s) { - return htmlspecialchars_decode($s, ENT_QUOTES); - } + /** + * @brief Converts special HTML entities back to characters. + * + * @param string $s + * @return string + */ + public static function unescape($s) + { + return htmlspecialchars_decode($s, ENT_QUOTES); + } } diff --git a/Zotlabs/Lib/MastAPI.php b/Zotlabs/Lib/MastAPI.php index 7bfd7191a..724325169 100644 --- a/Zotlabs/Lib/MastAPI.php +++ b/Zotlabs/Lib/MastAPI.php @@ -6,16 +6,18 @@ use App; use Zotlabs\Lib\PConfig; -class MastAPI { +class MastAPI +{ - static function format_channel($channel) { - $p = q("select * from profile where uid = %d and is_default = 1", - intval($channel['channel_id']) - ); + public static function format_channel($channel) + { + $p = q("select * from profile where uid = %d and is_default = 1", + intval($channel['channel_id']) + ); - $a = q("select * from account where account_id = %d", - intval($channel['channel_account_id']) - ); + $a = q("select * from account where account_id = %d", + intval($channel['channel_account_id']) + ); $followers = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 ", intval($channel['channel_id']), @@ -23,13 +25,13 @@ class MastAPI { dbesc($channel['channel_hash']) ); - $following = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", - intval($channel['channel_id']), - intval($channel['channel_id']), - dbesc($channel['channel_hash']) - ); + $following = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", + intval($channel['channel_id']), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); - $cover_photo = get_cover_photo($channel['channel_id'],'array'); + $cover_photo = get_cover_photo($channel['channel_id'], 'array'); $item_normal = item_normal(); @@ -38,66 +40,67 @@ class MastAPI { WHERE uid = %d AND author_xchan = '%s' $item_normal ", intval($channel['channel_id']), - dbesc($channel['channel_hash']) + dbesc($channel['channel_hash']) ); - $ret = []; - $ret['id'] = (string) $channel['channel_id']; - $ret['username'] = $channel['channel_address']; - $ret['acct'] = $channel['channel_address']; - $ret['display_name'] = $channel['channel_name']; - $ret['locked'] = ((intval(PConfig::Get($channel['channel_id'],'system','autoperms'))) ? false : true ); - $ret['discoverable'] = ((1 - intval($channel['xchan_hidden'])) ? true : false); - $ret['created_at'] = datetime_convert('UTC','UTC', $a[0]['account_created'], ATOM_TIME); - $ret['note'] = bbcode($p[0]['about'], [ 'export' => true ]); - $ret['url'] = channel_url($channel); - $ret['avatar'] = $channel['xchan_photo_l']; - $ret['avatar_static'] = $channel['xchan_photo_l']; - if ($cover_photo) { - $ret['header'] = $cover_photo['url']; - $ret['header_static'] = $cover_photo['url']; - } - $ret['followers_count'] = intval($followers[0]['total']); - $ret['following_count'] = intval($following[0]['total']); - $ret['statuses_count'] = intval($statuses[0]['total']); - $ret['last_status_at'] = datetime_convert('UTC','UTC', $channel['lastpost'], ATOM_TIME); + $ret = []; + $ret['id'] = (string)$channel['channel_id']; + $ret['username'] = $channel['channel_address']; + $ret['acct'] = $channel['channel_address']; + $ret['display_name'] = $channel['channel_name']; + $ret['locked'] = ((intval(PConfig::Get($channel['channel_id'], 'system', 'autoperms'))) ? false : true); + $ret['discoverable'] = ((1 - intval($channel['xchan_hidden'])) ? true : false); + $ret['created_at'] = datetime_convert('UTC', 'UTC', $a[0]['account_created'], ATOM_TIME); + $ret['note'] = bbcode($p[0]['about'], ['export' => true]); + $ret['url'] = channel_url($channel); + $ret['avatar'] = $channel['xchan_photo_l']; + $ret['avatar_static'] = $channel['xchan_photo_l']; + if ($cover_photo) { + $ret['header'] = $cover_photo['url']; + $ret['header_static'] = $cover_photo['url']; + } + $ret['followers_count'] = intval($followers[0]['total']); + $ret['following_count'] = intval($following[0]['total']); + $ret['statuses_count'] = intval($statuses[0]['total']); + $ret['last_status_at'] = datetime_convert('UTC', 'UTC', $channel['lastpost'], ATOM_TIME); - return $ret; - } + return $ret; + } - static function format_site() { + public static function format_site() + { - $register = intval(get_config('system','register_policy')); + $register = intval(get_config('system', 'register_policy')); - $u = q("select count(channel_id) as total from channel where channel_removed = 0"); - $i = q("select count(id) as total from item where item_origin = 1"); - $s = q("select count(site_url) as total from site"); + $u = q("select count(channel_id) as total from channel where channel_removed = 0"); + $i = q("select count(id) as total from item where item_origin = 1"); + $s = q("select count(site_url) as total from site"); - $admins = q("select * from channel left join account on account_id = channel_account_id where ( account_roles & 4096 ) > 0 and account_default_channel = channel_id"); - $adminsx = channelx_by_n($admins[0]['channel_id']); + $admins = q("select * from channel left join account on account_id = channel_account_id where ( account_roles & 4096 ) > 0 and account_default_channel = channel_id"); + $adminsx = channelx_by_n($admins[0]['channel_id']); - $ret = []; - $ret['uri'] = z_root(); - $ret['title'] = System::get_site_name(); - $ret['description'] = bbcode(get_config('system','siteinfo',''), [ 'export' => true ] ); - $ret['email'] = get_config('system','admin_email'); - $ret['version'] = System::get_project_version(); - $ret['registrations'] = (($register) ? true : false); - $ret['approval_required'] = (($register === REGISTER_APPROVE) ? true : false); - $ret['invites_enabled'] = false; - $ret['urls'] = []; - $ret['stats'] = [ - 'user_count' => intval($u[0]['total']), - 'status_count' => intval($i[0]['total']), - 'domain_count' => intval($s[0]['total']), - ]; + $ret = []; + $ret['uri'] = z_root(); + $ret['title'] = System::get_site_name(); + $ret['description'] = bbcode(get_config('system', 'siteinfo', ''), ['export' => true]); + $ret['email'] = get_config('system', 'admin_email'); + $ret['version'] = System::get_project_version(); + $ret['registrations'] = (($register) ? true : false); + $ret['approval_required'] = (($register === REGISTER_APPROVE) ? true : false); + $ret['invites_enabled'] = false; + $ret['urls'] = []; + $ret['stats'] = [ + 'user_count' => intval($u[0]['total']), + 'status_count' => intval($i[0]['total']), + 'domain_count' => intval($s[0]['total']), + ]; - $ret['contact_account'] = self::format_channel($adminsx); + $ret['contact_account'] = self::format_channel($adminsx); - return $ret; - - } + return $ret; + + } } \ No newline at end of file diff --git a/Zotlabs/Lib/MessageFilter.php b/Zotlabs/Lib/MessageFilter.php index c11fdf8db..f6c6c6c30 100644 --- a/Zotlabs/Lib/MessageFilter.php +++ b/Zotlabs/Lib/MessageFilter.php @@ -7,7 +7,7 @@ namespace Zotlabs\Lib; class MessageFilter { - static public function evaluate($item,$incl,$excl) { + public static function evaluate($item, $incl, $excl) { require_once('include/html2plain.php'); diff --git a/Zotlabs/Lib/Nodeinfo.php b/Zotlabs/Lib/Nodeinfo.php index 62efd7583..128bb5261 100644 --- a/Zotlabs/Lib/Nodeinfo.php +++ b/Zotlabs/Lib/Nodeinfo.php @@ -6,7 +6,7 @@ namespace Zotlabs\Lib; class Nodeinfo { - static public function fetch($url) { + public static function fetch($url) { $href = EMPTY_STR; $m = parse_url($url); if ($m['scheme'] && $m['host']) { diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php index 5bd8f27ef..0745080b0 100644 --- a/Zotlabs/Lib/PConfig.php +++ b/Zotlabs/Lib/PConfig.php @@ -30,7 +30,7 @@ class PConfig { * The channel_id * @return void|false Nothing or false if $uid is null or false */ - static public function Load($uid) { + public static function Load($uid) { if(is_null($uid) || $uid === false) return false; @@ -82,7 +82,7 @@ class PConfig { * Default value to return if key does not exist * @return mixed Stored value or false if it does not exist */ - static public function Get($uid, $family, $key, $default = false) { + public static function Get($uid, $family, $key, $default = false) { if(is_null($uid) || $uid === false) return $default; @@ -112,7 +112,7 @@ class PConfig { * The value to store * @return mixed Stored $value or false */ - static public function Set($uid, $family, $key, $value) { + public static function Set($uid, $family, $key, $value) { // this catches subtle errors where this function has been called // with local_channel() when not logged in (which returns false) @@ -185,7 +185,7 @@ class PConfig { * The configuration key to delete * @return mixed */ - static public function Delete($uid, $family, $key) { + public static function Delete($uid, $family, $key) { if(is_null($uid) || $uid === false) return false; diff --git a/Zotlabs/Lib/Permcat.php b/Zotlabs/Lib/Permcat.php index 92f69cdbd..e0805c147 100644 --- a/Zotlabs/Lib/Permcat.php +++ b/Zotlabs/Lib/Permcat.php @@ -157,7 +157,7 @@ class Permcat { return $permcats; } - static public function find_permcat($arr, $name) { + public static function find_permcat($arr, $name) { if((! $arr) || (! $name)) return false; @@ -166,11 +166,11 @@ class Permcat { return $p['value']; } - static public function update($channel_id, $name, $permarr) { + public static function update($channel_id, $name, $permarr) { PConfig::Set($channel_id, 'permcat', $name, $permarr); } - static public function delete($channel_id, $name) { + public static function delete($channel_id, $name) { PConfig::Delete($channel_id, 'permcat', $name); } diff --git a/Zotlabs/Lib/PermissionDescription.php b/Zotlabs/Lib/PermissionDescription.php index d99145756..101a22b39 100644 --- a/Zotlabs/Lib/PermissionDescription.php +++ b/Zotlabs/Lib/PermissionDescription.php @@ -55,7 +55,7 @@ class PermissionDescription { * default permission. You should pass one of the constants from boot.php - PERMS_PUBLIC, * PERMS_NETWORK etc. * - * @param integer $perm - a single enumerated constant permission - PERMS_PUBLIC, PERMS_NETWORK etc. + * @param int $perm - a single enumerated constant permission - PERMS_PUBLIC, PERMS_NETWORK etc. * @return a new instance of PermissionDescription */ public static function fromStandalonePermission($perm) { diff --git a/Zotlabs/Lib/Queue.php b/Zotlabs/Lib/Queue.php index 1904a9048..62ecec61f 100644 --- a/Zotlabs/Lib/Queue.php +++ b/Zotlabs/Lib/Queue.php @@ -9,485 +9,480 @@ use Zotlabs\Lib\ActivityStreams; use Zotlabs\Zot6\Receiver; use Zotlabs\Zot6\Zot6Handler; -class Queue { +class Queue +{ - static function update($id, $add_priority = 0) { + public static function update($id, $add_priority = 0) + { - logger('queue: requeue item ' . $id,LOGGER_DEBUG); + logger('queue: requeue item ' . $id, LOGGER_DEBUG); - // This queue item failed. Perhaps it was rejected. Perhaps the site is dead. - // Since we don't really know, check and see if we've got something else destined - // for that server and give it priority. At a minimum it will keep the queue from - // getting stuck on a particular message when another one with different content - // might actually succeed. - - $x = q("select outq_created, outq_hash, outq_posturl from outq where outq_hash = '%s' limit 1", - dbesc($id) - ); - if (! $x) { - return; - } + // This queue item failed. Perhaps it was rejected. Perhaps the site is dead. + // Since we don't really know, check and see if we've got something else destined + // for that server and give it priority. At a minimum it will keep the queue from + // getting stuck on a particular message when another one with different content + // might actually succeed. - $g = q("select outq_created, outq_hash, outq_posturl from outq where outq_posturl = '%s' and outq_hash != '%s' limit 1", - dbesc($x[0]['outq_posturl']), - dbesc($id) - ); + $x = q("select outq_created, outq_hash, outq_posturl from outq where outq_hash = '%s' limit 1", + dbesc($id) + ); + if (!$x) { + return; + } - // swap them - - if ($g) { - $x = $g; - } - + $g = q("select outq_created, outq_hash, outq_posturl from outq where outq_posturl = '%s' and outq_hash != '%s' limit 1", + dbesc($x[0]['outq_posturl']), + dbesc($id) + ); + + // swap them + + if ($g) { + $x = $g; + } - $y = q("select min(outq_created) as earliest from outq where outq_posturl = '%s'", - dbesc($x[0]['outq_posturl']) - ); + $y = q("select min(outq_created) as earliest from outq where outq_posturl = '%s'", + dbesc($x[0]['outq_posturl']) + ); - // look for the oldest queue entry with this destination URL. If it's older than a couple of days, - // the destination is considered to be down and only scheduled once an hour, regardless of the - // age of the current queue item. + // look for the oldest queue entry with this destination URL. If it's older than a couple of days, + // the destination is considered to be down and only scheduled once an hour, regardless of the + // age of the current queue item. - $might_be_down = false; + $might_be_down = false; - if($y) - $might_be_down = ((datetime_convert('UTC','UTC',$y[0]['earliest']) < datetime_convert('UTC','UTC','now - 2 days')) ? true : false); + if ($y) + $might_be_down = ((datetime_convert('UTC', 'UTC', $y[0]['earliest']) < datetime_convert('UTC', 'UTC', 'now - 2 days')) ? true : false); - // Set all other records for this destination way into the future. - // The queue delivers by destination. We'll keep one queue item for - // this destination (this one) with a shorter delivery. If we succeed - // once, we'll try to deliver everything for that destination. - // The delivery will be set to at most once per hour, and if the - // queue item is less than 12 hours old, we'll schedule for fifteen - // minutes. + // Set all other records for this destination way into the future. + // The queue delivers by destination. We'll keep one queue item for + // this destination (this one) with a shorter delivery. If we succeed + // once, we'll try to deliver everything for that destination. + // The delivery will be set to at most once per hour, and if the + // queue item is less than 12 hours old, we'll schedule for fifteen + // minutes. - $r = q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'", - dbesc(datetime_convert('UTC','UTC','now + 5 days')), - dbesc($x[0]['outq_posturl']) - ); - - $since = datetime_convert('UTC','UTC',$y[0]['earliest']); + $r = q("UPDATE outq SET outq_scheduled = '%s' WHERE outq_posturl = '%s'", + dbesc(datetime_convert('UTC', 'UTC', 'now + 5 days')), + dbesc($x[0]['outq_posturl']) + ); - if(($might_be_down) || ($since < datetime_convert('UTC','UTC','now - 12 hour'))) { - $next = datetime_convert('UTC','UTC','now + 1 hour'); - } - else { - $next = datetime_convert('UTC','UTC','now + ' . intval($add_priority) . ' minutes'); - } + $since = datetime_convert('UTC', 'UTC', $y[0]['earliest']); - q("UPDATE outq SET outq_updated = '%s', + if (($might_be_down) || ($since < datetime_convert('UTC', 'UTC', 'now - 12 hour'))) { + $next = datetime_convert('UTC', 'UTC', 'now + 1 hour'); + } else { + $next = datetime_convert('UTC', 'UTC', 'now + ' . intval($add_priority) . ' minutes'); + } + + q("UPDATE outq SET outq_updated = '%s', outq_priority = outq_priority + %d, outq_scheduled = '%s' WHERE outq_hash = '%s'", - dbesc(datetime_convert()), - intval($add_priority), - dbesc($next), - dbesc($x[0]['outq_hash']) - ); - } + dbesc(datetime_convert()), + intval($add_priority), + dbesc($next), + dbesc($x[0]['outq_hash']) + ); + } - static function remove($id,$channel_id = 0) { - logger('queue: remove queue item ' . $id,LOGGER_DEBUG); - $sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : ''); - - q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra", - dbesc($id) - ); - } + public static function remove($id, $channel_id = 0) + { + logger('queue: remove queue item ' . $id, LOGGER_DEBUG); + $sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : ''); + + q("DELETE FROM outq WHERE outq_hash = '%s' $sql_extra", + dbesc($id) + ); + } - static function remove_by_posturl($posturl) { - logger('queue: remove queue posturl ' . $posturl,LOGGER_DEBUG); - - q("DELETE FROM outq WHERE outq_posturl = '%s' ", - dbesc($posturl) - ); - } + public static function remove_by_posturl($posturl) + { + logger('queue: remove queue posturl ' . $posturl, LOGGER_DEBUG); + + q("DELETE FROM outq WHERE outq_posturl = '%s' ", + dbesc($posturl) + ); + } + public static function set_delivered($id, $channel = 0) + { + logger('queue: set delivered ' . $id, LOGGER_DEBUG); + $sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : ''); - static function set_delivered($id,$channel = 0) { - logger('queue: set delivered ' . $id,LOGGER_DEBUG); - $sql_extra = (($channel_id) ? " and outq_channel = " . intval($channel_id) . " " : ''); + // Set the next scheduled run date so far in the future that it will be expired + // long before it ever makes it back into the delivery chain. - // Set the next scheduled run date so far in the future that it will be expired - // long before it ever makes it back into the delivery chain. - - q("update outq set outq_delivered = 1, outq_updated = '%s', outq_scheduled = '%s' where outq_hash = '%s' $sql_extra ", - dbesc(datetime_convert()), - dbesc(datetime_convert('UTC','UTC','now + 5 days')), - dbesc($id) - ); - } + q("update outq set outq_delivered = 1, outq_updated = '%s', outq_scheduled = '%s' where outq_hash = '%s' $sql_extra ", + dbesc(datetime_convert()), + dbesc(datetime_convert('UTC', 'UTC', 'now + 5 days')), + dbesc($id) + ); + } + public static function insert($arr) + { - static function insert($arr) { + logger('insert: ' . print_r($arr, true), LOGGER_DATA); - logger('insert: ' . print_r($arr,true), LOGGER_DATA); + // do not queue anything with no destination - // do not queue anything with no destination - - if (! (array_key_exists('posturl',$arr) && trim($arr['posturl']))) { - logger('no destination'); - return false; - } + if (!(array_key_exists('posturl', $arr) && trim($arr['posturl']))) { + logger('no destination'); + return false; + } - $x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority, + $x = q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_priority, outq_created, outq_updated, outq_scheduled, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s' )", - dbesc($arr['hash']), - intval($arr['account_id']), - intval($arr['channel_id']), - dbesc((isset($arr['driver']) && $arr['driver']) ? $arr['driver'] : 'zot6'), - dbesc($arr['posturl']), - intval(1), - intval((isset($arr['priority'])) ? $arr['priority'] : 0), - dbesc(datetime_convert()), - dbesc(datetime_convert()), - dbesc((isset($arr['scheduled'])) ? $arr['scheduled'] : datetime_convert()), - dbesc($arr['notify']), - dbesc(($arr['msg']) ? $arr['msg'] : '') - ); - return $x; + dbesc($arr['hash']), + intval($arr['account_id']), + intval($arr['channel_id']), + dbesc((isset($arr['driver']) && $arr['driver']) ? $arr['driver'] : 'zot6'), + dbesc($arr['posturl']), + intval(1), + intval((isset($arr['priority'])) ? $arr['priority'] : 0), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc((isset($arr['scheduled'])) ? $arr['scheduled'] : datetime_convert()), + dbesc($arr['notify']), + dbesc(($arr['msg']) ? $arr['msg'] : '') + ); + return $x; - } + } + public static function deliver($outq, $immediate = false) + { - static function deliver($outq, $immediate = false) { + $base = null; + $h = parse_url($outq['outq_posturl']); + if ($h !== false) { + $base = $h['scheme'] . '://' . $h['host'] . ((isset($h['port']) && intval($h['port'])) ? ':' . $h['port'] : ''); + } - $base = null; - $h = parse_url($outq['outq_posturl']); - if ($h !== false) { - $base = $h['scheme'] . '://' . $h['host'] . ((isset($h['port']) && intval($h['port'])) ? ':' . $h['port'] : ''); - } - - if (($base) && ($base !== z_root()) && ($immediate)) { - $y = q("select site_update, site_dead from site where site_url = '%s' ", - dbesc($base) - ); - if ($y) { - if (intval($y[0]['site_dead'])) { - q("update dreport set dreport_result = '%s' where dreport_queue = '%s'", - dbesc('site dead'), - dbesc($outq['outq_hash']) - ); + if (($base) && ($base !== z_root()) && ($immediate)) { + $y = q("select site_update, site_dead from site where site_url = '%s' ", + dbesc($base) + ); + if ($y) { + if (intval($y[0]['site_dead'])) { + q("update dreport set dreport_result = '%s' where dreport_queue = '%s'", + dbesc('site dead'), + dbesc($outq['outq_hash']) + ); - self::remove_by_posturl($outq['outq_posturl']); - logger('dead site ignored ' . $base); - return; - } - if ($y[0]['site_update'] < datetime_convert('UTC','UTC','now - 1 month')) { - q("update dreport set dreport_log = '%s' where dreport_queue = '%s'", - dbesc('site deferred'), - dbesc($outq['outq_hash']) - ); - self::update($outq['outq_hash'],10); - logger('immediate delivery deferred for site ' . $base); - return; - } - } - else { + self::remove_by_posturl($outq['outq_posturl']); + logger('dead site ignored ' . $base); + return; + } + if ($y[0]['site_update'] < datetime_convert('UTC', 'UTC', 'now - 1 month')) { + q("update dreport set dreport_log = '%s' where dreport_queue = '%s'", + dbesc('site deferred'), + dbesc($outq['outq_hash']) + ); + self::update($outq['outq_hash'], 10); + logger('immediate delivery deferred for site ' . $base); + return; + } + } else { - // zot sites should all have a site record, unless they've been dead for as long as - // your site has existed. Since we don't know for sure what these sites are, - // call them unknown + // zot sites should all have a site record, unless they've been dead for as long as + // your site has existed. Since we don't know for sure what these sites are, + // call them unknown - site_store_lowlevel( - [ - 'site_url' => $base, - 'site_update' => datetime_convert(), - 'site_dead' => 0, - 'site_type' => ((in_array($outq['outq_driver'], [ 'post', 'activitypub' ])) ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN), - 'site_crypto' => '' - ] - ); - } - } + site_store_lowlevel( + [ + 'site_url' => $base, + 'site_update' => datetime_convert(), + 'site_dead' => 0, + 'site_type' => ((in_array($outq['outq_driver'], ['post', 'activitypub'])) ? SITE_TYPE_NOTZOT : SITE_TYPE_UNKNOWN), + 'site_crypto' => '' + ] + ); + } + } - $arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate); - call_hooks('queue_deliver',$arr); - if($arr['handled']) - return; + $arr = array('outq' => $outq, 'base' => $base, 'handled' => false, 'immediate' => $immediate); + call_hooks('queue_deliver', $arr); + if ($arr['handled']) + return; - // "post" queue driver - used for diaspora and friendica-over-diaspora communications. + // "post" queue driver - used for diaspora and friendica-over-diaspora communications. - if($outq['outq_driver'] === 'post') { - $result = z_post_url($outq['outq_posturl'],$outq['outq_msg']); - if($result['success'] && $result['return_code'] < 300) { - logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG); - if($base) { - q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", - dbesc(datetime_convert()), - dbesc($base) - ); - } - q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", - dbesc('accepted for delivery'), - dbesc(datetime_convert()), - dbesc($outq['outq_hash']) - ); - self::remove($outq['outq_hash']); + if ($outq['outq_driver'] === 'post') { + $result = z_post_url($outq['outq_posturl'], $outq['outq_msg']); + if ($result['success'] && $result['return_code'] < 300) { + logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG); + if ($base) { + q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", + dbesc(datetime_convert()), + dbesc($base) + ); + } + q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", + dbesc('accepted for delivery'), + dbesc(datetime_convert()), + dbesc($outq['outq_hash']) + ); + self::remove($outq['outq_hash']); - // server is responding - see if anything else is going to this destination and is piled up - // and try to send some more. We're relying on the fact that do_delivery() results in an - // immediate delivery otherwise we could get into a queue loop. + // server is responding - see if anything else is going to this destination and is piled up + // and try to send some more. We're relying on the fact that do_delivery() results in an + // immediate delivery otherwise we could get into a queue loop. - if(! $immediate) { - $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", - dbesc($outq['outq_posturl']) - ); - - $piled_up = []; - if($x) { - foreach($x as $xx) { - $piled_up[] = $xx['outq_hash']; - } - } - if($piled_up) { - // call do_delivery() with the force flag - do_delivery($piled_up, true); - } - } - } - else { - logger('deliver: queue post returned ' . $result['return_code'] - . ' from ' . $outq['outq_posturl'],LOGGER_DEBUG); - self::update($outq['outq_hash'],10); - } - return; - } + if (!$immediate) { + $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", + dbesc($outq['outq_posturl']) + ); - if ($outq['outq_driver'] === 'asfetch') { + $piled_up = []; + if ($x) { + foreach ($x as $xx) { + $piled_up[] = $xx['outq_hash']; + } + } + if ($piled_up) { + // call do_delivery() with the force flag + do_delivery($piled_up, true); + } + } + } else { + logger('deliver: queue post returned ' . $result['return_code'] + . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG); + self::update($outq['outq_hash'], 10); + } + return; + } - $channel = channelx_by_n($outq['outq_channel']); - if (! $channel) { - logger('missing channel: ' . $outq['outq_channel']); - return; - } + if ($outq['outq_driver'] === 'asfetch') { - if (! ActivityStreams::is_url($outq['outq_posturl'])) { - logger('fetch item is not url: ' . $outq['outq_posturl']); - self::remove($outq['outq_hash']); - return; - } + $channel = channelx_by_n($outq['outq_channel']); + if (!$channel) { + logger('missing channel: ' . $outq['outq_channel']); + return; + } - $j = Activity::fetch($outq['outq_posturl'],$channel); - if ($j) { - $AS = new ActivityStreams($j, null, true); - if ($AS->is_valid() && isset($AS->data['type'])) { - if (ActivityStreams::is_an_actor($AS->data['type'])) { - Activity::actor_store($AS->data['id'],$AS->data); - } - if (strpos($AS->data['type'],'Collection') !== false) { - // we are probably fetching a collection already - and do not support collection recursion at this time - self::remove($outq['outq_hash']); - return; - } - $item = Activity::decode_note($AS,true); - if ($item) { - Activity::store($channel,$channel['channnel_hash'],$AS,$item,true,true); - } - } - logger('deliver: queue fetch success from ' . $outq['outq_posturl'], LOGGER_DEBUG); - self::remove($outq['outq_hash']); + if (!ActivityStreams::is_url($outq['outq_posturl'])) { + logger('fetch item is not url: ' . $outq['outq_posturl']); + self::remove($outq['outq_hash']); + return; + } - // server is responding - see if anything else is going to this destination and is piled up - // and try to send some more. We're relying on the fact that do_delivery() results in an - // immediate delivery otherwise we could get into a queue loop. + $j = Activity::fetch($outq['outq_posturl'], $channel); + if ($j) { + $AS = new ActivityStreams($j, null, true); + if ($AS->is_valid() && isset($AS->data['type'])) { + if (ActivityStreams::is_an_actor($AS->data['type'])) { + Activity::actor_store($AS->data['id'], $AS->data); + } + if (strpos($AS->data['type'], 'Collection') !== false) { + // we are probably fetching a collection already - and do not support collection recursion at this time + self::remove($outq['outq_hash']); + return; + } + $item = Activity::decode_note($AS, true); + if ($item) { + Activity::store($channel, $channel['channnel_hash'], $AS, $item, true, true); + } + } + logger('deliver: queue fetch success from ' . $outq['outq_posturl'], LOGGER_DEBUG); + self::remove($outq['outq_hash']); - if (! $immediate) { - $x = q("select outq_hash from outq where outq_driver = 'asfetch' and outq_channel = %d and outq_delivered = 0", - dbesc($outq['outq_channel']) - ); + // server is responding - see if anything else is going to this destination and is piled up + // and try to send some more. We're relying on the fact that do_delivery() results in an + // immediate delivery otherwise we could get into a queue loop. - $piled_up = []; - if ($x) { - foreach ($x as $xx) { - $piled_up[] = $xx['outq_hash']; - } - } - if ($piled_up) { - do_delivery($piled_up,true); - } - } - } - else { - logger('deliver: queue fetch failed' . ' from ' . $outq['outq_posturl'],LOGGER_DEBUG); - self::update($outq['outq_hash'],10); - } - return; - } + if (!$immediate) { + $x = q("select outq_hash from outq where outq_driver = 'asfetch' and outq_channel = %d and outq_delivered = 0", + dbesc($outq['outq_channel']) + ); - if($outq['outq_driver'] === 'activitypub') { + $piled_up = []; + if ($x) { + foreach ($x as $xx) { + $piled_up[] = $xx['outq_hash']; + } + } + if ($piled_up) { + do_delivery($piled_up, true); + } + } + } else { + logger('deliver: queue fetch failed' . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG); + self::update($outq['outq_hash'], 10); + } + return; + } - $channel = channelx_by_n($outq['outq_channel']); - if (! $channel) { - logger('missing channel: ' . $outq['outq_channel']); - return; - } + if ($outq['outq_driver'] === 'activitypub') { + + $channel = channelx_by_n($outq['outq_channel']); + if (!$channel) { + logger('missing channel: ' . $outq['outq_channel']); + return; + } - $retries = 0; - $m = parse_url($outq['outq_posturl']); - - $headers = []; - $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ; - $ret = $outq['outq_msg']; - logger('ActivityPub send: ' . jindent($ret), LOGGER_DATA); - $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'); - $headers['Digest'] = HTTPSig::generate_digest_header($ret); - $headers['Host'] = $m['host']; - $headers['(request-target)'] = 'post ' . get_request_string($outq['outq_posturl']); + $retries = 0; + $m = parse_url($outq['outq_posturl']); - $xhead = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel)); - if(strpos($outq['outq_posturl'],'http') !== 0) { - logger('bad url: ' . $outq['outq_posturl']); - self::remove($outq['outq_hash']); - } + $headers = []; + $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; + $ret = $outq['outq_msg']; + logger('ActivityPub send: ' . jindent($ret), LOGGER_DATA); + $headers['Date'] = datetime_convert('UTC', 'UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'); + $headers['Digest'] = HTTPSig::generate_digest_header($ret); + $headers['Host'] = $m['host']; + $headers['(request-target)'] = 'post ' . get_request_string($outq['outq_posturl']); - $result = z_post_url($outq['outq_posturl'],$outq['outq_msg'],$retries,[ 'headers' => $xhead ]); + $xhead = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel)); + if (strpos($outq['outq_posturl'], 'http') !== 0) { + logger('bad url: ' . $outq['outq_posturl']); + self::remove($outq['outq_hash']); + } - if($result['success'] && $result['return_code'] < 300) { - logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG); - if($base) { - q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", - dbesc(datetime_convert()), - dbesc($base) - ); - } - q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", - dbesc('accepted for delivery'), - dbesc(datetime_convert()), - dbesc($outq['outq_hash']) - ); - self::remove($outq['outq_hash']); + $result = z_post_url($outq['outq_posturl'], $outq['outq_msg'], $retries, ['headers' => $xhead]); - // server is responding - see if anything else is going to this destination and is piled up - // and try to send some more. We're relying on the fact that do_delivery() results in an - // immediate delivery otherwise we could get into a queue loop. + if ($result['success'] && $result['return_code'] < 300) { + logger('deliver: queue post success to ' . $outq['outq_posturl'], LOGGER_DEBUG); + if ($base) { + q("update site set site_update = '%s', site_dead = 0 where site_url = '%s' ", + dbesc(datetime_convert()), + dbesc($base) + ); + } + q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", + dbesc('accepted for delivery'), + dbesc(datetime_convert()), + dbesc($outq['outq_hash']) + ); + self::remove($outq['outq_hash']); - if(! $immediate) { - $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", - dbesc($outq['outq_posturl']) - ); + // server is responding - see if anything else is going to this destination and is piled up + // and try to send some more. We're relying on the fact that do_delivery() results in an + // immediate delivery otherwise we could get into a queue loop. - $piled_up = []; - if($x) { - foreach($x as $xx) { - $piled_up[] = $xx['outq_hash']; - } - } - if($piled_up) { - do_delivery($piled_up,true); - } - } - } - else { - if ($result['return_code'] >= 300) { - q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", - dbesc('delivery rejected' . ' ' . $result['return_code']), - dbesc(datetime_convert()), - dbesc($outq['outq_hash']) - ); - } - else { - $dr = q("select * from dreport where dreport_queue = '%s'", - dbesc($outq['outq_hash']) - ); - if ($dr) { - // update every queue entry going to this site with the most recent communication error - q("update dreport set dreport_log = '%s' where dreport_site = '%s'", - dbesc(z_curl_error($result)), - dbesc($dr[0]['dreport_site']) - ); - } - } - logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $outq['outq_posturl'],LOGGER_DEBUG); - self::update($outq['outq_hash'],10); - } - return; - } + if (!$immediate) { + $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", + dbesc($outq['outq_posturl']) + ); - // normal zot delivery + $piled_up = []; + if ($x) { + foreach ($x as $xx) { + $piled_up[] = $xx['outq_hash']; + } + } + if ($piled_up) { + do_delivery($piled_up, true); + } + } + } else { + if ($result['return_code'] >= 300) { + q("update dreport set dreport_result = '%s', dreport_time = '%s' where dreport_queue = '%s'", + dbesc('delivery rejected' . ' ' . $result['return_code']), + dbesc(datetime_convert()), + dbesc($outq['outq_hash']) + ); + } else { + $dr = q("select * from dreport where dreport_queue = '%s'", + dbesc($outq['outq_hash']) + ); + if ($dr) { + // update every queue entry going to this site with the most recent communication error + q("update dreport set dreport_log = '%s' where dreport_site = '%s'", + dbesc(z_curl_error($result)), + dbesc($dr[0]['dreport_site']) + ); + } + } + logger('deliver: queue post returned ' . $result['return_code'] . ' from ' . $outq['outq_posturl'], LOGGER_DEBUG); + self::update($outq['outq_hash'], 10); + } + return; + } - logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG); + // normal zot delivery + + logger('deliver: dest: ' . $outq['outq_posturl'], LOGGER_DEBUG); - if($outq['outq_posturl'] === z_root() . '/zot') { - // local delivery - $zot = new Receiver(new Zot6Handler(),$outq['outq_notify']); - $result = $zot->run(); - logger('returned_json: ' . json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA); - logger('deliver: local zot delivery succeeded to ' . $outq['outq_posturl']); - Libzot::process_response($outq['outq_posturl'],[ 'success' => true, 'body' => json_encode($result) ], $outq); + if ($outq['outq_posturl'] === z_root() . '/zot') { + // local delivery + $zot = new Receiver(new Zot6Handler(), $outq['outq_notify']); + $result = $zot->run(); + logger('returned_json: ' . json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOGGER_DATA); + logger('deliver: local zot delivery succeeded to ' . $outq['outq_posturl']); + Libzot::process_response($outq['outq_posturl'], ['success' => true, 'body' => json_encode($result)], $outq); - if(! $immediate) { - $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", - dbesc($outq['outq_posturl']) - ); + if (!$immediate) { + $x = q("select outq_hash from outq where outq_posturl = '%s' and outq_delivered = 0", + dbesc($outq['outq_posturl']) + ); - $piled_up = []; - if($x) { - foreach($x as $xx) { - $piled_up[] = $xx['outq_hash']; - } - } - if($piled_up) { - do_delivery($piled_up,true); - } - } - } - else { - logger('remote'); - $channel = null; + $piled_up = []; + if ($x) { + foreach ($x as $xx) { + $piled_up[] = $xx['outq_hash']; + } + } + if ($piled_up) { + do_delivery($piled_up, true); + } + } + } else { + logger('remote'); + $channel = null; - if($outq['outq_channel']) { - $channel = channelx_by_n($outq['outq_channel'],true); - } + if ($outq['outq_channel']) { + $channel = channelx_by_n($outq['outq_channel'], true); + } - $host_crypto = null; + $host_crypto = null; - if($channel && $base) { - $h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_network = 'zot6' order by hubloc_id desc limit 1", - dbesc($base) - ); - if($h) { - $host_crypto = $h[0]; - } - } + if ($channel && $base) { + $h = q("select hubloc_sitekey, site_crypto from hubloc left join site on hubloc_url = site_url where site_url = '%s' and hubloc_network = 'zot6' order by hubloc_id desc limit 1", + dbesc($base) + ); + if ($h) { + $host_crypto = $h[0]; + } + } - $msg = $outq['outq_notify']; + $msg = $outq['outq_notify']; - $result = Libzot::zot($outq['outq_posturl'],$msg,$channel,$host_crypto); + $result = Libzot::zot($outq['outq_posturl'], $msg, $channel, $host_crypto); - if($result['success']) { - logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']); - Libzot::process_response($outq['outq_posturl'],$result, $outq); - } - else { - $dr = q("select * from dreport where dreport_queue = '%s'", - dbesc($outq['outq_hash']) - ); + if ($result['success']) { + logger('deliver: remote zot delivery succeeded to ' . $outq['outq_posturl']); + Libzot::process_response($outq['outq_posturl'], $result, $outq); + } else { + $dr = q("select * from dreport where dreport_queue = '%s'", + dbesc($outq['outq_hash']) + ); - // update every queue entry going to this site with the most recent communication error - q("update dreport set dreport_log = '%s' where dreport_site = '%s'", - dbesc(z_curl_error($result)), - dbesc($dr[0]['dreport_site']) - ); - - logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']); - logger('deliver: remote zot delivery fail data: ' . print_r($result,true), LOGGER_DATA); - self::update($outq['outq_hash'],10); - } - } - return; - } + // update every queue entry going to this site with the most recent communication error + q("update dreport set dreport_log = '%s' where dreport_site = '%s'", + dbesc(z_curl_error($result)), + dbesc($dr[0]['dreport_site']) + ); + + logger('deliver: remote zot delivery failed to ' . $outq['outq_posturl']); + logger('deliver: remote zot delivery fail data: ' . print_r($result, true), LOGGER_DATA); + self::update($outq['outq_hash'], 10); + } + } + return; + } } diff --git a/Zotlabs/Lib/SConfig.php b/Zotlabs/Lib/SConfig.php index 76e5b3af9..92161fc61 100644 --- a/Zotlabs/Lib/SConfig.php +++ b/Zotlabs/Lib/SConfig.php @@ -10,19 +10,19 @@ namespace Zotlabs\Lib; class SConfig { - static public function Load($server_id) { + public static function Load($server_id) { return XConfig::Load('s_' . $server_id); } - static public function Get($server_id,$family,$key,$default = false) { + public static function Get($server_id, $family, $key, $default = false) { return XConfig::Get('s_' . $server_id,$family,$key, $default); } - static public function Set($server_id,$family,$key,$value) { + public static function Set($server_id, $family, $key, $value) { return XConfig::Set('s_' . $server_id,$family,$key,$value); } - static public function Delete($server_id,$family,$key) { + public static function Delete($server_id, $family, $key) { return XConfig::Delete('s_' . $server_id,$family,$key); } diff --git a/Zotlabs/Lib/SvgSanitizer.php b/Zotlabs/Lib/SvgSanitizer.php index 906b4bb3e..220a7a796 100644 --- a/Zotlabs/Lib/SvgSanitizer.php +++ b/Zotlabs/Lib/SvgSanitizer.php @@ -16,141 +16,141 @@ use Zotlabs\Lib\Config; * @license http://opensource.org/licenses/mit-license.php The MIT License * @package svgsanitizer */ +class SvgSanitizer +{ -class SvgSanitizer { - - private $xmlDoc; // PHP XML DOMDocument + private $xmlDoc; // PHP XML DOMDocument - private $removedattrs = []; + private $removedattrs = []; - private static $allowed_functions = [ 'matrix', 'url', 'translate', 'rgb' ]; + private static $allowed_functions = ['matrix', 'url', 'translate', 'rgb']; - // defines the allowlist of elements and attributes allowed. - private static $allowlist = [ - 'a' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title' ], - 'circle' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ], - 'clipPath' => [ 'class', 'clipPathUnits', 'id' ], - 'defs' => [ ], - 'style' => [ 'type' ], - 'desc' => [ ], - 'ellipse' => [ 'class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ], - 'feGaussianBlur' => [ 'class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation' ], - 'filter' => [ 'class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y' ], - 'foreignObject' => [ 'class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y' ], - 'g' => [ 'class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor' ], - 'image' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y' ], - 'line' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2' ], - 'linearGradient' => [ 'class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2' ], - 'marker' => [ 'id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox' ], - 'mask' => [ 'class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y' ], - 'metadata' => [ 'class', 'id' ], - 'path' => [ 'class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ], - 'pattern' => [ 'class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y' ], - 'polygon' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ], - 'polyline' => [ 'class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform' ], - 'radialGradient' => [ 'class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href' ], - 'rect' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y' ], - 'stop' => [ 'class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage' ], - 'svg' => [ 'class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y' ], - 'switch' => [ 'class', 'id', 'requiredFeatures', 'systemLanguage' ], - 'symbol' => [ 'class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox' ], - 'text' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y' ], - 'textPath' => [ 'class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href' ], - 'title' => [ ], - 'tspan' => [ 'class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y' ], - 'use' => [ 'class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y' ], - ]; + // defines the allowlist of elements and attributes allowed. + private static $allowlist = [ + 'a' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'href', 'xlink:href', 'xlink:title'], + 'circle' => ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'], + 'clipPath' => ['class', 'clipPathUnits', 'id'], + 'defs' => [], + 'style' => ['type'], + 'desc' => [], + 'ellipse' => ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'], + 'feGaussianBlur' => ['class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation'], + 'filter' => ['class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'], + 'foreignObject' => ['class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y'], + 'g' => ['class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor'], + 'image' => ['class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y'], + 'line' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2'], + 'linearGradient' => ['class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2'], + 'marker' => ['id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox'], + 'mask' => ['class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'], + 'metadata' => ['class', 'id'], + 'path' => ['class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'], + 'pattern' => ['class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y'], + 'polygon' => ['class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'], + 'polyline' => ['class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'], + 'radialGradient' => ['class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'], + 'rect' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y'], + 'stop' => ['class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage'], + 'svg' => ['class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y'], + 'switch' => ['class', 'id', 'requiredFeatures', 'systemLanguage'], + 'symbol' => ['class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox'], + 'text' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y'], + 'textPath' => ['class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href'], + 'title' => [], + 'tspan' => ['class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y'], + 'use' => ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y'], + ]; - function __construct() { - $this->xmlDoc = new DOMDocument('1.0','UTF-8'); - $this->xmlDoc->preserveWhiteSpace = false; - libxml_use_internal_errors(true); - } + public function __construct() + { + $this->xmlDoc = new DOMDocument('1.0', 'UTF-8'); + $this->xmlDoc->preserveWhiteSpace = false; + libxml_use_internal_errors(true); + } - // load XML SVG - function load($file) { - $this->xmlDoc->load($file); - } + // load XML SVG + public function load($file) + { + $this->xmlDoc->load($file); + } - function loadXML($str) { - if (! $str) { - logger('loadxml: empty input', LOGGER_DEBUG); - return false; - } - if (! $this->xmlDoc->loadXML($str)) { - logger('loadxml: ' . print_r(array_slice(libxml_get_errors(),0,Config::Get('system','svg_backtrace_limit',3)),true), LOGGER_DEBUG); - return false; - } - return true; - } + public function loadXML($str) + { + if (!$str) { + logger('loadxml: empty input', LOGGER_DEBUG); + return false; + } + if (!$this->xmlDoc->loadXML($str)) { + logger('loadxml: ' . print_r(array_slice(libxml_get_errors(), 0, Config::Get('system', 'svg_backtrace_limit', 3)), true), LOGGER_DEBUG); + return false; + } + return true; + } - function sanitize() - { - // all elements in xml doc - $allElements = $this->xmlDoc->getElementsByTagName('*'); + public function sanitize() + { + // all elements in xml doc + $allElements = $this->xmlDoc->getElementsByTagName('*'); - // loop through all elements - for($i = 0; $i < $allElements->length; $i++) - { - $this->removedattrs = []; - - $currentNode = $allElements->item($i); + // loop through all elements + for ($i = 0; $i < $allElements->length; $i++) { + $this->removedattrs = []; - // logger('current_node: ' . print_r($currentNode,true)); + $currentNode = $allElements->item($i); - // array of allowed attributes in specific element - $allowlist_attr_arr = self::$allowlist[$currentNode->tagName]; + // logger('current_node: ' . print_r($currentNode,true)); - // does element exist in allowlist? - if(isset($allowlist_attr_arr)) { - $total = $currentNode->attributes->length; - - for($x = 0; $x < $total; $x++) { + // array of allowed attributes in specific element + $allowlist_attr_arr = self::$allowlist[$currentNode->tagName]; - // get attributes name - $attrName = $currentNode->attributes->item($x)->nodeName; + // does element exist in allowlist? + if (isset($allowlist_attr_arr)) { + $total = $currentNode->attributes->length; - // logger('checking: ' . print_r($currentNode->attributes->item($x),true)); - $matches = false; - - // check if attribute isn't in allowlist - if(! in_array($attrName, $allowlist_attr_arr)) { - $this->removedattrs[] = $attrName; - } - // check for disallowed functions - elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/', - $currentNode->attributes->item($x)->textContent,$matches,PREG_SET_ORDER)) { - if ($attrName === 'text') { - continue; - } - foreach ($matches as $match) { - if(! in_array($match[1],self::$allowed_functions)) { - logger('queue_remove_function: ' . $match[1],LOGGER_DEBUG); - $this->removedattrs[] = $attrName; - } - } - } - } - if ($this->removedattrs) { - foreach ($this->removedattrs as $attr) { - $currentNode->removeAttribute($attr); - logger('removed: ' . $attr, LOGGER_DEBUG); - } - } + for ($x = 0; $x < $total; $x++) { - } + // get attributes name + $attrName = $currentNode->attributes->item($x)->nodeName; - // else remove element - else { - logger('remove_node: ' . print_r($currentNode,true)); - $currentNode->parentNode->removeChild($currentNode); - } - } - return true; - } + // logger('checking: ' . print_r($currentNode->attributes->item($x),true)); + $matches = false; - function saveSVG() { - $this->xmlDoc->formatOutput = true; - return($this->xmlDoc->saveXML()); - } + // check if attribute isn't in allowlist + if (!in_array($attrName, $allowlist_attr_arr)) { + $this->removedattrs[] = $attrName; + } // check for disallowed functions + elseif (preg_match_all('/([a-zA-Z0-9]+)[\s]*\(/', + $currentNode->attributes->item($x)->textContent, $matches, PREG_SET_ORDER)) { + if ($attrName === 'text') { + continue; + } + foreach ($matches as $match) { + if (!in_array($match[1], self::$allowed_functions)) { + logger('queue_remove_function: ' . $match[1], LOGGER_DEBUG); + $this->removedattrs[] = $attrName; + } + } + } + } + if ($this->removedattrs) { + foreach ($this->removedattrs as $attr) { + $currentNode->removeAttribute($attr); + logger('removed: ' . $attr, LOGGER_DEBUG); + } + } + + } // else remove element + else { + logger('remove_node: ' . print_r($currentNode, true)); + $currentNode->parentNode->removeChild($currentNode); + } + } + return true; + } + + public function saveSVG() + { + $this->xmlDoc->formatOutput = true; + return ($this->xmlDoc->saveXML()); + } } diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php index 672d7da0e..968729aef 100644 --- a/Zotlabs/Lib/System.php +++ b/Zotlabs/Lib/System.php @@ -6,19 +6,19 @@ use App; class System { - static public function get_platform_name() { + public static function get_platform_name() { if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('platform_name',App::$config['system'])) return App::$config['system']['platform_name']; return PLATFORM_NAME; } - static public function get_site_name() { + public static function get_site_name() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['sitename']) return App::$config['system']['sitename']; return ''; } - static public function get_banner() { + public static function get_banner() { if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('banner',App::$config['system']) && App::$config['system']['banner']) { return App::$config['system']['banner']; @@ -26,14 +26,14 @@ class System { return self::get_site_name(); } - static public function get_project_icon() { + public static function get_project_icon() { if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('icon',App::$config['system'])) { return App::$config['system']['icon']; } return z_root() . '/images/' . PLATFORM_NAME . '-64.png'; } - static public function get_project_favicon() { + public static function get_project_favicon() { if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('favicon',App::$config['system'])) { return App::$config['system']['favicon']; } @@ -41,7 +41,7 @@ class System { } - static public function get_project_version() { + public static function get_project_version() { if(array_path_exists('system/hide_version', App::$config) && intval(App::$config['system']['hide_version'])) return ''; if(is_array(App::$config) && is_array(App::$config['system']) && array_key_exists('std_version',App::$config['system'])) @@ -50,63 +50,63 @@ class System { return self::get_std_version(); } - static public function get_update_version() { + public static function get_update_version() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['hide_version']) return EMPTY_STR; return DB_UPDATE_VERSION; } - static public function get_notify_icon() { + public static function get_notify_icon() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['email_notify_icon_url']) return App::$config['system']['email_notify_icon_url']; return self::get_project_icon(); } - static public function get_site_icon() { + public static function get_site_icon() { if(is_array(App::$config) && is_array(App::$config['system']) && isset(App::$config['system']['site_icon_url']) && App::$config['system']['site_icon_url']) return App::$config['system']['site_icon_url']; return self::get_project_icon(); } - static public function get_site_favicon() { + public static function get_site_favicon() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['site_favicon_url']) return App::$config['system']['site_favicon_url']; return self::get_project_favicon(); } - static public function get_project_link() { + public static function get_project_link() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['project_link']) return App::$config['system']['project_link']; return 'https://zotlabs.com/' . PLATFORM_NAME; } - static public function get_project_srclink() { + public static function get_project_srclink() { if(is_array(App::$config) && is_array(App::$config['system']) && App::$config['system']['project_srclink']) return App::$config['system']['project_srclink']; return 'https://codeberg.org/zot/' . PLATFORM_NAME; } - static public function ebs() { + public static function ebs() { if(defined('EBSSTATE')) { return EBSSTATE; } return 'armed'; } - static public function get_zot_revision() { + public static function get_zot_revision() { $x = [ 'revision' => ZOT_REVISION ]; call_hooks('zot_revision',$x); return $x['revision']; } - static public function get_std_version() { + public static function get_std_version() { if(defined('STD_VERSION')) return STD_VERSION; return '0.0.0'; } - static public function compatible_project($p) { + public static function compatible_project($p) { if (in_array(strtolower($p),['hubzilla', 'zap', 'red', 'misty', 'mistpark', 'redmatrix', 'osada', 'roadhouse'])) { return true; diff --git a/Zotlabs/Lib/ThreadListener.php b/Zotlabs/Lib/ThreadListener.php index 308e02255..ed2ed8f48 100644 --- a/Zotlabs/Lib/ThreadListener.php +++ b/Zotlabs/Lib/ThreadListener.php @@ -4,7 +4,7 @@ namespace Zotlabs\Lib; class ThreadListener { - static public function store($target_id,$portable_id,$ltype = 0) { + public static function store($target_id, $portable_id, $ltype = 0) { $x = self::fetch($target_id,$portable_id,$ltype = 0); if(! $x) { $r = q("insert into listeners ( target_id, portable_id, ltype ) values ( '%s', '%s' , %d ) ", @@ -15,7 +15,7 @@ class ThreadListener { } } - static public function fetch($target_id,$portable_id,$ltype = 0) { + public static function fetch($target_id, $portable_id, $ltype = 0) { $x = q("select * from listeners where target_id = '%s' and portable_id = '%s' and ltype = %d limit 1", dbesc($target_id), dbesc($portable_id), @@ -27,7 +27,7 @@ class ThreadListener { return false; } - static public function fetch_by_target($target_id,$ltype = 0) { + public static function fetch_by_target($target_id, $ltype = 0) { $x = q("select * from listeners where target_id = '%s' and ltype = %d", dbesc($target_id), intval($ltype) @@ -36,14 +36,14 @@ class ThreadListener { return $x; } - static public function delete_by_target($target_id, $ltype = 0) { + public static function delete_by_target($target_id, $ltype = 0) { return q("delete from listeners where target_id = '%s' and ltype = %d", dbesc($target_id), intval($ltype) ); } - static public function delete_by_pid($portable_id, $ltype = 0) { + public static function delete_by_pid($portable_id, $ltype = 0) { return q("delete from listeners where portable_id = '%s' and ltype = %d", dbesc($portable_id), intval($ltype) diff --git a/Zotlabs/Lib/Verify.php b/Zotlabs/Lib/Verify.php index d1f39d513..e1b8f9b2a 100644 --- a/Zotlabs/Lib/Verify.php +++ b/Zotlabs/Lib/Verify.php @@ -3,61 +3,66 @@ namespace Zotlabs\Lib; -class Verify { +class Verify +{ - static function create($type,$channel_id,$token,$meta) { - return q("insert into verify ( vtype, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )", - dbesc($type), - intval($channel_id), - dbesc($token), - dbesc($meta), - dbesc(datetime_convert()) - ); - } + public static function create($type, $channel_id, $token, $meta) + { + return q("insert into verify ( vtype, channel, token, meta, created ) values ( '%s', %d, '%s', '%s', '%s' )", + dbesc($type), + intval($channel_id), + dbesc($token), + dbesc($meta), + dbesc(datetime_convert()) + ); + } - static function match($type,$channel_id,$token,$meta) { - $r = q("select id from verify where vtype = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1", - dbesc($type), - intval($channel_id), - dbesc($token), - dbesc($meta) - ); - if($r) { - q("delete from verify where id = %d", - intval($r[0]['id']) - ); - return true; - } - return false; - } + public static function match($type, $channel_id, $token, $meta) + { + $r = q("select id from verify where vtype = '%s' and channel = %d and token = '%s' and meta = '%s' limit 1", + dbesc($type), + intval($channel_id), + dbesc($token), + dbesc($meta) + ); + if ($r) { + q("delete from verify where id = %d", + intval($r[0]['id']) + ); + return true; + } + return false; + } - static function get_meta($type,$channel_id,$token) { - $r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1", - dbesc($type), - intval($channel_id), - dbesc($token) - ); - if($r) { - q("delete from verify where id = %d", - intval($r[0]['id']) - ); - return $r[0]['meta']; - } - return false; - } + public static function get_meta($type, $channel_id, $token) + { + $r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1", + dbesc($type), + intval($channel_id), + dbesc($token) + ); + if ($r) { + q("delete from verify where id = %d", + intval($r[0]['id']) + ); + return $r[0]['meta']; + } + return false; + } - /** - * @brief Purge entries of a verify-type older than interval. - * - * @param string $type Verify type - * @param string $interval SQL compatible time interval - */ - static function purge($type, $interval) { - q("delete from verify where vtype = '%s' and created < ( %s - INTERVAL %s )", - dbesc($type), - db_utcnow(), - db_quoteinterval($interval) - ); - } + /** + * @brief Purge entries of a verify-type older than interval. + * + * @param string $type Verify type + * @param string $interval SQL compatible time interval + */ + public static function purge($type, $interval) + { + q("delete from verify where vtype = '%s' and created < ( %s - INTERVAL %s )", + dbesc($type), + db_utcnow(), + db_quoteinterval($interval) + ); + } } \ No newline at end of file diff --git a/Zotlabs/Lib/Webfinger.php b/Zotlabs/Lib/Webfinger.php index 4ee9bfff6..fa7aac96c 100644 --- a/Zotlabs/Lib/Webfinger.php +++ b/Zotlabs/Lib/Webfinger.php @@ -6,104 +6,103 @@ namespace Zotlabs\Lib; * @brief Fetch and return a webfinger for a resource * * @param string $resource - The resource - * @return boolean|string false or associative array from result JSON + * @return bool|string false or associative array from result JSON */ +class Webfinger +{ -class Webfinger { + private static $server = EMPTY_STR; + private static $resource = EMPTY_STR; - static private $server = EMPTY_STR; - static private $resource = EMPTY_STR; + public static function exec($resource) + { - static function exec($resource) { + if (!$resource) { + return false; + } - if (! $resource) { - return false; - } + self::parse_resource($resource); - self::parse_resource($resource); + if (!(self::$server && self::$resource)) { + return false; + } - if (! ( self::$server && self::$resource)) { - return false; - } + if (!check_siteallowed(self::$server)) { + logger('denied: ' . self::$server); + return false; + } - if (! check_siteallowed(self::$server)) { - logger('denied: ' . self::$server); - return false; - } + logger('fetching resource: ' . self::$resource . ' from ' . self::$server, LOGGER_DEBUG, LOG_INFO); - logger('fetching resource: ' . self::$resource . ' from ' . self::$server, LOGGER_DEBUG, LOG_INFO); + $url = 'https://' . self::$server . '/.well-known/webfinger?f=&resource=' . self::$resource; - $url = 'https://' . self::$server . '/.well-known/webfinger?f=&resource=' . self::$resource ; + $counter = 0; + $s = z_fetch_url($url, false, $counter, ['headers' => ['Accept: application/jrd+json, */*']]); - $counter = 0; - $s = z_fetch_url($url, false, $counter, [ 'headers' => [ 'Accept: application/jrd+json, */*' ] ]); + if ($s['success']) { + $j = json_decode($s['body'], true); + return ($j); + } - if ($s['success']) { - $j = json_decode($s['body'], true); - return($j); - } + return false; + } - return false; - } + public static function parse_resource($resource) + { - static function parse_resource($resource) { + self::$resource = urlencode($resource); - self::$resource = urlencode($resource); + if (strpos($resource, 'http') === 0) { + $m = parse_url($resource); + if ($m) { + if ($m['scheme'] !== 'https') { + return false; + } + self::$server = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); + } else { + return false; + } + } elseif (strpos($resource, 'tag:') === 0) { + $arr = explode(':', $resource); // split the tag + $h = explode(',', $arr[1]); // split the host,date + self::$server = $h[0]; + } else { + $x = explode('@', $resource); + if (!strlen($x[0])) { + // e.g. @dan@pixelfed.org + array_shift($x); + } + $username = $x[0]; + if (count($x) > 1) { + self::$server = $x[1]; + } else { + return false; + } + if (strpos($resource, 'acct:') !== 0) { + self::$resource = urlencode('acct:' . $resource); + } + } + } - if (strpos($resource,'http') === 0) { - $m = parse_url($resource); - if ($m) { - if ($m['scheme'] !== 'https') { - return false; - } - self::$server = $m['host'] . (($m['port']) ? ':' . $m['port'] : ''); - } - else { - return false; - } - } - elseif (strpos($resource,'tag:') === 0) { - $arr = explode(':',$resource); // split the tag - $h = explode(',',$arr[1]); // split the host,date - self::$server = $h[0]; - } - else { - $x = explode('@',$resource); - if (! strlen($x[0])) { - // e.g. @dan@pixelfed.org - array_shift($x); - } - $username = $x[0]; - if (count($x) > 1) { - self::$server = $x[1]; - } - else { - return false; - } - if (strpos($resource,'acct:') !== 0) { - self::$resource = urlencode('acct:' . $resource); - } - } - } + /** + * @brief fetch a webfinger resource and return a zot6 discovery url if present + * + */ - /** - * @brief fetch a webfinger resource and return a zot6 discovery url if present - * - */ + public static function zot_url($resource) + { - static function zot_url($resource) { + $arr = self::exec($resource); - $arr = self::exec($resource); - - if (is_array($arr) && array_key_exists('links',$arr)) { - foreach ($arr['links'] as $link) { - if (array_key_exists('rel',$link) && $link['rel'] === PROTOCOL_ZOT6) { - if (array_key_exists('href',$link) && $link['href'] !== EMPTY_STR) { - return $link['href']; - } - } - } - } - return false; - } + if (is_array($arr) && array_key_exists('links', $arr)) { + foreach ($arr['links'] as $link) { + if (array_key_exists('rel', $link) && $link['rel'] === PROTOCOL_ZOT6) { + if (array_key_exists('href', $link) && $link['href'] !== EMPTY_STR) { + return $link['href']; + } + } + } + } + return false; + } } \ No newline at end of file diff --git a/Zotlabs/Lib/XConfig.php b/Zotlabs/Lib/XConfig.php index 79e442d5a..0b20b7b5c 100644 --- a/Zotlabs/Lib/XConfig.php +++ b/Zotlabs/Lib/XConfig.php @@ -36,7 +36,7 @@ class XConfig { * The observer's hash * @return void|false Returns false if xchan is not set */ - static public function Load($xchan) { + public static function Load($xchan) { if(! $xchan) return false; @@ -76,10 +76,10 @@ class XConfig { * The category of the configuration value * @param string $key * The configuration key to query - * @param boolean $default (optional) default false + * @param bool $default (optional) default false * @return mixed Stored $value or false if it does not exist */ - static public function Get($xchan, $family, $key, $default = false) { + public static function Get($xchan, $family, $key, $default = false) { if(! $xchan) return $default; @@ -109,7 +109,7 @@ class XConfig { * The value to store * @return mixed Stored $value or false */ - static public function Set($xchan, $family, $key, $value) { + public static function Set($xchan, $family, $key, $value) { // manage array value $dbvalue = ((is_array($value)) ? serialise($value) : $value); @@ -159,7 +159,7 @@ class XConfig { * The configuration key to delete * @return mixed */ - static public function Delete($xchan, $family, $key) { + public static function Delete($xchan, $family, $key) { if(isset(App::$config[$xchan]) && isset(App::$config[$xchan][$family]) && isset(App::$config[$xchan][$family][$key])) unset(App::$config[$xchan][$family][$key]); diff --git a/Zotlabs/Lib/ZotURL.php b/Zotlabs/Lib/ZotURL.php index 531aebf24..5110410dc 100644 --- a/Zotlabs/Lib/ZotURL.php +++ b/Zotlabs/Lib/ZotURL.php @@ -7,7 +7,7 @@ use Zotlabs\Web\HTTPSig; class ZotURL { - static public function fetch($url,$channel,$hub = null) { + public static function fetch($url, $channel, $hub = null) { $ret = [ 'success' => false ]; @@ -66,7 +66,7 @@ class ZotURL { } - static public function is_zoturl($s) { + public static function is_zoturl($s) { if(strpos($url,'x-zot:') === 0) { return true; @@ -75,7 +75,7 @@ class ZotURL { } - static public function lookup($portable_id,$hub) { + public static function lookup($portable_id, $hub) { $r = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0 order by hubloc_primary desc", dbesc($portable_id) @@ -107,7 +107,7 @@ class ZotURL { } - static public function parse_response($arr) { + public static function parse_response($arr) { if(! $arr['success']) { return false; } diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php index 272003941..9ebc7e0c8 100644 --- a/Zotlabs/Lib/Zotfinger.php +++ b/Zotlabs/Lib/Zotfinger.php @@ -4,60 +4,61 @@ namespace Zotlabs\Lib; use Zotlabs\Web\HTTPSig; -class Zotfinger { +class Zotfinger +{ - static function exec($resource,$channel = null,$verify = true) { + public static function exec($resource, $channel = null, $verify = true) + { - if (! $resource) { - return false; - } + if (!$resource) { + return false; + } - $m = parse_url($resource); - - if ($m['host'] !== punify($m['host'])) { - $url = str_replace($m['host'],punify($m['host']),$url); - $m['host'] = punify($m['host']); - } + $m = parse_url($resource); - $data = json_encode([ 'zot_token' => random_string() ]); + if ($m['host'] !== punify($m['host'])) { + $url = str_replace($m['host'], punify($m['host']), $url); + $m['host'] = punify($m['host']); + } - if ($channel && $m) { + $data = json_encode(['zot_token' => random_string()]); - $headers = [ - 'Accept' => 'application/x-zot+json', - 'Content-Type' => 'application/x-zot+json', - 'X-Zot-Token' => random_string(), - 'Digest' => HTTPSig::generate_digest_header($data), - 'Host' => $m['host'], - '(request-target)' => 'post ' . get_request_string($resource) - ]; - $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false); - } - else { - $h = [ 'Accept: application/x-zot+json' ]; - } - - $result = []; + if ($channel && $m) { - $redirects = 0; - $x = z_post_url($resource,$data,$redirects, [ 'headers' => $h ] ); + $headers = [ + 'Accept' => 'application/x-zot+json', + 'Content-Type' => 'application/x-zot+json', + 'X-Zot-Token' => random_string(), + 'Digest' => HTTPSig::generate_digest_header($data), + 'Host' => $m['host'], + '(request-target)' => 'post ' . get_request_string($resource) + ]; + $h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), false); + } else { + $h = ['Accept: application/x-zot+json']; + } - if ($x['success']) { + $result = []; - if ($verify) { - $result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6'); - } - - $result['data'] = json_decode($x['body'],true); + $redirects = 0; + $x = z_post_url($resource, $data, $redirects, ['headers' => $h]); - if ($result['data'] && is_array($result['data']) && array_key_exists('encrypted',$result['data']) && $result['data']['encrypted']) { - $result['data'] = json_decode(Crypto::unencapsulate($result['data'],get_config('system','prvkey')),true); - } + if ($x['success']) { - return $result; - } + if ($verify) { + $result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6'); + } - return false; - } + $result['data'] = json_decode($x['body'], true); + + if ($result['data'] && is_array($result['data']) && array_key_exists('encrypted', $result['data']) && $result['data']['encrypted']) { + $result['data'] = json_decode(Crypto::unencapsulate($result['data'], get_config('system', 'prvkey')), true); + } + + return $result; + } + + return false; + } } \ No newline at end of file diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php index da6c50e75..76661a00d 100644 --- a/Zotlabs/Module/Acl.php +++ b/Zotlabs/Module/Acl.php @@ -23,101 +23,100 @@ require_once('include/acl_selectors.php'); * keys however this functionality has grown in an ad-hoc manner and has gotten * quite messy over time. */ - -class Acl extends Controller { +class Acl extends Controller +{ - function init() { + public function init() + { - // logger('mod_acl: ' . print_r($_REQUEST,true),LOGGER_DATA); + // logger('mod_acl: ' . print_r($_REQUEST,true),LOGGER_DATA); - $start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0); - $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500); - $search = (x($_REQUEST,'search') ? $_REQUEST['search'] : ''); - $type = (x($_REQUEST,'type') ? $_REQUEST['type'] : ''); - $noforums = (x($_REQUEST,'n') ? $_REQUEST['n'] : false); + $start = (x($_REQUEST, 'start') ? $_REQUEST['start'] : 0); + $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 500); + $search = (x($_REQUEST, 'search') ? $_REQUEST['search'] : ''); + $type = (x($_REQUEST, 'type') ? $_REQUEST['type'] : ''); + $noforums = (x($_REQUEST, 'n') ? $_REQUEST['n'] : false); - // $type = - // '' => standard ACL request - // 'g' => Groups only ACL request - // 'f' => forums only ACL request - // 'c' => Connections only ACL request or editor (textarea) mention request - // $_REQUEST['search'] contains ACL search text. + // $type = + // '' => standard ACL request + // 'g' => Groups only ACL request + // 'f' => forums only ACL request + // 'c' => Connections only ACL request or editor (textarea) mention request + // $_REQUEST['search'] contains ACL search text. - // $type = - // 'm' => autocomplete private mail recipient (checks post_mail permission) - // 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos) - // 'x' => nav search bar autocomplete (match any xchan) - // 'z' => autocomplete any xchan, but also include abook_alias, requires non-zero local_channel() - // and also contains xid without urlencode, used specifically by activity_filter widget - // $_REQUEST['query'] contains autocomplete search text. - - - // The different autocomplete libraries use different names for the search text - // parameter. Internally we'll use $search to represent the search text no matter - // what request variable it was attached to. - - if (array_key_exists('query',$_REQUEST)) { - $search = $_REQUEST['query']; - } - - if ( (! local_channel()) && (! in_array($type, [ 'x', 'c', 'f' ]))) { - killme(); - } - - $permitted = []; - - if (in_array($type, [ 'm', 'a', 'f' ])) { - - // These queries require permission checking. We'll create a simple array of xchan_hash for those with - // the requisite permissions which we can check against. - - $x = q("select xchan from abconfig where chan = %d and cat = 'system' and k = 'their_perms' and v like '%s'", - intval(local_channel()), - dbesc(($type === 'm') ? '%post_mail%' : '%tag_deliver%') - ); - - $permitted = ids_to_array($x,'xchan'); - } + // $type = + // 'm' => autocomplete private mail recipient (checks post_mail permission) + // 'a' => autocomplete connections (mod_connections, mod_poke, mod_sources, mod_photos) + // 'x' => nav search bar autocomplete (match any xchan) + // 'z' => autocomplete any xchan, but also include abook_alias, requires non-zero local_channel() + // and also contains xid without urlencode, used specifically by activity_filter widget + // $_REQUEST['query'] contains autocomplete search text. - if ($search) { - $sql_extra = " AND pgrp.gname LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " "; - // sql_extra2 is typically used when we don't have a local_channel - so we are not search abook_alias - $sql_extra2 = " AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . ") "; + // The different autocomplete libraries use different names for the search text + // parameter. Internally we'll use $search to represent the search text no matter + // what request variable it was attached to. + + if (array_key_exists('query', $_REQUEST)) { + $search = $_REQUEST['query']; + } + + if ((!local_channel()) && (!in_array($type, ['x', 'c', 'f']))) { + killme(); + } + + $permitted = []; + + if (in_array($type, ['m', 'a', 'f'])) { + + // These queries require permission checking. We'll create a simple array of xchan_hash for those with + // the requisite permissions which we can check against. + + $x = q("select xchan from abconfig where chan = %d and cat = 'system' and k = 'their_perms' and v like '%s'", + intval(local_channel()), + dbesc(($type === 'm') ? '%post_mail%' : '%tag_deliver%') + ); + + $permitted = ids_to_array($x, 'xchan'); + } - - // This horrible mess is needed because position also returns 0 if nothing is found. - // Would be MUCH easier if it instead returned a very large value - // Otherwise we could just - // order by LEAST(POSITION($search IN xchan_name),POSITION($search IN xchan_addr)). - - $order_extra2 = "CASE WHEN xchan_name LIKE " - . protect_sprintf( "'%" . dbesc($search) . "%'" ) - . " then POSITION('" . protect_sprintf(dbesc($search)) - . "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, "; - - $sql_extra3 = "AND ( xchan_addr like " . protect_sprintf( "'%" . dbesc(punify($search)) . "%'" ) . " OR xchan_name like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR abook_alias like " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " ) "; - - $sql_extra4 = "AND ( xchan_name LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'" ) . " OR xchan_addr LIKE " . protect_sprintf( "'%" . dbesc(punify($search)) . ((strpos($search,'@') === false) ? "%@%'" : "%'")) . " OR abook_alias LIKE " . protect_sprintf( "'%" . dbesc($search) . "%'") . ") "; + if ($search) { + $sql_extra = " AND pgrp.gname LIKE " . protect_sprintf("'%" . dbesc($search) . "%'") . " "; + // sql_extra2 is typically used when we don't have a local_channel - so we are not search abook_alias + $sql_extra2 = " AND ( xchan_name LIKE " . protect_sprintf("'%" . dbesc($search) . "%'") . " OR xchan_addr LIKE " . protect_sprintf("'%" . dbesc(punify($search)) . ((strpos($search, '@') === false) ? "%@%'" : "%'")) . ") "; - } - else { - $sql_extra = $sql_extra2 = $sql_extra3 = $sql_extra4 = ""; - } - - - $groups = []; - $contacts = []; - - if ($type == '' || $type == 'g') { + // This horrible mess is needed because position also returns 0 if nothing is found. + // Would be MUCH easier if it instead returned a very large value + // Otherwise we could just + // order by LEAST(POSITION($search IN xchan_name),POSITION($search IN xchan_addr)). - // Normal privacy groups + $order_extra2 = "CASE WHEN xchan_name LIKE " + . protect_sprintf("'%" . dbesc($search) . "%'") + . " then POSITION('" . protect_sprintf(dbesc($search)) + . "' IN xchan_name) else position('" . protect_sprintf(dbesc(punify($search))) . "' IN xchan_addr) end, "; - $r = q("SELECT pgrp.id, pgrp.hash, pgrp.gname + $sql_extra3 = "AND ( xchan_addr like " . protect_sprintf("'%" . dbesc(punify($search)) . "%'") . " OR xchan_name like " . protect_sprintf("'%" . dbesc($search) . "%'") . " OR abook_alias like " . protect_sprintf("'%" . dbesc($search) . "%'") . " ) "; + + $sql_extra4 = "AND ( xchan_name LIKE " . protect_sprintf("'%" . dbesc($search) . "%'") . " OR xchan_addr LIKE " . protect_sprintf("'%" . dbesc(punify($search)) . ((strpos($search, '@') === false) ? "%@%'" : "%'")) . " OR abook_alias LIKE " . protect_sprintf("'%" . dbesc($search) . "%'") . ") "; + + + } else { + $sql_extra = $sql_extra2 = $sql_extra3 = $sql_extra4 = ""; + } + + + $groups = []; + $contacts = []; + + if ($type == '' || $type == 'g') { + + // Normal privacy groups + + $r = q("SELECT pgrp.id, pgrp.hash, pgrp.gname FROM pgrp, pgrp_member WHERE pgrp.deleted = 0 AND pgrp.uid = %d AND pgrp_member.gid = pgrp.id @@ -125,238 +124,232 @@ class Acl extends Controller { GROUP BY pgrp.id ORDER BY pgrp.gname LIMIT %d OFFSET %d", - intval(local_channel()), - intval($count), - intval($start) - ); + intval(local_channel()), + intval($count), + intval($start) + ); - if ($r) { - foreach ($r as $g) { - // logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(),$g['id'])); - $groups[] = [ - "type" => "g", - "photo" => "images/twopeople.png", - "name" => $g['gname'], - "id" => $g['id'], - "xid" => $g['hash'], - "uids" => AccessList::members_xchan(local_channel(),$g['id']), - "link" => '' - ]; - } - } - } - - if ($type == '' || $type == 'c' || $type === 'f') { + if ($r) { + foreach ($r as $g) { + // logger('acl: group: ' . $g['gname'] . ' members: ' . AccessList::members_xchan(local_channel(),$g['id'])); + $groups[] = [ + "type" => "g", + "photo" => "images/twopeople.png", + "name" => $g['gname'], + "id" => $g['id'], + "xid" => $g['hash'], + "uids" => AccessList::members_xchan(local_channel(), $g['id']), + "link" => '' + ]; + } + } + } - // Getting info from the abook is better for local users because it contains info about permissions - if (local_channel()) { + if ($type == '' || $type == 'c' || $type === 'f') { - // add connections + // Getting info from the abook is better for local users because it contains info about permissions + if (local_channel()) { - $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, xchan_type, abook_flags, abook_self + // add connections + + $r = q("SELECT abook_id as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, xchan_type, abook_flags, abook_self FROM abook left join xchan on abook_xchan = xchan_hash - WHERE abook_channel = %d AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra4 order by xchan_name asc limit $count" , - intval(local_channel()) - ); + WHERE abook_channel = %d AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 $sql_extra4 order by xchan_name asc limit $count", + intval(local_channel()) + ); - } - else { // Visitors - $r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_flags, 0 as abook_self + } else { // Visitors + $r = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_flags, 0 as abook_self FROM xchan left join xlink on xlink_link = xchan_hash - WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc limit $count" , - dbesc(get_observer_hash()) - ); - - } - if ((count($r) < 100) && $type == 'c') { - $r2 = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_flags, 0 as abook_self - FROM xchan WHERE xchan_deleted = 0 and xchan_network != 'unknown' $sql_extra2 order by $order_extra2 xchan_name asc limit $count" - ); - if ($r2) { - $r = array_merge($r,$r2); - $r = unique_multidim_array($r,'hash'); - } - } + WHERE xlink_xchan = '%s' AND xchan_deleted = 0 $sql_extra2 order by $order_extra2 xchan_name asc limit $count", + dbesc(get_observer_hash()) + ); - } - elseif ($type == 'm') { + } + if ((count($r) < 100) && $type == 'c') { + $r2 = q("SELECT xchan_hash as id, xchan_hash as hash, xchan_name as name, xchan_photo_s as micro, xchan_url as url, xchan_addr as nick, 0 as abook_flags, 0 as abook_self + FROM xchan WHERE xchan_deleted = 0 and xchan_network != 'unknown' $sql_extra2 order by $order_extra2 xchan_name asc limit $count" + ); + if ($r2) { + $r = array_merge($r, $r2); + $r = unique_multidim_array($r, 'hash'); + } + } - $r = []; - $z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url + } elseif ($type == 'm') { + + $r = []; + $z = q("SELECT xchan_hash as hash, xchan_name as name, xchan_addr as nick, xchan_photo_s as micro, xchan_url as url FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and xchan_deleted = 0 $sql_extra3 ORDER BY xchan_name ASC ", - intval(local_channel()) - ); - if ($z) { - foreach ($z as $zz) { - if (in_array($zz['hash'],$permitted)) { - $r[] = $zz; - } - } - } - - } - elseif ($type == 'a') { - - $r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag FROM abook left join xchan on abook_xchan = xchan_hash + intval(local_channel()) + ); + if ($z) { + foreach ($z as $zz) { + if (in_array($zz['hash'], $permitted)) { + $r[] = $zz; + } + } + } + + } elseif ($type == 'a') { + + $r = q("SELECT abook_id as id, xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and xchan_deleted = 0 $sql_extra3 ORDER BY xchan_name ASC ", - intval(local_channel()) - ); - - } - elseif ($type == 'z') { - $r = q("SELECT xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag FROM xchan left join abook on xchan_hash = abook_xchan + intval(local_channel()) + ); + + } elseif ($type == 'z') { + $r = q("SELECT xchan_name as name, xchan_hash as hash, xchan_addr as nick, xchan_photo_s as micro, xchan_network as network, xchan_url as url, xchan_addr as attag FROM xchan left join abook on xchan_hash = abook_xchan WHERE ( abook_channel = %d OR abook_channel IS NULL ) and xchan_deleted = 0 $sql_extra3 ORDER BY xchan_name ASC ", - intval(local_channel()) - ); - } + intval(local_channel()) + ); + } elseif ($type == 'x') { + $contacts = []; + $r = $this->navbar_complete(); + if ($r) { + foreach ($r as $g) { + $contacts[] = [ + "photo" => $g['photo'], + "name" => $g['name'], + "nick" => $g['address'], + 'link' => (($g['address']) ? $g['address'] : $g['url']), + 'xchan' => $g['hash'] + ]; + } + } - elseif ($type == 'x') { - $contacts = []; - $r = $this->navbar_complete(); - if ($r) { - foreach ($r as $g) { - $contacts[] = [ - "photo" => $g['photo'], - "name" => $g['name'], - "nick" => $g['address'], - 'link' => (($g['address']) ? $g['address'] : $g['url']), - 'xchan' => $g['hash'] - ]; - } - } - - $o = [ - 'start' => $start, - 'count' => $count, - 'items' => $contacts, - ]; - json_return_and_die($o); - } - else { - $r = []; - } - - if ($r) { - foreach ($r as $g) { - - if (isset($g['network']) && in_array($g['network'],['rss','anon','unknown']) && ($type != 'a')) { - continue; - } + $o = [ + 'start' => $start, + 'count' => $count, + 'items' => $contacts, + ]; + json_return_and_die($o); + } else { + $r = []; + } - // 'z' (activity_filter autocomplete) requires an un-encoded hash to prevent double encoding - - if ($type !== 'z') { - $g['hash'] = urlencode($g['hash']); - } - - if (! $g['nick']) { - $g['nick'] = $g['url']; - } + if ($r) { + foreach ($r as $g) { - if (in_array($g['hash'],$permitted) && $type === 'f' && (! $noforums)) { - $contacts[] = [ - "type" => "c", - "photo" => "images/twopeople.png", - "name" => $g['name'], - "id" => urlencode($g['id']), - "xid" => $g['hash'], - "link" => (($g['nick']) ? $g['nick'] : $g['url']), - "nick" => substr($g['nick'],0,strpos($g['nick'],'@')), - "self" => (intval($g['abook_self']) ? 'abook-self' : ''), - "taggable" => 'taggable', - "label" => t('network') - ]; - } - if ($type !== 'f') { - $contacts[] = [ - "type" => "c", - "photo" => $g['micro'], - "name" => $g['name'], - "id" => urlencode($g['id']), - "xid" => $g['hash'], - "link" => (($g['nick']) ? $g['nick'] : $g['url']), - "nick" => ((strpos($g['nick'],'@')) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']), - "self" => (intval($g['abook_self']) ? 'abook-self' : ''), - "taggable" => '', - "label" => '', - ]; - } - } - } - - $items = array_merge($groups, $contacts); - - $o = [ - 'start' => $start, - 'count' => $count, - 'items' => $items, - ]; + if (isset($g['network']) && in_array($g['network'], ['rss', 'anon', 'unknown']) && ($type != 'a')) { + continue; + } - json_return_and_die($o); - } + // 'z' (activity_filter autocomplete) requires an un-encoded hash to prevent double encoding + + if ($type !== 'z') { + $g['hash'] = urlencode($g['hash']); + } + + if (!$g['nick']) { + $g['nick'] = $g['url']; + } + + if (in_array($g['hash'], $permitted) && $type === 'f' && (!$noforums)) { + $contacts[] = [ + "type" => "c", + "photo" => "images/twopeople.png", + "name" => $g['name'], + "id" => urlencode($g['id']), + "xid" => $g['hash'], + "link" => (($g['nick']) ? $g['nick'] : $g['url']), + "nick" => substr($g['nick'], 0, strpos($g['nick'], '@')), + "self" => (intval($g['abook_self']) ? 'abook-self' : ''), + "taggable" => 'taggable', + "label" => t('network') + ]; + } + if ($type !== 'f') { + $contacts[] = [ + "type" => "c", + "photo" => $g['micro'], + "name" => $g['name'], + "id" => urlencode($g['id']), + "xid" => $g['hash'], + "link" => (($g['nick']) ? $g['nick'] : $g['url']), + "nick" => ((strpos($g['nick'], '@')) ? substr($g['nick'], 0, strpos($g['nick'], '@')) : $g['nick']), + "self" => (intval($g['abook_self']) ? 'abook-self' : ''), + "taggable" => '', + "label" => '', + ]; + } + } + } + + $items = array_merge($groups, $contacts); + + $o = [ + 'start' => $start, + 'count' => $count, + 'items' => $items, + ]; + + json_return_and_die($o); + } - function navbar_complete() { - - // logger('navbar_complete'); - - if (observer_prohibited()) { - return; - } - - $dirmode = intval(get_config('system','directory_mode')); - $search = ((x($_REQUEST,'search')) ? htmlentities($_REQUEST['search'],ENT_COMPAT,'UTF-8',false) : ''); - if (! $search || mb_strlen($search) < 2) { - return []; - } - - $star = false; - $address = false; - - if (substr($search,0,1) === '@') { - $search = substr($search,1); - } - - if (substr($search,0,1) === '*') { - $star = true; - $search = substr($search,1); - } + public function navbar_complete() + { - if (strpos($search,'@') !== false) { - $address = true; - } + // logger('navbar_complete'); - - $url = z_root() . '/dirsearch'; + if (observer_prohibited()) { + return; + } - - $results = []; + $dirmode = intval(get_config('system', 'directory_mode')); + $search = ((x($_REQUEST, 'search')) ? htmlentities($_REQUEST['search'], ENT_COMPAT, 'UTF-8', false) : ''); + if (!$search || mb_strlen($search) < 2) { + return []; + } - $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100); + $star = false; + $address = false; - if ($url) { - $query = $url . '?f='; - $query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : ''); - - $x = z_fetch_url($query); - if ($x['success']) { - $t = 0; - $j = json_decode($x['body'],true); - if ($j && $j['results']) { - $results = $j['results']; - } - } - } - return $results; - } + if (substr($search, 0, 1) === '@') { + $search = substr($search, 1); + } + + if (substr($search, 0, 1) === '*') { + $star = true; + $search = substr($search, 1); + } + + if (strpos($search, '@') !== false) { + $address = true; + } + + + $url = z_root() . '/dirsearch'; + + + $results = []; + + $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 100); + + if ($url) { + $query = $url . '?f='; + $query .= '&name=' . urlencode($search) . "&limit=$count" . (($address) ? '&address=' . urlencode(punify($search)) : ''); + + $x = z_fetch_url($query); + if ($x['success']) { + $t = 0; + $j = json_decode($x['body'], true); + if ($j && $j['results']) { + $results = $j['results']; + } + } + } + return $results; + } } diff --git a/Zotlabs/Module/Activity.php b/Zotlabs/Module/Activity.php index 71c896a5d..1051ace07 100644 --- a/Zotlabs/Module/Activity.php +++ b/Zotlabs/Module/Activity.php @@ -10,280 +10,280 @@ use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\ThreadListener; use App; -class Activity extends Controller { +class Activity extends Controller +{ - function init() { + public function init() + { - - if (ActivityStreams::is_as_request()) { - $item_id = argv(1); - if (! $item_id) { - return; - } + if (ActivityStreams::is_as_request()) { + $item_id = argv(1); - $ob_authorise = false; - $item_uid = 0; - - $bear = ZlibActivity::token_from_request(); - if ($bear) { - logger('bear: ' . $bear, LOGGER_DEBUG); - $t = q("select item.uid, iconfig.v from iconfig left join item on iid = item.id where cat = 'ocap' and item.uuid = '%s'", - dbesc($item_id) - ); - if ($t) { - foreach ($t as $token) { - if ($token['v'] === $bear) { - $ob_authorize = true; - $item_uid = $token['uid']; - break; - } - } - } - } + if (!$item_id) { + return; + } - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 + $ob_authorise = false; + $item_uid = 0; + + $bear = ZlibActivity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + $t = q("select item.uid, iconfig.v from iconfig left join item on iid = item.id where cat = 'ocap' and item.uuid = '%s'", + dbesc($item_id) + ); + if ($t) { + foreach ($t as $token) { + if ($token['v'] === $bear) { + $ob_authorize = true; + $item_uid = $token['uid']; + break; + } + } + } + } + + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 "; - $sigdata = HTTPSig::verify(EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { - http_status_exit(403, 'Permission denied'); - } - if (! check_siteallowed($sigdata['signer'])) { - http_status_exit(403, 'Permission denied'); - } - observer_auth($portable_id); - } + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (!check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (!check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + } - // if passed an owner_id of 0 to item_permissions_sql(), we force "guest access" or observer checking - // Give ocap tokens priority - - if ($ob_authorize) { - $sql_extra = " and item.uid = " . intval($token['uid']) . " "; - } - else { - $sql_extra = item_permissions_sql(0); - } + // if passed an owner_id of 0 to item_permissions_sql(), we force "guest access" or observer checking + // Give ocap tokens priority - $r = q("select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal $sql_extra limit 1", - dbesc($item_id), - dbesc(z_root() . '/activity/' . $item_id), - dbesc(z_root() . '/item/' . $item_id) - ); + if ($ob_authorize) { + $sql_extra = " and item.uid = " . intval($token['uid']) . " "; + } else { + $sql_extra = item_permissions_sql(0); + } - if (! $r) { - $r = q("select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal limit 1", - dbesc($item_id), - dbesc(z_root() . '/activity/' . $item_id), - dbesc(z_root() . '/item/' . $item_id) - ); + $r = q("select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal $sql_extra limit 1", + dbesc($item_id), + dbesc(z_root() . '/activity/' . $item_id), + dbesc(z_root() . '/item/' . $item_id) + ); - if ($r) { - http_status_exit(403, 'Forbidden'); - } - http_status_exit(404, 'Not found'); - } + if (!$r) { + $r = q("select * from item where ( uuid = '%s' or mid = '%s' or mid = '%s' ) $item_normal limit 1", + dbesc($item_id), + dbesc(z_root() . '/activity/' . $item_id), + dbesc(z_root() . '/item/' . $item_id) + ); - xchan_query($r,true); - $items = fetch_post_tags($r,false); + if ($r) { + http_status_exit(403, 'Forbidden'); + } + http_status_exit(404, 'Not found'); + } - if ($portable_id && (! intval($items[0]['item_private']))) { - $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", - intval($items[0]['uid']), - dbesc($portable_id) - ); - if (! $c) { - ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id); - } - } + xchan_query($r, true); + $items = fetch_post_tags($r, false); - $channel = channelx_by_n($items[0]['uid']); + if ($portable_id && (!intval($items[0]['item_private']))) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", + intval($items[0]['uid']), + dbesc($portable_id) + ); + if (!$c) { + ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id); + } + } - as_return_and_die(ZlibActivity::encode_activity($items[0],true),$channel); + $channel = channelx_by_n($items[0]['uid']); - } + as_return_and_die(ZlibActivity::encode_activity($items[0], true), $channel); - if (Libzot::is_zot_request()) { + } - $item_id = argv(1); + if (Libzot::is_zot_request()) { - if (! $item_id) { - http_status_exit(404, 'Not found'); - } - - $portable_id = EMPTY_STR; + $item_id = argv(1); - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) "; + if (!$item_id) { + http_status_exit(404, 'Not found'); + } - $i = null; + $portable_id = EMPTY_STR; - // do we have the item (at all)? + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) "; - $r = q("select * from item where mid = '%s' $item_normal limit 1", - dbesc(z_root() . '/activity/' . $item_id) - ); + $i = null; - if (! $r) { - $r = q("select * from item where mid = '%s' $item_normal limit 1", - dbesc(z_root() . '/item/' . $item_id) - ); - if ($r) { - goaway(z_root() . '/item/' . $item_id); - } - http_status_exit(404,'Not found'); - } + // do we have the item (at all)? - // process an authenticated fetch + $r = q("select * from item where mid = '%s' $item_normal limit 1", + dbesc(z_root() . '/activity/' . $item_id) + ); - $sigdata = HTTPSig::verify(EMPTY_STR); - if($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - observer_auth($portable_id); + if (!$r) { + $r = q("select * from item where mid = '%s' $item_normal limit 1", + dbesc(z_root() . '/item/' . $item_id) + ); + if ($r) { + goaway(z_root() . '/item/' . $item_id); + } + http_status_exit(404, 'Not found'); + } - // first see if we have a copy of this item's parent owned by the current signer - // include xchans for all zot-like networks - these will have the same guid and public key + // process an authenticated fetch - $x = q("select * from xchan where xchan_hash = '%s'", - dbesc($sigdata['portable_id']) - ); + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + observer_auth($portable_id); - if ($x) { - $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ", - dbesc($sigdata['portable_id']), - dbesc($x[0]['xchan_guid']), - dbesc($x[0]['xchan_pubkey']) - ); + // first see if we have a copy of this item's parent owned by the current signer + // include xchans for all zot-like networks - these will have the same guid and public key - if ($xchans) { - $hashes = ids_to_querystr($xchans,'xchan_hash',true); - $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1", - dbesc($r[0]['parent_mid']) - ); - } - } - } + $x = q("select * from xchan where xchan_hash = '%s'", + dbesc($sigdata['portable_id']) + ); - // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access - // with a bias towards those items owned by channels on this site (item_wall = 1) + if ($x) { + $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ", + dbesc($sigdata['portable_id']), + dbesc($x[0]['xchan_guid']), + dbesc($x[0]['xchan_pubkey']) + ); - $sql_extra = item_permissions_sql(0); + if ($xchans) { + $hashes = ids_to_querystr($xchans, 'xchan_hash', true); + $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1", + dbesc($r[0]['parent_mid']) + ); + } + } + } - if (! $i) { - $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", - dbesc($r[0]['parent_mid']) - ); - } + // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access + // with a bias towards those items owned by channels on this site (item_wall = 1) - $bear = ZlibActivity::token_from_request(); - if ($bear) { - logger('bear: ' . $bear, LOGGER_DEBUG); - if (! $i) { - $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'", - dbesc($bear) - ); - if ($t) { - $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1", - dbesc($item_id), - intval($t[0]['iid']) - ); - } - } - } + $sql_extra = item_permissions_sql(0); + + if (!$i) { + $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", + dbesc($r[0]['parent_mid']) + ); + } + + $bear = ZlibActivity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + if (!$i) { + $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'", + dbesc($bear) + ); + if ($t) { + $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1", + dbesc($item_id), + intval($t[0]['iid']) + ); + } + } + } - if (! $i) { - http_status_exit(403,'Forbidden'); - } + if (!$i) { + http_status_exit(403, 'Forbidden'); + } - $parents_str = ids_to_querystr($i,'item_id'); + $parents_str = ids_to_querystr($i, 'item_id'); - $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ", - dbesc($parents_str) - ); + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ", + dbesc($parents_str) + ); - if(! $items) { - http_status_exit(404, 'Not found'); - } + if (!$items) { + http_status_exit(404, 'Not found'); + } - xchan_query($items,true); - $items = fetch_post_tags($items,true); + xchan_query($items, true); + $items = fetch_post_tags($items, true); - $observer = App::get_observer(); - $parent = $items[0]; - $recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'],'activitypub','recips', []) : []); - $to = (($recips && array_key_exists('to',$recips) && is_array($recips['to'])) ? $recips['to'] : null); - $nitems = []; - foreach($items as $i) { + $observer = App::get_observer(); + $parent = $items[0]; + $recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'], 'activitypub', 'recips', []) : []); + $to = (($recips && array_key_exists('to', $recips) && is_array($recips['to'])) ? $recips['to'] : null); + $nitems = []; + foreach ($items as $i) { - $mids = []; + $mids = []; - if(intval($i['item_private'])) { - if(! $observer) { - continue; - } - // ignore private reshare, possibly from hubzilla - if($i['verb'] === 'Announce') { - if(! in_array($i['thr_parent'],$mids)) { - $mids[] = $i['thr_parent']; - } - continue; - } - // also ignore any children of the private reshares - if(in_array($i['thr_parent'],$mids)) { - continue; - } + if (intval($i['item_private'])) { + if (!$observer) { + continue; + } + // ignore private reshare, possibly from hubzilla + if ($i['verb'] === 'Announce') { + if (!in_array($i['thr_parent'], $mids)) { + $mids[] = $i['thr_parent']; + } + continue; + } + // also ignore any children of the private reshares + if (in_array($i['thr_parent'], $mids)) { + continue; + } - if((! $to) || (! in_array($observer['xchan_url'],$to))) { - continue; - } + if ((!$to) || (!in_array($observer['xchan_url'], $to))) { + continue; + } - } - $nitems[] = $i; - } + } + $nitems[] = $i; + } - if(! $nitems) - http_status_exit(404, 'Not found'); + if (!$nitems) + http_status_exit(404, 'Not found'); - $chan = channelx_by_n($nitems[0]['uid']); + $chan = channelx_by_n($nitems[0]['uid']); - if(! $chan) - http_status_exit(404, 'Not found'); + if (!$chan) + http_status_exit(404, 'Not found'); - if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) - http_status_exit(403, 'Forbidden'); + if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) + http_status_exit(403, 'Forbidden'); - $i = ZlibActivity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',true, count($nitems)); - if ($portable_id && (! intval($items[0]['item_private']))) { - ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id); - } + $i = ZlibActivity::encode_item_collection($nitems, 'conversation/' . $item_id, 'OrderedCollection', true, count($nitems)); + if ($portable_id && (!intval($items[0]['item_private']))) { + ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id); + } - if(! $i) - http_status_exit(404, 'Not found'); + if (!$i) + http_status_exit(404, 'Not found'); - $x = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - ZlibActivity::ap_schema() - ]], $i); + $x = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + ZlibActivity::ap_schema() + ]], $i); - $headers = []; - $headers['Content-Type'] = 'application/x-zot+json' ; - $x['signature'] = LDSignatures::sign($x,$chan); - $ret = json_encode($x, JSON_UNESCAPED_SLASHES); - $headers['Digest'] = HTTPSig::generate_digest_header($ret); - $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; - $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan)); - HTTPSig::set_headers($h); - echo $ret; - killme(); + $headers = []; + $headers['Content-Type'] = 'application/x-zot+json'; + $x['signature'] = LDSignatures::sign($x, $chan); + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + $headers['Digest'] = HTTPSig::generate_digest_header($ret); + $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; + $h = HTTPSig::create_sig($headers, $chan['channel_prvkey'], channel_url($chan)); + HTTPSig::set_headers($h); + echo $ret; + killme(); - } + } - - goaway(z_root() . '/item/' . argv(1)); - } + goaway(z_root() . '/item/' . argv(1)); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Admin.php b/Zotlabs/Module/Admin.php index 8c9a40a1f..b7f1f733f 100644 --- a/Zotlabs/Module/Admin.php +++ b/Zotlabs/Module/Admin.php @@ -18,174 +18,176 @@ use Zotlabs\Lib\Config; * @brief Admin area. * */ - -class Admin extends Controller { +class Admin extends Controller +{ - private $sm = null; + private $sm = null; - function __construct() { - $this->sm = new SubModule(); - } + public function __construct() + { + $this->sm = new SubModule(); + } - function init() { + public function init() + { - logger('admin_init', LOGGER_DEBUG); + logger('admin_init', LOGGER_DEBUG); - if (! is_site_admin()) { - logger('admin denied.'); - return; - } - - if (argc() > 1) { - $this->sm->call('init'); - } - } + if (!is_site_admin()) { + logger('admin denied.'); + return; + } + + if (argc() > 1) { + $this->sm->call('init'); + } + } - function post() { + public function post() + { - logger('admin_post', LOGGER_DEBUG); + logger('admin_post', LOGGER_DEBUG); - if (! is_site_admin()) { - logger('admin denied.'); - return; - } - - if (argc() > 1) { - $this->sm->call('post'); - } + if (!is_site_admin()) { + logger('admin denied.'); + return; + } - // goaway(z_root() . '/admin' ); - } + if (argc() > 1) { + $this->sm->call('post'); + } - /** - * @return string - */ + // goaway(z_root() . '/admin' ); + } - function get() { + /** + * @return string + */ - logger('admin_content', LOGGER_DEBUG); + public function get() + { - if (! is_site_admin()) { - logger('admin denied.'); - return login(false); - } + logger('admin_content', LOGGER_DEBUG); - /* - * Page content - */ + if (!is_site_admin()) { + logger('admin denied.'); + return login(false); + } - nav_set_selected('Admin'); + /* + * Page content + */ - $o = ''; + nav_set_selected('Admin'); - if (argc() > 1) { - $o = $this->sm->call('get'); - if ($o === false) { - notice( t('Item not found.') ); - } - } - else { - $o = $this->admin_page_summary(); - } + $o = ''; - if (is_ajax()) { - echo $o; - killme(); - } - else { - return $o; - } - } + if (argc() > 1) { + $o = $this->sm->call('get'); + if ($o === false) { + notice(t('Item not found.')); + } + } else { + $o = $this->admin_page_summary(); + } + + if (is_ajax()) { + echo $o; + killme(); + } else { + return $o; + } + } - /** - * @brief Returns content for Admin Summary Page. - * - * @return string HTML from parsed admin_summary.tpl - */ + /** + * @brief Returns content for Admin Summary Page. + * + * @return string HTML from parsed admin_summary.tpl + */ - function admin_page_summary() { + public function admin_page_summary() + { - // list total user accounts, expirations etc. - $accounts = []; - $r = q("SELECT COUNT(CASE WHEN account_id > 0 THEN 1 ELSE NULL END) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account", - db_utcnow(), - db_utcnow(), - dbesc(NULL_DATE), - intval(ACCOUNT_BLOCKED) - ); - if ($r) { - $accounts['total'] = [ 'label' => t('Accounts'), 'val' => $r[0]['total'] ]; - $accounts['blocked'] = [ 'label' => t('Blocked accounts'), 'val' => $r[0]['blocked'] ]; - $accounts['expired'] = [ 'label' => t('Expired accounts'), 'val' => $r[0]['expired'] ]; - $accounts['expiring'] = [ 'label' => t('Expiring accounts'), 'val' => $r[0]['expiring'] ]; - } + // list total user accounts, expirations etc. + $accounts = []; + $r = q("SELECT COUNT(CASE WHEN account_id > 0 THEN 1 ELSE NULL END) AS total, COUNT(CASE WHEN account_expires > %s THEN 1 ELSE NULL END) AS expiring, COUNT(CASE WHEN account_expires < %s AND account_expires > '%s' THEN 1 ELSE NULL END) AS expired, COUNT(CASE WHEN (account_flags & %d)>0 THEN 1 ELSE NULL END) AS blocked FROM account", + db_utcnow(), + db_utcnow(), + dbesc(NULL_DATE), + intval(ACCOUNT_BLOCKED) + ); + if ($r) { + $accounts['total'] = ['label' => t('Accounts'), 'val' => $r[0]['total']]; + $accounts['blocked'] = ['label' => t('Blocked accounts'), 'val' => $r[0]['blocked']]; + $accounts['expired'] = ['label' => t('Expired accounts'), 'val' => $r[0]['expired']]; + $accounts['expiring'] = ['label' => t('Expiring accounts'), 'val' => $r[0]['expiring']]; + } - // pending registrations + // pending registrations - $pdg = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ", - intval(ACCOUNT_PENDING) - ); + $pdg = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ", + intval(ACCOUNT_PENDING) + ); - $pending = (($pdg) ? count($pdg) : 0); + $pending = (($pdg) ? count($pdg) : 0); - // available channels, primary and clones - $channels = []; - $r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0 and channel_system = 0"); - if ($r) { - $channels['total'] = [ 'label' => t('Channels'), 'val' => $r[0]['total'] ]; - $channels['main'] = [ 'label' => t('Primary'), 'val' => $r[0]['main'] ]; - $channels['clones'] = [ 'label' => t('Clones'), 'val' => $r[0]['clones'] ]; - } + // available channels, primary and clones + $channels = []; + $r = q("SELECT COUNT(*) AS total, COUNT(CASE WHEN channel_primary = 1 THEN 1 ELSE NULL END) AS main, COUNT(CASE WHEN channel_primary = 0 THEN 1 ELSE NULL END) AS clones FROM channel WHERE channel_removed = 0 and channel_system = 0"); + if ($r) { + $channels['total'] = ['label' => t('Channels'), 'val' => $r[0]['total']]; + $channels['main'] = ['label' => t('Primary'), 'val' => $r[0]['main']]; + $channels['clones'] = ['label' => t('Clones'), 'val' => $r[0]['clones']]; + } - // We can do better, but this is a quick queue status - $r = q("SELECT COUNT(outq_delivered) AS total FROM outq WHERE outq_delivered = 0"); - $queue = (($r) ? $r[0]['total'] : 0); - $queues = [ 'label' => t('Message queues'), 'queue' => $queue ]; + // We can do better, but this is a quick queue status + $r = q("SELECT COUNT(outq_delivered) AS total FROM outq WHERE outq_delivered = 0"); + $queue = (($r) ? $r[0]['total'] : 0); + $queues = ['label' => t('Message queues'), 'queue' => $queue]; - $plugins = []; + $plugins = []; - if (is_array(App::$plugins) && App::$plugins) { - foreach (App::$plugins as $p) { - if ($p) { - $plugins[] = $p; - } - } - sort($plugins); - } - else { - $plugins = 0; - } + if (is_array(App::$plugins) && App::$plugins) { + foreach (App::$plugins as $p) { + if ($p) { + $plugins[] = $p; + } + } + sort($plugins); + } else { + $plugins = 0; + } - // Could be extended to provide also other alerts to the admin + // Could be extended to provide also other alerts to the admin - $alertmsg = ''; + $alertmsg = ''; - $upgrade = EMPTY_STR; + $upgrade = EMPTY_STR; - if((! defined('PLATFORM_ARCHITECTURE')) || (PLATFORM_ARCHITECTURE === 'zap')) { - $vrelease = get_repository_version('release'); - $vdev = get_repository_version('dev'); - $upgrade = ((version_compare(STD_VERSION,$vrelease) < 0) ? t('Your software should be updated') : ''); - } + if ((!defined('PLATFORM_ARCHITECTURE')) || (PLATFORM_ARCHITECTURE === 'zap')) { + $vrelease = get_repository_version('release'); + $vdev = get_repository_version('dev'); + $upgrade = ((version_compare(STD_VERSION, $vrelease) < 0) ? t('Your software should be updated') : ''); + } - $t = get_markup_template('admin_summary.tpl'); - return replace_macros($t, [ - '$title' => t('Administration'), - '$page' => t('Summary'), - '$adminalertmsg' => $alertmsg, - '$queues' => $queues, - '$accounts' => [ t('Registered accounts'), $accounts ], - '$pending' => [ t('Pending registrations'), $pending ], - '$channels' => [ t('Registered channels'), $channels ], - '$plugins' => (($plugins) ? [ t('Active addons'), $plugins ] : EMPTY_STR), - '$version' => [ t('Version'), STD_VERSION ], - '$vmaster' => [ t('Repository version (release)'), $vrelease ], - '$vdev' => [ t('Repository version (dev)'), $vdev ], - '$upgrade' => $upgrade, - '$build' => Config::Get('system', 'db_version') - ]); - } + $t = get_markup_template('admin_summary.tpl'); + return replace_macros($t, [ + '$title' => t('Administration'), + '$page' => t('Summary'), + '$adminalertmsg' => $alertmsg, + '$queues' => $queues, + '$accounts' => [t('Registered accounts'), $accounts], + '$pending' => [t('Pending registrations'), $pending], + '$channels' => [t('Registered channels'), $channels], + '$plugins' => (($plugins) ? [t('Active addons'), $plugins] : EMPTY_STR), + '$version' => [t('Version'), STD_VERSION], + '$vmaster' => [t('Repository version (release)'), $vrelease], + '$vdev' => [t('Repository version (dev)'), $vdev], + '$upgrade' => $upgrade, + '$build' => Config::Get('system', 'db_version') + ]); + } } diff --git a/Zotlabs/Module/Admin/Account_edit.php b/Zotlabs/Module/Admin/Account_edit.php index d9156c744..5f3847c34 100644 --- a/Zotlabs/Module/Admin/Account_edit.php +++ b/Zotlabs/Module/Admin/Account_edit.php @@ -3,79 +3,81 @@ namespace Zotlabs\Module\Admin; +class Account_edit +{ -class Account_edit { + public function post() + { - function post() { + $account_id = $_REQUEST['aid']; - $account_id = $_REQUEST['aid']; + if (!$account_id) + return; - if(! $account_id) - return; - - $pass1 = trim($_REQUEST['pass1']); - $pass2 = trim($_REQUEST['pass2']); - if($pass1 && $pass2 && ($pass1 === $pass2)) { - $salt = random_string(32); - $password_encoded = hash('whirlpool', $salt . $pass1); - $r = q("update account set account_salt = '%s', account_password = '%s', + $pass1 = trim($_REQUEST['pass1']); + $pass2 = trim($_REQUEST['pass2']); + if ($pass1 && $pass2 && ($pass1 === $pass2)) { + $salt = random_string(32); + $password_encoded = hash('whirlpool', $salt . $pass1); + $r = q("update account set account_salt = '%s', account_password = '%s', account_password_changed = '%s' where account_id = %d", - dbesc($salt), - dbesc($password_encoded), - dbesc(datetime_convert()), - intval($account_id) - ); - if($r) - info( sprintf( t('Password changed for account %d.'), $account_id). EOL); + dbesc($salt), + dbesc($password_encoded), + dbesc(datetime_convert()), + intval($account_id) + ); + if ($r) + info(sprintf(t('Password changed for account %d.'), $account_id) . EOL); - } + } - $service_class = trim($_REQUEST['service_class']); - $account_language = trim($_REQUEST['account_language']); + $service_class = trim($_REQUEST['service_class']); + $account_language = trim($_REQUEST['account_language']); - $r = q("update account set account_service_class = '%s', account_language = '%s' + $r = q("update account set account_service_class = '%s', account_language = '%s' where account_id = %d", - dbesc($service_class), - dbesc($account_language), - intval($account_id) - ); + dbesc($service_class), + dbesc($account_language), + intval($account_id) + ); - if($r) - info( t('Account settings updated.') . EOL); + if ($r) + info(t('Account settings updated.') . EOL); - goaway(z_root() . '/admin/accounts'); - } + goaway(z_root() . '/admin/accounts'); + } - function get() { - if(argc() > 2) - $account_id = argv(2); + public function get() + { + if (argc() > 2) + $account_id = argv(2); - $x = q("select * from account where account_id = %d limit 1", - intval($account_id) - ); + $x = q("select * from account where account_id = %d limit 1", + intval($account_id) + ); - if(! $x) { - notice ( t('Account not found.') . EOL); - return ''; - } + if (!$x) { + notice(t('Account not found.') . EOL); + return ''; + } - $a = replace_macros(get_markup_template('admin_account_edit.tpl'), [ - '$account' => $x[0], - '$title' => t('Account Edit'), - '$pass1' => [ 'pass1', t('New Password'), ' ','' ], - '$pass2' => [ 'pass2', t('New Password again'), ' ','' ], - '$account_language' => [ 'account_language' , t('Account language (for emails)'), $x[0]['account_language'], '', language_list() ], - '$service_class' => [ 'service_class', t('Service class'), $x[0]['account_service_class'], '' ], - '$submit' => t('Submit'), - ] - ); + $a = replace_macros(get_markup_template('admin_account_edit.tpl'), [ + '$account' => $x[0], + '$title' => t('Account Edit'), + '$pass1' => ['pass1', t('New Password'), ' ', ''], + '$pass2' => ['pass2', t('New Password again'), ' ', ''], + '$account_language' => ['account_language', t('Account language (for emails)'), $x[0]['account_language'], '', language_list()], + '$service_class' => ['service_class', t('Service class'), $x[0]['account_service_class'], ''], + '$submit' => t('Submit'), + ] + ); - return $a; + return $a; - } + } } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Accounts.php b/Zotlabs/Module/Admin/Accounts.php index 1b9b0d768..1c703c93d 100644 --- a/Zotlabs/Module/Admin/Accounts.php +++ b/Zotlabs/Module/Admin/Accounts.php @@ -4,199 +4,202 @@ namespace Zotlabs\Module\Admin; use App; -class Accounts { - - /** - * @brief Handle POST actions on accounts admin page. - * - * This function is called when on the admin user/account page the form was - * submitted to handle multiple operations at once. If one of the icons next - * to an entry are pressed the function admin_page_accounts() will handle this. - * - */ +class Accounts +{ - function post() { + /** + * @brief Handle POST actions on accounts admin page. + * + * This function is called when on the admin user/account page the form was + * submitted to handle multiple operations at once. If one of the icons next + * to an entry are pressed the function admin_page_accounts() will handle this. + * + */ - $pending = ( x($_POST, 'pending') ? $_POST['pending'] : [] ); - $users = ( x($_POST, 'user') ? $_POST['user'] : [] ); - $blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : [] ); - - check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts'); - + public function post() + { - // account block/unblock button was submitted - if (x($_POST, 'page_accounts_block')) { - for ($i = 0; $i < count($users); $i++) { - // if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag - $op = ($blocked[$i]) ? '& ~' : '| '; - q("UPDATE account SET account_flags = (account_flags $op %d) WHERE account_id = %d", - intval(ACCOUNT_BLOCKED), - intval($users[$i]) - ); - } - notice( sprintf( tt("%s account blocked/unblocked", "%s accounts blocked/unblocked", count($users)), count($users)) ); - } + $pending = (x($_POST, 'pending') ? $_POST['pending'] : []); + $users = (x($_POST, 'user') ? $_POST['user'] : []); + $blocked = (x($_POST, 'blocked') ? $_POST['blocked'] : []); - // account delete button was submitted - if (x($_POST, 'page_accounts_delete')) { - foreach ($users as $uid){ - account_remove($uid, true, false); - } - notice( sprintf( tt("%s account deleted", "%s accounts deleted", count($users)), count($users)) ); - } - - // registration approved button was submitted - if (x($_POST, 'page_accounts_approve')) { - foreach ($pending as $hash) { - account_allow($hash); - } - } - - // registration deny button was submitted - if (x($_POST, 'page_accounts_deny')) { - foreach ($pending as $hash) { - account_deny($hash); - } - } - - goaway(z_root() . '/admin/accounts' ); - } + check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts'); - /** - * @brief Generate accounts admin page and handle single item operations. - * - * This function generates the accounts/account admin page and handles the actions - * if an icon next to an entry was clicked. If several items were selected and - * the form was submitted it is handled by the function admin_page_accounts_post(). - * - * @return string - */ - function get(){ - if (argc() > 2) { - $uid = argv(3); - $account = q("SELECT * FROM account WHERE account_id = %d", - intval($uid) - ); - - if (! $account) { - notice( t('Account not found') . EOL); - goaway(z_root() . '/admin/accounts' ); - } - - check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't'); - - switch (argv(2)) { - case 'delete': - // delete user - account_remove($uid,true,false); - - notice( sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL); - break; - case 'block': - q("UPDATE account SET account_flags = ( account_flags | %d ) WHERE account_id = %d", - intval(ACCOUNT_BLOCKED), - intval($uid) - ); - - notice( sprintf( t("Account '%s' blocked") , $account[0]['account_email']) . EOL); - break; - case 'unblock': - q("UPDATE account SET account_flags = ( account_flags & ~ %d ) WHERE account_id = %d", - intval(ACCOUNT_BLOCKED), - intval($uid) - ); - - notice( sprintf( t("Account '%s' unblocked"), $account[0]['account_email']) . EOL); - break; - } - - goaway(z_root() . '/admin/accounts' ); - } - - /* get pending */ - $pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) != 0 ", - intval(ACCOUNT_PENDING) - ); - - /* get accounts */ - - $total = q("SELECT count(*) as total FROM account"); - if (count($total)) { - App::set_pager_total($total[0]['total']); - App::set_pager_itemspage(100); - } - - $serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : ''); + // account block/unblock button was submitted + if (x($_POST, 'page_accounts_block')) { + for ($i = 0; $i < count($users); $i++) { + // if account is blocked remove blocked bit-flag, otherwise add blocked bit-flag + $op = ($blocked[$i]) ? '& ~' : '| '; + q("UPDATE account SET account_flags = (account_flags $op %d) WHERE account_id = %d", + intval(ACCOUNT_BLOCKED), + intval($users[$i]) + ); + } + notice(sprintf(tt("%s account blocked/unblocked", "%s accounts blocked/unblocked", count($users)), count($users))); + } - $key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id'); - $dir = 'asc'; - if (array_key_exists('dir',$_REQUEST)) { - $dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc'); - } - - $base = z_root() . '/admin/accounts?f='; - $odir = (($dir === 'asc') ? '0' : '1'); + // account delete button was submitted + if (x($_POST, 'page_accounts_delete')) { + foreach ($users as $uid) { + account_remove($uid, true, false); + } + notice(sprintf(tt("%s account deleted", "%s accounts deleted", count($users)), count($users))); + } - $users = q("SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked, + // registration approved button was submitted + if (x($_POST, 'page_accounts_approve')) { + foreach ($pending as $hash) { + account_allow($hash); + } + } + + // registration deny button was submitted + if (x($_POST, 'page_accounts_deny')) { + foreach ($pending as $hash) { + account_deny($hash); + } + } + + goaway(z_root() . '/admin/accounts'); + } + + /** + * @brief Generate accounts admin page and handle single item operations. + * + * This function generates the accounts/account admin page and handles the actions + * if an icon next to an entry was clicked. If several items were selected and + * the form was submitted it is handled by the function admin_page_accounts_post(). + * + * @return string + */ + + public function get() + { + if (argc() > 2) { + $uid = argv(3); + $account = q("SELECT * FROM account WHERE account_id = %d", + intval($uid) + ); + + if (!$account) { + notice(t('Account not found') . EOL); + goaway(z_root() . '/admin/accounts'); + } + + check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't'); + + switch (argv(2)) { + case 'delete': + // delete user + account_remove($uid, true, false); + + notice(sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL); + break; + case 'block': + q("UPDATE account SET account_flags = ( account_flags | %d ) WHERE account_id = %d", + intval(ACCOUNT_BLOCKED), + intval($uid) + ); + + notice(sprintf(t("Account '%s' blocked"), $account[0]['account_email']) . EOL); + break; + case 'unblock': + q("UPDATE account SET account_flags = ( account_flags & ~ %d ) WHERE account_id = %d", + intval(ACCOUNT_BLOCKED), + intval($uid) + ); + + notice(sprintf(t("Account '%s' unblocked"), $account[0]['account_email']) . EOL); + break; + } + + goaway(z_root() . '/admin/accounts'); + } + + /* get pending */ + $pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) != 0 ", + intval(ACCOUNT_PENDING) + ); + + /* get accounts */ + + $total = q("SELECT count(*) as total FROM account"); + if (count($total)) { + App::set_pager_total($total[0]['total']); + App::set_pager_itemspage(100); + } + + $serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : ''); + + $key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id'); + $dir = 'asc'; + if (array_key_exists('dir', $_REQUEST)) { + $dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc'); + } + + $base = z_root() . '/admin/accounts?f='; + $odir = (($dir === 'asc') ? '0' : '1'); + + $users = q("SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked, (SELECT %s FROM channel as ch WHERE ch.channel_account_id = ac.account_id and ch.channel_removed = 0 ) as channels FROM account as ac where true $serviceclass and account_flags != %d order by $key $dir limit %d offset %d ", - intval(ACCOUNT_BLOCKED), - db_concat('ch.channel_address', ' '), - intval(ACCOUNT_BLOCKED | ACCOUNT_PENDING), - intval(App::$pager['itemspage']), - intval(App::$pager['start']) - ); + intval(ACCOUNT_BLOCKED), + db_concat('ch.channel_address', ' '), + intval(ACCOUNT_BLOCKED | ACCOUNT_PENDING), + intval(App::$pager['itemspage']), + intval(App::$pager['start']) + ); - if ($users) { - for($x = 0; $x < count($users); $x ++) { - $channel_arr = explode(' ',$users[$x]['channels']); - if ($channel_arr) { - $linked = []; - foreach ( $channel_arr as $c) { - $linked[] = '' . $c . ''; - } - $users[$x]['channels'] = implode(' ',$linked); - } - } - } + if ($users) { + for ($x = 0; $x < count($users); $x++) { + $channel_arr = explode(' ', $users[$x]['channels']); + if ($channel_arr) { + $linked = []; + foreach ($channel_arr as $c) { + $linked[] = '' . $c . ''; + } + $users[$x]['channels'] = implode(' ', $linked); + } + } + } - $t = - $o = replace_macros(get_markup_template('admin_accounts.tpl'), [ - '$title' => t('Administration'), - '$page' => t('Accounts'), - '$submit' => t('Submit'), - '$select_all' => t('select all'), - '$h_pending' => t('Registrations waiting for confirm'), - '$th_pending' => array( t('Request date'), t('Email') ), - '$no_pending' => t('No registrations.'), - '$approve' => t('Approve'), - '$deny' => t('Deny'), - '$delete' => t('Delete'), - '$block' => t('Block'), - '$unblock' => t('Unblock'), - '$odir' => $odir, - '$base' => $base, - '$h_users' => t('Accounts'), - '$th_users' => [ - [ t('ID'), 'account_id' ], - [ t('Email'), 'account_email' ], - [ t('All Channels'), 'channels' ], - [ t('Register date'), 'account_created' ], - [ t('Last login'), 'account_lastlog' ], - [ t('Expires'), 'account_expires' ], - [ t('Service Class'), 'account_service_class'] - ], - '$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'), - '$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'), - '$form_security_token' => get_form_security_token("admin_accounts"), - '$baseurl' => z_root(), - '$pending' => $pending, - '$users' => $users, - ]); - - $o .= paginate($a); - - return $o; - } + $t = + $o = replace_macros(get_markup_template('admin_accounts.tpl'), [ + '$title' => t('Administration'), + '$page' => t('Accounts'), + '$submit' => t('Submit'), + '$select_all' => t('select all'), + '$h_pending' => t('Registrations waiting for confirm'), + '$th_pending' => array(t('Request date'), t('Email')), + '$no_pending' => t('No registrations.'), + '$approve' => t('Approve'), + '$deny' => t('Deny'), + '$delete' => t('Delete'), + '$block' => t('Block'), + '$unblock' => t('Unblock'), + '$odir' => $odir, + '$base' => $base, + '$h_users' => t('Accounts'), + '$th_users' => [ + [t('ID'), 'account_id'], + [t('Email'), 'account_email'], + [t('All Channels'), 'channels'], + [t('Register date'), 'account_created'], + [t('Last login'), 'account_lastlog'], + [t('Expires'), 'account_expires'], + [t('Service Class'), 'account_service_class'] + ], + '$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'), + '$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'), + '$form_security_token' => get_form_security_token("admin_accounts"), + '$baseurl' => z_root(), + '$pending' => $pending, + '$users' => $users, + ]); + + $o .= paginate($a); + + return $o; + } } diff --git a/Zotlabs/Module/Admin/Addons.php b/Zotlabs/Module/Admin/Addons.php index 423de77c4..5fe8e1c3a 100644 --- a/Zotlabs/Module/Admin/Addons.php +++ b/Zotlabs/Module/Admin/Addons.php @@ -7,476 +7,478 @@ use PHPGit\Exception\GitException; use Zotlabs\Storage\GitRepo; use Michelf\MarkdownExtra; -class Addons { +class Addons +{ - /** - * @brief - * - */ - function post() { + /** + * @brief + * + */ + public function post() + { - if(argc() > 2 && is_file("addon/" . argv(2) . "/" . argv(2) . ".php")) { - @include_once("addon/" . argv(2) . "/" . argv(2) . ".php"); - if(function_exists(argv(2).'_plugin_admin_post')) { - $func = argv(2) . '_plugin_admin_post'; - $func($a); - } + if (argc() > 2 && is_file("addon/" . argv(2) . "/" . argv(2) . ".php")) { + @include_once("addon/" . argv(2) . "/" . argv(2) . ".php"); + if (function_exists(argv(2) . '_plugin_admin_post')) { + $func = argv(2) . '_plugin_admin_post'; + $func($a); + } - goaway(z_root() . '/admin/addons/' . argv(2) ); - } - elseif(argc() > 2) { - switch(argv(2)) { - case 'updaterepo': - if (array_key_exists('repoName', $_REQUEST)) { - $repoName = $_REQUEST['repoName']; - } - else { - json_return_and_die(array('message' => 'No repo name provided.', 'success' => false)); - } - $extendDir = 'cache/git/sys/extend'; - $addonDir = $extendDir . '/addon'; - if (!file_exists($extendDir)) { - if (!mkdir($extendDir, 0770, true)) { - logger('Error creating extend folder: ' . $extendDir); - json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); - } - else { - if (!symlink(realpath('extend/addon'), $addonDir)) { - logger('Error creating symlink to addon folder: ' . $addonDir); - json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); - } - } - } - $repoDir = 'cache/git/sys/extend/addon/' . $repoName; - if (!is_dir($repoDir)) { - logger('Repo directory does not exist: ' . $repoDir); - json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false)); - } - if (!is_writable($repoDir)) { - logger('Repo directory not writable to web server: ' . $repoDir); - json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false)); - } - $git = new GitRepo('sys', null, false, $repoName, $repoDir); - try { - if ($git->pull()) { - $files = array_diff(scandir($repoDir), array('.', '..')); - foreach ($files as $file) { - if (is_dir($repoDir . '/' . $file) && $file !== '.git') { - $source = '../extend/addon/' . $repoName . '/' . $file; - $target = realpath('addon/') . '/' . $file; - unlink($target); - if (!symlink($source, $target)) { - logger('Error linking addons to /addon'); - json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false)); - } - } - } - json_return_and_die(array('message' => 'Repo updated.', 'success' => true)); - } else { - json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false)); - } - } catch (GitException $e) { - json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false)); - } - case 'removerepo': - if (array_key_exists('repoName', $_REQUEST)) { - $repoName = $_REQUEST['repoName']; - } else { - json_return_and_die(array('message' => 'No repo name provided.', 'success' => false)); - } - $extendDir = 'cache/git/sys/extend'; - $addonDir = $extendDir . '/addon'; - if (!file_exists($extendDir)) { - if (!mkdir($extendDir, 0770, true)) { - logger('Error creating extend folder: ' . $extendDir); - json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); - } else { - if (!symlink(realpath('extend/addon'), $addonDir)) { - logger('Error creating symlink to addon folder: ' . $addonDir); - json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); - } - } - } - $repoDir = 'cache/git/sys/extend/addon/' . $repoName; - if (!is_dir($repoDir)) { - logger('Repo directory does not exist: ' . $repoDir); - json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false)); - } - if (!is_writable($repoDir)) { - logger('Repo directory not writable to web server: ' . $repoDir); - json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false)); - } - /// @TODO remove directory and unlink /addon/files - if (rrmdir($repoDir)) { - json_return_and_die(array('message' => 'Repo deleted.', 'success' => true)); - } else { - json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false)); - } - case 'installrepo': - if (array_key_exists('repoURL', $_REQUEST)) { - $repoURL = $_REQUEST['repoURL']; - $extendDir = 'cache/git/sys/extend'; - $addonDir = $extendDir . '/addon'; - if (!file_exists($extendDir)) { - if (!mkdir($extendDir, 0770, true)) { - logger('Error creating extend folder: ' . $extendDir); - json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); - } else { - if (!symlink(realpath('extend/addon'), $addonDir)) { - logger('Error creating symlink to addon folder: ' . $addonDir); - json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); - } - } - } - if (!is_writable($extendDir)) { - logger('Directory not writable to web server: ' . $extendDir); - json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false)); - } - $repoName = null; - if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') { - $repoName = $_REQUEST['repoName']; - } else { - $repoName = GitRepo::getRepoNameFromURL($repoURL); - } - if (!$repoName) { - logger('Invalid git repo'); - json_return_and_die(array('message' => 'Invalid git repo', 'success' => false)); - } - $repoDir = $addonDir . '/' . $repoName; - $tempRepoBaseDir = 'cache/git/sys/temp/'; - $tempAddonDir = $tempRepoBaseDir . $repoName; + goaway(z_root() . '/admin/addons/' . argv(2)); + } elseif (argc() > 2) { + switch (argv(2)) { + case 'updaterepo': + if (array_key_exists('repoName', $_REQUEST)) { + $repoName = $_REQUEST['repoName']; + } else { + json_return_and_die(array('message' => 'No repo name provided.', 'success' => false)); + } + $extendDir = 'cache/git/sys/extend'; + $addonDir = $extendDir . '/addon'; + if (!file_exists($extendDir)) { + if (!mkdir($extendDir, 0770, true)) { + logger('Error creating extend folder: ' . $extendDir); + json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); + } else { + if (!symlink(realpath('extend/addon'), $addonDir)) { + logger('Error creating symlink to addon folder: ' . $addonDir); + json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); + } + } + } + $repoDir = 'cache/git/sys/extend/addon/' . $repoName; + if (!is_dir($repoDir)) { + logger('Repo directory does not exist: ' . $repoDir); + json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false)); + } + if (!is_writable($repoDir)) { + logger('Repo directory not writable to web server: ' . $repoDir); + json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false)); + } + $git = new GitRepo('sys', null, false, $repoName, $repoDir); + try { + if ($git->pull()) { + $files = array_diff(scandir($repoDir), array('.', '..')); + foreach ($files as $file) { + if (is_dir($repoDir . '/' . $file) && $file !== '.git') { + $source = '../extend/addon/' . $repoName . '/' . $file; + $target = realpath('addon/') . '/' . $file; + unlink($target); + if (!symlink($source, $target)) { + logger('Error linking addons to /addon'); + json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false)); + } + } + } + json_return_and_die(array('message' => 'Repo updated.', 'success' => true)); + } else { + json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false)); + } + } catch (GitException $e) { + json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false)); + } + case 'removerepo': + if (array_key_exists('repoName', $_REQUEST)) { + $repoName = $_REQUEST['repoName']; + } else { + json_return_and_die(array('message' => 'No repo name provided.', 'success' => false)); + } + $extendDir = 'cache/git/sys/extend'; + $addonDir = $extendDir . '/addon'; + if (!file_exists($extendDir)) { + if (!mkdir($extendDir, 0770, true)) { + logger('Error creating extend folder: ' . $extendDir); + json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); + } else { + if (!symlink(realpath('extend/addon'), $addonDir)) { + logger('Error creating symlink to addon folder: ' . $addonDir); + json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); + } + } + } + $repoDir = 'cache/git/sys/extend/addon/' . $repoName; + if (!is_dir($repoDir)) { + logger('Repo directory does not exist: ' . $repoDir); + json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false)); + } + if (!is_writable($repoDir)) { + logger('Repo directory not writable to web server: ' . $repoDir); + json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false)); + } + /// @TODO remove directory and unlink /addon/files + if (rrmdir($repoDir)) { + json_return_and_die(array('message' => 'Repo deleted.', 'success' => true)); + } else { + json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false)); + } + case 'installrepo': + if (array_key_exists('repoURL', $_REQUEST)) { + $repoURL = $_REQUEST['repoURL']; + $extendDir = 'cache/git/sys/extend'; + $addonDir = $extendDir . '/addon'; + if (!file_exists($extendDir)) { + if (!mkdir($extendDir, 0770, true)) { + logger('Error creating extend folder: ' . $extendDir); + json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); + } else { + if (!symlink(realpath('extend/addon'), $addonDir)) { + logger('Error creating symlink to addon folder: ' . $addonDir); + json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); + } + } + } + if (!is_writable($extendDir)) { + logger('Directory not writable to web server: ' . $extendDir); + json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false)); + } + $repoName = null; + if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') { + $repoName = $_REQUEST['repoName']; + } else { + $repoName = GitRepo::getRepoNameFromURL($repoURL); + } + if (!$repoName) { + logger('Invalid git repo'); + json_return_and_die(array('message' => 'Invalid git repo', 'success' => false)); + } + $repoDir = $addonDir . '/' . $repoName; + $tempRepoBaseDir = 'cache/git/sys/temp/'; + $tempAddonDir = $tempRepoBaseDir . $repoName; - if (!is_writable($addonDir) || !is_writable($tempAddonDir)) { - logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir); - json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false)); - } - rename($tempAddonDir, $repoDir); + if (!is_writable($addonDir) || !is_writable($tempAddonDir)) { + logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir); + json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false)); + } + rename($tempAddonDir, $repoDir); - if (!is_writable(realpath('addon/'))) { - logger('/addon directory not writable to web server: ' . $tempAddonDir); - json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false)); - } - $files = array_diff(scandir($repoDir), array('.', '..')); - foreach ($files as $file) { - if (is_dir($repoDir . '/' . $file) && $file !== '.git') { - $source = '../extend/addon/' . $repoName . '/' . $file; - $target = realpath('addon/') . '/' . $file; - unlink($target); - if (!symlink($source, $target)) { - logger('Error linking addons to /addon'); - json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false)); - } - } - } - $git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir); - $repo = $git->probeRepo(); - json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true)); - } - case 'addrepo': - if (array_key_exists('repoURL', $_REQUEST)) { - $repoURL = $_REQUEST['repoURL']; - $extendDir = 'cache/git/sys/extend'; - $addonDir = $extendDir . '/addon'; - $tempAddonDir = realpath('cache') . '/git/sys/temp'; - if (!file_exists($extendDir)) { - if (!mkdir($extendDir, 0770, true)) { - logger('Error creating extend folder: ' . $extendDir); - json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); - } else { - if (!symlink(realpath('extend/addon'), $addonDir)) { - logger('Error creating symlink to addon folder: ' . $addonDir); - json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); - } - } - } - if (!is_dir($tempAddonDir)) { - if (!mkdir($tempAddonDir, 0770, true)) { - logger('Error creating temp plugin repo folder: ' . $tempAddonDir); - json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false)); - } - } - $repoName = null; - if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') { - $repoName = $_REQUEST['repoName']; - } else { - $repoName = GitRepo::getRepoNameFromURL($repoURL); - } - if (!$repoName) { - logger('Invalid git repo'); - json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false)); - } - $repoDir = $tempAddonDir . '/' . $repoName; - if (!is_writable($tempAddonDir)) { - logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir); - json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false)); - } - // clone the repo if new automatically - $git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir); + if (!is_writable(realpath('addon/'))) { + logger('/addon directory not writable to web server: ' . $tempAddonDir); + json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false)); + } + $files = array_diff(scandir($repoDir), array('.', '..')); + foreach ($files as $file) { + if (is_dir($repoDir . '/' . $file) && $file !== '.git') { + $source = '../extend/addon/' . $repoName . '/' . $file; + $target = realpath('addon/') . '/' . $file; + unlink($target); + if (!symlink($source, $target)) { + logger('Error linking addons to /addon'); + json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false)); + } + } + } + $git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir); + $repo = $git->probeRepo(); + json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true)); + } + case 'addrepo': + if (array_key_exists('repoURL', $_REQUEST)) { + $repoURL = $_REQUEST['repoURL']; + $extendDir = 'cache/git/sys/extend'; + $addonDir = $extendDir . '/addon'; + $tempAddonDir = realpath('cache') . '/git/sys/temp'; + if (!file_exists($extendDir)) { + if (!mkdir($extendDir, 0770, true)) { + logger('Error creating extend folder: ' . $extendDir); + json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false)); + } else { + if (!symlink(realpath('extend/addon'), $addonDir)) { + logger('Error creating symlink to addon folder: ' . $addonDir); + json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false)); + } + } + } + if (!is_dir($tempAddonDir)) { + if (!mkdir($tempAddonDir, 0770, true)) { + logger('Error creating temp plugin repo folder: ' . $tempAddonDir); + json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false)); + } + } + $repoName = null; + if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') { + $repoName = $_REQUEST['repoName']; + } else { + $repoName = GitRepo::getRepoNameFromURL($repoURL); + } + if (!$repoName) { + logger('Invalid git repo'); + json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false)); + } + $repoDir = $tempAddonDir . '/' . $repoName; + if (!is_writable($tempAddonDir)) { + logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir); + json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false)); + } + // clone the repo if new automatically + $git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir); - $remotes = $git->git->remote(); - $fetchURL = $remotes['origin']['fetch']; - if ($fetchURL !== $git->url) { - if (rrmdir($repoDir)) { - $git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir); - } else { - json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false)); - } - } - $repo = $git->probeRepo(); - $repo['readme'] = $repo['manifest'] = null; - foreach ($git->git->tree('master') as $object) { - if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) { - $repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash'])); - } else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') { - $repo['manifest'] = $git->git->cat->blob($object['hash']); - } - } - json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true)); - } else { - json_return_and_die(array('message' => 'No repo URL provided', 'success' => false)); - } - break; - default: - break; - } - } - } + $remotes = $git->git->remote(); + $fetchURL = $remotes['origin']['fetch']; + if ($fetchURL !== $git->url) { + if (rrmdir($repoDir)) { + $git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir); + } else { + json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false)); + } + } + $repo = $git->probeRepo(); + $repo['readme'] = $repo['manifest'] = null; + foreach ($git->git->tree('master') as $object) { + if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) { + $repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash'])); + } else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') { + $repo['manifest'] = $git->git->cat->blob($object['hash']); + } + } + json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true)); + } else { + json_return_and_die(array('message' => 'No repo URL provided', 'success' => false)); + } + break; + default: + break; + } + } + } - /** - * @brief Addons admin page. - * - * @return string with parsed HTML - */ - function get() { + /** + * @brief Addons admin page. + * + * @return string with parsed HTML + */ + public function get() + { - /* - * Single plugin - */ + /* + * Single plugin + */ - if (App::$argc == 3){ - $plugin = App::$argv[2]; - if (!is_file("addon/$plugin/$plugin.php")){ - notice( t("Item not found.") ); - return ''; - } + if (App::$argc == 3) { + $plugin = App::$argv[2]; + if (!is_file("addon/$plugin/$plugin.php")) { + notice(t("Item not found.")); + return ''; + } - $enabled = in_array($plugin, App::$plugins); - $info = get_plugin_info($plugin); - $x = check_plugin_versions($info); + $enabled = in_array($plugin, App::$plugins); + $info = get_plugin_info($plugin); + $x = check_plugin_versions($info); - // disable plugins which are installed but incompatible versions + // disable plugins which are installed but incompatible versions - if($enabled && ! $x) { - $enabled = false; - $idz = array_search($plugin, App::$plugins); - if ($idz !== false) { - unset(App::$plugins[$idz]); - uninstall_plugin($plugin); - set_config("system","addon", implode(", ", App::$plugins)); - } - } - $info['disabled'] = 1-intval($x); + if ($enabled && !$x) { + $enabled = false; + $idz = array_search($plugin, App::$plugins); + if ($idz !== false) { + unset(App::$plugins[$idz]); + uninstall_plugin($plugin); + set_config("system", "addon", implode(", ", App::$plugins)); + } + } + $info['disabled'] = 1 - intval($x); - if (x($_GET,"a") && $_GET['a']=="t"){ - check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't'); - $pinstalled = false; - // Toggle plugin status - $idx = array_search($plugin, App::$plugins); - if ($idx !== false){ - unset(App::$plugins[$idx]); - uninstall_plugin($plugin); - $pinstalled = false; - info( sprintf( t("Plugin %s disabled."), $plugin ) ); - } else { - App::$plugins[] = $plugin; - install_plugin($plugin); - $pinstalled = true; - info( sprintf( t("Plugin %s enabled."), $plugin ) ); - } - set_config("system","addon", implode(", ", App::$plugins)); + if (x($_GET, "a") && $_GET['a'] == "t") { + check_form_security_token_redirectOnErr('/admin/addons', 'admin_addons', 't'); + $pinstalled = false; + // Toggle plugin status + $idx = array_search($plugin, App::$plugins); + if ($idx !== false) { + unset(App::$plugins[$idx]); + uninstall_plugin($plugin); + $pinstalled = false; + info(sprintf(t("Plugin %s disabled."), $plugin)); + } else { + App::$plugins[] = $plugin; + install_plugin($plugin); + $pinstalled = true; + info(sprintf(t("Plugin %s enabled."), $plugin)); + } + set_config("system", "addon", implode(", ", App::$plugins)); - if($pinstalled) { - @require_once("addon/$plugin/$plugin.php"); - if(function_exists($plugin.'_plugin_admin')) - goaway(z_root() . '/admin/addons/' . $plugin); - } - goaway(z_root() . '/admin/addons' ); - } + if ($pinstalled) { + @require_once("addon/$plugin/$plugin.php"); + if (function_exists($plugin . '_plugin_admin')) + goaway(z_root() . '/admin/addons/' . $plugin); + } + goaway(z_root() . '/admin/addons'); + } - // display plugin details + // display plugin details - if (in_array($plugin, App::$plugins)){ - $status = 'on'; - $action = t('Disable'); - } else { - $status = 'off'; - $action = t('Enable'); - } + if (in_array($plugin, App::$plugins)) { + $status = 'on'; + $action = t('Disable'); + } else { + $status = 'off'; + $action = t('Enable'); + } - $readme = null; - if (is_file("addon/$plugin/README.md")){ - $readme = file_get_contents("addon/$plugin/README.md"); - $readme = MarkdownExtra::defaultTransform($readme); - } else if (is_file("addon/$plugin/README")){ - $readme = "
        ". file_get_contents("addon/$plugin/README") ."
        "; - } + $readme = null; + if (is_file("addon/$plugin/README.md")) { + $readme = file_get_contents("addon/$plugin/README.md"); + $readme = MarkdownExtra::defaultTransform($readme); + } else if (is_file("addon/$plugin/README")) { + $readme = "
        " . file_get_contents("addon/$plugin/README") . "
        "; + } - $admin_form = ''; + $admin_form = ''; - $r = q("select * from addon where plugin_admin = 1 and aname = '%s' limit 1", - dbesc($plugin) - ); + $r = q("select * from addon where plugin_admin = 1 and aname = '%s' limit 1", + dbesc($plugin) + ); - if($r) { - @require_once("addon/$plugin/$plugin.php"); - if(function_exists($plugin.'_plugin_admin')) { - $func = $plugin.'_plugin_admin'; - $func($a, $admin_form); - } - } + if ($r) { + @require_once("addon/$plugin/$plugin.php"); + if (function_exists($plugin . '_plugin_admin')) { + $func = $plugin . '_plugin_admin'; + $func($a, $admin_form); + } + } - $t = get_markup_template('admin_plugins_details.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Addons'), - '$toggle' => t('Toggle'), - '$settings' => t('Settings'), - '$baseurl' => z_root(), + $t = get_markup_template('admin_plugins_details.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Addons'), + '$toggle' => t('Toggle'), + '$settings' => t('Settings'), + '$baseurl' => z_root(), - '$plugin' => $plugin, - '$status' => $status, - '$action' => $action, - '$info' => $info, - '$str_author' => t('Author: '), - '$str_maintainer' => t('Maintainer: '), - '$str_minversion' => t('Minimum project version: '), - '$str_maxversion' => t('Maximum project version: '), - '$str_minphpversion' => t('Minimum PHP version: '), - '$str_serverroles' => t('Compatible Server Roles: '), - '$str_requires' => t('Requires: '), - '$disabled' => t('Disabled - version incompatibility'), + '$plugin' => $plugin, + '$status' => $status, + '$action' => $action, + '$info' => $info, + '$str_author' => t('Author: '), + '$str_maintainer' => t('Maintainer: '), + '$str_minversion' => t('Minimum project version: '), + '$str_maxversion' => t('Maximum project version: '), + '$str_minphpversion' => t('Minimum PHP version: '), + '$str_serverroles' => t('Compatible Server Roles: '), + '$str_requires' => t('Requires: '), + '$disabled' => t('Disabled - version incompatibility'), - '$admin_form' => $admin_form, - '$function' => 'addons', - '$screenshot' => '', - '$readme' => $readme, + '$admin_form' => $admin_form, + '$function' => 'addons', + '$screenshot' => '', + '$readme' => $readme, - '$form_security_token' => get_form_security_token('admin_addons'), - )); - } + '$form_security_token' => get_form_security_token('admin_addons'), + )); + } - /* - * List plugins - */ - $plugins = []; - $files = glob('addon/*/'); - if($files) { - foreach($files as $file) { - if ($file === 'addon/vendor/') { - continue; - } - if (is_dir($file)){ - list($tmp, $id) = array_map('trim', explode('/', $file)); - $info = get_plugin_info($id); - $enabled = in_array($id, App::$plugins); - $x = check_plugin_versions($info); + /* + * List plugins + */ + $plugins = []; + $files = glob('addon/*/'); + if ($files) { + foreach ($files as $file) { + if ($file === 'addon/vendor/') { + continue; + } + if (is_dir($file)) { + list($tmp, $id) = array_map('trim', explode('/', $file)); + $info = get_plugin_info($id); + $enabled = in_array($id, App::$plugins); + $x = check_plugin_versions($info); - // disable plugins which are installed but incompatible versions + // disable plugins which are installed but incompatible versions - if($enabled && ! $x) { - $enabled = false; - $idz = array_search($id, App::$plugins); - if ($idz !== false) { - unset(App::$plugins[$idz]); - uninstall_plugin($id); - set_config("system","addon", implode(", ", App::$plugins)); - } - } - $info['disabled'] = 1-intval($x); + if ($enabled && !$x) { + $enabled = false; + $idz = array_search($id, App::$plugins); + if ($idz !== false) { + unset(App::$plugins[$idz]); + uninstall_plugin($id); + set_config("system", "addon", implode(", ", App::$plugins)); + } + } + $info['disabled'] = 1 - intval($x); - $plugins[] = array( $id, (($enabled)?"on":"off") , $info); - } - } - } + $plugins[] = array($id, (($enabled) ? "on" : "off"), $info); + } + } + } - usort($plugins,'self::plugin_sort'); + usort($plugins, 'self::plugin_sort'); - $allowManageRepos = false; - if(is_writable('extend/addon') && is_writable('cache')) { - $allowManageRepos = true; - } + $allowManageRepos = false; + if (is_writable('extend/addon') && is_writable('cache')) { + $allowManageRepos = true; + } - $admin_plugins_add_repo_form= replace_macros( - get_markup_template('admin_plugins_addrepo.tpl'), array( - '$post' => 'admin/addons/addrepo', - '$desc' => t('Enter the public git repository URL of the addon repo.'), - '$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''), - '$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')), - '$submit' => t('Download Addon Repo') - ) - ); - $newRepoModalID = random_string(3); - $newRepoModal = replace_macros( - get_markup_template('generic_modal.tpl'), array( - '$id' => $newRepoModalID, - '$title' => t('Install new repo'), - '$ok' => t('Install'), - '$cancel' => t('Cancel') - ) - ); + $admin_plugins_add_repo_form = replace_macros( + get_markup_template('admin_plugins_addrepo.tpl'), array( + '$post' => 'admin/addons/addrepo', + '$desc' => t('Enter the public git repository URL of the addon repo.'), + '$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''), + '$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')), + '$submit' => t('Download Addon Repo') + ) + ); + $newRepoModalID = random_string(3); + $newRepoModal = replace_macros( + get_markup_template('generic_modal.tpl'), array( + '$id' => $newRepoModalID, + '$title' => t('Install new repo'), + '$ok' => t('Install'), + '$cancel' => t('Cancel') + ) + ); - $reponames = $this->listAddonRepos(); - $addonrepos = []; - foreach($reponames as $repo) { - $addonrepos[] = array('name' => $repo, 'description' => ''); - /// @TODO Parse repo info to provide more information about repos - } + $reponames = $this->listAddonRepos(); + $addonrepos = []; + foreach ($reponames as $repo) { + $addonrepos[] = array('name' => $repo, 'description' => ''); + /// @TODO Parse repo info to provide more information about repos + } - $t = get_markup_template('admin_plugins.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Addons'), - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$function' => 'addons', - '$plugins' => $plugins, - '$disabled' => t('Disabled - version incompatibility'), - '$form_security_token' => get_form_security_token('admin_addons'), - '$allowManageRepos' => $allowManageRepos, - '$managerepos' => t('Manage Repos'), - '$installedtitle' => t('Installed Addon Repositories'), - '$addnewrepotitle' => t('Install a New Addon Repository'), - '$expandform' => false, - '$form' => $admin_plugins_add_repo_form, - '$newRepoModal' => $newRepoModal, - '$newRepoModalID' => $newRepoModalID, - '$addonrepos' => $addonrepos, - '$repoUpdateButton' => t('Update'), - '$repoBranchButton' => t('Switch branch'), - '$repoRemoveButton' => t('Remove') - )); - } + $t = get_markup_template('admin_plugins.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Addons'), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$function' => 'addons', + '$plugins' => $plugins, + '$disabled' => t('Disabled - version incompatibility'), + '$form_security_token' => get_form_security_token('admin_addons'), + '$allowManageRepos' => $allowManageRepos, + '$managerepos' => t('Manage Repos'), + '$installedtitle' => t('Installed Addon Repositories'), + '$addnewrepotitle' => t('Install a New Addon Repository'), + '$expandform' => false, + '$form' => $admin_plugins_add_repo_form, + '$newRepoModal' => $newRepoModal, + '$newRepoModalID' => $newRepoModalID, + '$addonrepos' => $addonrepos, + '$repoUpdateButton' => t('Update'), + '$repoBranchButton' => t('Switch branch'), + '$repoRemoveButton' => t('Remove') + )); + } - function listAddonRepos() { - $addonrepos = []; - $addonDir = 'extend/addon/'; - if(is_dir($addonDir)) { - if ($handle = opendir($addonDir)) { - while (false !== ($entry = readdir($handle))) { - if ($entry != "." && $entry != "..") { - $addonrepos[] = $entry; - } - } - closedir($handle); - } - } - return $addonrepos; - } + public function listAddonRepos() + { + $addonrepos = []; + $addonDir = 'extend/addon/'; + if (is_dir($addonDir)) { + if ($handle = opendir($addonDir)) { + while (false !== ($entry = readdir($handle))) { + if ($entry != "." && $entry != "..") { + $addonrepos[] = $entry; + } + } + closedir($handle); + } + } + return $addonrepos; + } - static public function plugin_sort($a,$b) { - return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name']))); - } + public static function plugin_sort($a, $b) + { + return (strcmp(strtolower($a[2]['name']), strtolower($b[2]['name']))); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Channels.php b/Zotlabs/Module/Admin/Channels.php index d477ed73c..78047daf4 100644 --- a/Zotlabs/Module/Admin/Channels.php +++ b/Zotlabs/Module/Admin/Channels.php @@ -9,178 +9,183 @@ use Zotlabs\Daemon\Run; * @brief Admin Module for Channels. * */ - -class Channels { +class Channels +{ - /** - * @brief Handle POST actions on channels admin page. - * - */ - function post() { + /** + * @brief Handle POST actions on channels admin page. + * + */ + public function post() + { - $channels = ( x($_POST, 'channel') ? $_POST['channel'] : Array() ); + $channels = (x($_POST, 'channel') ? $_POST['channel'] : array()); - check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels'); + check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels'); - $xor = db_getfunc('^'); + $xor = db_getfunc('^'); - if(x($_POST, 'page_channels_block')) { - foreach($channels as $uid) { - q("UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d", - intval(PAGE_CENSORED), - intval( $uid ) - ); - Run::Summon( [ 'Directory', $uid, 'nopush' ] ); - } - notice( sprintf( tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels)) ); - } - if(x($_POST, 'page_channels_code')) { - foreach($channels as $uid) { - q("UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d", - intval(PAGE_ALLOWCODE), - intval( $uid ) - ); - } - notice( sprintf( tt("%s channel code allowed/disallowed", "%s channels code allowed/disallowed", count($channels)), count($channels)) ); - } - if(x($_POST, 'page_channels_delete')) { - foreach($channels as $uid) { - channel_remove($uid, true); - } - notice( sprintf( tt("%s channel deleted", "%s channels deleted", count($channels)), count($channels)) ); - } + if (x($_POST, 'page_channels_block')) { + foreach ($channels as $uid) { + q("UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d", + intval(PAGE_CENSORED), + intval($uid) + ); + Run::Summon(['Directory', $uid, 'nopush']); + } + notice(sprintf(tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels))); + } + if (x($_POST, 'page_channels_code')) { + foreach ($channels as $uid) { + q("UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d", + intval(PAGE_ALLOWCODE), + intval($uid) + ); + } + notice(sprintf(tt("%s channel code allowed/disallowed", "%s channels code allowed/disallowed", count($channels)), count($channels))); + } + if (x($_POST, 'page_channels_delete')) { + foreach ($channels as $uid) { + channel_remove($uid, true); + } + notice(sprintf(tt("%s channel deleted", "%s channels deleted", count($channels)), count($channels))); + } - goaway(z_root() . '/admin/channels' ); - } + goaway(z_root() . '/admin/channels'); + } - /** - * @brief Generate channels admin page and handle single item operations. - * - * @return string with parsed HTML - */ - function get() { - if(argc() > 2) { - $uid = argv(3); - $channel = q("SELECT * FROM channel WHERE channel_id = %d", - intval($uid) - ); + /** + * @brief Generate channels admin page and handle single item operations. + * + * @return string with parsed HTML + */ + public function get() + { + if (argc() > 2) { + $uid = argv(3); + $channel = q("SELECT * FROM channel WHERE channel_id = %d", + intval($uid) + ); - if(! $channel) { - notice( t('Channel not found') . EOL); - goaway(z_root() . '/admin/channels' ); - } + if (!$channel) { + notice(t('Channel not found') . EOL); + goaway(z_root() . '/admin/channels'); + } - switch(argv(2)) { - case "delete":{ - check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); - // delete channel - channel_remove($uid,true); + switch (argv(2)) { + case "delete": + { + check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); + // delete channel + channel_remove($uid, true); - notice( sprintf(t("Channel '%s' deleted"), $channel[0]['channel_name']) . EOL); - } + notice(sprintf(t("Channel '%s' deleted"), $channel[0]['channel_name']) . EOL); + } break; - case "block":{ - check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); - $pflags = $channel[0]['channel_pageflags'] ^ PAGE_CENSORED; - q("UPDATE channel SET channel_pageflags = %d where channel_id = %d", - intval($pflags), - intval( $uid ) - ); - Run::Summon( [ 'Directory', $uid, 'nopush' ]); + case "block": + { + check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); + $pflags = $channel[0]['channel_pageflags'] ^ PAGE_CENSORED; + q("UPDATE channel SET channel_pageflags = %d where channel_id = %d", + intval($pflags), + intval($uid) + ); + Run::Summon(['Directory', $uid, 'nopush']); - notice( sprintf( (($pflags & PAGE_CENSORED) ? t("Channel '%s' censored"): t("Channel '%s' uncensored")) , $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')' ) . EOL); - } + notice(sprintf((($pflags & PAGE_CENSORED) ? t("Channel '%s' censored") : t("Channel '%s' uncensored")), $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')') . EOL); + } break; - case "code":{ - check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); - $pflags = $channel[0]['channel_pageflags'] ^ PAGE_ALLOWCODE; - q("UPDATE channel SET channel_pageflags = %d where channel_id = %d", - intval($pflags), - intval( $uid ) - ); + case "code": + { + check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't'); + $pflags = $channel[0]['channel_pageflags'] ^ PAGE_ALLOWCODE; + q("UPDATE channel SET channel_pageflags = %d where channel_id = %d", + intval($pflags), + intval($uid) + ); - notice( sprintf( (($pflags & PAGE_ALLOWCODE) ? t("Channel '%s' code allowed"): t("Channel '%s' code disallowed")) , $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')' ) . EOL); - } + notice(sprintf((($pflags & PAGE_ALLOWCODE) ? t("Channel '%s' code allowed") : t("Channel '%s' code disallowed")), $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')') . EOL); + } break; - default: - break; - } - goaway(z_root() . '/admin/channels' ); - } + default: + break; + } + goaway(z_root() . '/admin/channels'); + } - $key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'channel_id'); - $dir = 'asc'; - if(array_key_exists('dir',$_REQUEST)) - $dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc'); + $key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'channel_id'); + $dir = 'asc'; + if (array_key_exists('dir', $_REQUEST)) + $dir = ((intval($_REQUEST['dir'])) ? 'asc' : 'desc'); - $base = z_root() . '/admin/channels?f='; - $odir = (($dir === 'asc') ? '0' : '1'); + $base = z_root() . '/admin/channels?f='; + $odir = (($dir === 'asc') ? '0' : '1'); - /* get channels */ + /* get channels */ - $total = q("SELECT count(*) as total FROM channel where channel_removed = 0 and channel_system = 0"); - if($total) { - App::set_pager_total($total[0]['total']); - App::set_pager_itemspage(100); - } + $total = q("SELECT count(*) as total FROM channel where channel_removed = 0 and channel_system = 0"); + if ($total) { + App::set_pager_total($total[0]['total']); + App::set_pager_itemspage(100); + } - $channels = q("SELECT * from channel where channel_removed = 0 and channel_system = 0 order by $key $dir limit %d offset %d ", - intval(App::$pager['itemspage']), - intval(App::$pager['start']) - ); + $channels = q("SELECT * from channel where channel_removed = 0 and channel_system = 0 order by $key $dir limit %d offset %d ", + intval(App::$pager['itemspage']), + intval(App::$pager['start']) + ); - if($channels) { - for($x = 0; $x < count($channels); $x ++) { - if($channels[$x]['channel_pageflags'] & PAGE_CENSORED) - $channels[$x]['blocked'] = true; - else - $channels[$x]['blocked'] = false; + if ($channels) { + for ($x = 0; $x < count($channels); $x++) { + if ($channels[$x]['channel_pageflags'] & PAGE_CENSORED) + $channels[$x]['blocked'] = true; + else + $channels[$x]['blocked'] = false; - if($channels[$x]['channel_pageflags'] & PAGE_ALLOWCODE) - $channels[$x]['allowcode'] = true; - else - $channels[$x]['allowcode'] = false; - - $channels[$x]['channel_link'] = z_root() . '/channel/' . $channels[$x]['channel_address']; - } - } + if ($channels[$x]['channel_pageflags'] & PAGE_ALLOWCODE) + $channels[$x]['allowcode'] = true; + else + $channels[$x]['allowcode'] = false; - call_hooks('admin_channels',$channels); + $channels[$x]['channel_link'] = z_root() . '/channel/' . $channels[$x]['channel_address']; + } + } - $o = replace_macros(get_markup_template('admin_channels.tpl'), [ - // strings // - '$title' => t('Administration'), - '$page' => t('Channels'), - '$submit' => t('Submit'), - '$select_all' => t('select all'), - '$delete' => t('Delete'), - '$block' => t('Censor'), - '$unblock' => t('Uncensor'), - '$code' => t('Allow Code'), - '$uncode' => t('Disallow Code'), - '$h_channels' => t('Channel'), - '$base' => $base, - '$odir' => $odir, - '$th_channels' => array( - [ t('UID'), 'channel_id' ], - [ t('Name'), 'channel_name' ], - [ t('Address'), 'channel_address' ]), + call_hooks('admin_channels', $channels); - '$confirm_delete_multi' => t('Selected channels will be deleted!\n\nEverything that was posted in these channels on this site will be permanently deleted!\n\nAre you sure?'), - '$confirm_delete' => t('The channel {0} will be deleted!\n\nEverything that was posted in this channel on this site will be permanently deleted!\n\nAre you sure?'), + $o = replace_macros(get_markup_template('admin_channels.tpl'), [ + // strings // + '$title' => t('Administration'), + '$page' => t('Channels'), + '$submit' => t('Submit'), + '$select_all' => t('select all'), + '$delete' => t('Delete'), + '$block' => t('Censor'), + '$unblock' => t('Uncensor'), + '$code' => t('Allow Code'), + '$uncode' => t('Disallow Code'), + '$h_channels' => t('Channel'), + '$base' => $base, + '$odir' => $odir, + '$th_channels' => array( + [t('UID'), 'channel_id'], + [t('Name'), 'channel_name'], + [t('Address'), 'channel_address']), - '$form_security_token' => get_form_security_token('admin_channels'), + '$confirm_delete_multi' => t('Selected channels will be deleted!\n\nEverything that was posted in these channels on this site will be permanently deleted!\n\nAre you sure?'), + '$confirm_delete' => t('The channel {0} will be deleted!\n\nEverything that was posted in this channel on this site will be permanently deleted!\n\nAre you sure?'), - // values // - '$baseurl' => z_root(), - '$channels' => $channels, - ]); - $o .= paginate($a); + '$form_security_token' => get_form_security_token('admin_channels'), - return $o; - } + // values // + '$baseurl' => z_root(), + '$channels' => $channels, + ]); + $o .= paginate($a); + + return $o; + } } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Cover_photo.php b/Zotlabs/Module/Admin/Cover_photo.php index 78c9db161..27b1d390c 100644 --- a/Zotlabs/Module/Admin/Cover_photo.php +++ b/Zotlabs/Module/Admin/Cover_photo.php @@ -25,422 +25,419 @@ require_once('include/photos.php'); * @return void * */ +class Cover_photo +{ + + public function init() + { + if (!is_site_admin()) { + return; + } + + $channel = get_sys_channel(); + Libprofile::load($channel['channel_address']); + } + + /** + * @brief Evaluate posted values + * + * @return void + * + */ + + public function post() + { + + if (!is_site_admin()) { + return; + } + + $channel = get_sys_channel(); + + check_form_security_token_redirectOnErr('/admin/cover_photo', 'cover_photo'); + + if ((array_key_exists('cropfinal', $_POST)) && ($_POST['cropfinal'] == 1)) { + + // phase 2 - we have finished cropping + + if (argc() != 3) { + notice(t('Image uploaded but image cropping failed.') . EOL); + return; + } + + $image_id = argv(2); + + if (substr($image_id, -2, 1) == '-') { + $scale = substr($image_id, -1, 1); + $image_id = substr($image_id, 0, -2); + } -class Cover_photo { + $srcX = intval($_POST['xstart']); + $srcY = intval($_POST['ystart']); + $srcW = intval($_POST['xfinal']) - $srcX; + $srcH = intval($_POST['yfinal']) - $srcY; - function init() { - if (! is_site_admin()) { - return; - } - - $channel = get_sys_channel(); - Libprofile::load($channel['channel_address']); - } - - /** - * @brief Evaluate posted values - * - * @return void - * - */ - - function post() { - - if (! is_site_admin()) { - return; - } - - $channel = get_sys_channel(); - - check_form_security_token_redirectOnErr('/admin/cover_photo', 'cover_photo'); - - if ((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) { - - // phase 2 - we have finished cropping - - if (argc() != 3) { - notice( t('Image uploaded but image cropping failed.') . EOL ); - return; - } - - $image_id = argv(2); - - if (substr($image_id,-2,1) == '-') { - $scale = substr($image_id,-1,1); - $image_id = substr($image_id,0,-2); - } - + $r = q("select gender from profile where uid = %d and is_default = 1 limit 1", + intval($channel['channel_id']) + ); + if ($r) { + $profile = array_shift($r); + } + + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1", + dbesc($image_id), + intval($channel['channel_id']) + ); + + if ($r) { + + $max_thumb = intval(get_config('system', 'max_thumbnail', 1600)); + $iscaled = false; + if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) { + $imagick_path = get_config('system', 'imagick_convert_path'); + if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) { + + $fname = dbunescbin($r[0]['content']); + $tmp_name = $fname . '-001'; + $newsize = photo_calculate_scale(array_merge(getimagesize($fname), ['max' => $max_thumb])); + $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name); + // logger('imagick thumbnail command: ' . $cmd); + for ($x = 0; $x < 4; $x++) { + exec($cmd); + if (file_exists($tmp_name)) { + break; + } + } + if (file_exists($tmp_name)) { + $base_image = $r[0]; + $gis = getimagesize($tmp_name); + logger('gis: ' . print_r($gis, true)); + $base_image['width'] = $gis[0]; + $base_image['height'] = $gis[1]; + $base_image['content'] = @file_get_contents($tmp_name); + $iscaled = true; + @unlink($tmp_name); + } + } + } + if (!$iscaled) { + $base_image = $r[0]; + $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); + } + + $im = photo_factory($base_image['content'], $base_image['mimetype']); + if ($im->is_valid()) { + + // We are scaling and cropping the relative pixel locations to the original photo instead of the + // scaled photo we operated on. + + // First load the scaled photo to check its size. (Should probably pass this in the post form and save + // a query.) + + $g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3", + dbesc($image_id), + intval($channel['channel_id']) + ); - $srcX = intval($_POST['xstart']); - $srcY = intval($_POST['ystart']); - $srcW = intval($_POST['xfinal']) - $srcX; - $srcH = intval($_POST['yfinal']) - $srcY; - - $r = q("select gender from profile where uid = %d and is_default = 1 limit 1", - intval($channel['channel_id']) - ); - if ($r) { - $profile = array_shift($r); - } - - $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1", - dbesc($image_id), - intval($channel['channel_id']) - ); - - if ($r) { + $scaled_width = $g[0]['width']; + $scaled_height = $g[0]['height']; - $max_thumb = intval(get_config('system','max_thumbnail',1600)); - $iscaled = false; - if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) { - $imagick_path = get_config('system','imagick_convert_path'); - if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) { + if ((!$scaled_width) || (!$scaled_height)) { + logger('potential divide by zero scaling cover photo'); + return; + } - $fname = dbunescbin($r[0]['content']); - $tmp_name = $fname . '-001'; - $newsize = photo_calculate_scale(array_merge(getimagesize($fname),['max' => $max_thumb])); - $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name); - // logger('imagick thumbnail command: ' . $cmd); - for ($x = 0; $x < 4; $x ++) { - exec($cmd); - if (file_exists($tmp_name)) { - break; - } - } - if (file_exists($tmp_name)) { - $base_image = $r[0]; - $gis = getimagesize($tmp_name); -logger('gis: ' . print_r($gis,true)); - $base_image['width'] = $gis[0]; - $base_image['height'] = $gis[1]; - $base_image['content'] = @file_get_contents($tmp_name); - $iscaled = true; - @unlink($tmp_name); - } - } - } - if (! $iscaled) { - $base_image = $r[0]; - $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); - } + // unset all other cover photos - $im = photo_factory($base_image['content'], $base_image['mimetype']); - if ($im->is_valid()) { - - // We are scaling and cropping the relative pixel locations to the original photo instead of the - // scaled photo we operated on. - - // First load the scaled photo to check its size. (Should probably pass this in the post form and save - // a query.) - - $g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3", - dbesc($image_id), - intval($channel['channel_id']) - ); - - - $scaled_width = $g[0]['width']; - $scaled_height = $g[0]['height']; - - if ((! $scaled_width) || (! $scaled_height)) { - logger('potential divide by zero scaling cover photo'); - return; - } - - // unset all other cover photos - - q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_COVER), - intval($channel['channel_id']) - ); - - $orig_srcx = ( $base_image['width'] / $scaled_width ) * $srcX; - $orig_srcy = ( $base_image['height'] / $scaled_height ) * $srcY; - $orig_srcw = ( $srcW / $scaled_width ) * $base_image['width']; - $orig_srch = ( $srcH / $scaled_height ) * $base_image['height']; - - $im->cropImageRect(1200,435,$orig_srcx, $orig_srcy, $orig_srcw, $orig_srch); - - $aid = get_account_id(); - - $p = [ - 'aid' => 0, - 'uid' => $channel['channel_id'], - 'resource_id' => $base_image['resource_id'], - 'filename' => $base_image['filename'], - 'album' => t('Cover Photos'), - 'os_path' => $base_image['os_path'], - 'display_path' => $base_image['display_path'], - 'created' => $base_image['created'], - 'edited' => $base_image['edited'] - ]; - - $p['imgscale'] = 7; - $p['photo_usage'] = PHOTO_COVER; - - $r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200); + q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_COVER), + intval($channel['channel_id']) + ); - $im->doScaleImage(850,310); - $p['imgscale'] = 8; + $orig_srcx = ($base_image['width'] / $scaled_width) * $srcX; + $orig_srcy = ($base_image['height'] / $scaled_height) * $srcY; + $orig_srcw = ($srcW / $scaled_width) * $base_image['width']; + $orig_srch = ($srcH / $scaled_height) * $base_image['height']; - $r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850); - - $im->doScaleImage(425,160); - $p['imgscale'] = 9; - - $r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425); - - if ($r1 === false || $r2 === false || $r3 === false) { - // if one failed, delete them all so we can start over. - notice( t('Image resize failed.') . EOL ); - $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ", - dbesc($base_image['resource_id']), - intval($channel['channel_id']) - ); - return; - } - - } - else - notice( t('Unable to process image') . EOL); - } - - goaway(z_root() . '/admin'); - - } - - - $hash = photo_new_resource(); - $smallest = 0; - - $matches = []; - $partial = false; + $im->cropImageRect(1200, 435, $orig_srcx, $orig_srcy, $orig_srcw, $orig_srch); - if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { - $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); - if ($pm) { - logger('Content-Range: ' . print_r($matches,true)); - $partial = true; - } - } + $aid = get_account_id(); - if ($partial) { - $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + $p = [ + 'aid' => 0, + 'uid' => $channel['channel_id'], + 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], + 'album' => t('Cover Photos'), + 'os_path' => $base_image['os_path'], + 'display_path' => $base_image['display_path'], + 'created' => $base_image['created'], + 'edited' => $base_image['edited'] + ]; - if ($x['partial']) { - header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($x); - } - else { - header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + $p['imgscale'] = 7; + $p['photo_usage'] = PHOTO_COVER; - $_FILES['userfile'] = [ - 'name' => $x['name'], - 'type' => $x['type'], - 'tmp_name' => $x['tmp_name'], - 'error' => $x['error'], - 'size' => $x['size'] - ]; - } - } - else { - if (! array_key_exists('userfile',$_FILES)) { - $_FILES['userfile'] = [ - 'name' => $_FILES['files']['name'], - 'type' => $_FILES['files']['type'], - 'tmp_name' => $_FILES['files']['tmp_name'], - 'error' => $_FILES['files']['error'], - 'size' => $_FILES['files']['size'] - ]; - } - } + $r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200); - $res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Cover Photos'), 'hash' => $hash)); - - logger('attach_store: ' . print_r($res,true),LOGGER_DEBUG); + $im->doScaleImage(850, 310); + $p['imgscale'] = 8; - json_return_and_die([ 'message' => $hash ]); - - } - - - /** - * @brief Generate content of profile-photo view - * - * @return string - * - */ - - - function get() { - - if (! is_site_admin()) { - notice( t('Permission denied.') . EOL ); - return; - } - - $channel = get_sys_channel(); - - $newuser = false; - - if (argc() == 3 && argv(1) === 'new') - $newuser = true; + $r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850); + + $im->doScaleImage(425, 160); + $p['imgscale'] = 9; + + $r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425); + + if ($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice(t('Image resize failed.') . EOL); + $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ", + dbesc($base_image['resource_id']), + intval($channel['channel_id']) + ); + return; + } + + } else + notice(t('Unable to process image') . EOL); + } + + goaway(z_root() . '/admin'); + + } - if (argv(2) === 'reset') { - q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_COVER), - intval($channel['channel_id']) - ); - } + $hash = photo_new_resource(); + $smallest = 0; - if (argv(2) === 'use') { - if (argc() < 4) { - notice( t('Permission denied.') . EOL ); - return; - } + $matches = []; + $partial = false; + + if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches, true)); + $partial = true; + } + } + + if ($partial) { + $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]); + + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($x); + } else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } else { + if (!array_key_exists('userfile', $_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Cover Photos'), 'hash' => $hash)); + + logger('attach_store: ' . print_r($res, true), LOGGER_DEBUG); + + json_return_and_die(['message' => $hash]); + + } + + + /** + * @brief Generate content of profile-photo view + * + * @return string + * + */ + + + public function get() + { + + if (!is_site_admin()) { + notice(t('Permission denied.') . EOL); + return; + } + + $channel = get_sys_channel(); + + $newuser = false; + + if (argc() == 3 && argv(1) === 'new') + $newuser = true; + + + if (argv(2) === 'reset') { + q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_COVER), + intval($channel['channel_id']) + ); + } + + if (argv(2) === 'use') { + if (argc() < 4) { + notice(t('Permission denied.') . EOL); + return; + } // check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); - - $resource_id = argv(3); - - $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC", - intval($channel['channel_id']), - dbesc($resource_id) - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - $havescale = false; - foreach ($r as $rr) { - if ($rr['imgscale'] == 7) { - $havescale = true; - } - } - - $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", - intval($r[0]['id']), - intval($channel['channel_id']) - - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - - if (intval($r[0]['os_storage'])) { - $data = @file_get_contents(dbunescbin($r[0]['content'])); - } - else { - $data = dbunescbin($r[0]['content']); - } - - $ph = photo_factory($data, $r[0]['mimetype']); - $smallest = 0; - if ($ph->is_valid()) { - // go ahead as if we have just uploaded a new photo to crop - $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0", - dbesc($r[0]['resource_id']), - intval($channel['channel_id']) - ); - - if ($i) { - $hash = $i[0]['resource_id']; - foreach ($i as $ii) { - $smallest = intval($ii['imgscale']); - } - } - } - - $this->cover_photo_crop_ui_head($ph, $hash, $smallest); - } - - - if(! array_key_exists('imagecrop',App::$data)) { - - $o .= replace_macros(get_markup_template('admin_cover_photo.tpl'), [ - '$user' => $channel['channel_address'], - '$channel_id' => $channel['channel_id'], - '$info' => t('Your cover photo may be visible to anybody on the internet'), - '$existing' => get_cover_photo($channel['channel_id'],'array',PHOTO_RES_COVER_850), - '$lbl_upfile' => t('Upload File:'), - '$lbl_profiles' => t('Select a profile:'), - '$title' => t('Change Cover Photo'), - '$submit' => t('Upload'), - '$profiles' => $profiles, - '$embedPhotos' => t('Use a photo from your albums'), - '$embedPhotosModalTitle' => t('Use a photo from your albums'), - '$embedPhotosModalCancel' => t('Cancel'), - '$embedPhotosModalOK' => t('OK'), - '$modalchooseimages' => t('Choose images to embed'), - '$modalchoosealbum' => t('Choose an album'), - '$modaldiffalbum' => t('Choose a different album'), - '$modalerrorlist' => t('Error getting album list'), - '$modalerrorlink' => t('Error getting photo link'), - '$modalerroralbum' => t('Error getting album'), - '$form_security_token' => get_form_security_token("cover_photo"), - '$select' => t('Select previously uploaded photo'), - ]); - - call_hooks('cover_photo_content_end', $o); - - return $o; - } - else { - $filename = App::$data['imagecrop'] . '-3'; - $resolution = 3; + $resource_id = argv(3); + + $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC", + intval($channel['channel_id']), + dbesc($resource_id) + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + $havescale = false; + foreach ($r as $rr) { + if ($rr['imgscale'] == 7) { + $havescale = true; + } + } + + $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval($channel['channel_id']) + + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + + if (intval($r[0]['os_storage'])) { + $data = @file_get_contents(dbunescbin($r[0]['content'])); + } else { + $data = dbunescbin($r[0]['content']); + } + + $ph = photo_factory($data, $r[0]['mimetype']); + $smallest = 0; + if ($ph->is_valid()) { + // go ahead as if we have just uploaded a new photo to crop + $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0", + dbesc($r[0]['resource_id']), + intval($channel['channel_id']) + ); + + if ($i) { + $hash = $i[0]['resource_id']; + foreach ($i as $ii) { + $smallest = intval($ii['imgscale']); + } + } + } + + $this->cover_photo_crop_ui_head($ph, $hash, $smallest); + } + + + if (!array_key_exists('imagecrop', App::$data)) { + + $o .= replace_macros(get_markup_template('admin_cover_photo.tpl'), [ + '$user' => $channel['channel_address'], + '$channel_id' => $channel['channel_id'], + '$info' => t('Your cover photo may be visible to anybody on the internet'), + '$existing' => get_cover_photo($channel['channel_id'], 'array', PHOTO_RES_COVER_850), + '$lbl_upfile' => t('Upload File:'), + '$lbl_profiles' => t('Select a profile:'), + '$title' => t('Change Cover Photo'), + '$submit' => t('Upload'), + '$profiles' => $profiles, + '$embedPhotos' => t('Use a photo from your albums'), + '$embedPhotosModalTitle' => t('Use a photo from your albums'), + '$embedPhotosModalCancel' => t('Cancel'), + '$embedPhotosModalOK' => t('OK'), + '$modalchooseimages' => t('Choose images to embed'), + '$modalchoosealbum' => t('Choose an album'), + '$modaldiffalbum' => t('Choose a different album'), + '$modalerrorlist' => t('Error getting album list'), + '$modalerrorlink' => t('Error getting photo link'), + '$modalerroralbum' => t('Error getting album'), + '$form_security_token' => get_form_security_token("cover_photo"), + '$select' => t('Select previously uploaded photo'), + + ]); + + call_hooks('cover_photo_content_end', $o); + + return $o; + } else { + $filename = App::$data['imagecrop'] . '-3'; + $resolution = 3; + + $o .= replace_macros(get_markup_template('admin_cropcover.tpl'), [ + '$filename' => $filename, + '$profile' => intval($_REQUEST['profile']), + '$resource' => App::$data['imagecrop'] . '-3', + '$image_url' => z_root() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), + '$form_security_token' => get_form_security_token("cover_photo"), + '$done' => t('Done Editing') + ]); + return $o; + } + } + + /* @brief Generate the UI for photo-cropping + * + * @param $a Current application + * @param $ph Photo-Factory + * @return void + * + */ + + public function cover_photo_crop_ui_head($ph, $hash, $smallest) + { + + $max_length = get_config('system', 'max_image_length', MAX_IMAGE_LENGTH); + + if ($max_length > 0) { + $ph->scaleImage($max_length); + } + + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + if ($width < 300 || $height < 300) { + $ph->scaleImageUp(240); + $width = $ph->getWidth(); + $height = $ph->getHeight(); + } + + + App::$data['imagecrop'] = $hash; + App::$data['imagecrop_resolution'] = $smallest; + App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); + return; + } - $o .= replace_macros(get_markup_template('admin_cropcover.tpl'), [ - '$filename' => $filename, - '$profile' => intval($_REQUEST['profile']), - '$resource' => App::$data['imagecrop'] . '-3', - '$image_url' => z_root() . '/photo/' . $filename, - '$title' => t('Crop Image'), - '$desc' => t('Please adjust the image cropping for optimum viewing.'), - '$form_security_token' => get_form_security_token("cover_photo"), - '$done' => t('Done Editing') - ]); - return $o; - } - } - - /* @brief Generate the UI for photo-cropping - * - * @param $a Current application - * @param $ph Photo-Factory - * @return void - * - */ - - function cover_photo_crop_ui_head($ph, $hash, $smallest){ - - $max_length = get_config('system','max_image_length', MAX_IMAGE_LENGTH); - if ($max_length > 0) { - $ph->scaleImage($max_length); - } - - $width = $ph->getWidth(); - $height = $ph->getHeight(); - - if ($width < 300 || $height < 300) { - $ph->scaleImageUp(240); - $width = $ph->getWidth(); - $height = $ph->getHeight(); - } - - - App::$data['imagecrop'] = $hash; - App::$data['imagecrop_resolution'] = $smallest; - App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); - return; - } - - } diff --git a/Zotlabs/Module/Admin/Dbsync.php b/Zotlabs/Module/Admin/Dbsync.php index 3d8130fe6..8d8cda46e 100644 --- a/Zotlabs/Module/Admin/Dbsync.php +++ b/Zotlabs/Module/Admin/Dbsync.php @@ -3,111 +3,101 @@ namespace Zotlabs\Module\Admin; - -class Dbsync { - - - function get() { - $o = ''; - - if(argc() > 3 && intval(argv(3)) && argv(2) === 'mark') { - // remove the old style config if it exists - del_config('database', 'update_r' . intval(argv(3))); - set_config('database', '_' . intval(argv(3)), 'success'); - if(intval(get_config('system','db_version')) < intval(argv(3))) - set_config('system','db_version',intval(argv(3))); - info( t('Update has been marked successful') . EOL); - goaway(z_root() . '/admin/dbsync'); - } - - if(argc() > 3 && intval(argv(3)) && argv(2) === 'verify') { - - $s = '_' . intval(argv(3)); - $cls = '\\Zotlabs\Update\\' . $s ; - if(class_exists($cls)) { - $c = new $cls(); - if(method_exists($c,'verify')) { - $retval = $c->verify(); - if($retval === UPDATE_FAILED) { - $o .= sprintf( t('Verification of update %s failed. Check system logs.'), $s); - } - elseif($retval === UPDATE_SUCCESS) { - $o .= sprintf( t('Update %s was successfully applied.'), $s); - set_config('database',$s, 'success'); - } - else - $o .= sprintf( t('Verifying update %s did not return a status. Unknown if it succeeded.'), $s); - } - else { - $o .= sprintf( t('Update %s does not contain a verification function.'), $s ); - } - } - else - $o .= sprintf( t('Update function %s could not be found.'), $s); - - return $o; +class Dbsync +{ + public function get() + { + $o = ''; + + if (argc() > 3 && intval(argv(3)) && argv(2) === 'mark') { + // remove the old style config if it exists + del_config('database', 'update_r' . intval(argv(3))); + set_config('database', '_' . intval(argv(3)), 'success'); + if (intval(get_config('system', 'db_version')) < intval(argv(3))) + set_config('system', 'db_version', intval(argv(3))); + info(t('Update has been marked successful') . EOL); + goaway(z_root() . '/admin/dbsync'); + } + + if (argc() > 3 && intval(argv(3)) && argv(2) === 'verify') { + + $s = '_' . intval(argv(3)); + $cls = '\\Zotlabs\Update\\' . $s; + if (class_exists($cls)) { + $c = new $cls(); + if (method_exists($c, 'verify')) { + $retval = $c->verify(); + if ($retval === UPDATE_FAILED) { + $o .= sprintf(t('Verification of update %s failed. Check system logs.'), $s); + } elseif ($retval === UPDATE_SUCCESS) { + $o .= sprintf(t('Update %s was successfully applied.'), $s); + set_config('database', $s, 'success'); + } else + $o .= sprintf(t('Verifying update %s did not return a status. Unknown if it succeeded.'), $s); + } else { + $o .= sprintf(t('Update %s does not contain a verification function.'), $s); + } + } else + $o .= sprintf(t('Update function %s could not be found.'), $s); + + return $o; + // remove the old style config if it exists + del_config('database', 'update_r' . intval(argv(3))); + set_config('database', '_' . intval(argv(3)), 'success'); + if (intval(get_config('system', 'db_version')) < intval(argv(3))) + set_config('system', 'db_version', intval(argv(3))); + info(t('Update has been marked successful') . EOL); + goaway(z_root() . '/admin/dbsync'); + } - // remove the old style config if it exists - del_config('database', 'update_r' . intval(argv(3))); - set_config('database', '_' . intval(argv(3)), 'success'); - if(intval(get_config('system','db_version')) < intval(argv(3))) - set_config('system','db_version',intval(argv(3))); - info( t('Update has been marked successful') . EOL); - goaway(z_root() . '/admin/dbsync'); - } + if (argc() > 2 && intval(argv(2))) { + $x = intval(argv(2)); + $s = '_' . $x; + $cls = '\\Zotlabs\Update\\' . $s; + if (class_exists($cls)) { + $c = new $cls(); + $retval = $c->run(); + if ($retval === UPDATE_FAILED) { + $o .= sprintf(t('Executing update procedure %s failed. Check system logs.'), $s); + } elseif ($retval === UPDATE_SUCCESS) { + $o .= sprintf(t('Update %s was successfully applied.'), $s); + set_config('database', $s, 'success'); + } else + $o .= sprintf(t('Update %s did not return a status. It cannot be determined if it was successful.'), $s); + } else + $o .= sprintf(t('Update function %s could not be found.'), $s); - if(argc() > 2 && intval(argv(2))) { - $x = intval(argv(2)); - $s = '_' . $x; - $cls = '\\Zotlabs\Update\\' . $s ; - if(class_exists($cls)) { - $c = new $cls(); - $retval = $c->run(); - if($retval === UPDATE_FAILED) { - $o .= sprintf( t('Executing update procedure %s failed. Check system logs.'), $s); - } - elseif($retval === UPDATE_SUCCESS) { - $o .= sprintf( t('Update %s was successfully applied.'), $s); - set_config('database',$s, 'success'); - } - else - $o .= sprintf( t('Update %s did not return a status. It cannot be determined if it was successful.'), $s); - } - else - $o .= sprintf( t('Update function %s could not be found.'), $s); - - return $o; - } - - $failed = []; - $r = q("select * from config where cat = 'database' "); - if(count($r)) { - foreach($r as $rr) { - $upd = intval(substr($rr['k'],-4)); - if($rr['v'] === 'success') - continue; - $failed[] = $upd; - } - } - if(count($failed)) { - $o = replace_macros(get_markup_template('failed_updates.tpl'),array( - '$base' => z_root(), - '$banner' => t('Failed Updates'), - '$desc' => '', - '$mark' => t('Mark success (if update was manually applied)'), - '$verify' => t('Attempt to verify this update if a verification procedure exists'), - '$apply' => t('Attempt to execute this update step automatically'), - '$failed' => $failed - )); - } - else { - return '

        ' . t('No failed updates.') . '

        '; - } - - return $o; - } + return $o; + } + + $failed = []; + $r = q("select * from config where cat = 'database' "); + if (count($r)) { + foreach ($r as $rr) { + $upd = intval(substr($rr['k'], -4)); + if ($rr['v'] === 'success') + continue; + $failed[] = $upd; + } + } + if (count($failed)) { + $o = replace_macros(get_markup_template('failed_updates.tpl'), array( + '$base' => z_root(), + '$banner' => t('Failed Updates'), + '$desc' => '', + '$mark' => t('Mark success (if update was manually applied)'), + '$verify' => t('Attempt to verify this update if a verification procedure exists'), + '$apply' => t('Attempt to execute this update step automatically'), + '$failed' => $failed + )); + } else { + return '

        ' . t('No failed updates.') . '

        '; + } + + return $o; + } } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Logs.php b/Zotlabs/Module/Admin/Logs.php index c83fc6a9a..f5c5fa325 100644 --- a/Zotlabs/Module/Admin/Logs.php +++ b/Zotlabs/Module/Admin/Logs.php @@ -3,99 +3,97 @@ namespace Zotlabs\Module\Admin; -class Logs { +class Logs +{ - - /** - * @brief POST handler for logs admin page. - * - */ + /** + * @brief POST handler for logs admin page. + * + */ - function post() { - if (x($_POST, 'page_logs')) { - check_form_security_token_redirectOnErr('/admin/logs', 'admin_logs'); - - $logfile = ((x($_POST,'logfile')) ? notags(trim($_POST['logfile'])) : ''); - $debugging = ((x($_POST,'debugging')) ? true : false); - $loglevel = ((x($_POST,'loglevel')) ? intval(trim($_POST['loglevel'])) : 0); - - set_config('system','logfile', $logfile); - set_config('system','debugging', $debugging); - set_config('system','loglevel', $loglevel); - } - - info( t('Log settings updated.') ); - goaway(z_root() . '/admin/logs' ); - } - - /** - * @brief Logs admin page. - * - * @return string - */ + public function post() + { + if (x($_POST, 'page_logs')) { + check_form_security_token_redirectOnErr('/admin/logs', 'admin_logs'); - function get() { - - $log_choices = Array( - LOGGER_NORMAL => 'Normal', - LOGGER_TRACE => 'Trace', - LOGGER_DEBUG => 'Debug', - LOGGER_DATA => 'Data', - LOGGER_ALL => 'All' - ); - - $t = get_markup_template('admin_logs.tpl'); - - $f = get_config('system', 'logfile'); - - $data = ''; - - if(!file_exists($f)) { - $data = t("Error trying to open $f log file.\r\n
        Check to see if file $f exist and is + $logfile = ((x($_POST, 'logfile')) ? notags(trim($_POST['logfile'])) : ''); + $debugging = ((x($_POST, 'debugging')) ? true : false); + $loglevel = ((x($_POST, 'loglevel')) ? intval(trim($_POST['loglevel'])) : 0); + + set_config('system', 'logfile', $logfile); + set_config('system', 'debugging', $debugging); + set_config('system', 'loglevel', $loglevel); + } + + info(t('Log settings updated.')); + goaway(z_root() . '/admin/logs'); + } + + /** + * @brief Logs admin page. + * + * @return string + */ + + public function get() + { + + $log_choices = array( + LOGGER_NORMAL => 'Normal', + LOGGER_TRACE => 'Trace', + LOGGER_DEBUG => 'Debug', + LOGGER_DATA => 'Data', + LOGGER_ALL => 'All' + ); + + $t = get_markup_template('admin_logs.tpl'); + + $f = get_config('system', 'logfile'); + + $data = ''; + + if (!file_exists($f)) { + $data = t("Error trying to open $f log file.\r\n
        Check to see if file $f exist and is readable."); - } - else { - $fp = fopen($f, 'r'); - if(!$fp) { - $data = t("Couldn't open $f log file.\r\n
        Check to see if file $f is readable."); - } - else { - $fstat = fstat($fp); - $size = $fstat['size']; - if($size != 0) - { - if($size > 5000000 || $size < 0) - $size = 5000000; - $seek = fseek($fp,0-$size,SEEK_END); - if($seek === 0) { - $data = escape_tags(fread($fp,$size)); - while(! feof($fp)) - $data .= escape_tags(fread($fp,4096)); - } - } - fclose($fp); - } - } - - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Logs'), - '$submit' => t('Submit'), - '$clear' => t('Clear'), - '$data' => $data, - '$baseurl' => z_root(), - '$logname' => get_config('system','logfile'), - - // name, label, value, help string, extra data... - '$debugging' => array('debugging', t("Debugging"),get_config('system','debugging'), ""), - '$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), t("Must be writable by web server. Relative to your top-level webserver directory.")), - '$loglevel' => array('loglevel', t("Log level"), get_config('system','loglevel'), "", $log_choices), - - '$form_security_token' => get_form_security_token('admin_logs'), - )); - } - + } else { + $fp = fopen($f, 'r'); + if (!$fp) { + $data = t("Couldn't open $f log file.\r\n
        Check to see if file $f is readable."); + } else { + $fstat = fstat($fp); + $size = $fstat['size']; + if ($size != 0) { + if ($size > 5000000 || $size < 0) + $size = 5000000; + $seek = fseek($fp, 0 - $size, SEEK_END); + if ($seek === 0) { + $data = escape_tags(fread($fp, $size)); + while (!feof($fp)) + $data .= escape_tags(fread($fp, 4096)); + } + } + fclose($fp); + } + } + + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Logs'), + '$submit' => t('Submit'), + '$clear' => t('Clear'), + '$data' => $data, + '$baseurl' => z_root(), + '$logname' => get_config('system', 'logfile'), + + // name, label, value, help string, extra data... + '$debugging' => array('debugging', t("Debugging"), get_config('system', 'debugging'), ""), + '$logfile' => array('logfile', t("Log file"), get_config('system', 'logfile'), t("Must be writable by web server. Relative to your top-level webserver directory.")), + '$loglevel' => array('loglevel', t("Log level"), get_config('system', 'loglevel'), "", $log_choices), + + '$form_security_token' => get_form_security_token('admin_logs'), + )); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Profile_photo.php b/Zotlabs/Module/Admin/Profile_photo.php index a1c731324..a888503ec 100644 --- a/Zotlabs/Module/Admin/Profile_photo.php +++ b/Zotlabs/Module/Admin/Profile_photo.php @@ -19,516 +19,513 @@ require_once('include/photo_factory.php'); require_once('include/photos.php'); -class Profile_photo { - - - /* @brief Initalize the profile-photo edit view - * - * @return void - * - */ - - function init() { - - if(! is_site_admin()) { - return; - } - - $channel = get_sys_channel(); - Libprofile::load($channel['channel_address']); - - } - - /* @brief Evaluate posted values - * - * @param $a Current application - * @return void - * - */ - - function post() { - - if (! is_site_admin()) { - return; - } - - $channel = get_sys_channel(); - - check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); - - if ((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) { - - // logger('crop: ' . print_r($_POST,true)); - - // phase 2 - we have finished cropping - - if (argc() != 3) { - notice( t('Image uploaded but image cropping failed.') . EOL ); - return; - } - - $image_id = argv(2); - - if (substr($image_id,-2,1) == '-') { - $scale = substr($image_id,-1,1); - $image_id = substr($image_id,0,-2); - } - - // unless proven otherwise - $is_default_profile = 1; - - if ($_REQUEST['profile']) { - $r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1", - intval($_REQUEST['profile']), - intval($channel['channel_id']) - ); - if ($r) { - $profile = array_shift($r); - if (! intval($profile['is_default'])) { - $is_default_profile = 0; - } - } - } - - $srcX = intval($_POST['xstart']); - $srcY = intval($_POST['ystart']); - $srcW = intval($_POST['xfinal']) - $srcX; - $srcH = intval($_POST['yfinal']) - $srcY; - - $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1", - dbesc($image_id), - dbesc($channel['channel_id']), - intval($scale)); - if ($r) { - - $base_image = array_shift($r); - $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); - - $im = photo_factory($base_image['content'], $base_image['mimetype']); - if ($im->is_valid()) { - - $im->cropImage(300,$srcX,$srcY,$srcW,$srcH); - - $aid = 0; - - $p = [ - 'aid' => $aid, - 'uid' => $channel['channel_id'], - 'resource_id' => $base_image['resource_id'], - 'filename' => $base_image['filename'], - 'album' => t('Profile Photos'), - 'os_path' => $base_image['os_path'], - 'display_path' => $base_image['display_path'], - 'created' => $base_image['created'], - 'edited' => $base_image['edited'] - ]; - - $p['imgscale'] = PHOTO_RES_PROFILE_300; - $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); - - $r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300); - - $im->scaleImage(80); - $p['imgscale'] = PHOTO_RES_PROFILE_80; - - $r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80); - - $im->scaleImage(48); - $p['imgscale'] = PHOTO_RES_PROFILE_48; - - $r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48); - - if ($r1 === false || $r2 === false || $r3 === false) { - // if one failed, delete them all so we can start over. - notice( t('Image resize failed.') . EOL ); - $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ", - dbesc($base_image['resource_id']), - $channel['channel_id'], - intval(PHOTO_RES_PROFILE_300), - intval(PHOTO_RES_PROFILE_80), - intval(PHOTO_RES_PROFILE_48) - ); - return; - } +class Profile_photo +{ - $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d + /* @brief Initalize the profile-photo edit view + * + * @return void + * + */ + + public function init() + { + + if (!is_site_admin()) { + return; + } + + $channel = get_sys_channel(); + Libprofile::load($channel['channel_address']); + + } + + /* @brief Evaluate posted values + * + * @param $a Current application + * @return void + * + */ + + public function post() + { + + if (!is_site_admin()) { + return; + } + + $channel = get_sys_channel(); + + check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); + + if ((array_key_exists('cropfinal', $_POST)) && (intval($_POST['cropfinal']) == 1)) { + + // logger('crop: ' . print_r($_POST,true)); + + // phase 2 - we have finished cropping + + if (argc() != 3) { + notice(t('Image uploaded but image cropping failed.') . EOL); + return; + } + + $image_id = argv(2); + + if (substr($image_id, -2, 1) == '-') { + $scale = substr($image_id, -1, 1); + $image_id = substr($image_id, 0, -2); + } + + // unless proven otherwise + $is_default_profile = 1; + + if ($_REQUEST['profile']) { + $r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1", + intval($_REQUEST['profile']), + intval($channel['channel_id']) + ); + if ($r) { + $profile = array_shift($r); + if (!intval($profile['is_default'])) { + $is_default_profile = 0; + } + } + } + + $srcX = intval($_POST['xstart']); + $srcY = intval($_POST['ystart']); + $srcW = intval($_POST['xfinal']) - $srcX; + $srcH = intval($_POST['yfinal']) - $srcY; + + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1", + dbesc($image_id), + dbesc($channel['channel_id']), + intval($scale)); + if ($r) { + + $base_image = array_shift($r); + $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); + + $im = photo_factory($base_image['content'], $base_image['mimetype']); + if ($im->is_valid()) { + + $im->cropImage(300, $srcX, $srcY, $srcW, $srcH); + + $aid = 0; + + $p = [ + 'aid' => $aid, + 'uid' => $channel['channel_id'], + 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], + 'album' => t('Profile Photos'), + 'os_path' => $base_image['os_path'], + 'display_path' => $base_image['display_path'], + 'created' => $base_image['created'], + 'edited' => $base_image['edited'] + ]; + + $p['imgscale'] = PHOTO_RES_PROFILE_300; + $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); + + $r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300); + + $im->scaleImage(80); + $p['imgscale'] = PHOTO_RES_PROFILE_80; + + $r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80); + + $im->scaleImage(48); + $p['imgscale'] = PHOTO_RES_PROFILE_48; + + $r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48); + + if ($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice(t('Image resize failed.') . EOL); + $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ", + dbesc($base_image['resource_id']), + $channel['channel_id'], + intval(PHOTO_RES_PROFILE_300), + intval(PHOTO_RES_PROFILE_80), + intval(PHOTO_RES_PROFILE_48) + ); + return; + } + + + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - dbesc($base_image['resource_id']), - intval($channel['channel_id']) - ); - - // We'll set the updated profile-photo timestamp even if it isn't the default profile, - // so that browsers will do a cache update unconditionally - // Also set links back to site-specific profile photo url in case it was - // changed to a generic URL by a clone operation. Otherwise the new photo may - // not get pushed to other sites correctly. - - $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($base_image['resource_id']), + intval($channel['channel_id']) + ); + + // We'll set the updated profile-photo timestamp even if it isn't the default profile, + // so that browsers will do a cache update unconditionally + // Also set links back to site-specific profile photo url in case it was + // changed to a generic URL by a clone operation. Otherwise the new photo may + // not get pushed to other sites correctly. + + $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'", - dbesc($im->getType()), - dbesc(datetime_convert()), - dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']), - dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']), - dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), - dbesc($channel['xchan_hash']) - ); + dbesc($im->getType()), + dbesc(datetime_convert()), + dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), + dbesc($channel['xchan_hash']) + ); - // Similarly, tell the nav bar to bypass the cache and update the avatar image. - $_SESSION['reload_avatar'] = true; + // Similarly, tell the nav bar to bypass the cache and update the avatar image. + $_SESSION['reload_avatar'] = true; - Config::Set('system','site_icon_url',z_root() . '/photo/profile/m/' . $channel['channel_id']); + Config::Set('system', 'site_icon_url', z_root() . '/photo/profile/m/' . $channel['channel_id']); - info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); - - } - else { - notice( t('Unable to process image') . EOL); - } - } - - goaway(z_root() . '/admin'); - } - - // A new photo was uploaded. Store it and save some important details - // in App::$data for use in the cropping function - - - $hash = photo_new_resource(); - $importing = false; - $smallest = 0; - + info(t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); - if ($_REQUEST['importfile']) { - $hash = $_REQUEST['importfile']; - $importing = true; - } - else { + } else { + notice(t('Unable to process image') . EOL); + } + } - $matches = []; - $partial = false; + goaway(z_root() . '/admin'); + } - if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { - $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); - if ($pm) { - logger('Content-Range: ' . print_r($matches,true), LOGGER_DEBUG); - $partial = true; - } - } + // A new photo was uploaded. Store it and save some important details + // in App::$data for use in the cropping function - if ($partial) { - $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); - if ($x['partial']) { - header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($x); - } - else { - header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + $hash = photo_new_resource(); + $importing = false; + $smallest = 0; - $_FILES['userfile'] = [ - 'name' => $x['name'], - 'type' => $x['type'], - 'tmp_name' => $x['tmp_name'], - 'error' => $x['error'], - 'size' => $x['size'] - ]; - } - } - else { - if (! array_key_exists('userfile',$_FILES)) { - $_FILES['userfile'] = [ - 'name' => $_FILES['files']['name'], - 'type' => $_FILES['files']['type'], - 'tmp_name' => $_FILES['files']['tmp_name'], - 'error' => $_FILES['files']['error'], - 'size' => $_FILES['files']['size'] - ]; - } - } - $res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Profile Photos'), 'hash' => $hash)); - - logger('attach_store: ' . print_r($res,true), LOGGER_DEBUG); + if ($_REQUEST['importfile']) { + $hash = $_REQUEST['importfile']; + $importing = true; + } else { - json_return_and_die([ 'message' => $hash ]); - } - - if (($res && intval($res['data']['is_photo'])) || $importing) { - $i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale", - dbesc($hash), - intval($channel['channel_hash']) - ); - - if (! $i) { - notice( t('Image upload failed.') . EOL ); - return; - } - $os_storage = false; - - foreach ($i as $ii) { - if (intval($ii['imgscale']) < PHOTO_RES_640) { - $smallest = intval($ii['imgscale']); - $os_storage = intval($ii['os_storage']); - $imagedata = $ii['content']; - $filetype = $ii['mimetype']; - } - } - } - - $imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata)); - $ph = photo_factory($imagedata, $filetype); - - if (! $ph->is_valid()) { - notice( t('Unable to process image.') . EOL ); - return; - } - - return $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + $matches = []; + $partial = false; - // This will "fall through" to the get() method, and since - // App::$data['imagecrop'] is set, it will proceed to cropping - // rather than present the upload form - } - - - /* @brief Generate content of profile-photo view - * - * @return void - * - */ - - - function get() { - - if (! is_site_admin()) { - notice( t('Permission denied.') . EOL ); - return; - } - - $channel = get_sys_channel(); - $pf = 0; - $newuser = false; - - if (argc() == 3 && argv(2) === 'new') { - $newuser = true; - } + if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches, true), LOGGER_DEBUG); + $partial = true; + } + } - if (argv(2) === 'reset') { - Config::Delete('system','site_icon_url'); - } + if ($partial) { + $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]); - if (argv(2) === 'use') { - if (argc() < 4) { - notice( t('Permission denied.') . EOL ); - return; - } + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($x); + } else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } else { + if (!array_key_exists('userfile', $_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $res = attach_store($channel, $channel['channel_hash'], '', array('album' => t('Profile Photos'), 'hash' => $hash)); + + logger('attach_store: ' . print_r($res, true), LOGGER_DEBUG); + + json_return_and_die(['message' => $hash]); + } + + if (($res && intval($res['data']['is_photo'])) || $importing) { + $i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale", + dbesc($hash), + intval($channel['channel_hash']) + ); + + if (!$i) { + notice(t('Image upload failed.') . EOL); + return; + } + $os_storage = false; + + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { + $smallest = intval($ii['imgscale']); + $os_storage = intval($ii['os_storage']); + $imagedata = $ii['content']; + $filetype = $ii['mimetype']; + } + } + } + + $imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata)); + $ph = photo_factory($imagedata, $filetype); + + if (!$ph->is_valid()) { + notice(t('Unable to process image.') . EOL); + return; + } + + return $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + + // This will "fall through" to the get() method, and since + // App::$data['imagecrop'] is set, it will proceed to cropping + // rather than present the upload form + } + + + /* @brief Generate content of profile-photo view + * + * @return void + * + */ + + + public function get() + { + + if (!is_site_admin()) { + notice(t('Permission denied.') . EOL); + return; + } + + $channel = get_sys_channel(); + $pf = 0; + $newuser = false; + + if (argc() == 3 && argv(2) === 'new') { + $newuser = true; + } + + if (argv(2) === 'reset') { + Config::Delete('system', 'site_icon_url'); + } + + if (argv(2) === 'use') { + if (argc() < 4) { + notice(t('Permission denied.') . EOL); + return; + } $resource_id = argv(3); - - $pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0); - $c = q("select id, is_default from profile where uid = %d", - intval($channel['channel_id']) - ); + $pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0); - $multi_profiles = true; + $c = q("select id, is_default from profile where uid = %d", + intval($channel['channel_id']) + ); - if (($c) && (count($c) === 1) && (intval($c[0]['is_default']))) { - $_REQUEST['profile'] = $c[0]['id']; - $multi_profiles = false; - } - else { - $_REQUEST['profile'] = $pf; - } + $multi_profiles = true; - $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC", - intval($channel['channel_id']), - dbesc($resource_id) - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - $havescale = false; - foreach ($r as $rr) { - if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) { - $havescale = true; - } - } - - // set an already loaded and cropped photo as profile photo - - if ($havescale) { - // unset any existing profile photos - $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - intval($channel['channel_id']) - ); - - $r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'", - intval(PHOTO_PROFILE), - intval($channel['channel_id']), - dbesc($resource_id) - ); - - $r = q("UPDATE xchan set xchan_photo_date = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc($channel['xchan_hash']) - ); - - goaway(z_root() . '/admin'); - } - - $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", - intval($r[0]['id']), - intval($channel['channel_id']) - - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - - if (intval($r[0]['os_storage'])) { - $data = @file_get_contents(dbunescbin($r[0]['content'])); - } - else { - $data = dbunescbin($r[0]['content']); - } - - $ph = photo_factory($data, $r[0]['mimetype']); - $smallest = 0; - if ($ph->is_valid()) { - // go ahead as if we have just uploaded a new photo to crop - $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale", - dbesc($r[0]['resource_id']), - intval($channel['channel_id']) - ); - - if ($i) { - $hash = $i[0]['resource_id']; - foreach ($i as $ii) { - if (intval($ii['imgscale']) < PHOTO_RES_640) { - $smallest = intval($ii['imgscale']); - } - } - } - } - - if ($multi_profiles) { - App::$data['importfile'] = $resource_id; - } - else { - $this->profile_photo_crop_ui_head($ph, $hash, $smallest); - } + if (($c) && (count($c) === 1) && (intval($c[0]['is_default']))) { + $_REQUEST['profile'] = $c[0]['id']; + $multi_profiles = false; + } else { + $_REQUEST['profile'] = $pf; + } - // falls through with App::$data['imagecrop'] set so we go straight to the cropping section + $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC", + intval($channel['channel_id']), + dbesc($resource_id) + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + $havescale = false; + foreach ($r as $rr) { + if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) { + $havescale = true; + } + } - } - - // present an upload form + // set an already loaded and cropped photo as profile photo - $profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc", - intval($channel['channel_id']) - ); + if ($havescale) { + // unset any existing profile photos + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval($channel['channel_id']) + ); - if ($profiles) { - for ($x = 0; $x < count($profiles); $x ++) { - $profiles[$x]['selected'] = false; - if ($pf && $profiles[$x]['id'] == $pf) { - $profiles[$x]['selected'] = true; - } - if ((! $pf) && $profiles[$x]['is_default']) { - $profiles[$x]['selected'] = true; - } - } - } + $r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'", + intval(PHOTO_PROFILE), + intval($channel['channel_id']), + dbesc($resource_id) + ); - $importing = ((array_key_exists('importfile',App::$data)) ? true : false); - - if (! array_key_exists('imagecrop', App::$data)) { - - $tpl = get_markup_template('admin_profile_photo.tpl'); - - $o .= replace_macros($tpl, [ - '$user' => $channel['channel_address'], - '$channel_id' => $channel['channel_id'], - '$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your site photo is visible to anybody on the internet and may be distributed to other websites.')), - '$importfile' => (($importing) ? App::$data['importfile'] : ''), - '$lbl_upfile' => t('Upload File:'), - '$lbl_profiles' => t('Select a profile:'), - '$title' => (($importing) ? t('Use Photo for Site Logo') : t('Change Site Logo')), - '$submit' => (($importing) ? t('Use') : t('Upload')), - '$profiles' => $profiles, - '$single' => ((count($profiles) == 1) ? true : false), - '$profile0' => $profiles[0], - '$embedPhotos' => t('Use a photo from your albums'), - '$embedPhotosModalTitle' => t('Use a photo from your albums'), - '$embedPhotosModalCancel' => t('Cancel'), - '$embedPhotosModalOK' => t('OK'), - '$modalchooseimages' => t('Choose images to embed'), - '$modalchoosealbum' => t('Choose an album'), - '$modaldiffalbum' => t('Choose a different album'), - '$modalerrorlist' => t('Error getting album list'), - '$modalerrorlink' => t('Error getting photo link'), - '$modalerroralbum' => t('Error getting album'), - '$form_security_token' => get_form_security_token("profile_photo"), - '$select' => t('Select previously uploaded photo'), - ]); - - call_hooks('profile_photo_content_end', $o); - return $o; - } - else { + $r = q("UPDATE xchan set xchan_photo_date = '%s' where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($channel['xchan_hash']) + ); - // present a cropping form + goaway(z_root() . '/admin'); + } - $filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution']; - $resolution = App::$data['imagecrop_resolution']; - $o .= replace_macros(get_markup_template('admin_cropbody.tpl'), [ - '$filename' => $filename, - '$profile' => intval($_REQUEST['profile']), - '$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'], - '$image_url' => z_root() . '/photo/' . $filename, - '$title' => t('Crop Image'), - '$desc' => t('Please adjust the image cropping for optimum viewing.'), - '$form_security_token' => get_form_security_token("profile_photo"), - '$done' => t('Done Editing') - ]); - return $o; - } - } - - /* @brief Generate the UI for photo-cropping - * - * @param $ph Photo-Factory - * @return void - * - */ - - function profile_photo_crop_ui_head($ph, $hash, $smallest) { - $max_length = get_config('system','max_image_length', MAX_IMAGE_LENGTH); + $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval($channel['channel_id']) - if ($max_length > 0) { - $ph->scaleImage($max_length); - } - - App::$data['width'] = $ph->getWidth(); - App::$data['height'] = $ph->getHeight(); - - if (App::$data['width'] < 500 || App::$data['height'] < 500) { - $ph->scaleImageUp(400); - App::$data['width'] = $ph->getWidth(); - App::$data['height'] = $ph->getHeight(); - } - - App::$data['imagecrop'] = $hash; - App::$data['imagecrop_resolution'] = $smallest; - App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); - return; - } + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + + if (intval($r[0]['os_storage'])) { + $data = @file_get_contents(dbunescbin($r[0]['content'])); + } else { + $data = dbunescbin($r[0]['content']); + } + + $ph = photo_factory($data, $r[0]['mimetype']); + $smallest = 0; + if ($ph->is_valid()) { + // go ahead as if we have just uploaded a new photo to crop + $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale", + dbesc($r[0]['resource_id']), + intval($channel['channel_id']) + ); + + if ($i) { + $hash = $i[0]['resource_id']; + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { + $smallest = intval($ii['imgscale']); + } + } + } + } + + if ($multi_profiles) { + App::$data['importfile'] = $resource_id; + } else { + $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + } + + // falls through with App::$data['imagecrop'] set so we go straight to the cropping section + + } + + // present an upload form + + $profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc", + intval($channel['channel_id']) + ); + + if ($profiles) { + for ($x = 0; $x < count($profiles); $x++) { + $profiles[$x]['selected'] = false; + if ($pf && $profiles[$x]['id'] == $pf) { + $profiles[$x]['selected'] = true; + } + if ((!$pf) && $profiles[$x]['is_default']) { + $profiles[$x]['selected'] = true; + } + } + } + + $importing = ((array_key_exists('importfile', App::$data)) ? true : false); + + if (!array_key_exists('imagecrop', App::$data)) { + + $tpl = get_markup_template('admin_profile_photo.tpl'); + + $o .= replace_macros($tpl, [ + '$user' => $channel['channel_address'], + '$channel_id' => $channel['channel_id'], + '$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your site photo is visible to anybody on the internet and may be distributed to other websites.')), + '$importfile' => (($importing) ? App::$data['importfile'] : ''), + '$lbl_upfile' => t('Upload File:'), + '$lbl_profiles' => t('Select a profile:'), + '$title' => (($importing) ? t('Use Photo for Site Logo') : t('Change Site Logo')), + '$submit' => (($importing) ? t('Use') : t('Upload')), + '$profiles' => $profiles, + '$single' => ((count($profiles) == 1) ? true : false), + '$profile0' => $profiles[0], + '$embedPhotos' => t('Use a photo from your albums'), + '$embedPhotosModalTitle' => t('Use a photo from your albums'), + '$embedPhotosModalCancel' => t('Cancel'), + '$embedPhotosModalOK' => t('OK'), + '$modalchooseimages' => t('Choose images to embed'), + '$modalchoosealbum' => t('Choose an album'), + '$modaldiffalbum' => t('Choose a different album'), + '$modalerrorlist' => t('Error getting album list'), + '$modalerrorlink' => t('Error getting photo link'), + '$modalerroralbum' => t('Error getting album'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$select' => t('Select previously uploaded photo'), + ]); + + call_hooks('profile_photo_content_end', $o); + return $o; + } else { + + // present a cropping form + + $filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution']; + $resolution = App::$data['imagecrop_resolution']; + $o .= replace_macros(get_markup_template('admin_cropbody.tpl'), [ + '$filename' => $filename, + '$profile' => intval($_REQUEST['profile']), + '$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'], + '$image_url' => z_root() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$done' => t('Done Editing') + ]); + return $o; + } + } + + /* @brief Generate the UI for photo-cropping + * + * @param $ph Photo-Factory + * @return void + * + */ + + public function profile_photo_crop_ui_head($ph, $hash, $smallest) + { + $max_length = get_config('system', 'max_image_length', MAX_IMAGE_LENGTH); + + if ($max_length > 0) { + $ph->scaleImage($max_length); + } + + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); + + if (App::$data['width'] < 500 || App::$data['height'] < 500) { + $ph->scaleImageUp(400); + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); + } + + App::$data['imagecrop'] = $hash; + App::$data['imagecrop_resolution'] = $smallest; + App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); + return; + } } diff --git a/Zotlabs/Module/Admin/Profs.php b/Zotlabs/Module/Admin/Profs.php index 9e5949a9e..9a42444dc 100644 --- a/Zotlabs/Module/Admin/Profs.php +++ b/Zotlabs/Module/Admin/Profs.php @@ -3,188 +3,187 @@ namespace Zotlabs\Module\Admin; -class Profs { +class Profs +{ - function post() { - - if(array_key_exists('basic',$_REQUEST)) { - $arr = explode(',',$_REQUEST['basic']); - array_walk($arr,'array_trim'); - $narr = []; - if(count($arr)) { - foreach($arr as $a) { - if(strlen($a)) { - $narr[] = $a; - } - } - } - if(! $narr) - del_config('system','profile_fields_basic'); - else - set_config('system','profile_fields_basic',$narr); + public function post() + { + + if (array_key_exists('basic', $_REQUEST)) { + $arr = explode(',', $_REQUEST['basic']); + array_walk($arr, 'array_trim'); + $narr = []; + if (count($arr)) { + foreach ($arr as $a) { + if (strlen($a)) { + $narr[] = $a; + } + } + } + if (!$narr) + del_config('system', 'profile_fields_basic'); + else + set_config('system', 'profile_fields_basic', $narr); - if(array_key_exists('advanced',$_REQUEST)) { - $arr = explode(',',$_REQUEST['advanced']); - array_walk($arr,'array_trim'); - $narr = []; - if(count($arr)) { - foreach($arr as $a) { - if(strlen($a)) { - $narr[] = $a; - } - } - } - if(! $narr) - del_config('system','profile_fields_advanced'); - else - set_config('system','profile_fields_advanced',$narr); + if (array_key_exists('advanced', $_REQUEST)) { + $arr = explode(',', $_REQUEST['advanced']); + array_walk($arr, 'array_trim'); + $narr = []; + if (count($arr)) { + foreach ($arr as $a) { + if (strlen($a)) { + $narr[] = $a; + } + } + } + if (!$narr) + del_config('system', 'profile_fields_advanced'); + else + set_config('system', 'profile_fields_advanced', $narr); - } - goaway(z_root() . '/admin/profs'); - } - - - if(array_key_exists('field_name',$_REQUEST)) { - if($_REQUEST['id']) { - $r = q("update profdef set field_name = '%s', field_type = '%s', field_desc = '%s' field_help = '%s', field_inputs = '%s' where id = %d", - dbesc($_REQUEST['field_name']), - dbesc($_REQUEST['field_type']), - dbesc($_REQUEST['field_desc']), - dbesc($_REQUEST['field_help']), - dbesc($_REQUEST['field_inputs']), - intval($_REQUEST['id']) - ); - } - else { - $r = q("insert into profdef ( field_name, field_type, field_desc, field_help, field_inputs ) values ( '%s' , '%s', '%s', '%s', '%s' )", - dbesc($_REQUEST['field_name']), - dbesc($_REQUEST['field_type']), - dbesc($_REQUEST['field_desc']), - dbesc($_REQUEST['field_help']), - dbesc($_REQUEST['field_inputs']) - ); - } - } - - - // add to chosen array basic or advanced - - goaway(z_root() . '/admin/profs'); - } - - function get() { - - if((argc() > 3) && argv(2) == 'drop' && intval(argv(3))) { - $r = q("delete from profdef where id = %d", - intval(argv(3)) - ); - // remove from allowed fields - - goaway(z_root() . '/admin/profs'); - } - - if((argc() > 2) && argv(2) === 'new') { - return replace_macros(get_markup_template('profdef_edit.tpl'),array( - '$header' => t('New Profile Field'), - '$field_name' => array('field_name',t('Field nickname'),$_REQUEST['field_name'],t('System name of field')), - '$field_type' => array('field_type',t('Input type'),(($_REQUEST['field_type']) ? $_REQUEST['field_type'] : 'text'),''), - '$field_desc' => array('field_desc',t('Field Name'),$_REQUEST['field_desc'],t('Label on profile pages')), - '$field_help' => array('field_help',t('Help text'),$_REQUEST['field_help'],t('Additional info (optional)')), - '$submit' => t('Save') - )); - } - - if((argc() > 2) && intval(argv(2))) { - $r = q("select * from profdef where id = %d limit 1", - intval(argv(2)) - ); - if(! $r) { - notice( t('Field definition not found') . EOL); - goaway(z_root() . '/admin/profs'); - } - - return replace_macros(get_markup_template('profdef_edit.tpl'),array( - '$id' => intval($r[0]['id']), - '$header' => t('Edit Profile Field'), - '$field_name' => array('field_name',t('Field nickname'),$r[0]['field_name'],t('System name of field')), - '$field_type' => array('field_type',t('Input type'),$r[0]['field_type'],''), - '$field_desc' => array('field_desc',t('Field Name'),$r[0]['field_desc'],t('Label on profile pages')), - '$field_help' => array('field_help',t('Help text'),$r[0]['field_help'],t('Additional info (optional)')), - '$submit' => t('Save') - )); - } - - $basic = ''; - $barr = []; - $fields = get_profile_fields_basic(); - - if(! $fields) - $fields = get_profile_fields_basic(1); - if($fields) { - foreach($fields as $k => $v) { - if($basic) - $basic .= ', '; - $basic .= trim($k); - $barr[] = trim($k); - } - } - - $advanced = ''; - $fields = get_profile_fields_advanced(); - if(! $fields) - $fields = get_profile_fields_advanced(1); - if($fields) { - foreach($fields as $k => $v) { - if(in_array(trim($k),$barr)) - continue; - if($advanced) - $advanced .= ', '; - $advanced .= trim($k); - } - } - - $all = ''; - $fields = get_profile_fields_advanced(1); - if($fields) { - foreach($fields as $k => $v) { - if($all) - $all .= ', '; - $all .= trim($k); - } - } - - $r = q("select * from profdef where true"); - if($r) { - foreach($r as $rr) { - if($all) - $all .= ', '; - $all .= $rr['field_name']; - } - } - - - $o = replace_macros(get_markup_template('admin_profiles.tpl'),array( - '$title' => t('Profile Fields'), - '$basic' => array('basic',t('Basic Profile Fields'),$basic,''), - '$advanced' => array('advanced',t('Advanced Profile Fields'),$advanced,t('(In addition to basic fields)')), - '$all' => $all, - '$all_desc' => t('All available fields'), - '$cust_field_desc' => t('Custom Fields'), - '$cust_fields' => $r, - '$edit' => t('Edit'), - '$drop' => t('Delete'), - '$new' => t('Create Custom Field'), - '$submit' => t('Submit') - )); - - return $o; - - - } + } + goaway(z_root() . '/admin/profs'); + } + if (array_key_exists('field_name', $_REQUEST)) { + if ($_REQUEST['id']) { + $r = q("update profdef set field_name = '%s', field_type = '%s', field_desc = '%s' field_help = '%s', field_inputs = '%s' where id = %d", + dbesc($_REQUEST['field_name']), + dbesc($_REQUEST['field_type']), + dbesc($_REQUEST['field_desc']), + dbesc($_REQUEST['field_help']), + dbesc($_REQUEST['field_inputs']), + intval($_REQUEST['id']) + ); + } else { + $r = q("insert into profdef ( field_name, field_type, field_desc, field_help, field_inputs ) values ( '%s' , '%s', '%s', '%s', '%s' )", + dbesc($_REQUEST['field_name']), + dbesc($_REQUEST['field_type']), + dbesc($_REQUEST['field_desc']), + dbesc($_REQUEST['field_help']), + dbesc($_REQUEST['field_inputs']) + ); + } + } + // add to chosen array basic or advanced + + goaway(z_root() . '/admin/profs'); + } + + public function get() + { + + if ((argc() > 3) && argv(2) == 'drop' && intval(argv(3))) { + $r = q("delete from profdef where id = %d", + intval(argv(3)) + ); + // remove from allowed fields + + goaway(z_root() . '/admin/profs'); + } + + if ((argc() > 2) && argv(2) === 'new') { + return replace_macros(get_markup_template('profdef_edit.tpl'), array( + '$header' => t('New Profile Field'), + '$field_name' => array('field_name', t('Field nickname'), $_REQUEST['field_name'], t('System name of field')), + '$field_type' => array('field_type', t('Input type'), (($_REQUEST['field_type']) ? $_REQUEST['field_type'] : 'text'), ''), + '$field_desc' => array('field_desc', t('Field Name'), $_REQUEST['field_desc'], t('Label on profile pages')), + '$field_help' => array('field_help', t('Help text'), $_REQUEST['field_help'], t('Additional info (optional)')), + '$submit' => t('Save') + )); + } + + if ((argc() > 2) && intval(argv(2))) { + $r = q("select * from profdef where id = %d limit 1", + intval(argv(2)) + ); + if (!$r) { + notice(t('Field definition not found') . EOL); + goaway(z_root() . '/admin/profs'); + } + + return replace_macros(get_markup_template('profdef_edit.tpl'), array( + '$id' => intval($r[0]['id']), + '$header' => t('Edit Profile Field'), + '$field_name' => array('field_name', t('Field nickname'), $r[0]['field_name'], t('System name of field')), + '$field_type' => array('field_type', t('Input type'), $r[0]['field_type'], ''), + '$field_desc' => array('field_desc', t('Field Name'), $r[0]['field_desc'], t('Label on profile pages')), + '$field_help' => array('field_help', t('Help text'), $r[0]['field_help'], t('Additional info (optional)')), + '$submit' => t('Save') + )); + } + + $basic = ''; + $barr = []; + $fields = get_profile_fields_basic(); + + if (!$fields) + $fields = get_profile_fields_basic(1); + if ($fields) { + foreach ($fields as $k => $v) { + if ($basic) + $basic .= ', '; + $basic .= trim($k); + $barr[] = trim($k); + } + } + + $advanced = ''; + $fields = get_profile_fields_advanced(); + if (!$fields) + $fields = get_profile_fields_advanced(1); + if ($fields) { + foreach ($fields as $k => $v) { + if (in_array(trim($k), $barr)) + continue; + if ($advanced) + $advanced .= ', '; + $advanced .= trim($k); + } + } + + $all = ''; + $fields = get_profile_fields_advanced(1); + if ($fields) { + foreach ($fields as $k => $v) { + if ($all) + $all .= ', '; + $all .= trim($k); + } + } + + $r = q("select * from profdef where true"); + if ($r) { + foreach ($r as $rr) { + if ($all) + $all .= ', '; + $all .= $rr['field_name']; + } + } + + + $o = replace_macros(get_markup_template('admin_profiles.tpl'), array( + '$title' => t('Profile Fields'), + '$basic' => array('basic', t('Basic Profile Fields'), $basic, ''), + '$advanced' => array('advanced', t('Advanced Profile Fields'), $advanced, t('(In addition to basic fields)')), + '$all' => $all, + '$all_desc' => t('All available fields'), + '$cust_field_desc' => t('Custom Fields'), + '$cust_fields' => $r, + '$edit' => t('Edit'), + '$drop' => t('Delete'), + '$new' => t('Create Custom Field'), + '$submit' => t('Submit') + )); + + return $o; + + + } + } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Queue.php b/Zotlabs/Module/Admin/Queue.php index defcffc14..b6fd6b291 100644 --- a/Zotlabs/Module/Admin/Queue.php +++ b/Zotlabs/Module/Admin/Queue.php @@ -4,48 +4,48 @@ namespace Zotlabs\Module\Admin; use Zotlabs\Lib\Queue as ZQueue; -class Queue { - - function get() { +class Queue +{ - $o = ''; - - $expert = ((array_key_exists('expert',$_REQUEST)) ? intval($_REQUEST['expert']) : 0); - - if($_REQUEST['drophub']) { - hubloc_mark_as_down($_REQUEST['drophub']); - ZQueue::remove_by_posturl($_REQUEST['drophub']); - } - - if($_REQUEST['emptyhub']) { - ZQueue::remove_by_posturl($_REQUEST['emptyhub']); - } - - $r = q("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq + public function get() + { + + $o = ''; + + $expert = ((array_key_exists('expert', $_REQUEST)) ? intval($_REQUEST['expert']) : 0); + + if ($_REQUEST['drophub']) { + hubloc_mark_as_down($_REQUEST['drophub']); + ZQueue::remove_by_posturl($_REQUEST['drophub']); + } + + if ($_REQUEST['emptyhub']) { + ZQueue::remove_by_posturl($_REQUEST['emptyhub']); + } + + $r = q("select count(outq_posturl) as total, max(outq_priority) as priority, outq_posturl from outq where outq_delivered = 0 group by outq_posturl order by total desc"); - - for($x = 0; $x < count($r); $x ++) { - $r[$x]['eurl'] = urlencode($r[$x]['outq_posturl']); - $r[$x]['connected'] = datetime_convert('UTC',date_default_timezone_get(),$r[$x]['connected'],'Y-m-d'); - } - - $o = replace_macros(get_markup_template('admin_queue.tpl'), array( - '$banner' => t('Queue Statistics'), - '$numentries' => t('Total Entries'), - '$priority' => t('Priority'), - '$desturl' => t('Destination URL'), - '$nukehub' => t('Mark hub permanently offline'), - '$empty' => t('Empty queue for this hub'), - '$lastconn' => t('Last known contact'), - '$hasentries' => ((count($r)) ? true : false), - '$entries' => $r, - '$expert' => $expert - )); - - return $o; - } - + for ($x = 0; $x < count($r); $x++) { + $r[$x]['eurl'] = urlencode($r[$x]['outq_posturl']); + $r[$x]['connected'] = datetime_convert('UTC', date_default_timezone_get(), $r[$x]['connected'], 'Y-m-d'); + } + + $o = replace_macros(get_markup_template('admin_queue.tpl'), array( + '$banner' => t('Queue Statistics'), + '$numentries' => t('Total Entries'), + '$priority' => t('Priority'), + '$desturl' => t('Destination URL'), + '$nukehub' => t('Mark hub permanently offline'), + '$empty' => t('Empty queue for this hub'), + '$lastconn' => t('Last known contact'), + '$hasentries' => ((count($r)) ? true : false), + '$entries' => $r, + '$expert' => $expert + )); + + return $o; + } } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Security.php b/Zotlabs/Module/Admin/Security.php index 7b900c2cf..b966322ce 100644 --- a/Zotlabs/Module/Admin/Security.php +++ b/Zotlabs/Module/Admin/Security.php @@ -3,185 +3,188 @@ namespace Zotlabs\Module\Admin; -class Security { +class Security +{ - function post() { - check_form_security_token_redirectOnErr('/admin/security', 'admin_security'); - - $allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : ''); - set_config('system','allowed_email', $allowed_email); + public function post() + { + check_form_security_token_redirectOnErr('/admin/security', 'admin_security'); - $not_allowed_email = ((x($_POST,'not_allowed_email')) ? notags(trim($_POST['not_allowed_email'])) : ''); - set_config('system','not_allowed_email', $not_allowed_email); + $allowed_email = ((x($_POST, 'allowed_email')) ? notags(trim($_POST['allowed_email'])) : ''); + set_config('system', 'allowed_email', $allowed_email); - $anonymous_comments = ((x($_POST,'anonymous_comments')) ? intval($_POST['anonymous_comments']) : 0); - set_config('system','anonymous_comments', $anonymous_comments); - - $block_public = ((x($_POST,'block_public')) ? True : False); - set_config('system','block_public',$block_public); + $not_allowed_email = ((x($_POST, 'not_allowed_email')) ? notags(trim($_POST['not_allowed_email'])) : ''); + set_config('system', 'not_allowed_email', $not_allowed_email); - $block_public_search = ((x($_POST,'block_public_search')) ? 1 : 0); - set_config('system','block_public_search',$block_public_search); + $anonymous_comments = ((x($_POST, 'anonymous_comments')) ? intval($_POST['anonymous_comments']) : 0); + set_config('system', 'anonymous_comments', $anonymous_comments); - $block_public_dir = ((x($_POST,'block_public_directory')) ? True : False); - set_config('system', 'block_public_directory', $block_public_dir); + $block_public = ((x($_POST, 'block_public')) ? True : False); + set_config('system', 'block_public', $block_public); - $localdir_hide = ((x($_POST,'localdir_hide')) ? 1 : 0); - set_config('system','localdir_hide',$localdir_hide); + $block_public_search = ((x($_POST, 'block_public_search')) ? 1 : 0); + set_config('system', 'block_public_search', $block_public_search); - $cloud_noroot = ((x($_POST,'cloud_noroot')) ? 1 : 0); - set_config('system','cloud_disable_siteroot',1 - $cloud_noroot); + $block_public_dir = ((x($_POST, 'block_public_directory')) ? True : False); + set_config('system', 'block_public_directory', $block_public_dir); - $cloud_disksize = ((x($_POST,'cloud_disksize')) ? 1 : 0); - set_config('system','cloud_report_disksize',$cloud_disksize); + $localdir_hide = ((x($_POST, 'localdir_hide')) ? 1 : 0); + set_config('system', 'localdir_hide', $localdir_hide); - $thumbnail_security = ((x($_POST,'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0); - set_config('system', 'thumbnail_security' , $thumbnail_security); + $cloud_noroot = ((x($_POST, 'cloud_noroot')) ? 1 : 0); + set_config('system', 'cloud_disable_siteroot', 1 - $cloud_noroot); - $inline_pdf = ((x($_POST,'inline_pdf')) ? intval($_POST['inline_pdf']) : 0); - set_config('system', 'inline_pdf' , $inline_pdf); + $cloud_disksize = ((x($_POST, 'cloud_disksize')) ? 1 : 0); + set_config('system', 'cloud_report_disksize', $cloud_disksize); - $ws = $this->trim_array_elems(explode("\n",$_POST['allowed_sites'])); - set_config('system','allowed_sites',$ws); - - $bs = $this->trim_array_elems(explode("\n",$_POST['denied_sites'])); - set_config('system','denied_sites',$bs); - - $wc = $this->trim_array_elems(explode("\n",$_POST['allowed_channels'])); - set_config('system','allowed_channels',$wc); - - $bc = $this->trim_array_elems(explode("\n",$_POST['denied_channels'])); - set_config('system','denied_channels',$bc); + $thumbnail_security = ((x($_POST, 'thumbnail_security')) ? intval($_POST['thumbnail_security']) : 0); + set_config('system', 'thumbnail_security', $thumbnail_security); - $ws = $this->trim_array_elems(explode("\n",$_POST['pubstream_allowed_sites'])); - set_config('system','pubstream_allowed_sites',$ws); - - $bs = $this->trim_array_elems(explode("\n",$_POST['pubstream_denied_sites'])); - set_config('system','pubstream_denied_sites',$bs); - - $wc = $this->trim_array_elems(explode("\n",$_POST['pubstream_allowed_channels'])); - set_config('system','pubstream_allowed_channels',$wc); - - $bc = $this->trim_array_elems(explode("\n",$_POST['pubstream_denied_channels'])); - set_config('system','pubstream_denied_channels',$bc); + $inline_pdf = ((x($_POST, 'inline_pdf')) ? intval($_POST['inline_pdf']) : 0); + set_config('system', 'inline_pdf', $inline_pdf); - $embed_sslonly = ((x($_POST,'embed_sslonly')) ? True : False); - set_config('system','embed_sslonly',$embed_sslonly); - - $we = $this->trim_array_elems(explode("\n",$_POST['embed_allow'])); - set_config('system','embed_allow',$we); - - $be = $this->trim_array_elems(explode("\n",$_POST['embed_deny'])); - set_config('system','embed_deny',$be); - - $ts = ((x($_POST,'transport_security')) ? True : False); - set_config('system','transport_security_header',$ts); + $ws = $this->trim_array_elems(explode("\n", $_POST['allowed_sites'])); + set_config('system', 'allowed_sites', $ws); - $cs = ((x($_POST,'content_security')) ? True : False); - set_config('system','content_security_policy',$cs); + $bs = $this->trim_array_elems(explode("\n", $_POST['denied_sites'])); + set_config('system', 'denied_sites', $bs); - goaway(z_root() . '/admin/security'); - } - - + $wc = $this->trim_array_elems(explode("\n", $_POST['allowed_channels'])); + set_config('system', 'allowed_channels', $wc); - function get() { - - $allowedsites = get_config('system','allowed_sites'); - $allowedsites_str = ((is_array($allowedsites)) ? implode("\n",$allowedsites) : ''); - - $deniedsites = get_config('system','denied_sites'); - $deniedsites_str = ((is_array($deniedsites)) ? implode("\n",$deniedsites) : ''); - - - $allowedchannels = get_config('system','allowed_channels'); - $allowedchannels_str = ((is_array($allowedchannels)) ? implode("\n",$allowedchannels) : ''); - - $deniedchannels = get_config('system','denied_channels'); - $deniedchannels_str = ((is_array($deniedchannels)) ? implode("\n",$deniedchannels) : ''); + $bc = $this->trim_array_elems(explode("\n", $_POST['denied_channels'])); + set_config('system', 'denied_channels', $bc); - $psallowedsites = get_config('system','pubstream_allowed_sites'); - $psallowedsites_str = ((is_array($psallowedsites)) ? implode("\n",$psallowedsites) : ''); - - $psdeniedsites = get_config('system','pubstream_denied_sites'); - $psdeniedsites_str = ((is_array($psdeniedsites)) ? implode("\n",$psdeniedsites) : ''); - - - $psallowedchannels = get_config('system','pubstream_allowed_channels'); - $psallowedchannels_str = ((is_array($psallowedchannels)) ? implode("\n",$psallowedchannels) : ''); - - $psdeniedchannels = get_config('system','pubstream_denied_channels'); - $psdeniedchannels_str = ((is_array($psdeniedchannels)) ? implode("\n",$psdeniedchannels) : ''); + $ws = $this->trim_array_elems(explode("\n", $_POST['pubstream_allowed_sites'])); + set_config('system', 'pubstream_allowed_sites', $ws); - $allowedembeds = get_config('system','embed_allow'); - $allowedembeds_str = ((is_array($allowedembeds)) ? implode("\n",$allowedembeds) : ''); - - $deniedembeds = get_config('system','embed_deny'); - $deniedembeds_str = ((is_array($deniedembeds)) ? implode("\n",$deniedembeds) : ''); - - $embed_coop = intval(get_config('system','embed_coop')); - - if((! $allowedembeds) && (! $deniedembeds)) { - $embedhelp1 = t("By default, unfiltered HTML is allowed in embedded media. This is inherently insecure."); - } + $bs = $this->trim_array_elems(explode("\n", $_POST['pubstream_denied_sites'])); + set_config('system', 'pubstream_denied_sites', $bs); - $embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:"); - $embedhelp3 = t("https://youtube.com/
        https://www.youtube.com/
        https://youtu.be/
        https://vimeo.com/
        https://soundcloud.com/
        "); - $embedhelp4 = t("All other embedded content will be filtered, unless embedded content from that site is explicitly blocked."); - - $t = get_markup_template('admin_security.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Security'), - '$form_security_token' => get_form_security_token('admin_security'), - '$block_public' => array('block_public', t("Block public"), get_config('system','block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.")), - '$block_public_search' => array('block_public_search', t("Block public search"), get_config('system','block_public_search', 1), t("Prevent access to search content unless you are currently authenticated.")), - '$block_public_dir' => [ 'block_public_directory', t('Block directory from visitors'), get_config('system','block_public_directory',true), t('Only allow authenticated access to directory.') ], - '$localdir_hide' => [ 'localdir_hide', t('Hide local directory'), intval(get_config('system','localdir_hide')), t('Only use the global directory') ], - '$cloud_noroot' => [ 'cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system','cloud_disable_siteroot',true)), t('The cloud root directory lists all channel names which provide public files. Otherwise only the names of connections are shown.') ], - '$cloud_disksize' => [ 'cloud_disksize', t('Show total disk space available to cloud uploads'), intval(get_config('system','cloud_report_disksize')), '' ], - '$thumbnail_security' => [ 'thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system','thumbnail_security',0), t("WARNING: SVG images may contain malicious code.") ], + $wc = $this->trim_array_elems(explode("\n", $_POST['pubstream_allowed_channels'])); + set_config('system', 'pubstream_allowed_channels', $wc); - '$inline_pdf' => [ 'inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system','inline_pdf',0), '' ], - '$anonymous_comments' => [ 'anonymous_comments', t('Permit anonymous comments'), intval(get_config('system','anonymous_comments')), t('Moderation will be performed by channels that select this comment option.') ], - '$transport_security' => array('transport_security', t('Set "Transport Security" HTTP header'),intval(get_config('system','transport_security_header')),''), - '$content_security' => array('content_security', t('Set "Content Security Policy" HTTP header'),intval(get_config('system','content_security_policy')),''), - '$allowed_email' => array('allowed_email', t("Allowed email domains"), get_config('system','allowed_email'), t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")), - '$not_allowed_email' => array('not_allowed_email', t("Not allowed email domains"), get_config('system','not_allowed_email'), t("Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined.")), - '$allowed_sites' => array('allowed_sites', t('Allow communications only from these sites'), $allowedsites_str, t('One site per line. Leave empty to allow communication from anywhere by default')), - '$denied_sites' => array('denied_sites', t('Block communications from these sites'), $deniedsites_str, ''), - '$allowed_channels' => array('allowed_channels', t('Allow communications only from these channels'), $allowedchannels_str, t('One channel (hash) per line. Leave empty to allow communication from any channel by default')), - '$denied_channels' => array('denied_channels', t('Block communications from these channels'), $deniedchannels_str, ''), + $bc = $this->trim_array_elems(explode("\n", $_POST['pubstream_denied_channels'])); + set_config('system', 'pubstream_denied_channels', $bc); - '$psallowed_sites' => array('pubstream_allowed_sites', t('Allow public stream communications only from these sites'), $psallowedsites_str, t('One site per line. Leave empty to allow communication from anywhere by default')), - '$psdenied_sites' => array('pubstream_denied_sites', t('Block public stream communications from these sites'), $psdeniedsites_str, ''), - '$psallowed_channels' => array('pubstream_allowed_channels', t('Allow public stream communications only from these channels'), $psallowedchannels_str, t('One channel (hash) per line. Leave empty to allow communication from any channel by default')), - '$psdenied_channels' => array('pubstream_denied_channels', t('Block public stream communications from these channels'), $psdeniedchannels_str, ''), + $embed_sslonly = ((x($_POST, 'embed_sslonly')) ? True : False); + set_config('system', 'embed_sslonly', $embed_sslonly); + + $we = $this->trim_array_elems(explode("\n", $_POST['embed_allow'])); + set_config('system', 'embed_allow', $we); + + $be = $this->trim_array_elems(explode("\n", $_POST['embed_deny'])); + set_config('system', 'embed_deny', $be); + + $ts = ((x($_POST, 'transport_security')) ? True : False); + set_config('system', 'transport_security_header', $ts); + + $cs = ((x($_POST, 'content_security')) ? True : False); + set_config('system', 'content_security_policy', $cs); + + goaway(z_root() . '/admin/security'); + } - '$embed_sslonly' => array('embed_sslonly',t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system','embed_sslonly')),''), - '$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $allowedembeds_str, t('One site per line. By default embedded content is filtered.')), - '$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $deniedembeds_str, ''), - + public function get() + { + + $allowedsites = get_config('system', 'allowed_sites'); + $allowedsites_str = ((is_array($allowedsites)) ? implode("\n", $allowedsites) : ''); + + $deniedsites = get_config('system', 'denied_sites'); + $deniedsites_str = ((is_array($deniedsites)) ? implode("\n", $deniedsites) : ''); + + + $allowedchannels = get_config('system', 'allowed_channels'); + $allowedchannels_str = ((is_array($allowedchannels)) ? implode("\n", $allowedchannels) : ''); + + $deniedchannels = get_config('system', 'denied_channels'); + $deniedchannels_str = ((is_array($deniedchannels)) ? implode("\n", $deniedchannels) : ''); + + $psallowedsites = get_config('system', 'pubstream_allowed_sites'); + $psallowedsites_str = ((is_array($psallowedsites)) ? implode("\n", $psallowedsites) : ''); + + $psdeniedsites = get_config('system', 'pubstream_denied_sites'); + $psdeniedsites_str = ((is_array($psdeniedsites)) ? implode("\n", $psdeniedsites) : ''); + + + $psallowedchannels = get_config('system', 'pubstream_allowed_channels'); + $psallowedchannels_str = ((is_array($psallowedchannels)) ? implode("\n", $psallowedchannels) : ''); + + $psdeniedchannels = get_config('system', 'pubstream_denied_channels'); + $psdeniedchannels_str = ((is_array($psdeniedchannels)) ? implode("\n", $psdeniedchannels) : ''); + + $allowedembeds = get_config('system', 'embed_allow'); + $allowedembeds_str = ((is_array($allowedembeds)) ? implode("\n", $allowedembeds) : ''); + + $deniedembeds = get_config('system', 'embed_deny'); + $deniedembeds_str = ((is_array($deniedembeds)) ? implode("\n", $deniedembeds) : ''); + + $embed_coop = intval(get_config('system', 'embed_coop')); + + if ((!$allowedembeds) && (!$deniedembeds)) { + $embedhelp1 = t("By default, unfiltered HTML is allowed in embedded media. This is inherently insecure."); + } + + $embedhelp2 = t("The recommended setting is to only allow unfiltered HTML from the following sites:"); + $embedhelp3 = t("https://youtube.com/
        https://www.youtube.com/
        https://youtu.be/
        https://vimeo.com/
        https://soundcloud.com/
        "); + $embedhelp4 = t("All other embedded content will be filtered, unless embedded content from that site is explicitly blocked."); + + $t = get_markup_template('admin_security.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Security'), + '$form_security_token' => get_form_security_token('admin_security'), + '$block_public' => array('block_public', t("Block public"), get_config('system', 'block_public'), t("Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.")), + '$block_public_search' => array('block_public_search', t("Block public search"), get_config('system', 'block_public_search', 1), t("Prevent access to search content unless you are currently authenticated.")), + '$block_public_dir' => ['block_public_directory', t('Block directory from visitors'), get_config('system', 'block_public_directory', true), t('Only allow authenticated access to directory.')], + '$localdir_hide' => ['localdir_hide', t('Hide local directory'), intval(get_config('system', 'localdir_hide')), t('Only use the global directory')], + '$cloud_noroot' => ['cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system', 'cloud_disable_siteroot', true)), t('The cloud root directory lists all channel names which provide public files. Otherwise only the names of connections are shown.')], + '$cloud_disksize' => ['cloud_disksize', t('Show total disk space available to cloud uploads'), intval(get_config('system', 'cloud_report_disksize')), ''], + '$thumbnail_security' => ['thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system', 'thumbnail_security', 0), t("WARNING: SVG images may contain malicious code.")], + + '$inline_pdf' => ['inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system', 'inline_pdf', 0), ''], + '$anonymous_comments' => ['anonymous_comments', t('Permit anonymous comments'), intval(get_config('system', 'anonymous_comments')), t('Moderation will be performed by channels that select this comment option.')], + '$transport_security' => array('transport_security', t('Set "Transport Security" HTTP header'), intval(get_config('system', 'transport_security_header')), ''), + '$content_security' => array('content_security', t('Set "Content Security Policy" HTTP header'), intval(get_config('system', 'content_security_policy')), ''), + '$allowed_email' => array('allowed_email', t("Allowed email domains"), get_config('system', 'allowed_email'), t("Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains")), + '$not_allowed_email' => array('not_allowed_email', t("Not allowed email domains"), get_config('system', 'not_allowed_email'), t("Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined.")), + '$allowed_sites' => array('allowed_sites', t('Allow communications only from these sites'), $allowedsites_str, t('One site per line. Leave empty to allow communication from anywhere by default')), + '$denied_sites' => array('denied_sites', t('Block communications from these sites'), $deniedsites_str, ''), + '$allowed_channels' => array('allowed_channels', t('Allow communications only from these channels'), $allowedchannels_str, t('One channel (hash) per line. Leave empty to allow communication from any channel by default')), + '$denied_channels' => array('denied_channels', t('Block communications from these channels'), $deniedchannels_str, ''), + + '$psallowed_sites' => array('pubstream_allowed_sites', t('Allow public stream communications only from these sites'), $psallowedsites_str, t('One site per line. Leave empty to allow communication from anywhere by default')), + '$psdenied_sites' => array('pubstream_denied_sites', t('Block public stream communications from these sites'), $psdeniedsites_str, ''), + '$psallowed_channels' => array('pubstream_allowed_channels', t('Allow public stream communications only from these channels'), $psallowedchannels_str, t('One channel (hash) per line. Leave empty to allow communication from any channel by default')), + '$psdenied_channels' => array('pubstream_denied_channels', t('Block public stream communications from these channels'), $psdeniedchannels_str, ''), + + + '$embed_sslonly' => array('embed_sslonly', t('Only allow embeds from secure (SSL) websites and links.'), intval(get_config('system', 'embed_sslonly')), ''), + '$embed_allow' => array('embed_allow', t('Allow unfiltered embedded HTML content only from these domains'), $allowedembeds_str, t('One site per line. By default embedded content is filtered.')), + '$embed_deny' => array('embed_deny', t('Block embedded HTML from these domains'), $deniedembeds_str, ''), + // '$embed_coop' => array('embed_coop', t('Cooperative embed security'), $embed_coop, t('Enable to share embed security with other compatible sites/hubs')), - '$submit' => t('Submit') - )); - } + '$submit' => t('Submit') + )); + } + + + public function trim_array_elems($arr) + { + $narr = []; + + if ($arr && is_array($arr)) { + for ($x = 0; $x < count($arr); $x++) { + $y = trim($arr[$x]); + if ($y) + $narr[] = $y; + } + } + return $narr; + } - function trim_array_elems($arr) { - $narr = []; - - if($arr && is_array($arr)) { - for($x = 0; $x < count($arr); $x ++) { - $y = trim($arr[$x]); - if($y) - $narr[] = $y; - } - } - return $narr; - } - - } \ No newline at end of file diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php index d0f7febaf..5e0326759 100644 --- a/Zotlabs/Module/Admin/Site.php +++ b/Zotlabs/Module/Admin/Site.php @@ -6,364 +6,365 @@ use App; use Zotlabs\Lib\System; use Zotlabs\Access\PermissionRoles; -class Site { +class Site +{ - /** - * @brief POST handler for Admin Site Page. - * - */ - function post() { + /** + * @brief POST handler for Admin Site Page. + * + */ + public function post() + { - if(! is_site_admin()) { - return; - } - - if (! x($_POST, 'page_site')) { - return; - } + if (!is_site_admin()) { + return; + } - $sys = get_sys_channel(); + if (!x($_POST, 'page_site')) { + return; + } - check_form_security_token_redirectOnErr('/admin/site', 'admin_site'); + $sys = get_sys_channel(); - $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : App::get_hostname()); + check_form_security_token_redirectOnErr('/admin/site', 'admin_site'); - $admininfo = ((x($_POST,'admininfo')) ? trim($_POST['admininfo']) : false); - $siteinfo = ((x($_POST,'siteinfo')) ? trim($_POST['siteinfo']) : ''); - $language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : 'en'); - $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : ''); + $sitename = ((x($_POST, 'sitename')) ? notags(trim($_POST['sitename'])) : App::get_hostname()); + + $admininfo = ((x($_POST, 'admininfo')) ? trim($_POST['admininfo']) : false); + $siteinfo = ((x($_POST, 'siteinfo')) ? trim($_POST['siteinfo']) : ''); + $language = ((x($_POST, 'language')) ? notags(trim($_POST['language'])) : 'en'); + $theme = ((x($_POST, 'theme')) ? notags(trim($_POST['theme'])) : ''); // $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : ''); // $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : ''); - $maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0); + $maximagesize = ((x($_POST, 'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0); - $register_policy = ((x($_POST,'register_policy')) ? intval(trim($_POST['register_policy'])) : 0); - $minimum_age = ((x($_POST,'minimum_age')) ? intval(trim($_POST['minimum_age'])) : 13); - $access_policy = ((x($_POST,'access_policy')) ? intval(trim($_POST['access_policy'])) : 0); - $invite_only = ((x($_POST,'invite_only')) ? True : False); - $abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0); + $register_policy = ((x($_POST, 'register_policy')) ? intval(trim($_POST['register_policy'])) : 0); + $minimum_age = ((x($_POST, 'minimum_age')) ? intval(trim($_POST['minimum_age'])) : 13); + $access_policy = ((x($_POST, 'access_policy')) ? intval(trim($_POST['access_policy'])) : 0); + $invite_only = ((x($_POST, 'invite_only')) ? True : False); + $abandon_days = ((x($_POST, 'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0); - $register_text = ((x($_POST,'register_text')) ? notags(trim($_POST['register_text'])) : ''); - $site_sellpage = ((x($_POST,'site_sellpage')) ? notags(trim($_POST['site_sellpage'])) : ''); - $site_location = ((x($_POST,'site_location')) ? notags(trim($_POST['site_location'])) : ''); - $frontpage = ((x($_POST,'frontpage')) ? notags(trim($_POST['frontpage'])) : ''); - $firstpage = ((x($_POST,'firstpage')) ? notags(trim($_POST['firstpage'])) : 'profiles'); - $first_page = ((x($_POST,'first_page')) ? notags(trim($_POST['first_page'])) : 'profiles'); - // check value after trim - if(! $first_page) { - $first_page = 'profiles'; - } - $mirror_frontpage = ((x($_POST,'mirror_frontpage')) ? intval(trim($_POST['mirror_frontpage'])) : 0); - $directory_server = ((x($_POST,'directory_server')) ? trim($_POST['directory_server']) : ''); - $force_publish = ((x($_POST,'publish_all')) ? True : False); - $open_pubstream = ((x($_POST,'open_pubstream')) ? True : False); - $public_stream_mode = ((x($_POST,'public_stream_mode')) ? intval($_POST['public_stream_mode']) : PUBLIC_STREAM_NONE); - $animations = ((x($_POST,'animations')) ? True : False); - $login_on_homepage = ((x($_POST,'login_on_homepage')) ? True : False); - $enable_context_help = ((x($_POST,'enable_context_help')) ? True : False); - $global_directory = ((x($_POST,'directory_submit_url')) ? notags(trim($_POST['directory_submit_url'])) : ''); - $no_community_page = !((x($_POST,'no_community_page')) ? True : False); - $default_expire_days = ((array_key_exists('default_expire_days',$_POST)) ? intval($_POST['default_expire_days']) : 0); - $active_expire_days = ((array_key_exists('active_expire_days',$_POST)) ? intval($_POST['active_expire_days']) : 7); - $max_imported_follow = ((x($_POST,'max_imported_follow')) ? intval(trim($_POST['max_imported_follow'])) : MAX_IMPORTED_FOLLOW); + $register_text = ((x($_POST, 'register_text')) ? notags(trim($_POST['register_text'])) : ''); + $site_sellpage = ((x($_POST, 'site_sellpage')) ? notags(trim($_POST['site_sellpage'])) : ''); + $site_location = ((x($_POST, 'site_location')) ? notags(trim($_POST['site_location'])) : ''); + $frontpage = ((x($_POST, 'frontpage')) ? notags(trim($_POST['frontpage'])) : ''); + $firstpage = ((x($_POST, 'firstpage')) ? notags(trim($_POST['firstpage'])) : 'profiles'); + $first_page = ((x($_POST, 'first_page')) ? notags(trim($_POST['first_page'])) : 'profiles'); + // check value after trim + if (!$first_page) { + $first_page = 'profiles'; + } + $mirror_frontpage = ((x($_POST, 'mirror_frontpage')) ? intval(trim($_POST['mirror_frontpage'])) : 0); + $directory_server = ((x($_POST, 'directory_server')) ? trim($_POST['directory_server']) : ''); + $force_publish = ((x($_POST, 'publish_all')) ? True : False); + $open_pubstream = ((x($_POST, 'open_pubstream')) ? True : False); + $public_stream_mode = ((x($_POST, 'public_stream_mode')) ? intval($_POST['public_stream_mode']) : PUBLIC_STREAM_NONE); + $animations = ((x($_POST, 'animations')) ? True : False); + $login_on_homepage = ((x($_POST, 'login_on_homepage')) ? True : False); + $enable_context_help = ((x($_POST, 'enable_context_help')) ? True : False); + $global_directory = ((x($_POST, 'directory_submit_url')) ? notags(trim($_POST['directory_submit_url'])) : ''); + $no_community_page = !((x($_POST, 'no_community_page')) ? True : False); + $default_expire_days = ((array_key_exists('default_expire_days', $_POST)) ? intval($_POST['default_expire_days']) : 0); + $active_expire_days = ((array_key_exists('active_expire_days', $_POST)) ? intval($_POST['active_expire_days']) : 7); + $max_imported_follow = ((x($_POST, 'max_imported_follow')) ? intval(trim($_POST['max_imported_follow'])) : MAX_IMPORTED_FOLLOW); - $reply_address = ((array_key_exists('reply_address',$_POST) && trim($_POST['reply_address'])) ? trim($_POST['reply_address']) : 'noreply@' . App::get_hostname()); - $from_email = ((array_key_exists('from_email',$_POST) && trim($_POST['from_email'])) ? trim($_POST['from_email']) : 'Administrator@' . App::get_hostname()); - $from_email_name = ((array_key_exists('from_email_name',$_POST) && trim($_POST['from_email_name'])) ? trim($_POST['from_email_name']) : System::get_site_name()); + $reply_address = ((array_key_exists('reply_address', $_POST) && trim($_POST['reply_address'])) ? trim($_POST['reply_address']) : 'noreply@' . App::get_hostname()); + $from_email = ((array_key_exists('from_email', $_POST) && trim($_POST['from_email'])) ? trim($_POST['from_email']) : 'Administrator@' . App::get_hostname()); + $from_email_name = ((array_key_exists('from_email_name', $_POST) && trim($_POST['from_email_name'])) ? trim($_POST['from_email_name']) : System::get_site_name()); - $verifyssl = ((x($_POST,'verifyssl')) ? True : False); - $proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['proxyuser'])) : ''); - $proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['proxy'])) : ''); - $timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['timeout'])) : 60); - $post_timeout = ((x($_POST,'post_timeout')) ? intval(trim($_POST['post_timeout'])) : 90); - $show_like_counts = ((x($_POST,'show_like_counts')) ? intval(trim($_POST['show_like_counts'])) : 0); - $cache_images = ((x($_POST,'cache_images')) ? intval(trim($_POST['cache_images'])) : 0); - $delivery_interval = ((x($_POST,'delivery_interval'))? intval(trim($_POST['delivery_interval'])) : 0); - $delivery_batch_count = ((x($_POST,'delivery_batch_count') && $_POST['delivery_batch_count'] > 0)? intval(trim($_POST['delivery_batch_count'])) : 3); - $poll_interval = ((x($_POST,'poll_interval')) ? intval(trim($_POST['poll_interval'])) : 0); - $maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50); + $verifyssl = ((x($_POST, 'verifyssl')) ? True : False); + $proxyuser = ((x($_POST, 'proxyuser')) ? notags(trim($_POST['proxyuser'])) : ''); + $proxy = ((x($_POST, 'proxy')) ? notags(trim($_POST['proxy'])) : ''); + $timeout = ((x($_POST, 'timeout')) ? intval(trim($_POST['timeout'])) : 60); + $post_timeout = ((x($_POST, 'post_timeout')) ? intval(trim($_POST['post_timeout'])) : 90); + $show_like_counts = ((x($_POST, 'show_like_counts')) ? intval(trim($_POST['show_like_counts'])) : 0); + $cache_images = ((x($_POST, 'cache_images')) ? intval(trim($_POST['cache_images'])) : 0); + $delivery_interval = ((x($_POST, 'delivery_interval')) ? intval(trim($_POST['delivery_interval'])) : 0); + $delivery_batch_count = ((x($_POST, 'delivery_batch_count') && $_POST['delivery_batch_count'] > 0) ? intval(trim($_POST['delivery_batch_count'])) : 3); + $poll_interval = ((x($_POST, 'poll_interval')) ? intval(trim($_POST['poll_interval'])) : 0); + $maxloadavg = ((x($_POST, 'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50); // $feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0); - $ap_contacts = ((x($_POST,'ap_contacts')) ? intval($_POST['ap_contacts']) : 0); - $verify_email = ((x($_POST,'verify_email')) ? 1 : 0); - $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : ''); - $force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000); - $pub_incl = escape_tags(trim($_POST['pub_incl'])); - $pub_excl = escape_tags(trim($_POST['pub_excl'])); + $ap_contacts = ((x($_POST, 'ap_contacts')) ? intval($_POST['ap_contacts']) : 0); + $verify_email = ((x($_POST, 'verify_email')) ? 1 : 0); + $imagick_path = ((x($_POST, 'imagick_path')) ? trim($_POST['imagick_path']) : ''); + $force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000); + $pub_incl = escape_tags(trim($_POST['pub_incl'])); + $pub_excl = escape_tags(trim($_POST['pub_excl'])); - $permissions_role = escape_tags(trim($_POST['permissions_role'])); + $permissions_role = escape_tags(trim($_POST['permissions_role'])); // set_config('system', 'feed_contacts', $feed_contacts); - set_config('system', 'activitypub', $ap_contacts); - set_config('system', 'delivery_interval', $delivery_interval); - set_config('system', 'delivery_batch_count', $delivery_batch_count); - set_config('system', 'poll_interval', $poll_interval); - set_config('system', 'maxloadavg', $maxloadavg); - set_config('system', 'frontpage', $frontpage); - set_config('system', 'cache_images', $cache_images); - set_config('system', 'sellpage', $site_sellpage); - set_config('system', 'workflow_channel_next', $first_page); - set_config('system', 'site_location', $site_location); - set_config('system', 'mirror_frontpage', $mirror_frontpage); - set_config('system', 'sitename', $sitename); - set_config('system', 'login_on_homepage', $login_on_homepage); - set_config('system', 'enable_context_help', $enable_context_help); - set_config('system', 'verify_email', $verify_email); - set_config('system', 'default_expire_days', $default_expire_days); - set_config('system', 'active_expire_days', $active_expire_days); - set_config('system', 'reply_address', $reply_address); - set_config('system', 'from_email', $from_email); - set_config('system', 'from_email_name' , $from_email_name); - set_config('system', 'imagick_convert_path' , $imagick_path); - set_config('system', 'default_permissions_role', $permissions_role); - set_config('system', 'show_like_counts', $show_like_counts); - set_config('system', 'pubstream_incl',$pub_incl); - set_config('system', 'pubstream_excl',$pub_excl); - set_config('system', 'max_imported_follow', $max_imported_follow); - set_config('system', 'animated_avatars', $animations); - - - if ($directory_server) { - set_config('system','directory_server',$directory_server); - } - - if ($admininfo == '') { - del_config('system', 'admininfo'); - } - else { - require_once('include/text.php'); - linkify_tags($admininfo, local_channel()); - set_config('system', 'admininfo', $admininfo); - } - set_config('system','siteinfo',$siteinfo); - - // sync sitename and siteinfo updates to the system channel - - q("update profile set about = '%s' where uid = %d and is_default = 1", - dbesc($siteinfo), - intval($sys['channel_id']) - ); - q("update profile set fullname = '%s' where uid = %d and is_default = 1", - dbesc($sitename), - intval($sys['channel_id']) - ); - q("update channel set channel_name = '%s' where channel_id = %d", - dbesc($sitename), - intval($sys['channel_id']) - ); - q("update xchan set xchan_name = '%s' , xchan_name_updated = '%s' where xchan_hash = '%s'", - dbesc($sitename), - dbesc(datetime_convert()), - dbesc($sys['channel_hash']) - ); - - set_config('system', 'language', $language); - set_config('system', 'theme', $theme); - // set_config('system','site_channel', $site_channel); - set_config('system','maximagesize', $maximagesize); - - set_config('system','register_policy', $register_policy); - set_config('system','minimum_age', $minimum_age); - set_config('system','invitation_only', $invite_only); - set_config('system','access_policy', $access_policy); - set_config('system','account_abandon_days', $abandon_days); - set_config('system','register_text', $register_text); - set_config('system','publish_all', $force_publish); - set_config('system','public_stream_mode', $public_stream_mode); - set_config('system','open_pubstream', $open_pubstream); - set_config('system','force_queue_threshold', $force_queue); - if ($global_directory == '') { - del_config('system', 'directory_submit_url'); - } else { - set_config('system', 'directory_submit_url', $global_directory); - } - - set_config('system','no_community_page', $no_community_page); - set_config('system','no_utf', $no_utf); - set_config('system','verifyssl', $verifyssl); - set_config('system','proxyuser', $proxyuser); - set_config('system','proxy', $proxy); - set_config('system','curl_timeout', $timeout); - set_config('system','curl_post_timeout', $post_timeout); - - info( t('Site settings updated.') . EOL); - goaway(z_root() . '/admin/site' ); - } - - /** - * @brief Admin page site. - * - * @return string with HTML - */ - - function get() { - - /* Installed langs */ - $lang_choices = []; - $langs = glob('view/*/strings.php'); - - if (is_array($langs) && count($langs)) { - if (! in_array('view/en/strings.php',$langs)) - $langs[] = 'view/en/'; - asort($langs); - foreach ($langs as $l) { - $t = explode("/",$l); - $lang_choices[$t[1]] = $t[1]; - } - } - - /* Installed themes */ - $theme_choices_mobile["---"] = t("Default"); - $theme_choices = []; - $files = glob('view/theme/*'); - if ($files) { - foreach ($files as $file) { - $vars = ''; - $f = basename($file); - - $info = get_theme_info($f); - $compatible = check_plugin_versions($info); - if (! $compatible) { - $theme_choices[$f] = $theme_choices_mobile[$f] = sprintf(t('%s - (Incompatible)'), $f); - continue; - } - - if (file_exists($file . '/library')) - continue; - if (file_exists($file . '/mobile')) - $vars = t('mobile'); - if (file_exists($file . '/experimental')) - $vars .= t('experimental'); - if (file_exists($file . '/unsupported')) - $vars .= t('unsupported'); - if ($vars) { - $theme_choices[$f] = $f . ' (' . $vars . ')'; - $theme_choices_mobile[$f] = $f . ' (' . $vars . ')'; - } - else { - $theme_choices[$f] = $f; - $theme_choices_mobile[$f] = $f; - } - } - } - - $dir_choices = null; - $dirmode = get_config('system','directory_mode'); - $realm = get_directory_realm(); - - // directory server should not be set or settable unless we are a directory client - // avoid older redmatrix servers which don't have modern encryption - - if ($dirmode == DIRECTORY_MODE_NORMAL) { - $x = q("select site_url from site where site_flags in (%d,%d) and site_realm = '%s' and site_dead = 0", - intval(DIRECTORY_MODE_SECONDARY), - intval(DIRECTORY_MODE_PRIMARY), - dbesc($realm) - ); - if ($x) { - $dir_choices = []; - foreach ($x as $xx) { - $dir_choices[$xx['site_url']] = $xx['site_url']; - } - } - } + set_config('system', 'activitypub', $ap_contacts); + set_config('system', 'delivery_interval', $delivery_interval); + set_config('system', 'delivery_batch_count', $delivery_batch_count); + set_config('system', 'poll_interval', $poll_interval); + set_config('system', 'maxloadavg', $maxloadavg); + set_config('system', 'frontpage', $frontpage); + set_config('system', 'cache_images', $cache_images); + set_config('system', 'sellpage', $site_sellpage); + set_config('system', 'workflow_channel_next', $first_page); + set_config('system', 'site_location', $site_location); + set_config('system', 'mirror_frontpage', $mirror_frontpage); + set_config('system', 'sitename', $sitename); + set_config('system', 'login_on_homepage', $login_on_homepage); + set_config('system', 'enable_context_help', $enable_context_help); + set_config('system', 'verify_email', $verify_email); + set_config('system', 'default_expire_days', $default_expire_days); + set_config('system', 'active_expire_days', $active_expire_days); + set_config('system', 'reply_address', $reply_address); + set_config('system', 'from_email', $from_email); + set_config('system', 'from_email_name', $from_email_name); + set_config('system', 'imagick_convert_path', $imagick_path); + set_config('system', 'default_permissions_role', $permissions_role); + set_config('system', 'show_like_counts', $show_like_counts); + set_config('system', 'pubstream_incl', $pub_incl); + set_config('system', 'pubstream_excl', $pub_excl); + set_config('system', 'max_imported_follow', $max_imported_follow); + set_config('system', 'animated_avatars', $animations); - /* Admin Info */ - - $admininfo = get_config('system', 'admininfo'); + if ($directory_server) { + set_config('system', 'directory_server', $directory_server); + } - /* Register policy */ - $register_choices = [ - REGISTER_CLOSED => t("No"), - REGISTER_APPROVE => t("Yes - with approval"), - REGISTER_OPEN => t("Yes") - ]; + if ($admininfo == '') { + del_config('system', 'admininfo'); + } else { + require_once('include/text.php'); + linkify_tags($admininfo, local_channel()); + set_config('system', 'admininfo', $admininfo); + } + set_config('system', 'siteinfo', $siteinfo); - /* Acess policy */ - $access_choices = [ - ACCESS_PRIVATE => t("My site is not a public server"), - ACCESS_FREE => t("My site provides free public access"), - ACCESS_PAID => t("My site provides paid public access"), - ACCESS_TIERED => t("My site provides free public access and premium paid plans") - ]; + // sync sitename and siteinfo updates to the system channel - $perm_roles = PermissionRoles::roles(); - $default_role = get_config('system','default_permissions_role','social'); + q("update profile set about = '%s' where uid = %d and is_default = 1", + dbesc($siteinfo), + intval($sys['channel_id']) + ); + q("update profile set fullname = '%s' where uid = %d and is_default = 1", + dbesc($sitename), + intval($sys['channel_id']) + ); + q("update channel set channel_name = '%s' where channel_id = %d", + dbesc($sitename), + intval($sys['channel_id']) + ); + q("update xchan set xchan_name = '%s' , xchan_name_updated = '%s' where xchan_hash = '%s'", + dbesc($sitename), + dbesc(datetime_convert()), + dbesc($sys['channel_hash']) + ); - $role = [ 'permissions_role' , t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'),$perm_roles ]; + set_config('system', 'language', $language); + set_config('system', 'theme', $theme); + // set_config('system','site_channel', $site_channel); + set_config('system', 'maximagesize', $maximagesize); + + set_config('system', 'register_policy', $register_policy); + set_config('system', 'minimum_age', $minimum_age); + set_config('system', 'invitation_only', $invite_only); + set_config('system', 'access_policy', $access_policy); + set_config('system', 'account_abandon_days', $abandon_days); + set_config('system', 'register_text', $register_text); + set_config('system', 'publish_all', $force_publish); + set_config('system', 'public_stream_mode', $public_stream_mode); + set_config('system', 'open_pubstream', $open_pubstream); + set_config('system', 'force_queue_threshold', $force_queue); + if ($global_directory == '') { + del_config('system', 'directory_submit_url'); + } else { + set_config('system', 'directory_submit_url', $global_directory); + } + + set_config('system', 'no_community_page', $no_community_page); + set_config('system', 'no_utf', $no_utf); + set_config('system', 'verifyssl', $verifyssl); + set_config('system', 'proxyuser', $proxyuser); + set_config('system', 'proxy', $proxy); + set_config('system', 'curl_timeout', $timeout); + set_config('system', 'curl_post_timeout', $post_timeout); + + info(t('Site settings updated.') . EOL); + goaway(z_root() . '/admin/site'); + } + + /** + * @brief Admin page site. + * + * @return string with HTML + */ + + public function get() + { + + /* Installed langs */ + $lang_choices = []; + $langs = glob('view/*/strings.php'); + + if (is_array($langs) && count($langs)) { + if (!in_array('view/en/strings.php', $langs)) + $langs[] = 'view/en/'; + asort($langs); + foreach ($langs as $l) { + $t = explode("/", $l); + $lang_choices[$t[1]] = $t[1]; + } + } + + /* Installed themes */ + $theme_choices_mobile["---"] = t("Default"); + $theme_choices = []; + $files = glob('view/theme/*'); + if ($files) { + foreach ($files as $file) { + $vars = ''; + $f = basename($file); + + $info = get_theme_info($f); + $compatible = check_plugin_versions($info); + if (!$compatible) { + $theme_choices[$f] = $theme_choices_mobile[$f] = sprintf(t('%s - (Incompatible)'), $f); + continue; + } + + if (file_exists($file . '/library')) + continue; + if (file_exists($file . '/mobile')) + $vars = t('mobile'); + if (file_exists($file . '/experimental')) + $vars .= t('experimental'); + if (file_exists($file . '/unsupported')) + $vars .= t('unsupported'); + if ($vars) { + $theme_choices[$f] = $f . ' (' . $vars . ')'; + $theme_choices_mobile[$f] = $f . ' (' . $vars . ')'; + } else { + $theme_choices[$f] = $f; + $theme_choices_mobile[$f] = $f; + } + } + } + + $dir_choices = null; + $dirmode = get_config('system', 'directory_mode'); + $realm = get_directory_realm(); + + // directory server should not be set or settable unless we are a directory client + // avoid older redmatrix servers which don't have modern encryption + + if ($dirmode == DIRECTORY_MODE_NORMAL) { + $x = q("select site_url from site where site_flags in (%d,%d) and site_realm = '%s' and site_dead = 0", + intval(DIRECTORY_MODE_SECONDARY), + intval(DIRECTORY_MODE_PRIMARY), + dbesc($realm) + ); + if ($x) { + $dir_choices = []; + foreach ($x as $xx) { + $dir_choices[$xx['site_url']] = $xx['site_url']; + } + } + } - $homelogin = get_config('system','login_on_homepage'); - $enable_context_help = get_config('system','enable_context_help'); + /* Admin Info */ - return replace_macros(get_markup_template('admin_site.tpl'), [ - '$title' => t('Administration'), - '$page' => t('Site'), - '$submit' => t('Submit'), - '$h_basic' => t('Site Configuration'), - '$registration' => t('Registration'), - '$upload' => t('File upload'), - '$corporate' => t('Policies'), - '$advanced' => t('Advanced'), - '$baseurl' => z_root(), - '$sitename' => [ 'sitename', t("Site name"), htmlspecialchars(get_config('system','sitename', App::get_hostname()), ENT_QUOTES, 'UTF-8'),'' ], - '$admininfo' => [ 'admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode may be used here.") ], - '$siteinfo' => [ 'siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode may be used here.") ], - '$language' => [ 'language', t("System language"), get_config('system','language','en'), "", $lang_choices ], - '$theme' => [ 'theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - change theme settings"), $theme_choices ], + $admininfo = get_config('system', 'admininfo'); + + /* Register policy */ + $register_choices = [ + REGISTER_CLOSED => t("No"), + REGISTER_APPROVE => t("Yes - with approval"), + REGISTER_OPEN => t("Yes") + ]; + + /* Acess policy */ + $access_choices = [ + ACCESS_PRIVATE => t("My site is not a public server"), + ACCESS_FREE => t("My site provides free public access"), + ACCESS_PAID => t("My site provides paid public access"), + ACCESS_TIERED => t("My site provides free public access and premium paid plans") + ]; + + $perm_roles = PermissionRoles::roles(); + $default_role = get_config('system', 'default_permissions_role', 'social'); + + $role = ['permissions_role', t('Default permission role for new accounts'), $default_role, t('This role will be used for the first channel created after registration.'), $perm_roles]; + + + $homelogin = get_config('system', 'login_on_homepage'); + $enable_context_help = get_config('system', 'enable_context_help'); + + return replace_macros(get_markup_template('admin_site.tpl'), [ + '$title' => t('Administration'), + '$page' => t('Site'), + '$submit' => t('Submit'), + '$h_basic' => t('Site Configuration'), + '$registration' => t('Registration'), + '$upload' => t('File upload'), + '$corporate' => t('Policies'), + '$advanced' => t('Advanced'), + '$baseurl' => z_root(), + '$sitename' => ['sitename', t("Site name"), htmlspecialchars(get_config('system', 'sitename', App::get_hostname()), ENT_QUOTES, 'UTF-8'), ''], + '$admininfo' => ['admininfo', t("Administrator Information"), $admininfo, t("Contact information for site administrators. Displayed on siteinfo page. BBCode may be used here.")], + '$siteinfo' => ['siteinfo', t('Site Information'), get_config('system', 'siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode may be used here.")], + '$language' => ['language', t("System language"), get_config('system', 'language', 'en'), "", $lang_choices], + '$theme' => ['theme', t("System theme"), get_config('system', 'theme'), t("Default system theme - may be over-ridden by user profiles - change theme settings"), $theme_choices], // '$theme_mobile' => [ 'theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile ], // '$site_channel' => [ 'site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel") ], - '$ap_contacts' => [ 'ap_contacts', t('ActivityPub protocol'),get_config('system','activitypub', ACTIVITYPUB_ENABLED),t('Provides access to software supporting the ActivityPub protocol.') ], - '$maximagesize' => [ 'maximagesize', t("Maximum image size"), intval(get_config('system','maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.") ], - '$cache_images' => [ 'cache_images', t('Cache all public images'), intval(get_config('system','cache_images',1)), t('If disabled, proxy non-SSL images, but do not store locally') ], - '$register_policy' => [ 'register_policy', t("Does this site allow new member registration?"), get_config('system','register_policy'), "", $register_choices ], - '$invite_only' => [ 'invite_only', t("Invitation only"), get_config('system','invitation_only'), t("Only allow new member registrations with an invitation code. New member registration must be allowed for this to work.") ], - '$invite_working' => defined('INVITE_WORKING'), - '$minimum_age' => [ 'minimum_age', t("Minimum age"), (x(get_config('system','minimum_age'))?get_config('system','minimum_age'):13), t("Minimum age (in years) for who may register on this site.") ], - '$access_policy' => [ 'access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system','access_policy'), t("If a public server policy is selected, this information may be displayed on the public server site list."), $access_choices ], - '$register_text' => [ 'register_text', t("Register text"), htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.") ], - '$role' => $role, - '$frontpage' => [ 'frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.") ], - '$mirror_frontpage' => [ 'mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting') ], - '$abandon_days' => [ 'abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.') ], - '$block_public_dir' => [ 'block_public_directory', t('Block directory from visitors'), get_config('system','block_public_directory',true), t('Only allow authenticated access to directory.') ], - '$verify_email' => [ 'verify_email', t("Verify Email Addresses"), get_config('system','verify_email'), t("Check to verify email addresses used in account registration (recommended).") ], - '$force_publish' => [ 'publish_all', t("Force publish in directory"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.") ], + '$ap_contacts' => ['ap_contacts', t('ActivityPub protocol'), get_config('system', 'activitypub', ACTIVITYPUB_ENABLED), t('Provides access to software supporting the ActivityPub protocol.')], + '$maximagesize' => ['maximagesize', t("Maximum image size"), intval(get_config('system', 'maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")], + '$cache_images' => ['cache_images', t('Cache all public images'), intval(get_config('system', 'cache_images', 1)), t('If disabled, proxy non-SSL images, but do not store locally')], + '$register_policy' => ['register_policy', t("Does this site allow new member registration?"), get_config('system', 'register_policy'), "", $register_choices], + '$invite_only' => ['invite_only', t("Invitation only"), get_config('system', 'invitation_only'), t("Only allow new member registrations with an invitation code. New member registration must be allowed for this to work.")], + '$invite_working' => defined('INVITE_WORKING'), + '$minimum_age' => ['minimum_age', t("Minimum age"), (x(get_config('system', 'minimum_age')) ? get_config('system', 'minimum_age') : 13), t("Minimum age (in years) for who may register on this site.")], + '$access_policy' => ['access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system', 'access_policy'), t("If a public server policy is selected, this information may be displayed on the public server site list."), $access_choices], + '$register_text' => ['register_text', t("Register text"), htmlspecialchars(get_config('system', 'register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")], + '$role' => $role, + '$frontpage' => ['frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system', 'frontpage'), t("example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")], + '$mirror_frontpage' => ['mirror_frontpage', t("Preserve site homepage URL"), get_config('system', 'mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')], + '$abandon_days' => ['abandon_days', t('Accounts abandoned after x days'), get_config('system', 'account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')], + '$block_public_dir' => ['block_public_directory', t('Block directory from visitors'), get_config('system', 'block_public_directory', true), t('Only allow authenticated access to directory.')], + '$verify_email' => ['verify_email', t("Verify Email Addresses"), get_config('system', 'verify_email'), t("Check to verify email addresses used in account registration (recommended).")], + '$force_publish' => ['publish_all', t("Force publish in directory"), get_config('system', 'publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")], - '$public_stream_mode' => [ 'public_stream_mode', t('Public stream'), intval(get_config('system','public_stream_mode',0)), t('Provide a Public stream on your site. This content is unmoderated.'), [ - 0 => t('the Public stream is disabled'), - 1 => t('the Public stream contains public conversations from this site only'), - 2 => t('the Public stream contains public conversations from anywhere on the internet'), - ]], - - '$open_pubstream' => [ 'open_pubstream', t('Allow anybody on the internet to access the Public stream'), get_config('system','open_pubstream',0), t('Default is to only allow viewing by site members. Warning: this content is unmoderated.') ], - '$show_like_counts' => [ 'show_like_counts', t('Show numbers of likes and dislikes in conversations'), get_config('system','show_like_counts',1), t('If disabled, the presence of likes and dislikes will be shown, but without totals.') ], - '$animations' => [ 'animations', t('Permit animated profile photos'), get_config('system','animated_avatars',true), t('Changing this may take several days to work through the system') ], - '$incl' => [ 'pub_incl',t('Only import Public stream posts with this text'), get_config('system','pubstream_incl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts') ], - '$excl' => [ 'pub_excl',t('Do not import Public stream posts with this text'), get_config('system','pubstream_excl'),t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts') ], - '$max_imported_follow' => [ 'max_imported_follow', t('Maximum number of imported friends of friends'), get_config('system','max_imported_follow', MAX_IMPORTED_FOLLOW), t('Warning: higher numbers will improve the quality of friend suggestions and directory results but can exponentially increase resource usage') ], - '$login_on_homepage' => [ 'login_on_homepage', t("Login on Homepage"),((intval($homelogin) || $homelogin === false) ? 1 : '') , t("Present a login box to visitors on the home page if no other content has been configured.") ], - '$enable_context_help' => [ 'enable_context_help', t("Enable context help"),((intval($enable_context_help) === 1 || $enable_context_help === false) ? 1 : 0) , t("Display contextual help for the current page when the help button is pressed.") ], - '$reply_address' => [ 'reply_address', t('Reply-to email address for system generated email.'), get_config('system','reply_address','noreply@' . App::get_hostname()),'' ], - '$from_email' => [ 'from_email', t('Sender (From) email address for system generated email.'), get_config('system','from_email','Administrator@' . App::get_hostname()),'' ], - '$from_email_name' => [ 'from_email_name', t('Display name of email sender for system generated email.'), get_config('system','from_email_name', System::get_site_name()),'' ], - '$directory_server' => (($dir_choices) ? [ 'directory_server', t("Directory Server URL"), get_config('system','directory_server'), t("Default directory server"), $dir_choices ] : null), - '$proxyuser' => [ 'proxyuser', t("Proxy user"), get_config('system','proxyuser'), "" ], - '$proxy' => [ 'proxy', t("Proxy URL"), get_config('system','proxy'), "" ], - '$timeout' => [ 'timeout', t("Network fetch timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), t("Value is in seconds. Set to 0 for unlimited (not recommended).") ], - '$post_timeout' => [ 'post_timeout', t("Network post timeout"), (x(get_config('system','curl_post_timeout'))?get_config('system','curl_post_timeout'):90), t("Value is in seconds. Set to 0 for unlimited (not recommended).") ], - '$delivery_interval' => [ 'delivery_interval', t("Delivery interval"), (x(get_config('system','delivery_interval'))?get_config('system','delivery_interval'):2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.") ], - '$delivery_batch_count' => [ 'delivery_batch_count', t('Deliveries per process'),(x(get_config('system','delivery_batch_count'))?get_config('system','delivery_batch_count'):3), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.") ], - '$force_queue' => [ 'force_queue', t("Queue Threshold"), get_config('system','force_queue_threshold',3000), t("Always defer immediate delivery if queue contains more than this number of entries.") ], - '$poll_interval' => [ 'poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.") ], - '$imagick_path' => [ 'imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert") ], - '$maxloadavg' => [ 'maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.") ], - '$default_expire_days' => [ 'default_expire_days', t('Expiration period in days for imported streams and cached images'), intval(get_config('system','default_expire_days',60)), t('0 for no expiration of imported content') ], - '$active_expire_days' => [ 'active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), '' ], - '$sellpage' => [ 'site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system','sellpage',''), sprintf( t('Create this page first. Default is %s/register'),z_root()) ], - '$first_page' => [ 'first_page', t('Page to display after creating a new channel'), get_config('system','workflow_channel_next','profiles'), t('Default: profiles') ], - '$location' => [ 'site_location', t('Site location'), get_config('system','site_location',''), t('Region or country - shared with other sites') ], - '$form_security_token' => get_form_security_token("admin_site"), - ]); - } + '$public_stream_mode' => ['public_stream_mode', t('Public stream'), intval(get_config('system', 'public_stream_mode', 0)), t('Provide a Public stream on your site. This content is unmoderated.'), [ + 0 => t('the Public stream is disabled'), + 1 => t('the Public stream contains public conversations from this site only'), + 2 => t('the Public stream contains public conversations from anywhere on the internet'), + ]], + + '$open_pubstream' => ['open_pubstream', t('Allow anybody on the internet to access the Public stream'), get_config('system', 'open_pubstream', 0), t('Default is to only allow viewing by site members. Warning: this content is unmoderated.')], + '$show_like_counts' => ['show_like_counts', t('Show numbers of likes and dislikes in conversations'), get_config('system', 'show_like_counts', 1), t('If disabled, the presence of likes and dislikes will be shown, but without totals.')], + '$animations' => ['animations', t('Permit animated profile photos'), get_config('system', 'animated_avatars', true), t('Changing this may take several days to work through the system')], + '$incl' => ['pub_incl', t('Only import Public stream posts with this text'), get_config('system', 'pubstream_incl'), t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')], + '$excl' => ['pub_excl', t('Do not import Public stream posts with this text'), get_config('system', 'pubstream_excl'), t('words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts')], + '$max_imported_follow' => ['max_imported_follow', t('Maximum number of imported friends of friends'), get_config('system', 'max_imported_follow', MAX_IMPORTED_FOLLOW), t('Warning: higher numbers will improve the quality of friend suggestions and directory results but can exponentially increase resource usage')], + '$login_on_homepage' => ['login_on_homepage', t("Login on Homepage"), ((intval($homelogin) || $homelogin === false) ? 1 : ''), t("Present a login box to visitors on the home page if no other content has been configured.")], + '$enable_context_help' => ['enable_context_help', t("Enable context help"), ((intval($enable_context_help) === 1 || $enable_context_help === false) ? 1 : 0), t("Display contextual help for the current page when the help button is pressed.")], + '$reply_address' => ['reply_address', t('Reply-to email address for system generated email.'), get_config('system', 'reply_address', 'noreply@' . App::get_hostname()), ''], + '$from_email' => ['from_email', t('Sender (From) email address for system generated email.'), get_config('system', 'from_email', 'Administrator@' . App::get_hostname()), ''], + '$from_email_name' => ['from_email_name', t('Display name of email sender for system generated email.'), get_config('system', 'from_email_name', System::get_site_name()), ''], + '$directory_server' => (($dir_choices) ? ['directory_server', t("Directory Server URL"), get_config('system', 'directory_server'), t("Default directory server"), $dir_choices] : null), + '$proxyuser' => ['proxyuser', t("Proxy user"), get_config('system', 'proxyuser'), ""], + '$proxy' => ['proxy', t("Proxy URL"), get_config('system', 'proxy'), ""], + '$timeout' => ['timeout', t("Network fetch timeout"), (x(get_config('system', 'curl_timeout')) ? get_config('system', 'curl_timeout') : 60), t("Value is in seconds. Set to 0 for unlimited (not recommended).")], + '$post_timeout' => ['post_timeout', t("Network post timeout"), (x(get_config('system', 'curl_post_timeout')) ? get_config('system', 'curl_post_timeout') : 90), t("Value is in seconds. Set to 0 for unlimited (not recommended).")], + '$delivery_interval' => ['delivery_interval', t("Delivery interval"), (x(get_config('system', 'delivery_interval')) ? get_config('system', 'delivery_interval') : 2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.")], + '$delivery_batch_count' => ['delivery_batch_count', t('Deliveries per process'), (x(get_config('system', 'delivery_batch_count')) ? get_config('system', 'delivery_batch_count') : 3), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.")], + '$force_queue' => ['force_queue', t("Queue Threshold"), get_config('system', 'force_queue_threshold', 3000), t("Always defer immediate delivery if queue contains more than this number of entries.")], + '$poll_interval' => ['poll_interval', t("Poll interval"), (x(get_config('system', 'poll_interval')) ? get_config('system', 'poll_interval') : 2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")], + '$imagick_path' => ['imagick_path', t("Path to ImageMagick convert program"), get_config('system', 'imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")], + '$maxloadavg' => ['maxloadavg', t("Maximum Load Average"), ((intval(get_config('system', 'maxloadavg')) > 0) ? get_config('system', 'maxloadavg') : 50), t("Maximum system load before delivery and poll processes are deferred - default 50.")], + '$default_expire_days' => ['default_expire_days', t('Expiration period in days for imported streams and cached images'), intval(get_config('system', 'default_expire_days', 60)), t('0 for no expiration of imported content')], + '$active_expire_days' => ['active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system', 'active_expire_days', 7)), ''], + '$sellpage' => ['site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system', 'sellpage', ''), sprintf(t('Create this page first. Default is %s/register'), z_root())], + '$first_page' => ['first_page', t('Page to display after creating a new channel'), get_config('system', 'workflow_channel_next', 'profiles'), t('Default: profiles')], + '$location' => ['site_location', t('Site location'), get_config('system', 'site_location', ''), t('Region or country - shared with other sites')], + '$form_security_token' => get_form_security_token("admin_site"), + ]); + } } diff --git a/Zotlabs/Module/Admin/Themes.php b/Zotlabs/Module/Admin/Themes.php index 162029c05..2f30f1618 100644 --- a/Zotlabs/Module/Admin/Themes.php +++ b/Zotlabs/Module/Admin/Themes.php @@ -8,222 +8,228 @@ use Michelf\MarkdownExtra; /** * @brief Admin area theme settings. */ -class Themes { +class Themes +{ - /** - * @brief - * - */ - function post() { + /** + * @brief + * + */ + public function post() + { - $theme = argv(2); - if (is_file("view/theme/$theme/php/config.php")){ - require_once("view/theme/$theme/php/config.php"); - /// @FIXME add parent theme if derived - if (function_exists('theme_admin_post')){ - theme_admin_post($a); - } - } - info(t('Theme settings updated.')); - if(is_ajax()) - return; + $theme = argv(2); + if (is_file("view/theme/$theme/php/config.php")) { + require_once("view/theme/$theme/php/config.php"); + /// @FIXME add parent theme if derived + if (function_exists('theme_admin_post')) { + theme_admin_post($a); + } + } + info(t('Theme settings updated.')); + if (is_ajax()) + return; - goaway(z_root() . '/admin/themes/' . $theme ); - } + goaway(z_root() . '/admin/themes/' . $theme); + } - /** - * @brief Themes admin page. - * - * @return string with parsed HTML - */ - function get(){ - $allowed_themes_str = get_config('system', 'allowed_themes'); - $allowed_themes_raw = explode(',', $allowed_themes_str); - $allowed_themes = []; - if(count($allowed_themes_raw)) - foreach($allowed_themes_raw as $x) - if(strlen(trim($x))) - $allowed_themes[] = trim($x); + /** + * @brief Themes admin page. + * + * @return string with parsed HTML + */ + public function get() + { + $allowed_themes_str = get_config('system', 'allowed_themes'); + $allowed_themes_raw = explode(',', $allowed_themes_str); + $allowed_themes = []; + if (count($allowed_themes_raw)) + foreach ($allowed_themes_raw as $x) + if (strlen(trim($x))) + $allowed_themes[] = trim($x); - $themes = []; - $files = glob('view/theme/*'); - if($files) { - foreach($files as $file) { - $f = basename($file); - $is_experimental = intval(file_exists($file . '/.experimental')); - $is_supported = 1-(intval(file_exists($file . '/.unsupported'))); // Is not used yet - $is_allowed = intval(in_array($f,$allowed_themes)); - $themes[] = array('name' => $f, 'experimental' => $is_experimental, 'supported' => $is_supported, 'allowed' => $is_allowed); - } - } + $themes = []; + $files = glob('view/theme/*'); + if ($files) { + foreach ($files as $file) { + $f = basename($file); + $is_experimental = intval(file_exists($file . '/.experimental')); + $is_supported = 1 - (intval(file_exists($file . '/.unsupported'))); // Is not used yet + $is_allowed = intval(in_array($f, $allowed_themes)); + $themes[] = array('name' => $f, 'experimental' => $is_experimental, 'supported' => $is_supported, 'allowed' => $is_allowed); + } + } - if(! count($themes)) { - notice( t('No themes found.')); - return ''; - } + if (!count($themes)) { + notice(t('No themes found.')); + return ''; + } - /* - * Single theme - */ + /* + * Single theme + */ - if (App::$argc == 3){ - $theme = App::$argv[2]; - if(! is_dir("view/theme/$theme")){ - notice( t("Item not found.") ); - return ''; - } + if (App::$argc == 3) { + $theme = App::$argv[2]; + if (!is_dir("view/theme/$theme")) { + notice(t("Item not found.")); + return ''; + } - if (x($_GET,"a") && $_GET['a']=="t"){ - check_form_security_token_redirectOnErr('/admin/themes', 'admin_themes', 't'); + if (x($_GET, "a") && $_GET['a'] == "t") { + check_form_security_token_redirectOnErr('/admin/themes', 'admin_themes', 't'); - // Toggle theme status + // Toggle theme status - $this->toggle_theme($themes, $theme, $result); - $s = $this->rebuild_theme_table($themes); - if($result) - info( sprintf('Theme %s enabled.', $theme)); - else - info( sprintf('Theme %s disabled.', $theme)); + $this->toggle_theme($themes, $theme, $result); + $s = $this->rebuild_theme_table($themes); + if ($result) + info(sprintf('Theme %s enabled.', $theme)); + else + info(sprintf('Theme %s disabled.', $theme)); - set_config('system', 'allowed_themes', $s); - goaway(z_root() . '/admin/themes' ); - } + set_config('system', 'allowed_themes', $s); + goaway(z_root() . '/admin/themes'); + } - // display theme details + // display theme details - if ($this->theme_status($themes,$theme)) { - $status="on"; $action= t("Disable"); - } else { - $status="off"; $action= t("Enable"); - } + if ($this->theme_status($themes, $theme)) { + $status = "on"; + $action = t("Disable"); + } else { + $status = "off"; + $action = t("Enable"); + } - $readme=Null; - if (is_file("view/theme/$theme/README.md")){ - $readme = file_get_contents("view/theme/$theme/README.md"); - $readme = MarkdownExtra::defaultTransform($readme); - } else if (is_file("view/theme/$theme/README")){ - $readme = '
        '. file_get_contents("view/theme/$theme/README") .'
        '; - } + $readme = Null; + if (is_file("view/theme/$theme/README.md")) { + $readme = file_get_contents("view/theme/$theme/README.md"); + $readme = MarkdownExtra::defaultTransform($readme); + } else if (is_file("view/theme/$theme/README")) { + $readme = '
        ' . file_get_contents("view/theme/$theme/README") . '
        '; + } - $admin_form = ''; - if (is_file("view/theme/$theme/php/config.php")){ - require_once("view/theme/$theme/php/config.php"); - if(function_exists("theme_admin")){ - $admin_form = theme_admin($a); - } - } + $admin_form = ''; + if (is_file("view/theme/$theme/php/config.php")) { + require_once("view/theme/$theme/php/config.php"); + if (function_exists("theme_admin")) { + $admin_form = theme_admin($a); + } + } - $screenshot = array( get_theme_screenshot($theme), t('Screenshot')); - if(! stristr($screenshot[0],$theme)) - $screenshot = null; + $screenshot = array(get_theme_screenshot($theme), t('Screenshot')); + if (!stristr($screenshot[0], $theme)) + $screenshot = null; - $t = get_markup_template('admin_plugins_details.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Themes'), - '$toggle' => t('Toggle'), - '$settings' => t('Settings'), - '$baseurl' => z_root(), + $t = get_markup_template('admin_plugins_details.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Themes'), + '$toggle' => t('Toggle'), + '$settings' => t('Settings'), + '$baseurl' => z_root(), - '$plugin' => $theme, - '$status' => $status, - '$action' => $action, - '$info' => get_theme_info($theme), - '$function' => 'themes', - '$admin_form' => $admin_form, - '$str_author' => t('Author: '), - '$str_maintainer' => t('Maintainer: '), - '$screenshot' => $screenshot, - '$readme' => $readme, + '$plugin' => $theme, + '$status' => $status, + '$action' => $action, + '$info' => get_theme_info($theme), + '$function' => 'themes', + '$admin_form' => $admin_form, + '$str_author' => t('Author: '), + '$str_maintainer' => t('Maintainer: '), + '$screenshot' => $screenshot, + '$readme' => $readme, - '$form_security_token' => get_form_security_token('admin_themes'), - )); - } + '$form_security_token' => get_form_security_token('admin_themes'), + )); + } - /* - * List themes - */ + /* + * List themes + */ - $xthemes = []; - if($themes) { - foreach($themes as $th) { - $xthemes[] = array($th['name'],(($th['allowed']) ? "on" : "off"), get_theme_info($th['name'])); - } - } + $xthemes = []; + if ($themes) { + foreach ($themes as $th) { + $xthemes[] = array($th['name'], (($th['allowed']) ? "on" : "off"), get_theme_info($th['name'])); + } + } - $t = get_markup_template('admin_plugins.tpl'); - return replace_macros($t, array( - '$title' => t('Administration'), - '$page' => t('Themes'), - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$function' => 'themes', - '$plugins' => $xthemes, - '$experimental' => t('[Experimental]'), - '$unsupported' => t('[Unsupported]'), - '$form_security_token' => get_form_security_token('admin_themes'), - )); - } + $t = get_markup_template('admin_plugins.tpl'); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Themes'), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$function' => 'themes', + '$plugins' => $xthemes, + '$experimental' => t('[Experimental]'), + '$unsupported' => t('[Unsupported]'), + '$form_security_token' => get_form_security_token('admin_themes'), + )); + } - /** - * @brief Toggle a theme. - * - * @param array &$themes - * @param[in] string $th - * @param[out] int &$result - */ - function toggle_theme(&$themes, $th, &$result) { - for($x = 0; $x < count($themes); $x ++) { - if($themes[$x]['name'] === $th) { - if($themes[$x]['allowed']) { - $themes[$x]['allowed'] = 0; - $result = 0; - } - else { - $themes[$x]['allowed'] = 1; - $result = 1; - } - } - } - } + /** + * @brief Toggle a theme. + * + * @param array &$themes + * @param[in] string $th + * @param[out] int &$result + */ + public function toggle_theme(&$themes, $th, &$result) + { + for ($x = 0; $x < count($themes); $x++) { + if ($themes[$x]['name'] === $th) { + if ($themes[$x]['allowed']) { + $themes[$x]['allowed'] = 0; + $result = 0; + } else { + $themes[$x]['allowed'] = 1; + $result = 1; + } + } + } + } - /** - * @param array $themes - * @param string $th - * @return int - */ - function theme_status($themes, $th) { - for($x = 0; $x < count($themes); $x ++) { - if($themes[$x]['name'] === $th) { - if($themes[$x]['allowed']) { - return 1; - } - else { - return 0; - } - } - } - return 0; - } + /** + * @param array $themes + * @param string $th + * @return int + */ + public function theme_status($themes, $th) + { + for ($x = 0; $x < count($themes); $x++) { + if ($themes[$x]['name'] === $th) { + if ($themes[$x]['allowed']) { + return 1; + } else { + return 0; + } + } + } + return 0; + } - /** - * @param array $themes - * @return string - */ - function rebuild_theme_table($themes) { - $o = ''; - if(count($themes)) { - foreach($themes as $th) { - if($th['allowed']) { - if(strlen($o)) - $o .= ','; - $o .= $th['name']; - } - } - } - return $o; - } + /** + * @param array $themes + * @return string + */ + public function rebuild_theme_table($themes) + { + $o = ''; + if (count($themes)) { + foreach ($themes as $th) { + if ($th['allowed']) { + if (strlen($o)) + $o .= ','; + $o .= $th['name']; + } + } + } + return $o; + } } diff --git a/Zotlabs/Module/Affinity.php b/Zotlabs/Module/Affinity.php index 0389e77f4..052245114 100644 --- a/Zotlabs/Module/Affinity.php +++ b/Zotlabs/Module/Affinity.php @@ -6,87 +6,90 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Affinity extends Controller { +class Affinity extends Controller +{ - function post() { + public function post() + { - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Friend Zoom'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Friend Zoom'))) { return; } - if($_POST['affinity-submit']) { - $cmax = intval($_POST['affinity_cmax']); - if($cmax < 0 || $cmax > 99) - $cmax = 99; - $cmin = intval($_POST['affinity_cmin']); - if($cmin < 0 || $cmin > 99) - $cmin = 0; - set_pconfig(local_channel(),'affinity','cmin',0); - set_pconfig(local_channel(),'affinity','cmax',$cmax); + if ($_POST['affinity-submit']) { + $cmax = intval($_POST['affinity_cmax']); + if ($cmax < 0 || $cmax > 99) + $cmax = 99; + $cmin = intval($_POST['affinity_cmin']); + if ($cmin < 0 || $cmin > 99) + $cmin = 0; + set_pconfig(local_channel(), 'affinity', 'cmin', 0); + set_pconfig(local_channel(), 'affinity', 'cmax', $cmax); - info( t('Friend Zoom settings updated.') . EOL); + info(t('Friend Zoom settings updated.') . EOL); - } - - Libsync::build_sync_packet(); + } - } + Libsync::build_sync_packet(); + + } - function get() { + public function get() + { $desc = t('This app (when installed) presents a slider control in your connection editor and also on your stream page. The slider represents your degree of friendship with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Friend Zoom'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Friend Zoom'))) { return $text; } - $text .= EOL . t('The number below represents the default maximum slider position for your stream page as a percentage.') . EOL . EOL; + $text .= EOL . t('The number below represents the default maximum slider position for your stream page as a percentage.') . EOL . EOL; - $setting_fields = $text; + $setting_fields = $text; - $cmax = intval(get_pconfig(local_channel(),'affinity','cmax')); - $cmax = (($cmax) ? $cmax : 99); + $cmax = intval(get_pconfig(local_channel(), 'affinity', 'cmax')); + $cmax = (($cmax) ? $cmax : 99); // $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array( // '$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, t('0-99 default 99')) // )); - if(Apps::system_app_installed(local_channel(),'Friend Zoom')) { + if (Apps::system_app_installed(local_channel(), 'Friend Zoom')) { - $labels = array( - 0 => t('Me'), - 20 => t('Family'), - 40 => t('Friends'), - 60 => t('Peers'), - 80 => t('Connections'), - 99 => t('All') - ); - call_hooks('affinity_labels',$labels); + $labels = array( + 0 => t('Me'), + 20 => t('Family'), + 40 => t('Friends'), + 60 => t('Peers'), + 80 => t('Connections'), + 99 => t('All') + ); + call_hooks('affinity_labels', $labels); - $tpl = get_markup_template('affinity.tpl'); - $x = replace_macros($tpl, [ - '$cmin' => 0, - '$cmax' => $cmax, - '$lbl' => t('Default friend zoom in/out'), - '$refresh' => t('Refresh'), - '$labels' => $labels, - ]); - + $tpl = get_markup_template('affinity.tpl'); + $x = replace_macros($tpl, [ + '$cmin' => 0, + '$cmax' => $cmax, + '$lbl' => t('Default friend zoom in/out'), + '$refresh' => t('Refresh'), + '$labels' => $labels, + ]); - $arr = array('html' => $x); - call_hooks('affinity_slider',$arr); - $setting_fields .= $arr['html']; - } - $s .= replace_macros(get_markup_template('generic_app_settings.tpl'), array( - '$addon' => array('affinity', '' . t('Friend Zoom Settings'), '', t('Submit')), - '$content' => $setting_fields - )); + $arr = array('html' => $x); + call_hooks('affinity_slider', $arr); + $setting_fields .= $arr['html']; + } - return $s; - } + $s .= replace_macros(get_markup_template('generic_app_settings.tpl'), array( + '$addon' => array('affinity', '' . t('Friend Zoom Settings'), '', t('Submit')), + '$content' => $setting_fields + )); + + return $s; + } } \ No newline at end of file diff --git a/Zotlabs/Module/Album.php b/Zotlabs/Module/Album.php index 2102fd876..81dd48a26 100644 --- a/Zotlabs/Module/Album.php +++ b/Zotlabs/Module/Album.php @@ -15,89 +15,89 @@ require_once('include/photo_factory.php'); require_once('include/photos.php'); -class Album extends Controller { +class Album extends Controller +{ - function init() { - + public function init() + { - if (ActivityStreams::is_as_request()) { - $sigdata = HTTPSig::verify(EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { - http_status_exit(403, 'Permission denied'); - } - if (! check_siteallowed($sigdata['signer'])) { - http_status_exit(403, 'Permission denied'); - } - observer_auth($portable_id); - } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); - } + if (ActivityStreams::is_as_request()) { - $observer_xchan = get_observer_hash(); - $allowed = false; + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (!check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (!check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + } elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); + } - $bear = Activity::token_from_request(); - if ($bear) { - logger('bear: ' . $bear, LOGGER_DEBUG); - } + $observer_xchan = get_observer_hash(); + $allowed = false; - $channel = null; - - if (argc() > 1) { - $channel = channelx_by_nick(argv(1)); - } - if (! $channel) { - http_status_exit(404,'Not found.'); - } + $bear = Activity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + } - $sql_extra = permissions_sql($channel['channel_id'],$observer_xchan); + $channel = null; - if (argc() > 2) { - $folder = argv(2); - $r = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d $sql_extra limit 1", - dbesc($folder), - intval($channel['channel_id']) - ); - $allowed = (($r) ? attach_can_view($channel['channel_id'],$observer_xchan,$r[0]['hash'],$bear) : false); - } - else { - $folder = EMPTY_STR; - $allowed = perm_is_allowed($channel['channel_id'],$observer_xchan,'view_storage'); - } + if (argc() > 1) { + $channel = channelx_by_nick(argv(1)); + } + if (!$channel) { + http_status_exit(404, 'Not found.'); + } - if (! $allowed) { - http_status_exit(403,'Permission denied.'); - } + $sql_extra = permissions_sql($channel['channel_id'], $observer_xchan); - $x = q("select * from attach where folder = '%s' and uid = %d $sql_extra", - dbesc($folder), - intval($channel['channel_id']) - ); + if (argc() > 2) { + $folder = argv(2); + $r = q("select * from attach where is_dir = 1 and hash = '%s' and uid = %d $sql_extra limit 1", + dbesc($folder), + intval($channel['channel_id']) + ); + $allowed = (($r) ? attach_can_view($channel['channel_id'], $observer_xchan, $r[0]['hash'], $bear) : false); + } else { + $folder = EMPTY_STR; + $allowed = perm_is_allowed($channel['channel_id'], $observer_xchan, 'view_storage'); + } - $contents = []; + if (!$allowed) { + http_status_exit(403, 'Permission denied.'); + } - if ($x) { - foreach ($x as $xv) { - if (intval($xv['is_dir'])) { - continue; - } - if (! attach_can_view($channel['channel_id'],$observer_xchan,$xv['hash'],$bear)) { - continue; - } - if (intval($xv['is_photo'])) { - $contents[] = z_root() . '/photo/' . $xv['hash']; - } - } - } - - $obj = Activity::encode_simple_collection($contents, App::$query_string, 'OrderedCollection', count($contents)); - as_return_and_die($obj,$channel); + $x = q("select * from attach where folder = '%s' and uid = %d $sql_extra", + dbesc($folder), + intval($channel['channel_id']) + ); - } + $contents = []; - } + if ($x) { + foreach ($x as $xv) { + if (intval($xv['is_dir'])) { + continue; + } + if (!attach_can_view($channel['channel_id'], $observer_xchan, $xv['hash'], $bear)) { + continue; + } + if (intval($xv['is_photo'])) { + $contents[] = z_root() . '/photo/' . $xv['hash']; + } + } + } + + $obj = Activity::encode_simple_collection($contents, App::$query_string, 'OrderedCollection', count($contents)); + as_return_and_die($obj, $channel); + + } + + } } \ No newline at end of file diff --git a/Zotlabs/Module/Ap_probe.php b/Zotlabs/Module/Ap_probe.php index d5599df27..ee60ab8e8 100644 --- a/Zotlabs/Module/Ap_probe.php +++ b/Zotlabs/Module/Ap_probe.php @@ -8,37 +8,39 @@ use Zotlabs\Lib\ActivityStreams; use Zotlabs\Lib\Activity; -class Ap_probe extends Controller { +class Ap_probe extends Controller +{ - function get() { + public function get() + { - $channel = null; + $channel = null; - $o = replace_macros(get_markup_template('ap_probe.tpl'), [ - '$page_title' => t('ActivityPub Probe Diagnostic'), - '$resource' => [ 'resource', t('Object URL') , $_REQUEST['resource'], EMPTY_STR ], - '$authf' => [ 'authf', t('Authenticated fetch'), $_REQUEST['authf'], EMPTY_STR, [ t('No'), t('Yes') ] ], - '$submit' => t('Submit') - ]); + $o = replace_macros(get_markup_template('ap_probe.tpl'), [ + '$page_title' => t('ActivityPub Probe Diagnostic'), + '$resource' => ['resource', t('Object URL'), $_REQUEST['resource'], EMPTY_STR], + '$authf' => ['authf', t('Authenticated fetch'), $_REQUEST['authf'], EMPTY_STR, [t('No'), t('Yes')]], + '$submit' => t('Submit') + ]); - if (x($_REQUEST,'resource')) { - $resource = $_REQUEST['resource']; - if ($_REQUEST['authf']) { - $channel = App::get_channel(); - if (! $channel) { - $channel = get_sys_channel(); - } - } + if (x($_REQUEST, 'resource')) { + $resource = $_REQUEST['resource']; + if ($_REQUEST['authf']) { + $channel = App::get_channel(); + if (!$channel) { + $channel = get_sys_channel(); + } + } - $x = Activity::fetch($resource,$channel,null,true); + $x = Activity::fetch($resource, $channel, null, true); - if ($x) { - $o .= '
        ' . str_replace('\\n',"\n",htmlspecialchars(json_encode($x,JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT))) . '
        '; - } + if ($x) { + $o .= '
        ' . str_replace('\\n', "\n", htmlspecialchars(json_encode($x, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT))) . '
        '; + } - } + } + + return $o; + } - return $o; - } - } diff --git a/Zotlabs/Module/Api.php b/Zotlabs/Module/Api.php index e47dff5f4..6a6874412 100644 --- a/Zotlabs/Module/Api.php +++ b/Zotlabs/Module/Api.php @@ -11,125 +11,129 @@ use Zotlabs\Web\Controller; require_once('include/api.php'); -class Api extends Controller { +class Api extends Controller +{ - function init() { - zot_api_init(); + public function init() + { + zot_api_init(); - api_register_func('api/client/register', 'api_client_register', false); - api_register_func('api/oauth/request_token', 'api_oauth_request_token', false); - api_register_func('api/oauth/access_token', 'api_oauth_access_token', false); + api_register_func('api/client/register', 'api_client_register', false); + api_register_func('api/oauth/request_token', 'api_oauth_request_token', false); + api_register_func('api/oauth/access_token', 'api_oauth_access_token', false); - $args = []; - call_hooks('api_register',$args); + $args = []; + call_hooks('api_register', $args); - return; - } + return; + } - function post() { - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - } - - function get() { + public function post() + { + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - if(App::$cmd === 'api/oauth/authorize'){ - - /* - * api/oauth/authorize interact with the user. return a standard page - */ - - App::$page['template'] = 'minimal'; - - // get consumer/client from request token - try { - $request = OAuth1Request::from_request(); - } - catch(Exception $e) { - logger('OAuth exception: ' . print_r($e,true)); - // echo "
        "; var_dump($e); 
        -				killme();
        -			}
        -			
        -			
        -			if(x($_POST,'oauth_yes')){
        -			
        -				$app = $this->oauth_get_client($request);
        -				if (is_null($app)) 
        -					return "Invalid request. Unknown token.";
        +    }
         
        -				$consumer = new OAuth1Consumer($app['client_id'], $app['pw'], $app['redirect_uri']);
        -	
        -				$verifier = md5($app['secret'] . local_channel());
        -				set_config('oauth', $verifier, local_channel());
        -				
        -				
        -				if($consumer->callback_url != null) {
        -					$params = $request->get_parameters();
        -					$glue = '?';
        -					if(strstr($consumer->callback_url,$glue))
        -						$glue = '?';
        -					goaway($consumer->callback_url . $glue . "oauth_token=" . OAuth1Util::urlencode_rfc3986($params['oauth_token']) . "&oauth_verifier=" . OAuth1Util::urlencode_rfc3986($verifier));
        -					killme();
        -				}
        -							
        -				$tpl = get_markup_template("oauth_authorize_done.tpl");
        -				$o = replace_macros($tpl, array(
        -					'$title' => t('Authorize application connection'),
        -					'$info' => t('Return to your app and insert this Security Code:'),
        -					'$code' => $verifier,
        -				));
        -			
        -				return $o;
        -			}
        -			
        -			
        -			if(! local_channel()) {
        -				// TODO: we need login form to redirect to this page
        -				notice( t('Please login to continue.') . EOL );
        -				return login(false,'api-login',$request->get_parameters());
        -			}
        -			
        -			$app = $this->oauth_get_client($request);
        -			if (is_null($app))
        -				return "Invalid request. Unknown token.";
        -						
        -			$tpl = get_markup_template('oauth_authorize.tpl');
        -			$o = replace_macros($tpl, array(
        -				'$title'     => t('Authorize application connection'),
        -				'$app'       => $app,
        -				'$authorize' => t('Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'),
        -				'$yes'	     => t('Yes'),
        -				'$no'	     => t('No'),
        -			));
        -			
        -			// echo "
        "; var_dump($app); killme();
        -			
        -			return $o;
        -		}
        -		
        -		echo api_call();
        -		killme();
        -	}
        +    public function get()
        +    {
         
        -	function oauth_get_client($request){
        +        if (App::$cmd === 'api/oauth/authorize') {
         
        -		$params = $request->get_parameters();
        -		$token  = $params['oauth_token'];
        -	
        -		$r = q("SELECT clients.* FROM clients, tokens WHERE clients.client_id = tokens.client_id 
        +            /*
        +             * api/oauth/authorize interact with the user. return a standard page
        +             */
        +
        +            App::$page['template'] = 'minimal';
        +
        +            // get consumer/client from request token
        +            try {
        +                $request = OAuth1Request::from_request();
        +            } catch (Exception $e) {
        +                logger('OAuth exception: ' . print_r($e, true));
        +                // echo "
        "; var_dump($e);
        +                killme();
        +            }
        +
        +
        +            if (x($_POST, 'oauth_yes')) {
        +
        +                $app = $this->oauth_get_client($request);
        +                if (is_null($app))
        +                    return "Invalid request. Unknown token.";
        +
        +                $consumer = new OAuth1Consumer($app['client_id'], $app['pw'], $app['redirect_uri']);
        +
        +                $verifier = md5($app['secret'] . local_channel());
        +                set_config('oauth', $verifier, local_channel());
        +
        +
        +                if ($consumer->callback_url != null) {
        +                    $params = $request->get_parameters();
        +                    $glue = '?';
        +                    if (strstr($consumer->callback_url, $glue))
        +                        $glue = '?';
        +                    goaway($consumer->callback_url . $glue . "oauth_token=" . OAuth1Util::urlencode_rfc3986($params['oauth_token']) . "&oauth_verifier=" . OAuth1Util::urlencode_rfc3986($verifier));
        +                    killme();
        +                }
        +
        +                $tpl = get_markup_template("oauth_authorize_done.tpl");
        +                $o = replace_macros($tpl, array(
        +                    '$title' => t('Authorize application connection'),
        +                    '$info' => t('Return to your app and insert this Security Code:'),
        +                    '$code' => $verifier,
        +                ));
        +
        +                return $o;
        +            }
        +
        +
        +            if (!local_channel()) {
        +                // TODO: we need login form to redirect to this page
        +                notice(t('Please login to continue.') . EOL);
        +                return login(false, 'api-login', $request->get_parameters());
        +            }
        +
        +            $app = $this->oauth_get_client($request);
        +            if (is_null($app))
        +                return "Invalid request. Unknown token.";
        +
        +            $tpl = get_markup_template('oauth_authorize.tpl');
        +            $o = replace_macros($tpl, array(
        +                '$title' => t('Authorize application connection'),
        +                '$app' => $app,
        +                '$authorize' => t('Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'),
        +                '$yes' => t('Yes'),
        +                '$no' => t('No'),
        +            ));
        +
        +            // echo "
        "; var_dump($app); killme();
        +
        +            return $o;
        +        }
        +
        +        echo api_call();
        +        killme();
        +    }
        +
        +    public function oauth_get_client($request)
        +    {
        +
        +        $params = $request->get_parameters();
        +        $token = $params['oauth_token'];
        +
        +        $r = q("SELECT clients.* FROM clients, tokens WHERE clients.client_id = tokens.client_id 
         			AND tokens.id = '%s' AND tokens.auth_scope = 'request' ",
        -			dbesc($token)
        -		);
        -		if($r)
        -			return $r[0];
        +            dbesc($token)
        +        );
        +        if ($r)
        +            return $r[0];
        +
        +        return null;
        +
        +    }
         
        -		return null;
        -	
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Appman.php b/Zotlabs/Module/Appman.php
        index eecf1f95b..105aa7792 100644
        --- a/Zotlabs/Module/Appman.php
        +++ b/Zotlabs/Module/Appman.php
        @@ -6,144 +6,147 @@ use App;
         use Zotlabs\Web\Controller;
         use Zotlabs\Lib\Apps;
         
        -class Appman extends Controller {
        +class Appman extends Controller
        +{
         
        -	function post() {
        -	
        -		if (! local_channel()) {
        -			return;
        -		}
        -	
        -		if ($_POST['url']) {
        -			$arr = [
        -				'uid'        => intval($_REQUEST['uid']),
        -				'url'        => escape_tags($_REQUEST['url']),
        -				'guid'       => escape_tags($_REQUEST['guid']),
        -				'author'     => escape_tags($_REQUEST['author']),
        -				'addr'       => escape_tags($_REQUEST['addr']),
        -				'name'       => escape_tags($_REQUEST['name']),
        -				'desc'       => escape_tags($_REQUEST['desc']),
        -				'photo'      => escape_tags($_REQUEST['photo']),
        -				'version'    => escape_tags($_REQUEST['version']),
        -				'price'      => escape_tags($_REQUEST['price']),
        -				'page'       => escape_tags($_REQUEST['sellpage']), // do not use 'page' as a request variable here as it conflicts with pagination
        -				'requires'   => escape_tags($_REQUEST['requires']),
        -				'system'     => intval($_REQUEST['system']),
        -				'plugin'     => escape_tags($_REQUEST['plugin']),
        -				'sig'        => escape_tags($_REQUEST['sig']),
        -				'categories' => escape_tags($_REQUEST['categories'])
        -			];
        -	
        -			$_REQUEST['appid'] = Apps::app_install(local_channel(),$arr);
        -	
        -			if (Apps::app_installed(local_channel(),$arr)) {
        -				info( t('App installed.') . EOL);
        -			}
        +    public function post()
        +    {
         
        -			goaway(z_root() . '/apps');
        -		}
        -	
        -	
        -		$papp = Apps::app_decode($_POST['papp']);
        -	
        -		if (! is_array($papp)) {
        -			notice( t('Malformed app.') . EOL);
        -			return;
        -		}
        -	
        -		if ($_POST['install']) {
        -			Apps::app_install(local_channel(),$papp);
        -			if (Apps::app_installed(local_channel(),$papp))
        -				info( t('App installed.') . EOL);
        -		}
        -	
        -		if ($_POST['delete']) {
        -			Apps::app_destroy(local_channel(),$papp);
        -		}
        +        if (!local_channel()) {
        +            return;
        +        }
         
        -		if ($_POST['edit']) {
        -			return;
        -		}
        +        if ($_POST['url']) {
        +            $arr = [
        +                'uid' => intval($_REQUEST['uid']),
        +                'url' => escape_tags($_REQUEST['url']),
        +                'guid' => escape_tags($_REQUEST['guid']),
        +                'author' => escape_tags($_REQUEST['author']),
        +                'addr' => escape_tags($_REQUEST['addr']),
        +                'name' => escape_tags($_REQUEST['name']),
        +                'desc' => escape_tags($_REQUEST['desc']),
        +                'photo' => escape_tags($_REQUEST['photo']),
        +                'version' => escape_tags($_REQUEST['version']),
        +                'price' => escape_tags($_REQUEST['price']),
        +                'page' => escape_tags($_REQUEST['sellpage']), // do not use 'page' as a request variable here as it conflicts with pagination
        +                'requires' => escape_tags($_REQUEST['requires']),
        +                'system' => intval($_REQUEST['system']),
        +                'plugin' => escape_tags($_REQUEST['plugin']),
        +                'sig' => escape_tags($_REQUEST['sig']),
        +                'categories' => escape_tags($_REQUEST['categories'])
        +            ];
         
        -		if ($_POST['feature']) {
        -			Apps::app_feature(local_channel(), $papp, $_POST['feature']);
        -		}
        +            $_REQUEST['appid'] = Apps::app_install(local_channel(), $arr);
         
        -		if ($_POST['pin']) {
        -			Apps::app_feature(local_channel(), $papp, $_POST['pin']);
        -		}
        +            if (Apps::app_installed(local_channel(), $arr)) {
        +                info(t('App installed.') . EOL);
        +            }
         
        -		if ($_SESSION['return_url']) {
        -			goaway(z_root() . '/' . $_SESSION['return_url']);
        -		}
        -		
        -		goaway(z_root() . '/apps');
        -	}
        -	
        -	
        -	function get() {
        -	
        -		if (! local_channel()) {
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        +            goaway(z_root() . '/apps');
        +        }
         
        -		$channel = App::get_channel();
         
        -		if (argc() > 3) {
        -			if(argv(2) === 'moveup') {
        -				Apps::moveup(local_channel(),argv(1),argv(3));
        -			}
        -			if(argv(2) === 'movedown') {
        -				Apps::movedown(local_channel(),argv(1),argv(3));
        -			}
        -			goaway(z_root() . '/apporder');
        -		}
        +        $papp = Apps::app_decode($_POST['papp']);
         
        -		$app = null;
        -		$embed = null;
        -		if ($_REQUEST['appid']) {
        -			$r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
        -				dbesc($_REQUEST['appid']),
        -				dbesc(local_channel())
        -			);
        -			if ($r) {
        -				$app = $r[0];
        +        if (!is_array($papp)) {
        +            notice(t('Malformed app.') . EOL);
        +            return;
        +        }
         
        -				$term = q("select * from term where otype = %d and oid = %d and uid = %d",
        -					intval(TERM_OBJ_APP),
        -					intval($r[0]['id']),
        -					intval(local_channel())
        -				);
        -				if ($term) {
        -					$app['categories'] = array_elm_to_str($term,'term');
        -				}
        -			}
        +        if ($_POST['install']) {
        +            Apps::app_install(local_channel(), $papp);
        +            if (Apps::app_installed(local_channel(), $papp))
        +                info(t('App installed.') . EOL);
        +        }
        +
        +        if ($_POST['delete']) {
        +            Apps::app_destroy(local_channel(), $papp);
        +        }
        +
        +        if ($_POST['edit']) {
        +            return;
        +        }
        +
        +        if ($_POST['feature']) {
        +            Apps::app_feature(local_channel(), $papp, $_POST['feature']);
        +        }
        +
        +        if ($_POST['pin']) {
        +            Apps::app_feature(local_channel(), $papp, $_POST['pin']);
        +        }
        +
        +        if ($_SESSION['return_url']) {
        +            goaway(z_root() . '/' . $_SESSION['return_url']);
        +        }
        +
        +        goaway(z_root() . '/apps');
        +    }
        +
        +
        +    public function get()
        +    {
        +
        +        if (!local_channel()) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
        +
        +        $channel = App::get_channel();
        +
        +        if (argc() > 3) {
        +            if (argv(2) === 'moveup') {
        +                Apps::moveup(local_channel(), argv(1), argv(3));
        +            }
        +            if (argv(2) === 'movedown') {
        +                Apps::movedown(local_channel(), argv(1), argv(3));
        +            }
        +            goaway(z_root() . '/apporder');
        +        }
        +
        +        $app = null;
        +        $embed = null;
        +        if ($_REQUEST['appid']) {
        +            $r = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
        +                dbesc($_REQUEST['appid']),
        +                dbesc(local_channel())
        +            );
        +            if ($r) {
        +                $app = $r[0];
        +
        +                $term = q("select * from term where otype = %d and oid = %d and uid = %d",
        +                    intval(TERM_OBJ_APP),
        +                    intval($r[0]['id']),
        +                    intval(local_channel())
        +                );
        +                if ($term) {
        +                    $app['categories'] = array_elm_to_str($term, 'term');
        +                }
        +            }
        +
        +            $embed = ['embed', t('Embed code'), Apps::app_encode($app, true), EMPTY_STR, 'onclick="this.select();"'];
        +        }
        +
        +        return replace_macros(get_markup_template('app_create.tpl'), [
        +            '$banner' => (($app) ? t('Edit App') : t('Create App')),
        +            '$app' => $app,
        +            '$guid' => (($app) ? $app['app_id'] : EMPTY_STR),
        +            '$author' => (($app) ? $app['app_author'] : $channel['channel_hash']),
        +            '$addr' => (($app) ? $app['app_addr'] : $channel['xchan_addr']),
        +            '$name' => ['name', t('Name of app'), (($app) ? $app['app_name'] : EMPTY_STR), t('Required')],
        +            '$url' => ['url', t('Location (URL) of app'), (($app) ? $app['app_url'] : EMPTY_STR), t('Required')],
        +            '$desc' => ['desc', t('Description'), (($app) ? $app['app_desc'] : EMPTY_STR), EMPTY_STR],
        +            '$photo' => ['photo', t('Photo icon URL'), (($app) ? $app['app_photo'] : EMPTY_STR), t('80 x 80 pixels - optional')],
        +            '$categories' => ['categories', t('Categories (optional, comma separated list)'), (($app) ? $app['categories'] : EMPTY_STR), EMPTY_STR],
        +            '$version' => ['version', t('Version ID'), (($app) ? $app['app_version'] : EMPTY_STR), EMPTY_STR],
        +            '$price' => ['price', t('Price of app'), (($app) ? $app['app_price'] : EMPTY_STR), EMPTY_STR],
        +            '$page' => ['sellpage', t('Location (URL) to purchase app'), (($app) ? $app['app_page'] : EMPTY_STR), EMPTY_STR],
        +            '$system' => (($app) ? intval($app['app_system']) : 0),
        +            '$plugin' => (($app) ? $app['app_plugin'] : EMPTY_STR),
        +            '$requires' => (($app) ? $app['app_requires'] : EMPTY_STR),
        +            '$embed' => $embed,
        +            '$submit' => t('Submit')
        +        ]);
        +
        +    }
         
        -			$embed = [ 'embed', t('Embed code'), Apps::app_encode($app,true), EMPTY_STR, 'onclick="this.select();"' ];
        -		}
        -				
        -		return replace_macros(get_markup_template('app_create.tpl'), [
        -			'$banner'     => (($app) ? t('Edit App') : t('Create App')),
        -			'$app'        => $app,
        -			'$guid'       => (($app) ? $app['app_id'] : EMPTY_STR),
        -			'$author'     => (($app) ? $app['app_author'] : $channel['channel_hash']),
        -			'$addr'       => (($app) ? $app['app_addr'] : $channel['xchan_addr']),
        -			'$name'       => [ 'name', t('Name of app'),(($app) ? $app['app_name'] : EMPTY_STR), t('Required') ],
        -			'$url'        => [ 'url', t('Location (URL) of app'),(($app) ? $app['app_url'] : EMPTY_STR), t('Required') ],
        -	 		'$desc'       => [ 'desc', t('Description'),(($app) ? $app['app_desc'] : EMPTY_STR), EMPTY_STR],
        -			'$photo'      => [ 'photo', t('Photo icon URL'),(($app) ? $app['app_photo'] : EMPTY_STR), t('80 x 80 pixels - optional') ],
        -			'$categories' => [ 'categories',t('Categories (optional, comma separated list)'),(($app) ? $app['categories'] : EMPTY_STR), EMPTY_STR ],
        -			'$version'    => [ 'version', t('Version ID'),(($app) ? $app['app_version'] : EMPTY_STR), EMPTY_STR ],
        -			'$price'      => [ 'price', t('Price of app'),(($app) ? $app['app_price'] : EMPTY_STR), EMPTY_STR ],
        -			'$page'       => [ 'sellpage', t('Location (URL) to purchase app'),(($app) ? $app['app_page'] : EMPTY_STR), EMPTY_STR ],
        -			'$system'     => (($app) ? intval($app['app_system']) : 0),
        -			'$plugin'     => (($app) ? $app['app_plugin'] : EMPTY_STR),
        -			'$requires'   => (($app) ? $app['app_requires'] : EMPTY_STR),
        -			'$embed'      => $embed,
        -			'$submit'     => t('Submit')
        -		]);
        -	
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Apporder.php b/Zotlabs/Module/Apporder.php
        index d982aad70..27068089d 100644
        --- a/Zotlabs/Module/Apporder.php
        +++ b/Zotlabs/Module/Apporder.php
        @@ -9,45 +9,45 @@ class Apporder extends Controller
         {
         
         
        -	function get() {
        +    public function get()
        +    {
         
        -		if (! local_channel()) {
        -			return;
        -		}
        +        if (!local_channel()) {
        +            return;
        +        }
         
        -		nav_set_selected('Order Apps');
        +        nav_set_selected('Order Apps');
         
        -		foreach ( [ 'nav_featured_app', 'nav_pinned_app' ] as $l ) {
        -			$syslist = [];
        -			$list = Apps::app_list(local_channel(), false, [ $l ]);
        -			if ($list) {
        -				foreach ($list as $li) {
        -					$syslist[] = Apps::app_encode($li);
        -				}
        -			}
        -		
        -			Apps::translate_system_apps($syslist);
        +        foreach (['nav_featured_app', 'nav_pinned_app'] as $l) {
        +            $syslist = [];
        +            $list = Apps::app_list(local_channel(), false, [$l]);
        +            if ($list) {
        +                foreach ($list as $li) {
        +                    $syslist[] = Apps::app_encode($li);
        +                }
        +            }
         
        -			usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
        +            Apps::translate_system_apps($syslist);
         
        -			$syslist = Apps::app_order(local_channel(),$syslist, $l);
        +            usort($syslist, 'Zotlabs\\Lib\\Apps::app_name_compare');
         
        -			foreach ($syslist as $app) {
        -				if ($l === 'nav_pinned_app') {
        -					$navbar_apps[] = Apps::app_render($app,'nav-order-pinned');
        -				}
        -				else {
        -					$nav_apps[] = Apps::app_render($app,'nav-order');
        -				}
        -			}
        -		}
        +            $syslist = Apps::app_order(local_channel(), $syslist, $l);
         
        -		return replace_macros(get_markup_template('apporder.tpl'), [
        -				'$header'      => [ t('Change Order of Pinned Navbar Apps'), t('Change Order of App Tray Apps') ],
        -				'$desc'        => [ t('Use arrows to move the corresponding app left (top) or right (bottom) in the navbar'),
        -					t('Use arrows to move the corresponding app up or down in the app tray') ],
        -				'$nav_apps'    => $nav_apps,
        -				'$navbar_apps' => $navbar_apps
        -		]);
        -	}
        +            foreach ($syslist as $app) {
        +                if ($l === 'nav_pinned_app') {
        +                    $navbar_apps[] = Apps::app_render($app, 'nav-order-pinned');
        +                } else {
        +                    $nav_apps[] = Apps::app_render($app, 'nav-order');
        +                }
        +            }
        +        }
        +
        +        return replace_macros(get_markup_template('apporder.tpl'), [
        +            '$header' => [t('Change Order of Pinned Navbar Apps'), t('Change Order of App Tray Apps')],
        +            '$desc' => [t('Use arrows to move the corresponding app left (top) or right (bottom) in the navbar'),
        +                t('Use arrows to move the corresponding app up or down in the app tray')],
        +            '$nav_apps' => $nav_apps,
        +            '$navbar_apps' => $navbar_apps
        +        ]);
        +    }
         }
        diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php
        index 45e2af577..6f5d14fc0 100644
        --- a/Zotlabs/Module/Apps.php
        +++ b/Zotlabs/Module/Apps.php
        @@ -5,56 +5,57 @@ use App;
         use Zotlabs\Lib as Zlib;
         use Zotlabs\Web\Controller;
         
        -class Apps extends Controller {
        +class Apps extends Controller
        +{
         
        -	function get() {
        +    public function get()
        +    {
         
        -		nav_set_selected('Apps');
        -	
        -		if(argc() == 2 && argv(1) == 'edit')
        -			$mode = 'edit';
        -		else
        -			$mode = 'list';
        +        nav_set_selected('Apps');
         
        -		$available = ((argc() == 2 && argv(1) === 'available') ? true : false);
        +        if (argc() == 2 && argv(1) == 'edit')
        +            $mode = 'edit';
        +        else
        +            $mode = 'list';
         
        -		$_SESSION['return_url'] = App::$query_string;
        -	
        -		$apps = [];
        -	
        -		if(local_channel()) {
        -			Zlib\Apps::import_system_apps();
        -			$syslist = [];
        -			$cat = ((array_key_exists('cat',$_GET) && $_GET['cat']) ? [ escape_tags($_GET['cat']) ] : '');
        -			$list = Zlib\Apps::app_list((($available) ? 0 : local_channel()), (($mode == 'edit') ? true : false), $cat);
        -			if($list) {
        -				foreach($list as $x) {
        -					$syslist[] = Zlib\Apps::app_encode($x);
        -				}
        -			}
        -			Zlib\Apps::translate_system_apps($syslist);
        -		}
        -		else
        -			$syslist = Zlib\Apps::get_system_apps(true);
        +        $available = ((argc() == 2 && argv(1) === 'available') ? true : false);
         
        -		usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
        -	
        -	//	logger('apps: ' . print_r($syslist,true));
        -	
        -		foreach($syslist as $app) {
        -			$apps[] = Zlib\Apps::app_render($app,(($available) ? 'install' : $mode));
        -		}
        +        $_SESSION['return_url'] = App::$query_string;
        +
        +        $apps = [];
        +
        +        if (local_channel()) {
        +            Zlib\Apps::import_system_apps();
        +            $syslist = [];
        +            $cat = ((array_key_exists('cat', $_GET) && $_GET['cat']) ? [escape_tags($_GET['cat'])] : '');
        +            $list = Zlib\Apps::app_list((($available) ? 0 : local_channel()), (($mode == 'edit') ? true : false), $cat);
        +            if ($list) {
        +                foreach ($list as $x) {
        +                    $syslist[] = Zlib\Apps::app_encode($x);
        +                }
        +            }
        +            Zlib\Apps::translate_system_apps($syslist);
        +        } else
        +            $syslist = Zlib\Apps::get_system_apps(true);
        +
        +        usort($syslist, 'Zotlabs\\Lib\\Apps::app_name_compare');
        +
        +        //	logger('apps: ' . print_r($syslist,true));
        +
        +        foreach ($syslist as $app) {
        +            $apps[] = Zlib\Apps::app_render($app, (($available) ? 'install' : $mode));
        +        }
        +
        +        return replace_macros(get_markup_template('myapps.tpl'), array(
        +            '$sitename' => get_config('system', 'sitename'),
        +            '$cat' => $cat,
        +            '$title' => (($available) ? t('Available Apps') : t('Installed Apps')),
        +            '$apps' => $apps,
        +            '$authed' => ((local_channel()) ? true : false),
        +            '$manage' => (($available) ? EMPTY_STR : t('Manage apps')),
        +            '$create' => (($mode == 'edit') ? t('Create Custom App') : '')
        +        ));
        +
        +    }
         
        -		return replace_macros(get_markup_template('myapps.tpl'), array(
        -			'$sitename' => get_config('system','sitename'),
        -			'$cat' => $cat,
        -			'$title' => (($available) ? t('Available Apps') : t('Installed Apps')),
        -			'$apps' => $apps,
        -			'$authed' => ((local_channel()) ? true : false),
        -			'$manage' => (($available) ? EMPTY_STR : t('Manage apps')),
        -			'$create' => (($mode == 'edit') ? t('Create Custom App') : '')
        -		));
        -	
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Apschema.php b/Zotlabs/Module/Apschema.php
        index 0b0d15bcc..53e7f0dbe 100644
        --- a/Zotlabs/Module/Apschema.php
        +++ b/Zotlabs/Module/Apschema.php
        @@ -5,21 +5,21 @@ namespace Zotlabs\Module;
         use Zotlabs\Web\Controller;
         use Zotlabs\Lib\Activity;
         
        -class Apschema extends Controller {
        +class Apschema extends Controller
        +{
         
        -	function init() {
        +    public function init()
        +    {
         
        -		$arr = [
        -			'@context' => array_merge(['as' => 'https://www.w3.org/ns/activitystreams#'], Activity::ap_schema())
        -		];
        -
        -		header('Content-Type: application/ld+json');
        -		echo json_encode($arr,JSON_UNESCAPED_SLASHES);
        -		killme();
        -
        -	}
        +        $arr = [
        +            '@context' => array_merge(['as' => 'https://www.w3.org/ns/activitystreams#'], Activity::ap_schema())
        +        ];
         
        +        header('Content-Type: application/ld+json');
        +        echo json_encode($arr, JSON_UNESCAPED_SLASHES);
        +        killme();
         
        +    }
         
         
         }
        \ No newline at end of file
        diff --git a/Zotlabs/Module/Attach.php b/Zotlabs/Module/Attach.php
        index b650a957c..9aa254bc8 100644
        --- a/Zotlabs/Module/Attach.php
        +++ b/Zotlabs/Module/Attach.php
        @@ -7,48 +7,49 @@ require_once('include/security.php');
         require_once('include/attach.php');
         
         
        -class Attach extends Controller {
        +class Attach extends Controller
        +{
        +
        +    public function init()
        +    {
        +
        +        if (argc() < 2) {
        +            notice(t('Item not available.') . EOL);
        +            return;
        +        }
        +
        +        $r = attach_by_hash(argv(1), get_observer_hash(), ((argc() > 2) ? intval(argv(2)) : 0));
        +
        +        if (!$r['success']) {
        +            notice($r['message'] . EOL);
        +            return;
        +        }
        +
        +        $c = q("select channel_address from channel where channel_id = %d limit 1",
        +            intval($r['data']['uid'])
        +        );
        +
        +        if (!$c)
        +            return;
        +
        +        header('Content-type: ' . $r['data']['filetype']);
        +        header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"');
        +        if (intval($r['data']['os_storage'])) {
        +            $fname = dbunescbin($r['data']['content']);
        +            if (strpos($fname, 'store') !== false)
        +                $istream = fopen($fname, 'rb');
        +            else
        +                $istream = fopen('store/' . $c[0]['channel_address'] . '/' . $fname, 'rb');
        +            $ostream = fopen('php://output', 'wb');
        +            if ($istream && $ostream) {
        +                pipe_streams($istream, $ostream);
        +                fclose($istream);
        +                fclose($ostream);
        +            }
        +        } else
        +            echo dbunescbin($r['data']['content']);
        +        killme();
        +
        +    }
         
        -	function init() {
        -	
        -		if(argc() < 2) {
        -			notice( t('Item not available.') . EOL);
        -			return;
        -		}
        -	
        -		$r = attach_by_hash(argv(1),get_observer_hash(),((argc() > 2) ? intval(argv(2)) : 0));
        -	
        -		if(! $r['success']) {
        -			notice( $r['message'] . EOL);
        -			return;
        -		}
        -	
        -		$c = q("select channel_address from channel where channel_id = %d limit 1",
        -			intval($r['data']['uid'])
        -		);
        -	
        -		if(! $c)
        -			return;
        -	
        -		header('Content-type: ' . $r['data']['filetype']);
        -		header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"');
        -		if(intval($r['data']['os_storage'])) {
        -			$fname = dbunescbin($r['data']['content']);
        -			if(strpos($fname,'store') !== false)
        -				$istream = fopen($fname,'rb');
        -			else
        -				$istream = fopen('store/' . $c[0]['channel_address'] . '/' . $fname,'rb');
        -			$ostream = fopen('php://output','wb');
        -			if($istream && $ostream) {
        -				pipe_streams($istream,$ostream);
        -				fclose($istream);
        -				fclose($ostream);
        -			}
        -		}
        -		else
        -			echo dbunescbin($r['data']['content']);
        -		killme();
        -	
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Authorize.php b/Zotlabs/Module/Authorize.php
        index 709d76c18..b7dd58713 100644
        --- a/Zotlabs/Module/Authorize.php
        +++ b/Zotlabs/Module/Authorize.php
        @@ -11,133 +11,135 @@ use OAuth2\Request;
         use OAuth2\Response;
         
         
        -class Authorize extends Controller {
        +class Authorize extends Controller
        +{
         
        -	function get() {
        -		if (! local_channel()) {
        -			return login();
        -		} 
        -		else {
        +    public function get()
        +    {
        +        if (!local_channel()) {
        +            return login();
        +        } else {
         
        -			$name = $_REQUEST['client_name'];
        -			if(! $name) {
        -				$name = (($_REQUEST['client_id']) ?: t('Unknown App'));
        -			}
        +            $name = $_REQUEST['client_name'];
        +            if (!$name) {
        +                $name = (($_REQUEST['client_id']) ?: t('Unknown App'));
        +            }
         
        -			$app = [
        -				'name' => $name,
        -				'icon' => (x($_REQUEST, 'logo_uri')    ? $_REQUEST['logo_uri'] : z_root() . '/images/icons/plugin.png'),
        -				'url'  => (x($_REQUEST, 'client_uri')  ? $_REQUEST['client_uri'] : ''),
        -			];
        +            $app = [
        +                'name' => $name,
        +                'icon' => (x($_REQUEST, 'logo_uri') ? $_REQUEST['logo_uri'] : z_root() . '/images/icons/plugin.png'),
        +                'url' => (x($_REQUEST, 'client_uri') ? $_REQUEST['client_uri'] : ''),
        +            ];
         
        -			$link = (($app['url']) ? '' . $app['name'] . ' ' : $app['name']);
        +            $link = (($app['url']) ? '' . $app['name'] . ' ' : $app['name']);
         
        -			$o .= replace_macros(get_markup_template('oauth_authorize.tpl'), [
        -				'$title'        => t('Authorize'),
        -				'$authorize'    => sprintf( t('Do you authorize the app %s to access your channel data?'), $link ),
        -				'$app'          => $app,
        -				'$yes'          => t('Allow'),
        -				'$no'           => t('Deny'),
        -				'$client_id'    => (x($_REQUEST, 'client_id') ? $_REQUEST['client_id'] : ''),
        -				'$redirect_uri' => (x($_REQUEST, 'redirect_uri') ? $_REQUEST['redirect_uri'] : ''),
        -				'$state'        => (x($_REQUEST, 'state') ? $_REQUEST['state'] : ''),
        -			]);
        -			return $o;
        -		}
        -	}
        +            $o .= replace_macros(get_markup_template('oauth_authorize.tpl'), [
        +                '$title' => t('Authorize'),
        +                '$authorize' => sprintf(t('Do you authorize the app %s to access your channel data?'), $link),
        +                '$app' => $app,
        +                '$yes' => t('Allow'),
        +                '$no' => t('Deny'),
        +                '$client_id' => (x($_REQUEST, 'client_id') ? $_REQUEST['client_id'] : ''),
        +                '$redirect_uri' => (x($_REQUEST, 'redirect_uri') ? $_REQUEST['redirect_uri'] : ''),
        +                '$state' => (x($_REQUEST, 'state') ? $_REQUEST['state'] : ''),
        +            ]);
        +            return $o;
        +        }
        +    }
         
        -	function post() {
        -		if (! local_channel()) {
        -			return;
        -		}
        +    public function post()
        +    {
        +        if (!local_channel()) {
        +            return;
        +        }
         
        -		$storage = new OAuth2Storage(DBA::$dba->db);
        -		$s = new OAuth2Server($storage);
        +        $storage = new OAuth2Storage(DBA::$dba->db);
        +        $s = new OAuth2Server($storage);
         
        -		// TODO: The automatic client registration protocol below should adhere more
        -		// closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined
        -		// at https://tools.ietf.org/html/rfc7591
        +        // TODO: The automatic client registration protocol below should adhere more
        +        // closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined
        +        // at https://tools.ietf.org/html/rfc7591
         
        -		// If no client_id was provided, generate a new one.
        -		if (x($_POST, 'client_name')) {
        -			$client_name = $_POST['client_name'];
        -		} else {
        -			$client_name = $_POST['client_name'] = EMPTY_STR;
        -		}
        +        // If no client_id was provided, generate a new one.
        +        if (x($_POST, 'client_name')) {
        +            $client_name = $_POST['client_name'];
        +        } else {
        +            $client_name = $_POST['client_name'] = EMPTY_STR;
        +        }
         
        -		// If no client_id was provided, generate a new one.
        -		if (x($_POST, 'client_id')) {
        -			$client_id = $_POST['client_id'];
        -		} else {
        -			$client_id = $_POST['client_id'] = random_string(16);
        -		}
        +        // If no client_id was provided, generate a new one.
        +        if (x($_POST, 'client_id')) {
        +            $client_id = $_POST['client_id'];
        +        } else {
        +            $client_id = $_POST['client_id'] = random_string(16);
        +        }
         
        -		// If no redirect_uri was provided, generate a fake one.
        -		if (x($_POST, 'redirect_uri')) {
        -			$redirect_uri = $_POST['redirect_uri'];
        -		} else {
        -			$redirect_uri = $_POST['redirect_uri'] = 'https://fake.example.com/oauth';
        -		}
        +        // If no redirect_uri was provided, generate a fake one.
        +        if (x($_POST, 'redirect_uri')) {
        +            $redirect_uri = $_POST['redirect_uri'];
        +        } else {
        +            $redirect_uri = $_POST['redirect_uri'] = 'https://fake.example.com/oauth';
        +        }
         
        -		$request = Request::createFromGlobals();
        -		$response = new Response();
        +        $request = Request::createFromGlobals();
        +        $response = new Response();
         
        -		// Note, "sub" field must match type and content. $user_id is used to populate - make sure it's a string. 
        -		$channel = channelx_by_n(local_channel());
        -		$user_id = $channel['channel_id'];
        +        // Note, "sub" field must match type and content. $user_id is used to populate - make sure it's a string.
        +        $channel = channelx_by_n(local_channel());
        +        $user_id = $channel['channel_id'];
         
        -		$client_found = false;
        -		$client = $storage->getClientDetails($client_id);
        +        $client_found = false;
        +        $client = $storage->getClientDetails($client_id);
         
        -		logger('client: ' . print_r($client,true),LOGGER_DATA);
        +        logger('client: ' . print_r($client, true), LOGGER_DATA);
         
        -		if ($client) {
        -			if (intval($client['user_id']) === 0 || intval($client['user_id']) === intval($user_id)) {
        -				$client_found = true;
        -				$client_name = $client['client_name'];
        -				$client_secret = $client['client_secret'];
        -				// Until "Dynamic Client Registration" is fully tested - allow new clients to assign their own secret in the REQUEST
        -				if (! $client_secret) {
        -					$client_secret = ((isset($_REQUEST['client_secret'])) ? $_REQUEST['client_secret'] : random_string(16));
        -				}
        -				$grant_types = $client['grant_types'];
        -				// Client apps are registered per channel
        +        if ($client) {
        +            if (intval($client['user_id']) === 0 || intval($client['user_id']) === intval($user_id)) {
        +                $client_found = true;
        +                $client_name = $client['client_name'];
        +                $client_secret = $client['client_secret'];
        +                // Until "Dynamic Client Registration" is fully tested - allow new clients to assign their own secret in the REQUEST
        +                if (!$client_secret) {
        +                    $client_secret = ((isset($_REQUEST['client_secret'])) ? $_REQUEST['client_secret'] : random_string(16));
        +                }
        +                $grant_types = $client['grant_types'];
        +                // Client apps are registered per channel
         
         
        -logger('client_id: ' . $client_id);
        -logger('client_secret: ' . $client_secret);
        -logger('redirect_uri: ' . $redirect_uri);
        -logger('grant_types: ' . $_REQUEST['grant_types']);
        -logger('scope: ' . $_REQUEST['scope']);
        -logger('user_id: ' . $user_id);
        -logger('client_name: ' . $client_name);
        +                logger('client_id: ' . $client_id);
        +                logger('client_secret: ' . $client_secret);
        +                logger('redirect_uri: ' . $redirect_uri);
        +                logger('grant_types: ' . $_REQUEST['grant_types']);
        +                logger('scope: ' . $_REQUEST['scope']);
        +                logger('user_id: ' . $user_id);
        +                logger('client_name: ' . $client_name);
         
        -				$storage->setClientDetails($client_id, $client_secret, $redirect_uri, $grant_types, $_REQUEST['scope'], $user_id, $client_name);
        -			}
        -		}
        -		if (! $client_found) {
        -			$response->send();
        -			killme();
        -		}
        +                $storage->setClientDetails($client_id, $client_secret, $redirect_uri, $grant_types, $_REQUEST['scope'], $user_id, $client_name);
        +            }
        +        }
        +        if (!$client_found) {
        +            $response->send();
        +            killme();
        +        }
         
        -		$response->setParameter('client_secret', $client['client_secret']);
        +        $response->setParameter('client_secret', $client['client_secret']);
         
        -		// validate the authorize request
        -		if (!$s->validateAuthorizeRequest($request, $response)) {
        -			$response->send();
        -			killme();
        -		}
        +        // validate the authorize request
        +        if (!$s->validateAuthorizeRequest($request, $response)) {
        +            $response->send();
        +            killme();
        +        }
         
        -		// print the authorization code if the user has authorized your client
        -		$is_authorized = ($_POST['authorize'] === 'allow');
        -		$s->handleAuthorizeRequest($request, $response, $is_authorized, $user_id);
        -		if ($is_authorized) {
        -			$code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40);
        -			logger('Authorization Code: ' .  $code);
        -		}
        +        // print the authorization code if the user has authorized your client
        +        $is_authorized = ($_POST['authorize'] === 'allow');
        +        $s->handleAuthorizeRequest($request, $response, $is_authorized, $user_id);
        +        if ($is_authorized) {
        +            $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40);
        +            logger('Authorization Code: ' . $code);
        +        }
         
        -		$response->send();
        -		killme();
        -	}
        +        $response->send();
        +        killme();
        +    }
         
         }
        diff --git a/Zotlabs/Module/Block.php b/Zotlabs/Module/Block.php
        index aa9d01107..1dfdae59a 100644
        --- a/Zotlabs/Module/Block.php
        +++ b/Zotlabs/Module/Block.php
        @@ -7,87 +7,89 @@ use Zotlabs\Web\Controller;
         
         require_once('include/conversation.php');
         
        -class Block extends Controller {
        +class Block extends Controller
        +{
         
        -	function init() {
        -	
        -		$which = argv(1);
        -		$profile = 0;
        -		Libprofile::load($which,$profile);
        -	
        -		if(App::$profile['profile_uid'])
        -			head_set_icon(App::$profile['thumb']);
        -	
        -	}
        -	
        -	
        -		function get() {
        -	
        -		if(! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),'view_pages')) {
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        -	
        -		if(argc() < 3) {
        -			notice( t('Invalid item.') . EOL);
        -			return;
        -		}
        -	
        -		$channel_address = argv(1);
        -		$page_id = argv(2);
        -	
        -		$u = q("select channel_id from channel where channel_address = '%s' limit 1",
        -			dbesc($channel_address)
        -		);
        -	
        -		if(! $u) {
        -			notice( t('Channel not found.') . EOL);
        -			return;
        -		}
        -	
        -		if($_REQUEST['rev'])
        -			$revision = " and revision = " . intval($_REQUEST['rev']) . " ";
        -		else
        -			$revision = " order by revision desc ";
        -	
        -		require_once('include/security.php');
        -		$sql_options = item_permissions_sql($u[0]['channel_id']);
        -	
        -		$r = q("select item.* from item left join iconfig on item.id = iconfig.iid
        +    public function init()
        +    {
        +
        +        $which = argv(1);
        +        $profile = 0;
        +        Libprofile::load($which, $profile);
        +
        +        if (App::$profile['profile_uid'])
        +            head_set_icon(App::$profile['thumb']);
        +
        +    }
        +
        +
        +    public function get()
        +    {
        +
        +        if (!perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_pages')) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
        +
        +        if (argc() < 3) {
        +            notice(t('Invalid item.') . EOL);
        +            return;
        +        }
        +
        +        $channel_address = argv(1);
        +        $page_id = argv(2);
        +
        +        $u = q("select channel_id from channel where channel_address = '%s' limit 1",
        +            dbesc($channel_address)
        +        );
        +
        +        if (!$u) {
        +            notice(t('Channel not found.') . EOL);
        +            return;
        +        }
        +
        +        if ($_REQUEST['rev'])
        +            $revision = " and revision = " . intval($_REQUEST['rev']) . " ";
        +        else
        +            $revision = " order by revision desc ";
        +
        +        require_once('include/security.php');
        +        $sql_options = item_permissions_sql($u[0]['channel_id']);
        +
        +        $r = q("select item.* from item left join iconfig on item.id = iconfig.iid
         			where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and iconfig.k = 'BUILDBLOCK' and 
         			item_type = %d $sql_options $revision limit 1",
        -			intval($u[0]['channel_id']),
        -			dbesc($page_id),
        -			intval(ITEM_TYPE_BLOCK)
        -		);
        -	
        -		if(! $r) {
        -	
        -			// Check again with no permissions clause to see if it is a permissions issue
        -	
        -			$x = q("select item.* from item left join iconfig on item.id = iconfig.iid
        +            intval($u[0]['channel_id']),
        +            dbesc($page_id),
        +            intval(ITEM_TYPE_BLOCK)
        +        );
        +
        +        if (!$r) {
        +
        +            // Check again with no permissions clause to see if it is a permissions issue
        +
        +            $x = q("select item.* from item left join iconfig on item.id = iconfig.iid
         			where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and iconfig.k = 'BUILDBLOCK' and 
         			item_type = %d $revision limit 1",
        -				intval($u[0]['channel_id']),
        -				dbesc($page_id),
        -				intval(ITEM_TYPE_BLOCK)
        -			);
        -			if($x) {
        -				// Yes, it's there. You just aren't allowed to see it.
        -				notice( t('Permission denied.') . EOL);
        -			}
        -			else {
        -				notice( t('Page not found.') . EOL);
        -			}
        -			return;
        -		}
        -	
        -		xchan_query($r);
        -		$r = fetch_post_tags($r,true);
        -	
        -		$o .= prepare_page($r[0]);
        -		return $o;
        -	
        -	}
        -	
        +                intval($u[0]['channel_id']),
        +                dbesc($page_id),
        +                intval(ITEM_TYPE_BLOCK)
        +            );
        +            if ($x) {
        +                // Yes, it's there. You just aren't allowed to see it.
        +                notice(t('Permission denied.') . EOL);
        +            } else {
        +                notice(t('Page not found.') . EOL);
        +            }
        +            return;
        +        }
        +
        +        xchan_query($r);
        +        $r = fetch_post_tags($r, true);
        +
        +        $o .= prepare_page($r[0]);
        +        return $o;
        +
        +    }
        +
         }
        diff --git a/Zotlabs/Module/Blocks.php b/Zotlabs/Module/Blocks.php
        index 385a15784..0f59b3487 100644
        --- a/Zotlabs/Module/Blocks.php
        +++ b/Zotlabs/Module/Blocks.php
        @@ -10,168 +10,171 @@ require_once('include/conversation.php');
         require_once('include/acl_selectors.php');
         
         
        -class Blocks extends Controller {
        +class Blocks extends Controller
        +{
         
        -	function init() {
        -	
        -		if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) {
        -			$sys = get_sys_channel();
        -			if($sys && intval($sys['channel_id'])) {
        -				App::$is_sys = true;
        -			}
        -		}
        -	
        -		if(argc() > 1)
        -			$which = argv(1);
        -		else
        -			return;
        -	
        -		Libprofile::load($which);
        -	
        -	}
        -	
        -	
        -	function get() {
        -	
        -		if(! App::$profile) {
        -			notice( t('Requested profile is not available.') . EOL );
        -			App::$error = 404;
        -			return;
        -		}
        -	
        -		$which = argv(1);
        -	
        -		$_SESSION['return_url'] = App::$query_string;
        -	
        -		$uid = local_channel();
        -		$owner = 0;
        -		$channel = null;
        -		$observer = App::get_observer();
        -	
        -		$channel = App::get_channel();
        -	
        -		if(App::$is_sys && is_site_admin()) {
        -			$sys = get_sys_channel();
        -			if($sys && intval($sys['channel_id'])) {
        -				$uid = $owner = intval($sys['channel_id']);
        -				$channel = $sys;
        -				$observer = $sys;
        -			}
        -		}
        -	
        -		if(! $owner) {
        -			// Figure out who the page owner is.
        -			$r = q("select channel_id from channel where channel_address = '%s'",
        -				dbesc($which)
        -			);
        -			if($r) {
        -				$owner = intval($r[0]['channel_id']);
        -			}
        -		}
        -	
        -		$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
        -	
        -		$perms = get_all_perms($owner,$ob_hash);
        -	
        -		if(! $perms['write_pages']) {
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        -	
        -		// Block design features from visitors 
        -	
        -		if((! $uid) || ($uid != $owner)) {
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        -	
        -		$mimetype = (($_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner,'system','page_mimetype'));
        +    public function init()
        +    {
         
        -		$x = array(
        -			'webpage' => ITEM_TYPE_BLOCK,
        -			'is_owner' => true,
        -			'nickname' => App::$profile['channel_address'],
        -			'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
        -			'bang' => '',
        -			'showacl' => false,
        -			'visitor' => true,
        -			'mimetype' => $mimetype,
        -			'mimeselect' => true,
        -			'hide_location' => true,
        -			'ptlabel' => t('Block Name'),
        -			'profile_uid' => intval($owner),
        -			'expanded' => true,
        -			'novoting' => true,
        -			'bbco_autocomplete' => 'bbcode',
        -			'bbcode' => true
        -		);
        -	
        -		if($_REQUEST['title'])
        -			$x['title'] = $_REQUEST['title'];
        -		if($_REQUEST['body'])
        -			$x['body'] = $_REQUEST['body'];
        -		if($_REQUEST['pagetitle'])
        -			$x['pagetitle'] = $_REQUEST['pagetitle'];
        -	
        -		$editor = status_editor($x);
        -	
        +        if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) {
        +            $sys = get_sys_channel();
        +            if ($sys && intval($sys['channel_id'])) {
        +                App::$is_sys = true;
        +            }
        +        }
         
        -		$r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig 
        +        if (argc() > 1)
        +            $which = argv(1);
        +        else
        +            return;
        +
        +        Libprofile::load($which);
        +
        +    }
        +
        +
        +    public function get()
        +    {
        +
        +        if (!App::$profile) {
        +            notice(t('Requested profile is not available.') . EOL);
        +            App::$error = 404;
        +            return;
        +        }
        +
        +        $which = argv(1);
        +
        +        $_SESSION['return_url'] = App::$query_string;
        +
        +        $uid = local_channel();
        +        $owner = 0;
        +        $channel = null;
        +        $observer = App::get_observer();
        +
        +        $channel = App::get_channel();
        +
        +        if (App::$is_sys && is_site_admin()) {
        +            $sys = get_sys_channel();
        +            if ($sys && intval($sys['channel_id'])) {
        +                $uid = $owner = intval($sys['channel_id']);
        +                $channel = $sys;
        +                $observer = $sys;
        +            }
        +        }
        +
        +        if (!$owner) {
        +            // Figure out who the page owner is.
        +            $r = q("select channel_id from channel where channel_address = '%s'",
        +                dbesc($which)
        +            );
        +            if ($r) {
        +                $owner = intval($r[0]['channel_id']);
        +            }
        +        }
        +
        +        $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
        +
        +        $perms = get_all_perms($owner, $ob_hash);
        +
        +        if (!$perms['write_pages']) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
        +
        +        // Block design features from visitors
        +
        +        if ((!$uid) || ($uid != $owner)) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
        +
        +        $mimetype = (($_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner, 'system', 'page_mimetype'));
        +
        +        $x = array(
        +            'webpage' => ITEM_TYPE_BLOCK,
        +            'is_owner' => true,
        +            'nickname' => App::$profile['channel_address'],
        +            'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
        +            'bang' => '',
        +            'showacl' => false,
        +            'visitor' => true,
        +            'mimetype' => $mimetype,
        +            'mimeselect' => true,
        +            'hide_location' => true,
        +            'ptlabel' => t('Block Name'),
        +            'profile_uid' => intval($owner),
        +            'expanded' => true,
        +            'novoting' => true,
        +            'bbco_autocomplete' => 'bbcode',
        +            'bbcode' => true
        +        );
        +
        +        if ($_REQUEST['title'])
        +            $x['title'] = $_REQUEST['title'];
        +        if ($_REQUEST['body'])
        +            $x['body'] = $_REQUEST['body'];
        +        if ($_REQUEST['pagetitle'])
        +            $x['pagetitle'] = $_REQUEST['pagetitle'];
        +
        +        $editor = status_editor($x);
        +
        +
        +        $r = q("select iconfig.iid, iconfig.k, iconfig.v, mid, title, body, mimetype, created, edited from iconfig 
         			left join item on iconfig.iid = item.id
         			where uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' 
         			and item_type = %d order by item.created desc",
        -			intval($owner),
        -			intval(ITEM_TYPE_BLOCK)
        -		);
        -	
        -		$pages = null;
        -	
        -		if($r) {
        -			$pages = [];
        -			foreach($r as $rr) {
        -				$element_arr = array(
        -					'type'      => 'block',
        -					'title'	    => $rr['title'],
        -					'body'      => $rr['body'],
        -					'created'   => $rr['created'],
        -					'edited'    => $rr['edited'],
        -					'mimetype'  => $rr['mimetype'],
        -					'pagetitle' => $rr['v'],
        -					'mid'       => $rr['mid']
        -				);
        -				$pages[$rr['iid']][] = array(
        -					'url' => $rr['iid'],
        -					'name' => $rr['v'],
        -					'title' => $rr['title'],
        -					'created' => $rr['created'],
        -					'edited' => $rr['edited'],
        -					'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]'
        -				);
        -			} 
        -		}
        -	
        -		//Build the base URL for edit links
        -		$url = z_root() . '/editblock/' . $which; 
        -	
        -		$o .= replace_macros(get_markup_template('blocklist.tpl'), array(
        -			'$baseurl'    => $url,
        -			'$title'      => t('Blocks'),
        -			'$name'       => t('Block Name'),
        -			'$blocktitle' => t('Block Title'),
        -			'$created'    => t('Created'),
        -			'$edited'     => t('Edited'),
        -			'$create'     => t('Create'),
        -			'$edit'       => t('Edit'),
        -			'$share'      => t('Share'),
        -			'$delete'     => t('Delete'),
        -			'$editor'     => $editor,
        -			'$pages'      => $pages,
        -			'$channel'    => $which,
        -			'$view'       => t('View'),
        -			'$preview'    => '1',
        -		));
        -	    
        -		return $o;
        -	}
        -	
        +            intval($owner),
        +            intval(ITEM_TYPE_BLOCK)
        +        );
        +
        +        $pages = null;
        +
        +        if ($r) {
        +            $pages = [];
        +            foreach ($r as $rr) {
        +                $element_arr = array(
        +                    'type' => 'block',
        +                    'title' => $rr['title'],
        +                    'body' => $rr['body'],
        +                    'created' => $rr['created'],
        +                    'edited' => $rr['edited'],
        +                    'mimetype' => $rr['mimetype'],
        +                    'pagetitle' => $rr['v'],
        +                    'mid' => $rr['mid']
        +                );
        +                $pages[$rr['iid']][] = array(
        +                    'url' => $rr['iid'],
        +                    'name' => $rr['v'],
        +                    'title' => $rr['title'],
        +                    'created' => $rr['created'],
        +                    'edited' => $rr['edited'],
        +                    'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]'
        +                );
        +            }
        +        }
        +
        +        //Build the base URL for edit links
        +        $url = z_root() . '/editblock/' . $which;
        +
        +        $o .= replace_macros(get_markup_template('blocklist.tpl'), array(
        +            '$baseurl' => $url,
        +            '$title' => t('Blocks'),
        +            '$name' => t('Block Name'),
        +            '$blocktitle' => t('Block Title'),
        +            '$created' => t('Created'),
        +            '$edited' => t('Edited'),
        +            '$create' => t('Create'),
        +            '$edit' => t('Edit'),
        +            '$share' => t('Share'),
        +            '$delete' => t('Delete'),
        +            '$editor' => $editor,
        +            '$pages' => $pages,
        +            '$channel' => $which,
        +            '$view' => t('View'),
        +            '$preview' => '1',
        +        ));
        +
        +        return $o;
        +    }
        +
         }
        diff --git a/Zotlabs/Module/Ca.php b/Zotlabs/Module/Ca.php
        index ab48b9c6a..749c082bb 100644
        --- a/Zotlabs/Module/Ca.php
        +++ b/Zotlabs/Module/Ca.php
        @@ -17,7 +17,7 @@ class Ca extends Controller
              *
              * @return void
              */
        -    function get()
        +    public function get()
             {
                 if (argc() > 1) {
                     $path = 'cache/img/' . substr(argv(1), 0, 2) . '/' . argv(1);
        @@ -29,7 +29,7 @@ class Ca extends Controller
                         }
         
                         $cache = intval(get_config('system', 'photo_cache_time'));
        -                if (! $cache) {
        +                if (!$cache) {
                             $cache = (3600 * 24); // 1 day
                         }
                         header(
        @@ -39,7 +39,7 @@ class Ca extends Controller
                         // Set browser cache age as $cache.  But set timeout of
                         // 'shared caches' much lower in the event that infrastructure
                         // caching is present.
        -                $smaxage = intval($cache/12);
        +                $smaxage = intval($cache / 12);
                         header(
                             'Cache-Control: s-maxage=' . $smaxage
                             . '; max-age=' . $cache . ';'
        diff --git a/Zotlabs/Module/Cal.php b/Zotlabs/Module/Cal.php
        index 0a9736c65..937bc617a 100644
        --- a/Zotlabs/Module/Cal.php
        +++ b/Zotlabs/Module/Cal.php
        @@ -16,350 +16,353 @@ require_once('include/event.php');
         require_once('include/html2plain.php');
         
         
        -class Cal extends Controller {
        +class Cal extends Controller
        +{
         
        -	function init() {
        -		if(observer_prohibited()) {
        -			return;
        -		}
        -	
        -		$o = '';
        -	
        -		if(argc() > 1) {
        -			$nick = argv(1);
        -	
        -			Libprofile::load($nick);
        -	
        -			$channelx = channelx_by_nick($nick);
        -	
        -			if(! $channelx)
        -				return;
        -	
        -			App::$data['channel'] = $channelx;
        -	
        -			$observer = App::get_observer();
        -			App::$data['observer'] = $observer;
        -	
        -			$observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
        -	
        -			head_set_icon(App::$data['channel']['xchan_photo_s']);
        -	
        -			App::$page['htmlhead'] .= "" ;
        -	
        -		}
        -	
        -		return;
        -	}
        -	
        -	
        -	
        -	function get() {
        -	
        -		if(observer_prohibited()) {
        -			return;
        -		}
        -		
        -		$channel = null;
        -	
        -		if(argc() > 1) {
        -			$channel = channelx_by_nick(argv(1));
        -		}
        -	
        -	
        -		if(! $channel) {
        -			notice( t('Channel not found.') . EOL);
        -			return;
        -		}
        -	
        -		// since we don't currently have an event permission - use the stream permission
        -	
        -		if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
        -			notice( t('Permissions denied.') . EOL);
        -			return;
        -		}
        +    public function init()
        +    {
        +        if (observer_prohibited()) {
        +            return;
        +        }
         
        -		nav_set_selected('Calendar');
        -	
        -		$sql_extra = permissions_sql($channel['channel_id'],get_observer_hash(),'event');
        +        $o = '';
         
        -		$first_day = intval(get_pconfig($channel['channel_id'],'system','cal_first_day',0));
        -	
        -		$htpl = get_markup_template('event_head.tpl');
        -		App::$page['htmlhead'] .= replace_macros($htpl,array(
        -			'$baseurl' => z_root(),
        -			'$module_url' => '/cal/' . $channel['channel_address'],
        -			'$modparams' => 2,
        -			'$lang' => App::$language,
        -			'$first_day' => $first_day
        -		));
        -	
        -		$o = '';
        -	
        -		$mode = 'view';
        -		$y = 0;
        -		$m = 0;
        -		$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " "  : '');
        -	
        -		// logger('args: ' . print_r(\App::$argv,true));
        -	
        -		if(argc() > 3 && intval(argv(2)) && intval(argv(3))) {
        -			$mode = 'view';
        -			$y = intval(argv(2));
        -			$m = intval(argv(3));
        -		}
        -		if(argc() <= 3) {
        -			$mode = 'view';
        -			$event_id = argv(2);
        -		}
        -	
        -		if($mode == 'view') {
        -	
        -			/* edit/create form */
        -			if($event_id) {
        -				$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
        -					dbesc($event_id),
        -					intval($channel['channel_id'])
        -				);
        -				if(count($r))
        -					$orig_event = $r[0];
        -			}
        -	
        -	
        -			// Passed parameters overrides anything found in the DB
        -			if(!x($orig_event))
        -				$orig_event = [];
        -	
        -	
        -	
        -			$tz = date_default_timezone_get();
        -			if(x($orig_event))
        -				$tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC');
        -	
        -			$syear = datetime_convert('UTC', $tz, $sdt, 'Y');
        -			$smonth = datetime_convert('UTC', $tz, $sdt, 'm');
        -			$sday = datetime_convert('UTC', $tz, $sdt, 'd');
        -			$shour = datetime_convert('UTC', $tz, $sdt, 'H');
        -			$sminute = datetime_convert('UTC', $tz, $sdt, 'i');
        -	
        -			$stext = datetime_convert('UTC',$tz,$sdt);
        -			$stext = substr($stext,0,14) . "00:00";
        -	
        -			$fyear = datetime_convert('UTC', $tz, $fdt, 'Y');
        -			$fmonth = datetime_convert('UTC', $tz, $fdt, 'm');
        -			$fday = datetime_convert('UTC', $tz, $fdt, 'd');
        -			$fhour = datetime_convert('UTC', $tz, $fdt, 'H');
        -			$fminute = datetime_convert('UTC', $tz, $fdt, 'i');
        -	
        -			$ftext = datetime_convert('UTC',$tz,$fdt);
        -			$ftext = substr($ftext,0,14) . "00:00";
        -	
        -			$type = ((x($orig_event)) ? $orig_event['etype'] : 'event');
        -	
        -			$f = get_config('system','event_input_format');
        -			if(! $f)
        -				$f = 'ymd';
        -	
        -			$catsenabled = Apps::system_app_installed(local_channel(),'Categories');
        -	
        -	
        -			$show_bd = perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts');
        -			if(! $show_bd) {
        -				$sql_extra .= " and event.etype != 'birthday' ";
        -			}
        -	
        -	
        -			$category = '';
        -	
        -			$thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y');
        -			$thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m');
        -			if(! $y)
        -				$y = intval($thisyear);
        -			if(! $m)
        -				$m = intval($thismonth);
        -	
        -			// Put some limits on dates. The PHP date functions don't seem to do so well before 1900.
        -			// An upper limit was chosen to keep search engines from exploring links millions of years in the future. 
        -	
        -			if($y < 1901)
        -				$y = 1900;
        -			if($y > 2099)
        -				$y = 2100;
        -	
        -			$nextyear = $y;
        -			$nextmonth = $m + 1;
        -			if($nextmonth > 12) {
        -					$nextmonth = 1;
        -				$nextyear ++;
        -			}
        -	
        -			$prevyear = $y;
        -			if($m > 1)
        -				$prevmonth = $m - 1;
        -			else {
        -				$prevmonth = 12;
        -				$prevyear --;
        -			}
        -				
        -			$dim    = get_dim($y,$m);
        -			$start  = sprintf('%d-%d-%d %d:%d:%d',$y,$m,1,0,0,0);
        -			$finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59);
        -	
        -	
        -			if (argv(2) === 'json'){
        -				if (x($_GET,'start'))	$start = $_GET['start'];
        -				if (x($_GET,'end'))	$finish = $_GET['end'];
        -			}
        -	
        -			$start  = datetime_convert('UTC','UTC',$start);
        -			$finish = datetime_convert('UTC','UTC',$finish);
        -	
        -			$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
        -			$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
        -	
        +        if (argc() > 1) {
        +            $nick = argv(1);
         
        -			if(! perm_is_allowed(App::$profile['uid'],get_observer_hash(),'view_contacts'))
        -				$sql_extra .= " and etype != 'birthday' ";
        +            Libprofile::load($nick);
         
        -			if (x($_GET,'id')){
        -			  	$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
        +            $channelx = channelx_by_nick($nick);
        +
        +            if (!$channelx)
        +                return;
        +
        +            App::$data['channel'] = $channelx;
        +
        +            $observer = App::get_observer();
        +            App::$data['observer'] = $observer;
        +
        +            $observer_xchan = (($observer) ? $observer['xchan_hash'] : '');
        +
        +            head_set_icon(App::$data['channel']['xchan_photo_s']);
        +
        +            App::$page['htmlhead'] .= "";
        +
        +        }
        +
        +        return;
        +    }
        +
        +
        +    public function get()
        +    {
        +
        +        if (observer_prohibited()) {
        +            return;
        +        }
        +
        +        $channel = null;
        +
        +        if (argc() > 1) {
        +            $channel = channelx_by_nick(argv(1));
        +        }
        +
        +
        +        if (!$channel) {
        +            notice(t('Channel not found.') . EOL);
        +            return;
        +        }
        +
        +        // since we don't currently have an event permission - use the stream permission
        +
        +        if (!perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
        +            notice(t('Permissions denied.') . EOL);
        +            return;
        +        }
        +
        +        nav_set_selected('Calendar');
        +
        +        $sql_extra = permissions_sql($channel['channel_id'], get_observer_hash(), 'event');
        +
        +        $first_day = intval(get_pconfig($channel['channel_id'], 'system', 'cal_first_day', 0));
        +
        +        $htpl = get_markup_template('event_head.tpl');
        +        App::$page['htmlhead'] .= replace_macros($htpl, array(
        +            '$baseurl' => z_root(),
        +            '$module_url' => '/cal/' . $channel['channel_address'],
        +            '$modparams' => 2,
        +            '$lang' => App::$language,
        +            '$first_day' => $first_day
        +        ));
        +
        +        $o = '';
        +
        +        $mode = 'view';
        +        $y = 0;
        +        $m = 0;
        +        $ignored = ((x($_REQUEST, 'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
        +
        +        // logger('args: ' . print_r(\App::$argv,true));
        +
        +        if (argc() > 3 && intval(argv(2)) && intval(argv(3))) {
        +            $mode = 'view';
        +            $y = intval(argv(2));
        +            $m = intval(argv(3));
        +        }
        +        if (argc() <= 3) {
        +            $mode = 'view';
        +            $event_id = argv(2);
        +        }
        +
        +        if ($mode == 'view') {
        +
        +            /* edit/create form */
        +            if ($event_id) {
        +                $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
        +                    dbesc($event_id),
        +                    intval($channel['channel_id'])
        +                );
        +                if (count($r))
        +                    $orig_event = $r[0];
        +            }
        +
        +
        +            // Passed parameters overrides anything found in the DB
        +            if (!x($orig_event))
        +                $orig_event = [];
        +
        +
        +            $tz = date_default_timezone_get();
        +            if (x($orig_event))
        +                $tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC');
        +
        +            $syear = datetime_convert('UTC', $tz, $sdt, 'Y');
        +            $smonth = datetime_convert('UTC', $tz, $sdt, 'm');
        +            $sday = datetime_convert('UTC', $tz, $sdt, 'd');
        +            $shour = datetime_convert('UTC', $tz, $sdt, 'H');
        +            $sminute = datetime_convert('UTC', $tz, $sdt, 'i');
        +
        +            $stext = datetime_convert('UTC', $tz, $sdt);
        +            $stext = substr($stext, 0, 14) . "00:00";
        +
        +            $fyear = datetime_convert('UTC', $tz, $fdt, 'Y');
        +            $fmonth = datetime_convert('UTC', $tz, $fdt, 'm');
        +            $fday = datetime_convert('UTC', $tz, $fdt, 'd');
        +            $fhour = datetime_convert('UTC', $tz, $fdt, 'H');
        +            $fminute = datetime_convert('UTC', $tz, $fdt, 'i');
        +
        +            $ftext = datetime_convert('UTC', $tz, $fdt);
        +            $ftext = substr($ftext, 0, 14) . "00:00";
        +
        +            $type = ((x($orig_event)) ? $orig_event['etype'] : 'event');
        +
        +            $f = get_config('system', 'event_input_format');
        +            if (!$f)
        +                $f = 'ymd';
        +
        +            $catsenabled = Apps::system_app_installed(local_channel(), 'Categories');
        +
        +
        +            $show_bd = perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts');
        +            if (!$show_bd) {
        +                $sql_extra .= " and event.etype != 'birthday' ";
        +            }
        +
        +
        +            $category = '';
        +
        +            $thisyear = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y');
        +            $thismonth = datetime_convert('UTC', date_default_timezone_get(), 'now', 'm');
        +            if (!$y)
        +                $y = intval($thisyear);
        +            if (!$m)
        +                $m = intval($thismonth);
        +
        +            // Put some limits on dates. The PHP date functions don't seem to do so well before 1900.
        +            // An upper limit was chosen to keep search engines from exploring links millions of years in the future.
        +
        +            if ($y < 1901)
        +                $y = 1900;
        +            if ($y > 2099)
        +                $y = 2100;
        +
        +            $nextyear = $y;
        +            $nextmonth = $m + 1;
        +            if ($nextmonth > 12) {
        +                $nextmonth = 1;
        +                $nextyear++;
        +            }
        +
        +            $prevyear = $y;
        +            if ($m > 1)
        +                $prevmonth = $m - 1;
        +            else {
        +                $prevmonth = 12;
        +                $prevyear--;
        +            }
        +
        +            $dim = get_dim($y, $m);
        +            $start = sprintf('%d-%d-%d %d:%d:%d', $y, $m, 1, 0, 0, 0);
        +            $finish = sprintf('%d-%d-%d %d:%d:%d', $y, $m, $dim, 23, 59, 59);
        +
        +
        +            if (argv(2) === 'json') {
        +                if (x($_GET, 'start')) $start = $_GET['start'];
        +                if (x($_GET, 'end')) $finish = $_GET['end'];
        +            }
        +
        +            $start = datetime_convert('UTC', 'UTC', $start);
        +            $finish = datetime_convert('UTC', 'UTC', $finish);
        +
        +            $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
        +            $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
        +
        +
        +            if (!perm_is_allowed(App::$profile['uid'], get_observer_hash(), 'view_contacts'))
        +                $sql_extra .= " and etype != 'birthday' ";
        +
        +            if (x($_GET, 'id')) {
        +                $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
         	                                from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d $sql_extra limit 1",
        -					intval($channel['channel_id']),
        -					intval($_GET['id'])
        -				);
        -			} 
        -			else {
        -				// fixed an issue with "nofinish" events not showing up in the calendar.
        -				// There's still an issue if the finish date crosses the end of month.
        -				// Noting this for now - it will need to be fixed here and in Friendica.
        -				// Ultimately the finish date shouldn't be involved in the query. 
        -	
        -				$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
        +                    intval($channel['channel_id']),
        +                    intval($_GET['id'])
        +                );
        +            } else {
        +                // fixed an issue with "nofinish" events not showing up in the calendar.
        +                // There's still an issue if the finish date crosses the end of month.
        +                // Noting this for now - it will need to be fixed here and in Friendica.
        +                // Ultimately the finish date shouldn't be involved in the query.
        +
        +                $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan
         	                              from event left join item on event_hash = resource_id 
         					where resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored 
         					AND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' ) 
         					OR  (  adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) $sql_extra ",
        -					intval($channel['channel_id']),
        -					dbesc($start),
        -					dbesc($finish),
        -					dbesc($adjust_start),
        -					dbesc($adjust_finish)
        -				);
        -	
        -			}
        -	
        -			$links = [];
        -	
        -			if($r) {
        -				xchan_query($r);
        -				$r = fetch_post_tags($r,true);
        -	
        -				$r = sort_by_date($r);
        -			}
        -	
        -			if($r) {
        -				foreach($r as $rr) {
        -					$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
        -					if(! x($links,$j)) 
        -						$links[$j] = z_root() . '/' . App::$cmd . '#link-' . $j;
        -				}
        -			}
        -	
        -			$events=[];
        -	
        -			$last_date = '';
        -			$fmt = t('l, F j');
        -	
        -			if($r) {
        -	
        -				foreach($r as $rr) {
        -					
        -					$j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j'));
        -					$d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt));
        -					$d = day_translate($d);
        -					
        -					$start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
        -					if ($rr['nofinish']){
        -						$end = null;
        -					} else {
        -						$end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
        -					}
        -					
        -					
        -					$is_first = ($d !== $last_date);
        -						
        -					$last_date = $d;
        -	
        -					$edit = false;
        -	
        -					$drop = false;
        -	
        -					$title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8'));
        -					if(! $title) {
        -						list($title, $_trash) = explode("$rr['id'],
        -						'hash' => $rr['event_hash'],
        -						'start'=> $start,
        -						'end' => $end,
        -						'drop' => $drop,
        -						'allDay' => false,
        -						'title' => $title,
        -						
        -						'j' => $j,
        -						'd' => $d,
        -						'edit' => $edit,
        -						'is_first'=>$is_first,
        -						'item'=>$rr,
        -						'html'=>$html,
        -						'plink' => array($rr['plink'],t('Link to Source'),'',''),
        -					);
        -	
        -	
        -				}
        -			}
        -			
        -			if (argv(2) === 'json'){
        -				echo json_encode($events); killme();
        -			}
        -			
        -			// links: array('href', 'text', 'extra css classes', 'title')
        -			if (x($_GET,'id')){
        -				$tpl =  get_markup_template("event_cal.tpl");
        -			} 
        -			else {
        -				$tpl = get_markup_template("events_cal-js.tpl");
        -			}
        -	
        -			$nick = $channel['channel_address'];
        -	
        -			$o = replace_macros($tpl, array(
        -				'$baseurl'	=> z_root(),
        -				'$new_event'	=> array(z_root().'/cal',(($event_id) ? t('Edit Event') : t('Create Event')),'',''),
        -				'$previus'	=> array(z_root()."/cal/$nick/$prevyear/$prevmonth",t('Previous'),'',''),
        -				'$next'		=> array(z_root()."/cal/$nick/$nextyear/$nextmonth",t('Next'),'',''),
        -				'$export'	=> array(z_root()."/cal/$nick/$y/$m/export",t('Export'),'',''),
        -				'$calendar'	=> cal($y,$m,$links, ' eventcal'),
        -				'$events'	=> $events,
        -				'$upload'	=> t('Import'),
        -				'$submit'	=> t('Submit'),
        -				'$prev'		=> t('Previous'),
        -				'$next'		=> t('Next'),
        -				'$today'	=> t('Today'),
        -				'$form'		=> $form,
        -				'$expandform'	=> ((x($_GET,'expandform')) ? true : false)
        -			));
        -			
        -			if (x($_GET,'id')){ echo $o; killme(); }
        -			
        -			return $o;
        -		}
        -	
        -	}
        -	
        +                    intval($channel['channel_id']),
        +                    dbesc($start),
        +                    dbesc($finish),
        +                    dbesc($adjust_start),
        +                    dbesc($adjust_finish)
        +                );
        +
        +            }
        +
        +            $links = [];
        +
        +            if ($r) {
        +                xchan_query($r);
        +                $r = fetch_post_tags($r, true);
        +
        +                $r = sort_by_date($r);
        +            }
        +
        +            if ($r) {
        +                foreach ($r as $rr) {
        +                    $j = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'j') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'j'));
        +                    if (!x($links, $j))
        +                        $links[$j] = z_root() . '/' . App::$cmd . '#link-' . $j;
        +                }
        +            }
        +
        +            $events = [];
        +
        +            $last_date = '';
        +            $fmt = t('l, F j');
        +
        +            if ($r) {
        +
        +                foreach ($r as $rr) {
        +
        +                    $j = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'j') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'j'));
        +                    $d = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], $fmt) : datetime_convert('UTC', 'UTC', $rr['dtstart'], $fmt));
        +                    $d = day_translate($d);
        +
        +                    $start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
        +                    if ($rr['nofinish']) {
        +                        $end = null;
        +                    } else {
        +                        $end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
        +                    }
        +
        +
        +                    $is_first = ($d !== $last_date);
        +
        +                    $last_date = $d;
        +
        +                    $edit = false;
        +
        +                    $drop = false;
        +
        +                    $title = strip_tags(html_entity_decode(bbcode($rr['summary']), ENT_QUOTES, 'UTF-8'));
        +                    if (!$title) {
        +                        list($title, $_trash) = explode(" $rr['id'],
        +                        'hash' => $rr['event_hash'],
        +                        'start' => $start,
        +                        'end' => $end,
        +                        'drop' => $drop,
        +                        'allDay' => false,
        +                        'title' => $title,
        +
        +                        'j' => $j,
        +                        'd' => $d,
        +                        'edit' => $edit,
        +                        'is_first' => $is_first,
        +                        'item' => $rr,
        +                        'html' => $html,
        +                        'plink' => array($rr['plink'], t('Link to Source'), '', ''),
        +                    );
        +
        +
        +                }
        +            }
        +
        +            if (argv(2) === 'json') {
        +                echo json_encode($events);
        +                killme();
        +            }
        +
        +            // links: array('href', 'text', 'extra css classes', 'title')
        +            if (x($_GET, 'id')) {
        +                $tpl = get_markup_template("event_cal.tpl");
        +            } else {
        +                $tpl = get_markup_template("events_cal-js.tpl");
        +            }
        +
        +            $nick = $channel['channel_address'];
        +
        +            $o = replace_macros($tpl, array(
        +                '$baseurl' => z_root(),
        +                '$new_event' => array(z_root() . '/cal', (($event_id) ? t('Edit Event') : t('Create Event')), '', ''),
        +                '$previus' => array(z_root() . "/cal/$nick/$prevyear/$prevmonth", t('Previous'), '', ''),
        +                '$next' => array(z_root() . "/cal/$nick/$nextyear/$nextmonth", t('Next'), '', ''),
        +                '$export' => array(z_root() . "/cal/$nick/$y/$m/export", t('Export'), '', ''),
        +                '$calendar' => cal($y, $m, $links, ' eventcal'),
        +                '$events' => $events,
        +                '$upload' => t('Import'),
        +                '$submit' => t('Submit'),
        +                '$prev' => t('Previous'),
        +                '$next' => t('Next'),
        +                '$today' => t('Today'),
        +                '$form' => $form,
        +                '$expandform' => ((x($_GET, 'expandform')) ? true : false)
        +            ));
        +
        +            if (x($_GET, 'id')) {
        +                echo $o;
        +                killme();
        +            }
        +
        +            return $o;
        +        }
        +
        +    }
        +
         }
        diff --git a/Zotlabs/Module/Calendar.php b/Zotlabs/Module/Calendar.php
        index 0e979f44c..31cb47209 100644
        --- a/Zotlabs/Module/Calendar.php
        +++ b/Zotlabs/Module/Calendar.php
        @@ -18,472 +18,466 @@ require_once('include/text.php');
         require_once('include/html2plain.php');
         require_once('include/security.php');
         
        -class Calendar extends Controller {
        +class Calendar extends Controller
        +{
         
        -	function post() {
        -	
        -		logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA);
        -	
        -		if (! local_channel())
        -			return;
        -	
        -		$event_id    = ((x($_POST,'event_id')) ? intval($_POST['event_id']) : 0);
        -		$event_hash  = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : '');
        -		$xchan       = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : '');
        -		$summary     = escape_tags(trim($_POST['summary']));
        -		$desc        = escape_tags(trim($_POST['desc']));
        -		$location    = escape_tags(trim($_POST['location']));
        -		$type        = escape_tags(trim($_POST['type']));
        -		$start_text  = escape_tags($_REQUEST['dtstart']);
        -		$finish_text = escape_tags($_REQUEST['dtend']);
        -		$adjust      = intval($_POST['adjust']);
        -		$nofinish    = intval($_POST['nofinish']);
        -		$uid         = local_channel();
        -		$timezone    = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select']))     : '');
        -		$tz          = (($timezone) ? $timezone : date_default_timezone_get());
        -		$categories  = escape_tags(trim($_POST['categories']));
        -	
        +    public function post()
        +    {
         
        -		// only allow editing your own events. 
        -	
        -		if (($xchan) && ($xchan !== get_observer_hash())) {
        -			return;
        -		}
        +        logger('post: ' . print_r($_REQUEST, true), LOGGER_DATA);
        +
        +        if (!local_channel())
        +            return;
        +
        +        $event_id = ((x($_POST, 'event_id')) ? intval($_POST['event_id']) : 0);
        +        $event_hash = ((x($_POST, 'event_hash')) ? $_POST['event_hash'] : '');
        +        $xchan = ((x($_POST, 'xchan')) ? dbesc($_POST['xchan']) : '');
        +        $summary = escape_tags(trim($_POST['summary']));
        +        $desc = escape_tags(trim($_POST['desc']));
        +        $location = escape_tags(trim($_POST['location']));
        +        $type = escape_tags(trim($_POST['type']));
        +        $start_text = escape_tags($_REQUEST['dtstart']);
        +        $finish_text = escape_tags($_REQUEST['dtend']);
        +        $adjust = intval($_POST['adjust']);
        +        $nofinish = intval($_POST['nofinish']);
        +        $uid = local_channel();
        +        $timezone = ((x($_POST, 'timezone_select')) ? notags(trim($_POST['timezone_select'])) : '');
        +        $tz = (($timezone) ? $timezone : date_default_timezone_get());
        +        $categories = escape_tags(trim($_POST['categories']));
         
         
        -		if ($start_text) {
        -			$start = $start_text;
        -		}
        -		else {
        -			$start = sprintf('%d-%d-%d %d:%d:0',$startyear,$startmonth,$startday,$starthour,$startminute);
        -		}
        +        // only allow editing your own events.
         
        -		if ($finish_text) {
        -			$finish = $finish_text;
        -		}
        -		else {
        -			$finish = sprintf('%d-%d-%d %d:%d:0',$finishyear,$finishmonth,$finishday,$finishhour,$finishminute);
        -		}
        -
        -		if ($nofinish) {
        -			$finish = NULL_DATE;
        -		}
        -
        -		if ($adjust) {
        -			$start = datetime_convert($tz,'UTC',$start);
        -			if (! $nofinish) {
        -				$finish = datetime_convert($tz,'UTC',$finish);
        -			}
        -		}
        -		else {
        -			$start = datetime_convert('UTC','UTC',$start);
        -			if (! $nofinish) {
        -				$finish = datetime_convert('UTC','UTC',$finish);
        -			}
        -		}
        -
        -		linkify_tags($location, local_channel());
        -
        -		// Don't allow the event to finish before it begins.
        -		// It won't hurt anything, but somebody will file a bug report
        -		// and we'll waste a bunch of time responding to it. Time that 
        -		// could've been spent doing something else. 
        -
        -		if (strcmp($finish,$start) < 0 && (! $nofinish)) {
        -			notice( t('Event can not end before it has started.') . EOL);
        -			if (intval($_REQUEST['preview'])) {
        -				echo( t('Unable to generate preview.'));
        -			}
        -			killme();
        -		}
        -	
        -		if ((! $summary) || (! $start)) {
        -			notice( t('Event title and start time are required.') . EOL);
        -			if (intval($_REQUEST['preview'])) {
        -				echo( t('Unable to generate preview.'));
        -			}
        -			killme();
        -		}
        -
        -		$channel = App::get_channel();
        -		$acl = new AccessControl(false);
        -	
        -		if ($event_id) {
        -			$x = q("select * from event where id = %d and uid = %d limit 1",
        -				intval($event_id),
        -				intval(local_channel())
        -			);
        -			if (! $x) {
        -				notice( t('Event not found.') . EOL);
        -				if (intval($_REQUEST['preview'])) {
        -					echo( t('Unable to generate preview.'));
        -					killme();
        -				}
        -				return;
        -			}
        -	
        -			$acl->set($x[0]);
        -	
        -			$created = $x[0]['created'];
        -			$edited = datetime_convert();
        -		}
        -		else {
        -			$created = $edited = datetime_convert();
        -			$acl->set_from_array($_POST);
        -		}
        -	
        -		$post_tags = [];
        -		$ac = $acl->get();
        -
        -		$str_contact_allow = $ac['allow_cid'];
        -		$str_group_allow   = $ac['allow_gid'];
        -		$str_contact_deny  = $ac['deny_cid'];
        -		$str_group_deny    = $ac['deny_gid'];
        -	
        -		$private = $acl->is_private();
        -	
        -		$results = linkify_tags($desc, local_channel());
        -
        -		if ($results) {
        -			// Set permissions based on tag replacements
        -	
        -			set_linkified_perms($results, $str_contact_allow, $str_group_allow, local_channel(), false, $private);
        -
        -			foreach ($results as $result) {
        -				$success = $result['success'];
        -				if ($success['replaced']) {
        -					$post_tags[] = [
        -						'uid'   => local_channel(),
        -						'ttype' => $success['termtype'],
        -						'otype' => TERM_OBJ_POST,
        -						'term'  => $success['term'],
        -						'url'   => $success['url']
        -					];	
        -				}
        -			}
        -		}
        +        if (($xchan) && ($xchan !== get_observer_hash())) {
        +            return;
        +        }
         
         
        -		if (strlen($categories)) {
        -			$cats = explode(',',$categories);
        -			foreach ($cats as $cat) {
        -				$post_tags[] = array(
        -					'uid'   => local_channel(), 
        -					'ttype' => TERM_CATEGORY,
        -					'otype' => TERM_OBJ_POST,
        -					'term'  => trim($cat),
        -					'url'   => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
        -				);
        -			}
        -		}
        -	
        -		$datarray = [ 
        -			'dtstart'     => $start,
        -			'dtend'       => $finish,
        -			'summary'     => $summary,
        -			'description' => $desc,
        -			'location'    => $location,
        -			'etype'       => $type,
        -			'adjust'      => $adjust,
        -			'nofinish'    => $nofinish,
        -			'uid'         => local_channel(),
        -			'account'     => get_account_id(),
        -			'event_xchan' => $channel['channel_hash'],
        -			'allow_cid'   => $str_contact_allow,
        -			'allow_gid'   => $str_group_allow,
        -			'deny_cid'    => $str_contact_deny,
        -			'deny_gid'    => $str_group_deny,
        -			'private'     => intval($private),
        -			'id'          => $event_id,
        -			'created'     => $created,
        -			'edited'      => $edited
        -		];
        -	
        -		if (intval($_REQUEST['preview'])) {
        -			$html = format_event_html($datarray);
        -			echo $html;
        -			killme();
        -		}
        -	
        -		$event = event_store_event($datarray);
        -	
        -		if ($post_tags)	{
        -			$datarray['term'] = $post_tags;
        -		}
        -	
        -		$item_id = event_store_item($datarray,$event);
        -	
        -		if ($item_id) {
        -			$r = q("select * from item where id = %d",
        -				intval($item_id)
        -			);
        -			if ($r) {
        -				xchan_query($r);
        -				$sync_item = fetch_post_tags($r);
        -				$z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
        -					dbesc($r[0]['resource_id']),
        -					intval($channel['channel_id'])
        -				);
        -				if ($z) {
        -					Libsync::build_sync_packet($channel['channel_id'], [ 'event_item' => [ encode_item($sync_item[0],true) ], 'event' => $z]);
        -				}
        -			}
        -		}
        -	
        -		Run::Summon( [ 'Notifier', 'event', $item_id ] );
        -		killme();
        -	
        -	}
        -	
        -	
        -	
        -	function get() {
        -	
        -		if (argc() > 2 && argv(1) == 'ical') {
        -			$event_id = argv(2);
        -	
        -			$sql_extra = permissions_sql(local_channel());
        -	
        -			$r = q("select * from event where event_hash = '%s' $sql_extra limit 1",
        -				dbesc($event_id)
        -			);
        -			if ($r) { 
        -				header('Content-type: text/calendar');
        -				header('Content-Disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' );
        -				echo ical_wrapper($r);
        -				killme();
        -			}
        -			else {
        -				notice( t('Event not found.') . EOL );
        -				return;
        -			}
        -		}
        -	
        -		if (! local_channel()) {
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        +        if ($start_text) {
        +            $start = $start_text;
        +        } else {
        +            $start = sprintf('%d-%d-%d %d:%d:0', $startyear, $startmonth, $startday, $starthour, $startminute);
        +        }
         
        -		if ((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
        -			$r = q("update event set dismissed = 1 where id = %d and uid = %d",
        -				intval(argv(2)),
        -				intval(local_channel())
        -			);
        -		}
        -	
        -		if ((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) {
        -			$r = q("update event set dismissed = 0 where id = %d and uid = %d",
        -				intval(argv(2)),
        -				intval(local_channel())
        -			);
        -		}
        +        if ($finish_text) {
        +            $finish = $finish_text;
        +        } else {
        +            $finish = sprintf('%d-%d-%d %d:%d:0', $finishyear, $finishmonth, $finishday, $finishhour, $finishminute);
        +        }
         
        -		$channel = App::get_channel();
        -	
        -		$mode   = 'view';
        -		$export = false;
        +        if ($nofinish) {
        +            $finish = NULL_DATE;
        +        }
         
        -		$ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " "  : '');
        +        if ($adjust) {
        +            $start = datetime_convert($tz, 'UTC', $start);
        +            if (!$nofinish) {
        +                $finish = datetime_convert($tz, 'UTC', $finish);
        +            }
        +        } else {
        +            $start = datetime_convert('UTC', 'UTC', $start);
        +            if (!$nofinish) {
        +                $finish = datetime_convert('UTC', 'UTC', $finish);
        +            }
        +        }
         
        -		if (argc() > 1) {
        -			if (argc() > 2 && argv(1) === 'add') {
        -				$mode = 'add';
        -				$item_id = intval(argv(2));
        -			}
        -			if (argc() > 2 && argv(1) === 'drop') {
        -				$mode = 'drop';
        -				$event_id = argv(2);
        -			}
        -			if (argc() <= 2 && argv(1) === 'export') {
        -				$export = true;
        -			}
        -			if (argc() > 2 && intval(argv(1)) && intval(argv(2))) {
        -				$mode = 'view';
        -			}
        -			if(argc() <= 2) {
        -				$mode = 'view';
        -				$event_id = argv(1);
        -			}
        -		}
        -	
        -		if ($mode === 'add') {
        -			event_addtocal($item_id,local_channel());
        -			killme();
        -		}
        -	
        -		if ($mode == 'view') {
        -	
        -			/* edit/create form */
        -			if ($event_id) {
        -				$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
        -					dbesc($event_id),
        -					intval(local_channel())
        -				);
        -				if ($r) {
        -					$orig_event = $r[0];
        -				}
        -			}
        -	
        -			$channel = App::get_channel();
        -	
        -			if (argv(1) === 'json'){
        -				if (x($_GET,'start')) {
        -					$start = $_GET['start'];
        -				}
        -				if (x($_GET,'end'))	{
        -					$finish = $_GET['end'];
        -				}
        -			}
        -	
        -			$start  = datetime_convert('UTC','UTC',$start);
        -			$finish = datetime_convert('UTC','UTC',$finish);
        -	
        -			$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
        -			$adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
        -	
        -			if (x($_GET,'id')){
        -			  	$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
        +        linkify_tags($location, local_channel());
        +
        +        // Don't allow the event to finish before it begins.
        +        // It won't hurt anything, but somebody will file a bug report
        +        // and we'll waste a bunch of time responding to it. Time that
        +        // could've been spent doing something else.
        +
        +        if (strcmp($finish, $start) < 0 && (!$nofinish)) {
        +            notice(t('Event can not end before it has started.') . EOL);
        +            if (intval($_REQUEST['preview'])) {
        +                echo(t('Unable to generate preview.'));
        +            }
        +            killme();
        +        }
        +
        +        if ((!$summary) || (!$start)) {
        +            notice(t('Event title and start time are required.') . EOL);
        +            if (intval($_REQUEST['preview'])) {
        +                echo(t('Unable to generate preview.'));
        +            }
        +            killme();
        +        }
        +
        +        $channel = App::get_channel();
        +        $acl = new AccessControl(false);
        +
        +        if ($event_id) {
        +            $x = q("select * from event where id = %d and uid = %d limit 1",
        +                intval($event_id),
        +                intval(local_channel())
        +            );
        +            if (!$x) {
        +                notice(t('Event not found.') . EOL);
        +                if (intval($_REQUEST['preview'])) {
        +                    echo(t('Unable to generate preview.'));
        +                    killme();
        +                }
        +                return;
        +            }
        +
        +            $acl->set($x[0]);
        +
        +            $created = $x[0]['created'];
        +            $edited = datetime_convert();
        +        } else {
        +            $created = $edited = datetime_convert();
        +            $acl->set_from_array($_POST);
        +        }
        +
        +        $post_tags = [];
        +        $ac = $acl->get();
        +
        +        $str_contact_allow = $ac['allow_cid'];
        +        $str_group_allow = $ac['allow_gid'];
        +        $str_contact_deny = $ac['deny_cid'];
        +        $str_group_deny = $ac['deny_gid'];
        +
        +        $private = $acl->is_private();
        +
        +        $results = linkify_tags($desc, local_channel());
        +
        +        if ($results) {
        +            // Set permissions based on tag replacements
        +
        +            set_linkified_perms($results, $str_contact_allow, $str_group_allow, local_channel(), false, $private);
        +
        +            foreach ($results as $result) {
        +                $success = $result['success'];
        +                if ($success['replaced']) {
        +                    $post_tags[] = [
        +                        'uid' => local_channel(),
        +                        'ttype' => $success['termtype'],
        +                        'otype' => TERM_OBJ_POST,
        +                        'term' => $success['term'],
        +                        'url' => $success['url']
        +                    ];
        +                }
        +            }
        +        }
        +
        +
        +        if (strlen($categories)) {
        +            $cats = explode(',', $categories);
        +            foreach ($cats as $cat) {
        +                $post_tags[] = array(
        +                    'uid' => local_channel(),
        +                    'ttype' => TERM_CATEGORY,
        +                    'otype' => TERM_OBJ_POST,
        +                    'term' => trim($cat),
        +                    'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
        +                );
        +            }
        +        }
        +
        +        $datarray = [
        +            'dtstart' => $start,
        +            'dtend' => $finish,
        +            'summary' => $summary,
        +            'description' => $desc,
        +            'location' => $location,
        +            'etype' => $type,
        +            'adjust' => $adjust,
        +            'nofinish' => $nofinish,
        +            'uid' => local_channel(),
        +            'account' => get_account_id(),
        +            'event_xchan' => $channel['channel_hash'],
        +            'allow_cid' => $str_contact_allow,
        +            'allow_gid' => $str_group_allow,
        +            'deny_cid' => $str_contact_deny,
        +            'deny_gid' => $str_group_deny,
        +            'private' => intval($private),
        +            'id' => $event_id,
        +            'created' => $created,
        +            'edited' => $edited
        +        ];
        +
        +        if (intval($_REQUEST['preview'])) {
        +            $html = format_event_html($datarray);
        +            echo $html;
        +            killme();
        +        }
        +
        +        $event = event_store_event($datarray);
        +
        +        if ($post_tags) {
        +            $datarray['term'] = $post_tags;
        +        }
        +
        +        $item_id = event_store_item($datarray, $event);
        +
        +        if ($item_id) {
        +            $r = q("select * from item where id = %d",
        +                intval($item_id)
        +            );
        +            if ($r) {
        +                xchan_query($r);
        +                $sync_item = fetch_post_tags($r);
        +                $z = q("select * from event where event_hash = '%s' and uid = %d limit 1",
        +                    dbesc($r[0]['resource_id']),
        +                    intval($channel['channel_id'])
        +                );
        +                if ($z) {
        +                    Libsync::build_sync_packet($channel['channel_id'], ['event_item' => [encode_item($sync_item[0], true)], 'event' => $z]);
        +                }
        +            }
        +        }
        +
        +        Run::Summon(['Notifier', 'event', $item_id]);
        +        killme();
        +
        +    }
        +
        +
        +    public function get()
        +    {
        +
        +        if (argc() > 2 && argv(1) == 'ical') {
        +            $event_id = argv(2);
        +
        +            $sql_extra = permissions_sql(local_channel());
        +
        +            $r = q("select * from event where event_hash = '%s' $sql_extra limit 1",
        +                dbesc($event_id)
        +            );
        +            if ($r) {
        +                header('Content-type: text/calendar');
        +                header('Content-Disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"');
        +                echo ical_wrapper($r);
        +                killme();
        +            } else {
        +                notice(t('Event not found.') . EOL);
        +                return;
        +            }
        +        }
        +
        +        if (!local_channel()) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
        +
        +        if ((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
        +            $r = q("update event set dismissed = 1 where id = %d and uid = %d",
        +                intval(argv(2)),
        +                intval(local_channel())
        +            );
        +        }
        +
        +        if ((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) {
        +            $r = q("update event set dismissed = 0 where id = %d and uid = %d",
        +                intval(argv(2)),
        +                intval(local_channel())
        +            );
        +        }
        +
        +        $channel = App::get_channel();
        +
        +        $mode = 'view';
        +        $export = false;
        +
        +        $ignored = ((x($_REQUEST, 'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : '');
        +
        +        if (argc() > 1) {
        +            if (argc() > 2 && argv(1) === 'add') {
        +                $mode = 'add';
        +                $item_id = intval(argv(2));
        +            }
        +            if (argc() > 2 && argv(1) === 'drop') {
        +                $mode = 'drop';
        +                $event_id = argv(2);
        +            }
        +            if (argc() <= 2 && argv(1) === 'export') {
        +                $export = true;
        +            }
        +            if (argc() > 2 && intval(argv(1)) && intval(argv(2))) {
        +                $mode = 'view';
        +            }
        +            if (argc() <= 2) {
        +                $mode = 'view';
        +                $event_id = argv(1);
        +            }
        +        }
        +
        +        if ($mode === 'add') {
        +            event_addtocal($item_id, local_channel());
        +            killme();
        +        }
        +
        +        if ($mode == 'view') {
        +
        +            /* edit/create form */
        +            if ($event_id) {
        +                $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
        +                    dbesc($event_id),
        +                    intval(local_channel())
        +                );
        +                if ($r) {
        +                    $orig_event = $r[0];
        +                }
        +            }
        +
        +            $channel = App::get_channel();
        +
        +            if (argv(1) === 'json') {
        +                if (x($_GET, 'start')) {
        +                    $start = $_GET['start'];
        +                }
        +                if (x($_GET, 'end')) {
        +                    $finish = $_GET['end'];
        +                }
        +            }
        +
        +            $start = datetime_convert('UTC', 'UTC', $start);
        +            $finish = datetime_convert('UTC', 'UTC', $finish);
        +
        +            $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
        +            $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish);
        +
        +            if (x($_GET, 'id')) {
        +                $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
         	                                from event left join item on item.resource_id = event.event_hash
         					where item.resource_type = 'event' and event.uid = %d and event.id = %d limit 1",
        -					intval(local_channel()),
        -					intval($_GET['id'])
        -				);
        -			}
        -			elseif ($export) {
        -				$r = q("SELECT * from event where uid = %d",
        -					intval(local_channel())
        -				);
        -			}
        -			else {
        -				// fixed an issue with "nofinish" events not showing up in the calendar.
        -				// There's still an issue if the finish date crosses the end of month.
        -				// Noting this for now - it will need to be fixed here and in Friendica.
        -				// Ultimately the finish date shouldn't be involved in the query. 
        +                    intval(local_channel()),
        +                    intval($_GET['id'])
        +                );
        +            } elseif ($export) {
        +                $r = q("SELECT * from event where uid = %d",
        +                    intval(local_channel())
        +                );
        +            } else {
        +                // fixed an issue with "nofinish" events not showing up in the calendar.
        +                // There's still an issue if the finish date crosses the end of month.
        +                // Noting this for now - it will need to be fixed here and in Friendica.
        +                // Ultimately the finish date shouldn't be involved in the query.
         
        -				$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
        +                $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
         					from event left join item on event.event_hash = item.resource_id 
         					where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored 
         					AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ) 
         					OR  (  event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )) ",
        -					intval(local_channel()),
        -					dbesc($start),
        -					dbesc($finish),
        -					dbesc($adjust_start),
        -					dbesc($adjust_finish)
        -				);
        +                    intval(local_channel()),
        +                    dbesc($start),
        +                    dbesc($finish),
        +                    dbesc($adjust_start),
        +                    dbesc($adjust_finish)
        +                );
         
        -			}
        -		
        -			if($r && ! $export) {
        -				xchan_query($r);
        -				$r = fetch_post_tags($r,true);
        +            }
         
        -				$r = sort_by_date($r);
        -			}
        -	
        -			$events = [];
        -		
        -			if ($r) {
        -	
        -				foreach ($r as $rr) {					
        -					$start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c'));
        -					if ($rr['nofinish']) {
        -						$end = null;
        -					}
        -					else {
        -						$end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c'));
        +            if ($r && !$export) {
        +                xchan_query($r);
        +                $r = fetch_post_tags($r, true);
         
        -						// give a fake end to birthdays so they get crammed into a 
        -						// single day on the calendar
        +                $r = sort_by_date($r);
        +            }
         
        -						if ($rr['etype'] === 'birthday')
        -							$end = null;
        -					}
        +            $events = [];
         
        -					$catsenabled = Apps::system_app_installed($x['profile_uid'], 'Categories');
        -					$categories = '';
        -					if ($catsenabled){
        -						if ($rr['term']) {
        -							$categories = array_elm_to_str(get_terms_oftype($rr['term'], TERM_CATEGORY), 'term');
        -						}
        -					}
        +            if ($r) {
         
        -					$allDay = false;
        +                foreach ($r as $rr) {
        +                    $start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
        +                    if ($rr['nofinish']) {
        +                        $end = null;
        +                    } else {
        +                        $end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
         
        -					// allDay event rules
        -					if (!strpos($start, 'T') && !strpos($end, 'T'))
        -						$allDay = true;
        -					if (strpos($start, 'T00:00:00') && strpos($end, 'T00:00:00'))
        -						$allDay = true;
        -	
        -					$edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root().'/events/'.$rr['event_hash'].'?expandform=1',t('Edit event'),'','') : false);
        -	
        -					$drop = [ z_root() . '/events/drop/' . $rr['event_hash'], t('Delete event'), '', '' ];
        -	
        -					$events[] = [
        -						'calendar_id' => 'calendar',
        -						'rw'          => true,
        -						'id'          => $rr['id'],
        -						'uri'         => $rr['event_hash'],
        -						'start'       => $start,
        -						'end'         => $end,
        -						'drop'        => $drop,
        -						'allDay'      => $allDay,
        -						'title'       => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
        -						'editable'    => $edit ? true : false,
        -						'item'        => $rr,
        -						'plink'       => [ $rr['plink'], t('Link to source') ],
        -						'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8',false),
        -						'location'    => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8',false),
        -						'allow_cid'   => expand_acl($rr['allow_cid']),
        -						'allow_gid'   => expand_acl($rr['allow_gid']),
        -						'deny_cid'    => expand_acl($rr['deny_cid']),
        -						'deny_gid'    => expand_acl($rr['deny_gid']),
        -						'categories'  => $categories
        -					];
        -				}
        -			}
        +                        // give a fake end to birthdays so they get crammed into a
        +                        // single day on the calendar
         
        -			if ($export) {
        -				header('Content-type: text/calendar');
        -				header('Content-Disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' );
        -				echo ical_wrapper($r);
        -				killme();
        -			}
        -	
        -			if (App::$argv[1] === 'json'){
        -				json_return_and_die($events);
        -			}
        -		}
        +                        if ($rr['etype'] === 'birthday')
        +                            $end = null;
        +                    }
        +
        +                    $catsenabled = Apps::system_app_installed($x['profile_uid'], 'Categories');
        +                    $categories = '';
        +                    if ($catsenabled) {
        +                        if ($rr['term']) {
        +                            $categories = array_elm_to_str(get_terms_oftype($rr['term'], TERM_CATEGORY), 'term');
        +                        }
        +                    }
        +
        +                    $allDay = false;
        +
        +                    // allDay event rules
        +                    if (!strpos($start, 'T') && !strpos($end, 'T'))
        +                        $allDay = true;
        +                    if (strpos($start, 'T00:00:00') && strpos($end, 'T00:00:00'))
        +                        $allDay = true;
        +
        +                    $edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root() . '/events/' . $rr['event_hash'] . '?expandform=1', t('Edit event'), '', '') : false);
        +
        +                    $drop = [z_root() . '/events/drop/' . $rr['event_hash'], t('Delete event'), '', ''];
        +
        +                    $events[] = [
        +                        'calendar_id' => 'calendar',
        +                        'rw' => true,
        +                        'id' => $rr['id'],
        +                        'uri' => $rr['event_hash'],
        +                        'start' => $start,
        +                        'end' => $end,
        +                        'drop' => $drop,
        +                        'allDay' => $allDay,
        +                        'title' => html_entity_decode($rr['summary'], ENT_COMPAT, 'UTF-8'),
        +                        'editable' => $edit ? true : false,
        +                        'item' => $rr,
        +                        'plink' => [$rr['plink'], t('Link to source')],
        +                        'description' => htmlentities($rr['description'], ENT_COMPAT, 'UTF-8', false),
        +                        'location' => htmlentities($rr['location'], ENT_COMPAT, 'UTF-8', false),
        +                        'allow_cid' => expand_acl($rr['allow_cid']),
        +                        'allow_gid' => expand_acl($rr['allow_gid']),
        +                        'deny_cid' => expand_acl($rr['deny_cid']),
        +                        'deny_gid' => expand_acl($rr['deny_gid']),
        +                        'categories' => $categories
        +                    ];
        +                }
        +            }
        +
        +            if ($export) {
        +                header('Content-type: text/calendar');
        +                header('Content-Disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"');
        +                echo ical_wrapper($r);
        +                killme();
        +            }
        +
        +            if (App::$argv[1] === 'json') {
        +                json_return_and_die($events);
        +            }
        +        }
        +
        +
        +        if ($mode === 'drop' && $event_id) {
        +            $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
        +                dbesc($event_id),
        +                intval(local_channel())
        +            );
        +
        +            $sync_event = $r[0];
        +
        +            if ($r) {
        +                $r = q("delete from event where event_hash = '%s' and uid = %d",
        +                    dbesc($event_id),
        +                    intval(local_channel())
        +                );
        +                if ($r) {
        +                    $r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
        +                        dbesc($event_id),
        +                        intval(local_channel())
        +                    );
        +                    $sync_event['event_deleted'] = 1;
        +                    Libsync::build_sync_packet(0, ['event' => [$sync_event]]);
        +                    killme();
        +                }
        +                notice(t('Failed to remove event') . EOL);
        +                killme();
        +            }
        +        }
        +
        +    }
         
        -	
        -		if ($mode === 'drop' && $event_id) {
        -			$r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1",
        -				dbesc($event_id),
        -				intval(local_channel())
        -			);
        -	
        -			$sync_event = $r[0];
        -	
        -			if ($r) {
        -				$r = q("delete from event where event_hash = '%s' and uid = %d",
        -					dbesc($event_id),
        -					intval(local_channel())
        -				);
        -				if ($r) {
        -					$r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d",
        -						dbesc($event_id),
        -						intval(local_channel())
        -					);
        -					$sync_event['event_deleted'] = 1;
        -					Libsync::build_sync_packet(0, [ 'event' => [ $sync_event ] ]);
        -					killme();
        -				}
        -				notice( t('Failed to remove event' ) . EOL);
        -				killme();
        -			}
        -		}
        -	
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Card_edit.php b/Zotlabs/Module/Card_edit.php
        index fff0cfac9..bd6246591 100644
        --- a/Zotlabs/Module/Card_edit.php
        +++ b/Zotlabs/Module/Card_edit.php
        @@ -10,135 +10,134 @@ require_once('include/channel.php');
         require_once('include/acl_selectors.php');
         require_once('include/conversation.php');
         
        -class Card_edit extends Controller {
        +class Card_edit extends Controller
        +{
         
         
        -	function get() {
        +    public function get()
        +    {
         
        -		// Figure out which post we're editing
        -		$post_id = ((argc() > 1) ? intval(argv(1)) : 0);
        +        // Figure out which post we're editing
        +        $post_id = ((argc() > 1) ? intval(argv(1)) : 0);
         
        -		if(! $post_id) {
        -			notice( t('Item not found') . EOL);
        -			return;
        -		}
        +        if (!$post_id) {
        +            notice(t('Item not found') . EOL);
        +            return;
        +        }
         
        -		$itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1",
        -			intval($post_id),
        -			intval(ITEM_TYPE_CARD)
        -		);
        -		if($itm) {
        -			$item_id = q("select * from iconfig where cat = 'system' and k = 'CARD' and iid = %d limit 1",
        -				intval($itm[0]['id'])
        -			);
        -			if($item_id)
        -				$card_title = $item_id[0]['v'];
        -		}
        -		else {
        -			notice( t('Item not found') . EOL);
        -			return;
        -		}
        +        $itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1",
        +            intval($post_id),
        +            intval(ITEM_TYPE_CARD)
        +        );
        +        if ($itm) {
        +            $item_id = q("select * from iconfig where cat = 'system' and k = 'CARD' and iid = %d limit 1",
        +                intval($itm[0]['id'])
        +            );
        +            if ($item_id)
        +                $card_title = $item_id[0]['v'];
        +        } else {
        +            notice(t('Item not found') . EOL);
        +            return;
        +        }
         
        -		$owner = $itm[0]['uid'];
        -		$uid = local_channel();
        +        $owner = $itm[0]['uid'];
        +        $uid = local_channel();
         
        -		$observer = App::get_observer();
        +        $observer = App::get_observer();
         
        -		$channel = channelx_by_n($owner);
        -		if(! $channel) {
        -			notice( t('Channel not found.') . EOL);
        -			return;
        -		}
        +        $channel = channelx_by_n($owner);
        +        if (!$channel) {
        +            notice(t('Channel not found.') . EOL);
        +            return;
        +        }
         
        -		$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
        +        $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
         
        -		if(! perm_is_allowed($owner,$ob_hash,'write_pages')) {
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        +        if (!perm_is_allowed($owner, $ob_hash, 'write_pages')) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
         
        -		$is_owner = (($uid && $uid == $owner) ? true : false);
        +        $is_owner = (($uid && $uid == $owner) ? true : false);
         
        -		$o = '';
        +        $o = '';
         
         
        +        $category = '';
        +        $catsenabled = ((Apps::system_app_installed($owner, 'Categories')) ? 'categories' : '');
         
        -		$category = '';
        -		$catsenabled = ((Apps::system_app_installed($owner,'Categories')) ? 'categories' : '');
        +        if ($catsenabled) {
        +            $itm = fetch_post_tags($itm);
         
        -		if ($catsenabled){
        -		        $itm = fetch_post_tags($itm);
        -	
        -	                $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
        -	
        -		        foreach ($cats as $cat) {
        -		                if (strlen($category))
        -		                        $category .= ', ';
        -		                $category .= $cat['term'];
        -		        }
        -		}
        +            $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
         
        -		if($itm[0]['attach']) {
        -			$j = json_decode($itm[0]['attach'],true);
        -			if($j) {
        -				foreach($j as $jj) {
        -					$itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n";
        -				}
        -			}
        -		}
        +            foreach ($cats as $cat) {
        +                if (strlen($category))
        +                    $category .= ', ';
        +                $category .= $cat['term'];
        +            }
        +        }
        +
        +        if ($itm[0]['attach']) {
        +            $j = json_decode($itm[0]['attach'], true);
        +            if ($j) {
        +                foreach ($j as $jj) {
        +                    $itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n";
        +                }
        +            }
        +        }
         
         
        -		$mimetype = $itm[0]['mimetype'];
        +        $mimetype = $itm[0]['mimetype'];
         
        -		$content = $itm[0]['body'];
        +        $content = $itm[0]['body'];
         
         
        +        $rp = 'cards/' . $channel['channel_address'];
         
        -		$rp = 'cards/' . $channel['channel_address'];
        +        $x = array(
        +            'nickname' => $channel['channel_address'],
        +            'bbco_autocomplete' => 'bbcode',
        +            'return_path' => $rp,
        +            'webpage' => ITEM_TYPE_CARD,
        +            'button' => t('Edit'),
        +            'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'),
        +            'weblink' => t('Insert web link'),
        +            'hide_voting' => false,
        +            'hide_future' => false,
        +            'hide_location' => false,
        +            'hide_expire' => false,
        +            'showacl' => true,
        +            'acl' => populate_acl($itm[0], false, PermissionDescription::fromGlobalPermission('view_pages')),
        +            'permissions' => $itm[0],
        +            'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'),
        +            'ptyp' => $itm[0]['type'],
        +            'mimeselect' => false,
        +            'mimetype' => $itm[0]['mimetype'],
        +            'body' => undo_post_tagging($content),
        +            'post_id' => $post_id,
        +            'visitor' => true,
        +            'title' => htmlspecialchars($itm[0]['title'], ENT_COMPAT, 'UTF-8'),
        +            'placeholdertitle' => t('Title (optional)'),
        +            'pagetitle' => $card_title,
        +            'profile_uid' => (intval($channel['channel_id'])),
        +            'catsenabled' => $catsenabled,
        +            'category' => $category,
        +            'bbcode' => (($mimetype == 'text/bbcode') ? true : false)
        +        );
         
        -		$x = array(
        -			'nickname' => $channel['channel_address'],
        -			'bbco_autocomplete'=> 'bbcode',
        -			'return_path' => $rp,
        -			'webpage' => ITEM_TYPE_CARD,
        -			'button' => t('Edit'),
        -			'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'),
        -			'weblink' => t('Insert web link'),
        -			'hide_voting' => false,
        -			'hide_future' => false,
        -			'hide_location' => false,
        -			'hide_expire' => false,
        -			'showacl' => true,
        -			'acl' => populate_acl($itm[0],false, PermissionDescription::fromGlobalPermission('view_pages')),
        -			'permissions' => $itm[0],
        -			'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'),
        -			'ptyp' => $itm[0]['type'],
        -			'mimeselect' => false,
        -			'mimetype' => $itm[0]['mimetype'],
        -			'body' => undo_post_tagging($content),
        -			'post_id' => $post_id,
        -			'visitor' => true,
        -			'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
        -			'placeholdertitle' => t('Title (optional)'),
        -			'pagetitle' => $card_title,
        -			'profile_uid' => (intval($channel['channel_id'])),
        -			'catsenabled' => $catsenabled,
        -			'category' => $category,
        -			'bbcode' => (($mimetype  == 'text/bbcode') ? true : false)
        -		);
        +        $editor = status_editor($x);
         
        -		$editor = status_editor($x);
        +        $o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
        +            '$title' => t('Edit Card'),
        +            '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
        +            '$id' => $itm[0]['id'],
        +            '$cancel' => t('Cancel'),
        +            '$editor' => $editor
        +        ));
         
        -		$o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
        -			'$title' => t('Edit Card'),
        -			'$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
        -			'$id' => $itm[0]['id'],
        -			'$cancel' => t('Cancel'),
        -			'$editor' => $editor
        -		));
        +        return $o;
         
        -		return $o;
        -
        -	}
        +    }
         
         }
        diff --git a/Zotlabs/Module/Cards.php b/Zotlabs/Module/Cards.php
        index 211e036c8..16df9a1e4 100644
        --- a/Zotlabs/Module/Cards.php
        +++ b/Zotlabs/Module/Cards.php
        @@ -11,203 +11,203 @@ require_once('include/channel.php');
         require_once('include/conversation.php');
         require_once('include/acl_selectors.php');
         
        -class Cards extends Controller {
        +class Cards extends Controller
        +{
         
        -	function init() {
        +    public function init()
        +    {
         
        -		if(argc() > 1)
        -			$which = argv(1);
        -		else
        -			return;
        +        if (argc() > 1)
        +            $which = argv(1);
        +        else
        +            return;
         
        -		Libprofile::load($which);
        +        Libprofile::load($which);
         
        -	}
        +    }
         
        -	/**
        -	 * {@inheritDoc}
        -	 * @see \Zotlabs\Web\Controller::get()
        -	 */
        -	function get() {
        +    /**
        +     * {@inheritDoc}
        +     * @see \Zotlabs\Web\Controller::get()
        +     */
        +    public function get()
        +    {
         
        -		if(observer_prohibited(true)) {
        -			return login();
        -		}
        +        if (observer_prohibited(true)) {
        +            return login();
        +        }
         
        -		if(! App::$profile) {
        -			notice( t('Requested profile is not available.') . EOL );
        -			App::$error = 404;
        -			return;
        -		}
        +        if (!App::$profile) {
        +            notice(t('Requested profile is not available.') . EOL);
        +            App::$error = 404;
        +            return;
        +        }
         
        -		if(! Apps::system_app_installed(App::$profile_uid, 'Cards')) {
        -			//Do not display any associated widgets at this point
        -			App::$pdl = '';
        +        if (!Apps::system_app_installed(App::$profile_uid, 'Cards')) {
        +            //Do not display any associated widgets at this point
        +            App::$pdl = '';
         
        -			$o = 'Cards App (Not Installed):
        '; - $o .= t('Create personal planning cards'); - return $o; - } + $o = 'Cards App (Not Installed):
        '; + $o .= t('Create personal planning cards'); + return $o; + } - nav_set_selected('Cards'); + nav_set_selected('Cards'); - head_add_link([ - 'rel' => 'alternate', - 'type' => 'application/json+oembed', - 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), - 'title' => 'oembed' - ]); + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), + 'title' => 'oembed' + ]); - $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : ''); + $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : ''); - if($category) { - $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $category, TERM_CATEGORY)); - } + if ($category) { + $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $category, TERM_CATEGORY)); + } - $which = argv(1); + $which = argv(1); - $selected_card = ((argc() > 2) ? argv(2) : ''); + $selected_card = ((argc() > 2) ? argv(2) : ''); - $_SESSION['return_url'] = App::$query_string; + $_SESSION['return_url'] = App::$query_string; - $uid = local_channel(); - $owner = App::$profile_uid; - $observer = App::get_observer(); + $uid = local_channel(); + $owner = App::$profile_uid; + $observer = App::get_observer(); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - if(! perm_is_allowed($owner, $ob_hash, 'view_pages')) { - notice( t('Permission denied.') . EOL); - return; - } + if (!perm_is_allowed($owner, $ob_hash, 'view_pages')) { + notice(t('Permission denied.') . EOL); + return; + } - $is_owner = ($uid && $uid == $owner); + $is_owner = ($uid && $uid == $owner); - $channel = channelx_by_n($owner); + $channel = channelx_by_n($owner); - if($channel) { - $channel_acl = [ - 'allow_cid' => $channel['channel_allow_cid'], - 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ]; - } - else { - $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; - } + if ($channel) { + $channel_acl = [ + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ]; + } else { + $channel_acl = ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']; + } + if (perm_is_allowed($owner, $ob_hash, 'write_pages')) { - if(perm_is_allowed($owner, $ob_hash, 'write_pages')) { + $x = [ + 'webpage' => ITEM_TYPE_CARD, + 'is_owner' => true, + 'content_label' => t('Add Card'), + 'button' => t('Create'), + 'nickname' => $channel['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] + || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => (($is_owner) ? populate_acl($channel_acl, false, + PermissionDescription::fromGlobalPermission('view_pages')) : ''), + 'permissions' => $channel_acl, + 'showacl' => (($is_owner) ? true : false), + 'visitor' => true, + 'hide_location' => false, + 'hide_voting' => false, + 'profile_uid' => intval($owner), + 'mimetype' => 'text/bbcode', + 'mimeselect' => false, + 'layoutselect' => false, + 'expanded' => false, + 'novoting' => false, + 'catsenabled' => Apps::system_app_installed($owner, 'Categories'), + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true + ]; - $x = [ - 'webpage' => ITEM_TYPE_CARD, - 'is_owner' => true, - 'content_label' => t('Add Card'), - 'button' => t('Create'), - 'nickname' => $channel['channel_address'], - 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] - || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => (($is_owner) ? populate_acl($channel_acl, false, - PermissionDescription::fromGlobalPermission('view_pages')) : ''), - 'permissions' => $channel_acl, - 'showacl' => (($is_owner) ? true : false), - 'visitor' => true, - 'hide_location' => false, - 'hide_voting' => false, - 'profile_uid' => intval($owner), - 'mimetype' => 'text/bbcode', - 'mimeselect' => false, - 'layoutselect' => false, - 'expanded' => false, - 'novoting' => false, - 'catsenabled' => Apps::system_app_installed($owner, 'Categories'), - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true - ]; + if ($_REQUEST['title']) + $x['title'] = $_REQUEST['title']; + if ($_REQUEST['body']) + $x['body'] = $_REQUEST['body']; - if($_REQUEST['title']) - $x['title'] = $_REQUEST['title']; - if($_REQUEST['body']) - $x['body'] = $_REQUEST['body']; - - $editor = status_editor($x); - } - else { - $editor = ''; - } + $editor = status_editor($x); + } else { + $editor = ''; + } - $itemspage = get_pconfig(local_channel(),'system','itemspage'); - App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + $itemspage = get_pconfig(local_channel(), 'system', 'itemspage'); + App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - $sql_extra = item_permissions_sql($owner); - $sql_item = ''; + $sql_extra = item_permissions_sql($owner); + $sql_item = ''; - if($selected_card) { - $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1", - dbesc($selected_card) - ); - if($r) { - $sql_item = "and item.id = " . intval($r[0]['iid']) . " "; - } - } + if ($selected_card) { + $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1", + dbesc($selected_card) + ); + if ($r) { + $sql_item = "and item.id = " . intval($r[0]['iid']) . " "; + } + } - $r = q("select * from item + $r = q("select * from item where uid = %d and item_type = %d $sql_extra $sql_item order by item.created desc $pager_sql", - intval($owner), - intval(ITEM_TYPE_CARD) - ); + intval($owner), + intval(ITEM_TYPE_CARD) + ); - $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0 + $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 and item.item_blocked = 0 "; - $items_result = []; - if($r) { + $items_result = []; + if ($r) { - $pager_total = count($r); + $pager_total = count($r); - $parents_str = ids_to_querystr($r, 'id'); + $parents_str = ids_to_querystr($r, 'id'); - $items = q("SELECT item.*, item.id AS item_id + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.uid = %d $item_normal AND item.parent IN ( %s ) $sql_extra $sql_extra2 ", - intval(App::$profile['profile_uid']), - dbesc($parents_str) - ); - if($items) { - xchan_query($items); - $items = fetch_post_tags($items, true); - $items_result = conv_sort($items, 'updated'); - } - } + intval(App::$profile['profile_uid']), + dbesc($parents_str) + ); + if ($items) { + xchan_query($items); + $items = fetch_post_tags($items, true); + $items_result = conv_sort($items, 'updated'); + } + } - $mode = 'cards'; + $mode = 'cards'; - if(get_pconfig(local_channel(),'system','articles_list_mode') && (! $selected_card)) - $page_mode = 'pager_list'; - else - $page_mode = 'traditional'; + if (get_pconfig(local_channel(), 'system', 'articles_list_mode') && (!$selected_card)) + $page_mode = 'pager_list'; + else + $page_mode = 'traditional'; - $content = conversation($items_result, $mode, false, $page_mode); + $content = conversation($items_result, $mode, false, $page_mode); - $o = replace_macros(get_markup_template('cards.tpl'), [ - '$title' => t('Cards'), - '$editor' => $editor, - '$content' => $content, - '$pager' => alt_pager($pager_total) - ]); + $o = replace_macros(get_markup_template('cards.tpl'), [ + '$title' => t('Cards'), + '$editor' => $editor, + '$content' => $content, + '$pager' => alt_pager($pager_total) + ]); - return $o; - } + return $o; + } } diff --git a/Zotlabs/Module/Categories.php b/Zotlabs/Module/Categories.php index 4d0af6a6a..284352b9c 100644 --- a/Zotlabs/Module/Categories.php +++ b/Zotlabs/Module/Categories.php @@ -9,35 +9,38 @@ use Zotlabs\Lib\Libprofile; use Zotlabs\Web\Controller; use Zotlabs\Render\Comanche; -class Categories extends Controller { +class Categories extends Controller +{ - function init() { + public function init() + { - if(local_channel()) { - $channel = App::get_channel(); - if($channel && $channel['channel_address']) { - $which = $channel['channel_address']; - } - Libprofile::load($which,0); - } + if (local_channel()) { + $channel = App::get_channel(); + if ($channel && $channel['channel_address']) { + $which = $channel['channel_address']; + } + Libprofile::load($which, 0); + } - } + } - function get() { + public function get() + { $desc = t('This app allows you to add categories to posts and events.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Categories'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Categories'))) { return $text; } - $c = new Comanche; - return $c->widget('catcloud',EMPTY_STR); + $c = new Comanche(); + return $c->widget('catcloud', EMPTY_STR); - } + } } diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php index 8bd6a5b7e..206f6852f 100644 --- a/Zotlabs/Module/Cdav.php +++ b/Zotlabs/Module/Cdav.php @@ -33,1427 +33,1420 @@ require_once('include/event.php'); require_once('include/auth.php'); require_once('include/security.php'); -class Cdav extends Controller { - - function init() { - - $record = null; - $channel_login = false; - - if((argv(1) !== 'calendar') && (argv(1) !== 'addressbook')) { - - foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) { - - /* Basic authentication */ - - if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,5) === 'Basic') { - $userpass = @base64_decode(substr(trim($_SERVER[$head]),6)) ; - if(strlen($userpass)) { - list($name, $password) = explode(':', $userpass); - $_SERVER['PHP_AUTH_USER'] = $name; - $_SERVER['PHP_AUTH_PW'] = $password; - } - break; - } - - /* Signature authentication */ - - if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') { - if($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } - - $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); - if($sigblock) { - $keyId = str_replace('acct:','',$sigblock['keyId']); - if($keyId) { - $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", - dbesc($keyId) - ); - if($r) { - $c = channelx_by_hash($r[0]['hubloc_hash']); - if($c) { - $a = q("select * from account where account_id = %d limit 1", - intval($c['channel_account_id']) - ); - if($a) { - $record = [ 'channel' => $c, 'account' => $a[0] ]; - $channel_login = $c['channel_id']; - } - } - } - if(! $record) - continue; - - if($record) { - $verified = HTTPSig::verify('',$record['channel']['channel_pubkey']); - if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) { - $record = null; - } - if($record['account']) { - authenticate_success($record['account']); - if($channel_login) { - change_channel($channel_login); - } - } - break; - } - } - } - } - } - - - /** - * This server combines both CardDAV and CalDAV functionality into a single - * server. It is assumed that the server runs at the root of a HTTP domain (be - * that a domainname-based vhost or a specific TCP port. - * - * This example also assumes that you're using SQLite and the database has - * already been setup (along with the database tables). - * - * You may choose to use MySQL instead, just change the PDO connection - * statement. - */ - - /** - * UTC or GMT is easy to work with, and usually recommended for any - * application. - */ - date_default_timezone_set('UTC'); - - /** - * Make sure this setting is turned on and reflect the root url for your WebDAV - * server. - * - * This can be for example the root / or a complete path to your server script. - */ - - $baseUri = '/cdav/'; - - /** - * Database - * - */ - - $pdo = DBA::$dba->db; - - // Autoloader - require_once 'vendor/autoload.php'; - - /** - * The backends. Yes we do really need all of them. - * - * This allows any developer to subclass just any of them and hook into their - * own backend systems. - */ - - $auth = new BasicAuth(); - $auth->setRealm(ucfirst(System::get_platform_name()) . ' ' . 'CalDAV/CardDAV'); - - if (local_channel()) { - - logger('loggedin'); - - if ((argv(1) == 'addressbooks') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { - killme(); - } - - $channel = App::get_channel(); - $auth->setCurrentUser($channel['channel_address']); - $auth->channel_id = $channel['channel_id']; - $auth->channel_hash = $channel['channel_hash']; - $auth->channel_account_id = $channel['channel_account_id']; - if ($channel['channel_timezone']) { - $auth->setTimezone($channel['channel_timezone']); - } - $auth->observer = $channel['channel_hash']; - - $principalUri = 'principals/' . $channel['channel_address']; - if (!cdav_principal($principalUri)) { - $this->activate($pdo, $channel); - if (!cdav_principal($principalUri)) { - return; - } - } - - } - - - $principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo); - $carddavBackend = new PDO($pdo); - $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); - - /** - * The directory tree - * - * Basically this is an array which contains the 'top-level' directories in the - * WebDAV server. - */ - - $nodes = [ - // /principals - new Collection($principalBackend), +class Cdav extends Controller +{ + + public function init() + { + + $record = null; + $channel_login = false; + + if ((argv(1) !== 'calendar') && (argv(1) !== 'addressbook')) { + + foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $head) { + + /* Basic authentication */ + + if (array_key_exists($head, $_SERVER) && substr(trim($_SERVER[$head]), 0, 5) === 'Basic') { + $userpass = @base64_decode(substr(trim($_SERVER[$head]), 6)); + if (strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + break; + } + + /* Signature authentication */ + + if (array_key_exists($head, $_SERVER) && substr(trim($_SERVER[$head]), 0, 9) === 'Signature') { + if ($head !== 'HTTP_AUTHORIZATION') { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; + continue; + } + + $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); + if ($sigblock) { + $keyId = str_replace('acct:', '', $sigblock['keyId']); + if ($keyId) { + $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", + dbesc($keyId) + ); + if ($r) { + $c = channelx_by_hash($r[0]['hubloc_hash']); + if ($c) { + $a = q("select * from account where account_id = %d limit 1", + intval($c['channel_account_id']) + ); + if ($a) { + $record = ['channel' => $c, 'account' => $a[0]]; + $channel_login = $c['channel_id']; + } + } + } + if (!$record) + continue; + + if ($record) { + $verified = HTTPSig::verify('', $record['channel']['channel_pubkey']); + if (!($verified && $verified['header_signed'] && $verified['header_valid'])) { + $record = null; + } + if ($record['account']) { + authenticate_success($record['account']); + if ($channel_login) { + change_channel($channel_login); + } + } + break; + } + } + } + } + } + + + /** + * This server combines both CardDAV and CalDAV functionality into a single + * server. It is assumed that the server runs at the root of a HTTP domain (be + * that a domainname-based vhost or a specific TCP port. + * + * This example also assumes that you're using SQLite and the database has + * already been setup (along with the database tables). + * + * You may choose to use MySQL instead, just change the PDO connection + * statement. + */ + + /** + * UTC or GMT is easy to work with, and usually recommended for any + * application. + */ + date_default_timezone_set('UTC'); + + /** + * Make sure this setting is turned on and reflect the root url for your WebDAV + * server. + * + * This can be for example the root / or a complete path to your server script. + */ + + $baseUri = '/cdav/'; + + /** + * Database + * + */ + + $pdo = DBA::$dba->db; + + // Autoloader + require_once 'vendor/autoload.php'; + + /** + * The backends. Yes we do really need all of them. + * + * This allows any developer to subclass just any of them and hook into their + * own backend systems. + */ + + $auth = new BasicAuth(); + $auth->setRealm(ucfirst(System::get_platform_name()) . ' ' . 'CalDAV/CardDAV'); + + if (local_channel()) { + + logger('loggedin'); + + if ((argv(1) == 'addressbooks') && (!Apps::system_app_installed(local_channel(), 'CardDAV'))) { + killme(); + } + + $channel = App::get_channel(); + $auth->setCurrentUser($channel['channel_address']); + $auth->channel_id = $channel['channel_id']; + $auth->channel_hash = $channel['channel_hash']; + $auth->channel_account_id = $channel['channel_account_id']; + if ($channel['channel_timezone']) { + $auth->setTimezone($channel['channel_timezone']); + } + $auth->observer = $channel['channel_hash']; + + $principalUri = 'principals/' . $channel['channel_address']; + if (!cdav_principal($principalUri)) { + $this->activate($pdo, $channel); + if (!cdav_principal($principalUri)) { + return; + } + } + + } + + + $principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo); + $carddavBackend = new PDO($pdo); + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + + /** + * The directory tree + * + * Basically this is an array which contains the 'top-level' directories in the + * WebDAV server. + */ + + $nodes = [ + // /principals + new Collection($principalBackend), - // /calendars - new CalendarRoot($principalBackend, $caldavBackend), + // /calendars + new CalendarRoot($principalBackend, $caldavBackend), - // /addressbook - new AddressBookRoot($principalBackend, $carddavBackend) - ]; + // /addressbook + new AddressBookRoot($principalBackend, $carddavBackend) + ]; - // The object tree needs in turn to be passed to the server class + // The object tree needs in turn to be passed to the server class - $server = new Server($nodes); + $server = new Server($nodes); - if (isset($baseUri)) { - $server->setBaseUri($baseUri); - } + if (isset($baseUri)) { + $server->setBaseUri($baseUri); + } - // Plugins - $server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth)); - //$server->addPlugin(new \Sabre\DAV\Browser\Plugin()); - $server->addPlugin(new \Sabre\DAV\Sync\Plugin()); - $server->addPlugin(new \Sabre\DAV\Sharing\Plugin()); - $server->addPlugin(new \Sabre\DAVACL\Plugin()); + // Plugins + $server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth)); + //$server->addPlugin(new \Sabre\DAV\Browser\Plugin()); + $server->addPlugin(new \Sabre\DAV\Sync\Plugin()); + $server->addPlugin(new \Sabre\DAV\Sharing\Plugin()); + $server->addPlugin(new \Sabre\DAVACL\Plugin()); - // CalDAV plugins - $server->addPlugin(new \Sabre\CalDAV\Plugin()); - $server->addPlugin(new SharingPlugin()); - //$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin()); - $server->addPlugin(new ICSExportPlugin()); + // CalDAV plugins + $server->addPlugin(new \Sabre\CalDAV\Plugin()); + $server->addPlugin(new SharingPlugin()); + //$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin()); + $server->addPlugin(new ICSExportPlugin()); - // CardDAV plugins - $server->addPlugin(new Plugin()); - $server->addPlugin(new VCFExportPlugin()); + // CardDAV plugins + $server->addPlugin(new Plugin()); + $server->addPlugin(new VCFExportPlugin()); - // And off we go! - $server->exec(); + // And off we go! + $server->exec(); - killme(); + killme(); - } + } - } + } - function post() { + public function post() + { - if (! local_channel()) - return; + if (!local_channel()) + return; - if ((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { - return; - } + if ((argv(1) === 'addressbook') && (!Apps::system_app_installed(local_channel(), 'CardDAV'))) { + return; + } - $channel = App::get_channel(); - $principalUri = 'principals/' . $channel['channel_address']; + $channel = App::get_channel(); + $principalUri = 'principals/' . $channel['channel_address']; - if (!cdav_principal($principalUri)) - return; + if (!cdav_principal($principalUri)) + return; - $pdo = DBA::$dba->db; + $pdo = DBA::$dba->db; - require_once 'vendor/autoload.php'; + require_once 'vendor/autoload.php'; - if (argc() == 2 && argv(1) === 'calendar') { + if (argc() == 2 && argv(1) === 'calendar') { - $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); - $calendars = $caldavBackend->getCalendarsForUser($principalUri); + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $calendars = $caldavBackend->getCalendarsForUser($principalUri); - // create new calendar - if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { - do { - $duplicate = false; - $calendarUri = random_string(40); + // create new calendar + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + do { + $duplicate = false; + $calendarUri = random_string(40); - $r = q("SELECT uri FROM calendarinstances WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", - dbesc($principalUri), - dbesc($calendarUri) - ); + $r = q("SELECT uri FROM calendarinstances WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", + dbesc($principalUri), + dbesc($calendarUri) + ); - if ($r) { - $duplicate = true; - } - } while ($duplicate == true); + if ($r) { + $duplicate = true; + } + } while ($duplicate == true); - $properties = [ - '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], - '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'], - '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] - ]; + $properties = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], + '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'], + '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] + ]; - $id = $caldavBackend->createCalendar($principalUri, $calendarUri, $properties); + $id = $caldavBackend->createCalendar($principalUri, $calendarUri, $properties); - // set new calendar to be visible - set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); - } + // set new calendar to be visible + set_pconfig(local_channel(), 'cdav_calendar', $id[0], 1); + } - //create new calendar object via ajax request - if ($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { + //create new calendar object via ajax request + if ($_REQUEST['submit'] === 'create_event' && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { - $id = explode(':', $_REQUEST['target']); + $id = explode(':', $_REQUEST['target']); - if (!cdav_perms($id[0],$calendars,true)) - return; + if (!cdav_perms($id[0], $calendars, true)) + return; - $title = $_REQUEST['title']; - $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); - $dtstart = new DateTime($start); - if ($_REQUEST['dtend']) { - $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); - $dtend = new DateTime($end); - } - $description = $_REQUEST['description']; - $location = $_REQUEST['location']; + $title = $_REQUEST['title']; + $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); + $dtstart = new DateTime($start); + if ($_REQUEST['dtend']) { + $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); + $dtend = new DateTime($end); + } + $description = $_REQUEST['description']; + $location = $_REQUEST['location']; - do { - $duplicate = false; - $objectUri = random_string(40) . '.ics'; + do { + $duplicate = false; + $objectUri = random_string(40) . '.ics'; - $r = q("SELECT uri FROM calendarobjects WHERE calendarid = %s AND uri = '%s' LIMIT 1", - intval($id[0]), - dbesc($objectUri) - ); + $r = q("SELECT uri FROM calendarobjects WHERE calendarid = %s AND uri = '%s' LIMIT 1", + intval($id[0]), + dbesc($objectUri) + ); - if (count($r)) - $duplicate = true; - } while ($duplicate == true); + if (count($r)) + $duplicate = true; + } while ($duplicate == true); - $vcalendar = new VCalendar([ - 'VEVENT' => [ - 'SUMMARY' => $title, - 'DTSTART' => $dtstart - ] - ]); - if($dtend) { - $vcalendar->VEVENT->add('DTEND', $dtend); - $vcalendar->VEVENT->DTEND['TZID'] = App::$timezone; - } - if($description) - $vcalendar->VEVENT->add('DESCRIPTION', $description); - if($location) - $vcalendar->VEVENT->add('LOCATION', $location); + $vcalendar = new VCalendar([ + 'VEVENT' => [ + 'SUMMARY' => $title, + 'DTSTART' => $dtstart + ] + ]); + if ($dtend) { + $vcalendar->VEVENT->add('DTEND', $dtend); + $vcalendar->VEVENT->DTEND['TZID'] = App::$timezone; + } + if ($description) + $vcalendar->VEVENT->add('DESCRIPTION', $description); + if ($location) + $vcalendar->VEVENT->add('LOCATION', $location); - $vcalendar->VEVENT->DTSTART['TZID'] = App::$timezone; + $vcalendar->VEVENT->DTSTART['TZID'] = App::$timezone; - $calendarData = $vcalendar->serialize(); + $calendarData = $vcalendar->serialize(); - $caldavBackend->createCalendarObject($id, $objectUri, $calendarData); + $caldavBackend->createCalendarObject($id, $objectUri, $calendarData); - killme(); - } + killme(); + } - // edit calendar name and color - if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) { + // edit calendar name and color + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && $_REQUEST['id']) { - $id = explode(':', $_REQUEST['id']); + $id = explode(':', $_REQUEST['id']); - if (! cdav_perms($id[0],$calendars)) { - return; - } + if (!cdav_perms($id[0], $calendars)) { + return; + } - $mutations = [ - '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], - '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'] - ]; - - $patch = new PropPatch($mutations); - - $caldavBackend->updateCalendar($id, $patch); - - $patch->commit(); - } - - // edit calendar object via ajax request - if ($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { - - $id = explode(':', $_REQUEST['target']); + $mutations = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'], + '{http://apple.com/ns/ical/}calendar-color' => $_REQUEST['color'] + ]; + + $patch = new PropPatch($mutations); + + $caldavBackend->updateCalendar($id, $patch); + + $patch->commit(); + } - if (!cdav_perms($id[0],$calendars,true)) - return; + // edit calendar object via ajax request + if ($_REQUEST['submit'] === 'update_event' && $_REQUEST['uri'] && $_REQUEST['title'] && $_REQUEST['target'] && $_REQUEST['dtstart']) { - $uri = $_REQUEST['uri']; - $title = $_REQUEST['title']; - $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); - $dtstart = new DateTime($start); - if ($_REQUEST['dtend']) { - $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); - $dtend = new DateTime($end); - } - $description = $_REQUEST['description']; - $location = $_REQUEST['location']; + $id = explode(':', $_REQUEST['target']); - $object = $caldavBackend->getCalendarObject($id, $uri); + if (!cdav_perms($id[0], $calendars, true)) + return; - $vcalendar = Reader::read($object['calendardata']); + $uri = $_REQUEST['uri']; + $title = $_REQUEST['title']; + $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); + $dtstart = new DateTime($start); + if ($_REQUEST['dtend']) { + $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); + $dtend = new DateTime($end); + } + $description = $_REQUEST['description']; + $location = $_REQUEST['location']; - if ($title) { - $vcalendar->VEVENT->SUMMARY = $title; - } - if ($dtstart) { - $vcalendar->VEVENT->DTSTART = $dtstart; - } - if ($dtend) { - $vcalendar->VEVENT->DTEND = $dtend; - } - else { - unset($vcalendar->VEVENT->DTEND); - } - if ($description) { - $vcalendar->VEVENT->DESCRIPTION = $description; - } - if ($location) { - $vcalendar->VEVENT->LOCATION = $location; - } + $object = $caldavBackend->getCalendarObject($id, $uri); - $calendarData = $vcalendar->serialize(); + $vcalendar = Reader::read($object['calendardata']); - $caldavBackend->updateCalendarObject($id, $uri, $calendarData); - killme(); - } + if ($title) { + $vcalendar->VEVENT->SUMMARY = $title; + } + if ($dtstart) { + $vcalendar->VEVENT->DTSTART = $dtstart; + } + if ($dtend) { + $vcalendar->VEVENT->DTEND = $dtend; + } else { + unset($vcalendar->VEVENT->DTEND); + } + if ($description) { + $vcalendar->VEVENT->DESCRIPTION = $description; + } + if ($location) { + $vcalendar->VEVENT->LOCATION = $location; + } - // delete calendar object via ajax request - if ($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + $calendarData = $vcalendar->serialize(); - $id = explode(':', $_REQUEST['target']); + $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + killme(); + } - if (!cdav_perms($id[0],$calendars,true)) { - return; - } + // delete calendar object via ajax request + if ($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { - $uri = $_REQUEST['uri']; + $id = explode(':', $_REQUEST['target']); - $caldavBackend->deleteCalendarObject($id, $uri); - killme(); - } + if (!cdav_perms($id[0], $calendars, true)) { + return; + } - // edit calendar object date/timeme via ajax request (drag and drop) - if ($_REQUEST['update'] && $_REQUEST['id'] && $_REQUEST['uri']) { + $uri = $_REQUEST['uri']; - $id = [$_REQUEST['id'][0], $_REQUEST['id'][1]]; + $caldavBackend->deleteCalendarObject($id, $uri); + killme(); + } - if (! cdav_perms($id[0],$calendars,true)) { - return; - } + // edit calendar object date/timeme via ajax request (drag and drop) + if ($_REQUEST['update'] && $_REQUEST['id'] && $_REQUEST['uri']) { - $uri = $_REQUEST['uri']; - $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); - $dtstart = new DateTime($start); - if($_REQUEST['dtend']) { - $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); - $dtend = new DateTime($end); - } + $id = [$_REQUEST['id'][0], $_REQUEST['id'][1]]; - $object = $caldavBackend->getCalendarObject($id, $uri); + if (!cdav_perms($id[0], $calendars, true)) { + return; + } - $vcalendar = Reader::read($object['calendardata']); + $uri = $_REQUEST['uri']; + $start = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtstart']); + $dtstart = new DateTime($start); + if ($_REQUEST['dtend']) { + $end = datetime_convert(App::$timezone, 'UTC', $_REQUEST['dtend']); + $dtend = new DateTime($end); + } - if ($dtstart) { - $vcalendar->VEVENT->DTSTART = $dtstart; - } - if ($dtend) { - $vcalendar->VEVENT->DTEND = $dtend; - } - else { - unset($vcalendar->VEVENT->DTEND); - } + $object = $caldavBackend->getCalendarObject($id, $uri); - $calendarData = $vcalendar->serialize(); + $vcalendar = Reader::read($object['calendardata']); - $caldavBackend->updateCalendarObject($id, $uri, $calendarData); + if ($dtstart) { + $vcalendar->VEVENT->DTSTART = $dtstart; + } + if ($dtend) { + $vcalendar->VEVENT->DTEND = $dtend; + } else { + unset($vcalendar->VEVENT->DTEND); + } - killme(); - } + $calendarData = $vcalendar->serialize(); - // share a calendar - this only works on local system (with channels on the same server) - if ($_REQUEST['sharee'] && $_REQUEST['share']) { + $caldavBackend->updateCalendarObject($id, $uri, $calendarData); - $id = [intval($_REQUEST['calendarid']), intval($_REQUEST['instanceid'])]; + killme(); + } - if (! cdav_perms($id[0],$calendars)) { - return; - } + // share a calendar - this only works on local system (with channels on the same server) + if ($_REQUEST['sharee'] && $_REQUEST['share']) { - $hash = $_REQUEST['sharee']; + $id = [intval($_REQUEST['calendarid']), intval($_REQUEST['instanceid'])]; - $sharee_arr = channelx_by_hash($hash); + if (!cdav_perms($id[0], $calendars)) { + return; + } - $sharee = new Sharee(); + $hash = $_REQUEST['sharee']; - $sharee->href = 'mailto:' . $sharee_arr['xchan_addr']; - $sharee->principal = 'principals/' . $sharee_arr['channel_address']; - $sharee->access = intval($_REQUEST['access']); - $sharee->properties = ['{DAV:}displayname' => $channel['channel_name']]; + $sharee_arr = channelx_by_hash($hash); - $caldavBackend->updateInvites($id, [$sharee]); - } - } - - if (argc() >= 2 && argv(1) === 'addressbook') { - - $carddavBackend = new PDO($pdo); - $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); - - // create new addressbook - if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { - do { - $duplicate = false; - $addressbookUri = random_string(20); + $sharee = new Sharee(); - $r = q("SELECT uri FROM addressbooks WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", - dbesc($principalUri), - dbesc($addressbookUri) - ); + $sharee->href = 'mailto:' . $sharee_arr['xchan_addr']; + $sharee->principal = 'principals/' . $sharee_arr['channel_address']; + $sharee->access = intval($_REQUEST['access']); + $sharee->properties = ['{DAV:}displayname' => $channel['channel_name']]; - if ($r) { - $duplicate = true; - } - } while ($duplicate == true); - - $properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']]; - - $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties); - } - - // edit addressbook - if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) { - - $id = $_REQUEST['id']; - - if (! cdav_perms($id,$addressbooks)) { - return; - } - - $mutations = [ - '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'] - ]; - - $patch = new PropPatch($mutations); - - $carddavBackend->updateAddressBook($id, $patch); - - $patch->commit(); - } - - // create addressbook card - if ($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { - $id = $_REQUEST['target']; - - do { - $duplicate = false; - $uri = random_string(40) . '.vcf'; - - $r = q("SELECT uri FROM cards WHERE addressbookid = %s AND uri = '%s' LIMIT 1", - intval($id), - dbesc($uri) - ); - - if ($r) { - $duplicate = true; - } - } while ($duplicate == true); - - // TODO: this mostly duplictes the procedure in update addressbook card. - // Should move this part to a function to avoid duplication - $fn = $_REQUEST['fn']; - - $vcard = new \Sabre\VObject\Component\VCard([ - 'FN' => $fn, - 'N' => array_reverse(explode(' ', $fn)) - ]); - - $org = $_REQUEST['org']; - if ($org) { - $vcard->ORG = $org; - } - - $title = $_REQUEST['title']; - if ($title) { - $vcard->TITLE = $title; - } - - $tel = $_REQUEST['tel']; - $tel_type = $_REQUEST['tel_type']; - if ($tel) { - $i = 0; - foreach ($tel as $item) { - if ($item) { - $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); - } - $i++; - } - } - - $email = $_REQUEST['email']; - $email_type = $_REQUEST['email_type']; - if ($email) { - $i = 0; - foreach ($email as $item) { - if ($item) { - $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); - } - $i++; - } - } - - $impp = $_REQUEST['impp']; - $impp_type = $_REQUEST['impp_type']; - if ($impp) { - $i = 0; - foreach ($impp as $item) { - if ($item) { - $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); - } - $i++; - } - } - - $url = $_REQUEST['url']; - $url_type = $_REQUEST['url_type']; - if ($url) { - $i = 0; - foreach ($url as $item) { - if ($item) { - $vcard->add('URL', $item, ['type' => $url_type[$i]]); - } - $i++; - } - } - - $adr = $_REQUEST['adr']; - $adr_type = $_REQUEST['adr_type']; - - if ($adr) { - $i = 0; - foreach ($adr as $item) { - if ($item) { - $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); - } - $i++; - } - } - - $note = $_REQUEST['note']; - if ($note) { - $vcard->NOTE = $note; - } - - $cardData = $vcard->serialize(); - - $carddavBackend->createCard($id, $uri, $cardData); - - } - - // edit addressbook card - if ($_REQUEST['update'] && $_REQUEST['uri'] && $_REQUEST['target']) { - - $id = $_REQUEST['target']; - - if (!cdav_perms($id,$addressbooks)) { - return; - } - - $uri = $_REQUEST['uri']; - - $object = $carddavBackend->getCard($id, $uri); - $vcard = Reader::read($object['carddata']); - - $fn = $_REQUEST['fn']; - if ($fn) { - $vcard->FN = $fn; - $vcard->N = array_reverse(explode(' ', $fn)); - } - - $org = $_REQUEST['org']; - if ($org) { - $vcard->ORG = $org; - } - else { - unset($vcard->ORG); - } - - $title = $_REQUEST['title']; - if ($title) { - $vcard->TITLE = $title; - } - else { - unset($vcard->TITLE); - } - - $tel = $_REQUEST['tel']; - $tel_type = $_REQUEST['tel_type']; - if ($tel) { - $i = 0; - unset($vcard->TEL); - foreach ($tel as $item) { - if ($item) { - $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->TEL); - } - - $email = $_REQUEST['email']; - $email_type = $_REQUEST['email_type']; - if ($email) { - $i = 0; - unset($vcard->EMAIL); - foreach ($email as $item) { - if ($item) { - $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->EMAIL); - } - - $impp = $_REQUEST['impp']; - $impp_type = $_REQUEST['impp_type']; - if ($impp) { - $i = 0; - unset($vcard->IMPP); - foreach ($impp as $item) { - if ($item) { - $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->IMPP); - } - - $url = $_REQUEST['url']; - $url_type = $_REQUEST['url_type']; - if ($url) { - $i = 0; - unset($vcard->URL); - foreach ($url as $item) { - if ($item) { - $vcard->add('URL', $item, ['type' => $url_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->URL); - } - - $adr = $_REQUEST['adr']; - $adr_type = $_REQUEST['adr_type']; - if ($adr) { - $i = 0; - unset($vcard->ADR); - foreach ($adr as $item) { - if ($item) { - $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); - } - $i++; - } - } - else { - unset($vcard->ADR); - } - - $note = $_REQUEST['note']; - if ($note) { - $vcard->NOTE = $note; - } - else { - unset($vcard->NOTE); - } - - $cardData = $vcard->serialize(); - - $carddavBackend->updateCard($id, $uri, $cardData); - } - - // delete addressbook card - if ($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { - - $id = $_REQUEST['target']; - - if (!cdav_perms($id,$addressbooks)) { - return; - } - - $uri = $_REQUEST['uri']; - - $carddavBackend->deleteCard($id, $uri); - } - } - - // Import calendar or addressbook - if (($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) { - - $src = $_FILES['userfile']['tmp_name']; - - if ($src) { - - if ($_REQUEST['c_upload']) { - if ($_REQUEST['target'] == 'calendar') { - $result = parse_ical_file($src,local_channel()); - if ($result) { - info( t('Calendar entries imported.') . EOL); - } - else { - notice( t('No calendar entries found.') . EOL); - } - - @unlink($src); - return; - } - - $id = explode(':', $_REQUEST['target']); - $ext = 'ics'; - $table = 'calendarobjects'; - $column = 'calendarid'; - $objects = new ICalendar(@file_get_contents($src)); - $profile = Node::PROFILE_CALDAV; - $backend = new \Sabre\CalDAV\Backend\PDO($pdo); - } - - if ($_REQUEST['a_upload']) { - $id[] = intval($_REQUEST['target']); - $ext = 'vcf'; - $table = 'cards'; - $column = 'addressbookid'; - $objects = new VCard(@file_get_contents($src)); - $profile = Node::PROFILE_CARDDAV; - $backend = new PDO($pdo); - } - - while ($object = $objects->getNext()) { - - if ($_REQUEST['a_upload']) { - $object = $object->convert(Document::VCARD40); - } - - $ret = $object->validate($profile & Node::REPAIR); - - // level 3 Means that the document is invalid, - // level 2 means a warning. A warning means it's valid but it could cause interopability issues, - // level 1 means that there was a problem earlier, but the problem was automatically repaired. - - if ($ret[0]['level'] < 3) { - do { - $duplicate = false; - $objectUri = random_string(40) . '.' . $ext; - - $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1", - dbesc($id[0]), - dbesc($objectUri) - ); - - if ($r) { - $duplicate = true; - } - } while ($duplicate == true); - - if ($_REQUEST['c_upload']) { - $backend->createCalendarObject($id, $objectUri, $object->serialize()); - } - - if ($_REQUEST['a_upload']) { - $backend->createCard($id[0], $objectUri, $object->serialize()); - } - } - else { - if ($_REQUEST['c_upload']) { - notice( '' . t('INVALID EVENT DISMISSED!') . '' . EOL . - '' . t('Summary: ') . '' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . - '' . t('Date: ') . '' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . - '' . t('Reason: ') . '' . $ret[0]['message'] . EOL - ); - } - - if ($_REQUEST['a_upload']) { - notice( '' . t('INVALID CARD DISMISSED!') . '' . EOL . - '' . t('Name: ') . '' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . - '' . t('Reason: ') . '' . $ret[0]['message'] . EOL - ); - } - } - } - } - @unlink($src); - } - } - - function get() { - - if (! local_channel()) { - return; - } - - if ((argv(1) === 'addressbook') && (! Apps::system_app_installed(local_channel(), 'CardDAV'))) { - // Do not display any associated widgets at this point - App::$pdl = ''; - - $o = '' . t('CardDAV App') . ' (' . t('Not Installed') . '):
        '; - $o .= t('CalDAV capable addressbook'); - return $o; - } - - App::$profile_uid = local_channel(); - - $channel = App::get_channel(); - $principalUri = 'principals/' . $channel['channel_address']; - - $pdo = DBA::$dba->db; - - require_once 'vendor/autoload.php'; - - head_add_css('cdav.css'); - - if (! cdav_principal($principalUri)) { - $this->activate($pdo, $channel); - if (! cdav_principal($principalUri)) { - return; - } - } - - if (argv(1) === 'calendar') { - nav_set_selected('Calendar'); - $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); - $calendars = $caldavBackend->getCalendarsForUser($principalUri); - } - - // Display calendar(s) here - if(argc() <= 3 && argv(1) === 'calendar') { - - head_add_css('/library/fullcalendar/packages/core/main.min.css'); - head_add_css('/library/fullcalendar/packages/daygrid/main.min.css'); - head_add_css('/library/fullcalendar/packages/timegrid/main.min.css'); - head_add_css('/library/fullcalendar/packages/list/main.min.css'); - head_add_css('cdav_calendar.css'); - - head_add_js('/library/fullcalendar/packages/core/main.min.js'); - head_add_js('/library/fullcalendar/packages/interaction/main.min.js'); - head_add_js('/library/fullcalendar/packages/daygrid/main.min.js'); - head_add_js('/library/fullcalendar/packages/timegrid/main.min.js'); - head_add_js('/library/fullcalendar/packages/list/main.min.js'); - - $sources = ''; - $resource_id = ''; - $resource = null; - - if (argc() == 3) { - $resource_id = argv(2); - } - - if ($resource_id) { - $r = q("SELECT event.*, item.author_xchan, item.owner_xchan, item.plink, item.id as item_id FROM event LEFT JOIN item ON event.event_hash = item.resource_id + $caldavBackend->updateInvites($id, [$sharee]); + } + } + + if (argc() >= 2 && argv(1) === 'addressbook') { + + $carddavBackend = new PDO($pdo); + $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); + + // create new addressbook + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['create']) { + do { + $duplicate = false; + $addressbookUri = random_string(20); + + $r = q("SELECT uri FROM addressbooks WHERE principaluri = '%s' AND uri = '%s' LIMIT 1", + dbesc($principalUri), + dbesc($addressbookUri) + ); + + if ($r) { + $duplicate = true; + } + } while ($duplicate == true); + + $properties = ['{DAV:}displayname' => $_REQUEST['{DAV:}displayname']]; + + $carddavBackend->createAddressBook($principalUri, $addressbookUri, $properties); + } + + // edit addressbook + if ($_REQUEST['{DAV:}displayname'] && $_REQUEST['edit'] && intval($_REQUEST['id'])) { + + $id = $_REQUEST['id']; + + if (!cdav_perms($id, $addressbooks)) { + return; + } + + $mutations = [ + '{DAV:}displayname' => $_REQUEST['{DAV:}displayname'] + ]; + + $patch = new PropPatch($mutations); + + $carddavBackend->updateAddressBook($id, $patch); + + $patch->commit(); + } + + // create addressbook card + if ($_REQUEST['create'] && $_REQUEST['target'] && $_REQUEST['fn']) { + $id = $_REQUEST['target']; + + do { + $duplicate = false; + $uri = random_string(40) . '.vcf'; + + $r = q("SELECT uri FROM cards WHERE addressbookid = %s AND uri = '%s' LIMIT 1", + intval($id), + dbesc($uri) + ); + + if ($r) { + $duplicate = true; + } + } while ($duplicate == true); + + // TODO: this mostly duplictes the procedure in update addressbook card. + // Should move this part to a function to avoid duplication + $fn = $_REQUEST['fn']; + + $vcard = new \Sabre\VObject\Component\VCard([ + 'FN' => $fn, + 'N' => array_reverse(explode(' ', $fn)) + ]); + + $org = $_REQUEST['org']; + if ($org) { + $vcard->ORG = $org; + } + + $title = $_REQUEST['title']; + if ($title) { + $vcard->TITLE = $title; + } + + $tel = $_REQUEST['tel']; + $tel_type = $_REQUEST['tel_type']; + if ($tel) { + $i = 0; + foreach ($tel as $item) { + if ($item) { + $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); + } + $i++; + } + } + + $email = $_REQUEST['email']; + $email_type = $_REQUEST['email_type']; + if ($email) { + $i = 0; + foreach ($email as $item) { + if ($item) { + $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); + } + $i++; + } + } + + $impp = $_REQUEST['impp']; + $impp_type = $_REQUEST['impp_type']; + if ($impp) { + $i = 0; + foreach ($impp as $item) { + if ($item) { + $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); + } + $i++; + } + } + + $url = $_REQUEST['url']; + $url_type = $_REQUEST['url_type']; + if ($url) { + $i = 0; + foreach ($url as $item) { + if ($item) { + $vcard->add('URL', $item, ['type' => $url_type[$i]]); + } + $i++; + } + } + + $adr = $_REQUEST['adr']; + $adr_type = $_REQUEST['adr_type']; + + if ($adr) { + $i = 0; + foreach ($adr as $item) { + if ($item) { + $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); + } + $i++; + } + } + + $note = $_REQUEST['note']; + if ($note) { + $vcard->NOTE = $note; + } + + $cardData = $vcard->serialize(); + + $carddavBackend->createCard($id, $uri, $cardData); + + } + + // edit addressbook card + if ($_REQUEST['update'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = $_REQUEST['target']; + + if (!cdav_perms($id, $addressbooks)) { + return; + } + + $uri = $_REQUEST['uri']; + + $object = $carddavBackend->getCard($id, $uri); + $vcard = Reader::read($object['carddata']); + + $fn = $_REQUEST['fn']; + if ($fn) { + $vcard->FN = $fn; + $vcard->N = array_reverse(explode(' ', $fn)); + } + + $org = $_REQUEST['org']; + if ($org) { + $vcard->ORG = $org; + } else { + unset($vcard->ORG); + } + + $title = $_REQUEST['title']; + if ($title) { + $vcard->TITLE = $title; + } else { + unset($vcard->TITLE); + } + + $tel = $_REQUEST['tel']; + $tel_type = $_REQUEST['tel_type']; + if ($tel) { + $i = 0; + unset($vcard->TEL); + foreach ($tel as $item) { + if ($item) { + $vcard->add('TEL', $item, ['type' => $tel_type[$i]]); + } + $i++; + } + } else { + unset($vcard->TEL); + } + + $email = $_REQUEST['email']; + $email_type = $_REQUEST['email_type']; + if ($email) { + $i = 0; + unset($vcard->EMAIL); + foreach ($email as $item) { + if ($item) { + $vcard->add('EMAIL', $item, ['type' => $email_type[$i]]); + } + $i++; + } + } else { + unset($vcard->EMAIL); + } + + $impp = $_REQUEST['impp']; + $impp_type = $_REQUEST['impp_type']; + if ($impp) { + $i = 0; + unset($vcard->IMPP); + foreach ($impp as $item) { + if ($item) { + $vcard->add('IMPP', $item, ['type' => $impp_type[$i]]); + } + $i++; + } + } else { + unset($vcard->IMPP); + } + + $url = $_REQUEST['url']; + $url_type = $_REQUEST['url_type']; + if ($url) { + $i = 0; + unset($vcard->URL); + foreach ($url as $item) { + if ($item) { + $vcard->add('URL', $item, ['type' => $url_type[$i]]); + } + $i++; + } + } else { + unset($vcard->URL); + } + + $adr = $_REQUEST['adr']; + $adr_type = $_REQUEST['adr_type']; + if ($adr) { + $i = 0; + unset($vcard->ADR); + foreach ($adr as $item) { + if ($item) { + $vcard->add('ADR', $item, ['type' => $adr_type[$i]]); + } + $i++; + } + } else { + unset($vcard->ADR); + } + + $note = $_REQUEST['note']; + if ($note) { + $vcard->NOTE = $note; + } else { + unset($vcard->NOTE); + } + + $cardData = $vcard->serialize(); + + $carddavBackend->updateCard($id, $uri, $cardData); + } + + // delete addressbook card + if ($_REQUEST['delete'] && $_REQUEST['uri'] && $_REQUEST['target']) { + + $id = $_REQUEST['target']; + + if (!cdav_perms($id, $addressbooks)) { + return; + } + + $uri = $_REQUEST['uri']; + + $carddavBackend->deleteCard($id, $uri); + } + } + + // Import calendar or addressbook + if (($_FILES) && array_key_exists('userfile', $_FILES) && intval($_FILES['userfile']['size']) && $_REQUEST['target']) { + + $src = $_FILES['userfile']['tmp_name']; + + if ($src) { + + if ($_REQUEST['c_upload']) { + if ($_REQUEST['target'] == 'calendar') { + $result = parse_ical_file($src, local_channel()); + if ($result) { + info(t('Calendar entries imported.') . EOL); + } else { + notice(t('No calendar entries found.') . EOL); + } + + @unlink($src); + return; + } + + $id = explode(':', $_REQUEST['target']); + $ext = 'ics'; + $table = 'calendarobjects'; + $column = 'calendarid'; + $objects = new ICalendar(@file_get_contents($src)); + $profile = Node::PROFILE_CALDAV; + $backend = new \Sabre\CalDAV\Backend\PDO($pdo); + } + + if ($_REQUEST['a_upload']) { + $id[] = intval($_REQUEST['target']); + $ext = 'vcf'; + $table = 'cards'; + $column = 'addressbookid'; + $objects = new VCard(@file_get_contents($src)); + $profile = Node::PROFILE_CARDDAV; + $backend = new PDO($pdo); + } + + while ($object = $objects->getNext()) { + + if ($_REQUEST['a_upload']) { + $object = $object->convert(Document::VCARD40); + } + + $ret = $object->validate($profile & Node::REPAIR); + + // level 3 Means that the document is invalid, + // level 2 means a warning. A warning means it's valid but it could cause interopability issues, + // level 1 means that there was a problem earlier, but the problem was automatically repaired. + + if ($ret[0]['level'] < 3) { + do { + $duplicate = false; + $objectUri = random_string(40) . '.' . $ext; + + $r = q("SELECT uri FROM $table WHERE $column = %d AND uri = '%s' LIMIT 1", + dbesc($id[0]), + dbesc($objectUri) + ); + + if ($r) { + $duplicate = true; + } + } while ($duplicate == true); + + if ($_REQUEST['c_upload']) { + $backend->createCalendarObject($id, $objectUri, $object->serialize()); + } + + if ($_REQUEST['a_upload']) { + $backend->createCard($id[0], $objectUri, $object->serialize()); + } + } else { + if ($_REQUEST['c_upload']) { + notice('' . t('INVALID EVENT DISMISSED!') . '' . EOL . + '' . t('Summary: ') . '' . (($object->VEVENT->SUMMARY) ? $object->VEVENT->SUMMARY : t('Unknown')) . EOL . + '' . t('Date: ') . '' . (($object->VEVENT->DTSTART) ? $object->VEVENT->DTSTART : t('Unknown')) . EOL . + '' . t('Reason: ') . '' . $ret[0]['message'] . EOL + ); + } + + if ($_REQUEST['a_upload']) { + notice('' . t('INVALID CARD DISMISSED!') . '' . EOL . + '' . t('Name: ') . '' . (($object->FN) ? $object->FN : t('Unknown')) . EOL . + '' . t('Reason: ') . '' . $ret[0]['message'] . EOL + ); + } + } + } + } + @unlink($src); + } + } + + public function get() + { + + if (!local_channel()) { + return; + } + + if ((argv(1) === 'addressbook') && (!Apps::system_app_installed(local_channel(), 'CardDAV'))) { + // Do not display any associated widgets at this point + App::$pdl = ''; + + $o = '' . t('CardDAV App') . ' (' . t('Not Installed') . '):
        '; + $o .= t('CalDAV capable addressbook'); + return $o; + } + + App::$profile_uid = local_channel(); + + $channel = App::get_channel(); + $principalUri = 'principals/' . $channel['channel_address']; + + $pdo = DBA::$dba->db; + + require_once 'vendor/autoload.php'; + + head_add_css('cdav.css'); + + if (!cdav_principal($principalUri)) { + $this->activate($pdo, $channel); + if (!cdav_principal($principalUri)) { + return; + } + } + + if (argv(1) === 'calendar') { + nav_set_selected('Calendar'); + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $calendars = $caldavBackend->getCalendarsForUser($principalUri); + } + + // Display calendar(s) here + if (argc() <= 3 && argv(1) === 'calendar') { + + head_add_css('/library/fullcalendar/packages/core/main.min.css'); + head_add_css('/library/fullcalendar/packages/daygrid/main.min.css'); + head_add_css('/library/fullcalendar/packages/timegrid/main.min.css'); + head_add_css('/library/fullcalendar/packages/list/main.min.css'); + head_add_css('cdav_calendar.css'); + + head_add_js('/library/fullcalendar/packages/core/main.min.js'); + head_add_js('/library/fullcalendar/packages/interaction/main.min.js'); + head_add_js('/library/fullcalendar/packages/daygrid/main.min.js'); + head_add_js('/library/fullcalendar/packages/timegrid/main.min.js'); + head_add_js('/library/fullcalendar/packages/list/main.min.js'); + + $sources = ''; + $resource_id = ''; + $resource = null; + + if (argc() == 3) { + $resource_id = argv(2); + } + + if ($resource_id) { + $r = q("SELECT event.*, item.author_xchan, item.owner_xchan, item.plink, item.id as item_id FROM event LEFT JOIN item ON event.event_hash = item.resource_id WHERE event.uid = %d AND event.event_hash = '%s' LIMIT 1", - intval(local_channel()), - dbesc($resource_id) - ); - if ($r) { - xchan_query($r); - $r = fetch_post_tags($r,true); + intval(local_channel()), + dbesc($resource_id) + ); + if ($r) { + xchan_query($r); + $r = fetch_post_tags($r, true); - $r[0]['dtstart'] = (($r[0]['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$r[0]['dtstart'], 'c') : datetime_convert('UTC','UTC',$r[0]['dtstart'],'c')); - $r[0]['dtend'] = (($r[0]['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$r[0]['dtend'], 'c') : datetime_convert('UTC','UTC',$r[0]['dtend'],'c')); + $r[0]['dtstart'] = (($r[0]['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $r[0]['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $r[0]['dtstart'], 'c')); + $r[0]['dtend'] = (($r[0]['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $r[0]['dtend'], 'c') : datetime_convert('UTC', 'UTC', $r[0]['dtend'], 'c')); - $r[0]['plink'] = [$r[0]['plink'], t('Link to source')]; + $r[0]['plink'] = [$r[0]['plink'], t('Link to source')]; - $resource = $r[0]; + $resource = $r[0]; - $catsenabled = Apps::system_app_installed(local_channel(), 'Categories'); + $catsenabled = Apps::system_app_installed(local_channel(), 'Categories'); - $categories = ''; - if ($catsenabled){ - if($r[0]['term']) { - $categories = array_elm_to_str(get_terms_oftype($r[0]['term'], TERM_CATEGORY), 'term'); - } - } + $categories = ''; + if ($catsenabled) { + if ($r[0]['term']) { + $categories = array_elm_to_str(get_terms_oftype($r[0]['term'], TERM_CATEGORY), 'term'); + } + } - if ($r[0]['dismissed'] == 0) { - q("UPDATE event SET dismissed = 1 WHERE event.uid = %d AND event.event_hash = '%s'", - intval(local_channel()), - dbesc($resource_id) - ); - } - } - } + if ($r[0]['dismissed'] == 0) { + q("UPDATE event SET dismissed = 1 WHERE event.uid = %d AND event.event_hash = '%s'", + intval(local_channel()), + dbesc($resource_id) + ); + } + } + } - if (get_pconfig(local_channel(), 'cdav_calendar', 'calendar')) { - $sources .= '{ + if (get_pconfig(local_channel(), 'cdav_calendar', 'calendar')) { + $sources .= '{ id: \'calendar\', url: \'/calendar/json/\', color: \'#3a87ad\' }, '; - } + } - $calendars[] = [ - 'displayname' => $channel['channel_name'], - 'id' => 'calendar' - ]; + $calendars[] = [ + 'displayname' => $channel['channel_name'], + 'id' => 'calendar' + ]; - foreach ($calendars as $calendar) { - $editable = (($calendar['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript - $color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#6cad39'); - $sharer = (($calendar['share-access'] == 3) ? $calendar['{urn:ietf:params:xml:ns:caldav}calendar-description'] : ''); - $switch = get_pconfig(local_channel(), 'cdav_calendar', $calendar['id'][0]); - if ($switch) { - $sources .= '{ + foreach ($calendars as $calendar) { + $editable = (($calendar['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript + $color = (($calendar['{http://apple.com/ns/ical/}calendar-color']) ? $calendar['{http://apple.com/ns/ical/}calendar-color'] : '#6cad39'); + $sharer = (($calendar['share-access'] == 3) ? $calendar['{urn:ietf:params:xml:ns:caldav}calendar-description'] : ''); + $switch = get_pconfig(local_channel(), 'cdav_calendar', $calendar['id'][0]); + if ($switch) { + $sources .= '{ id: ' . $calendar['id'][0] . ', url: \'/cdav/calendar/json/' . $calendar['id'][0] . '/' . $calendar['id'][1] . '\', color: \'' . $color . '\' }, '; - } - - if ($calendar['share-access'] != 2) { - $writable_calendars[] = [ - 'displayname' => $calendar['{DAV:}displayname'], - 'sharer' => $sharer, - 'id' => $calendar['id'] - ]; - } - } - - $sources = rtrim($sources, ', '); - - $first_day = feature_enabled(local_channel(), 'cal_first_day'); - $first_day = (($first_day) ? $first_day : 0); - - $title = ['title', t('Event title')]; - $dtstart = ['dtstart', t('Start date and time')]; - $dtend = ['dtend', t('End date and time')]; - $description = ['description', t('Description')]; - $location = ['location', t('Location')]; - - $catsenabled = Apps::system_app_installed(local_channel(), 'Categories'); - - require_once('include/acl_selectors.php'); - - $accesslist = new AccessControl($channel); - $perm_defaults = $accesslist->get(); - - $acl = populate_acl($perm_defaults, false, PermissionDescription::fromGlobalPermission('view_stream')); - - $permissions = $perm_defaults; - - $o .= replace_macros(get_markup_template('cdav_calendar.tpl'), [ - '$sources' => $sources, - '$color' => $color, - '$lang' => App::$language, - '$timezone' => App::$timezone, - '$first_day' => $first_day, - '$prev' => t('Previous'), - '$next' => t('Next'), - '$today' => t('Today'), - '$month' => t('Month'), - '$week' => t('Week'), - '$day' => t('Day'), - '$list_month' => t('List month'), - '$list_week' => t('List week'), - '$list_day' => t('List day'), - '$title' => $title, - '$calendars' => $calendars, - '$writable_calendars' => $writable_calendars, - '$dtstart' => $dtstart, - '$dtend' => $dtend, - '$description' => $description, - '$location' => $location, - '$more' => t('More'), - '$less' => t('Less'), - '$update' => t('Update'), - '$calendar_select_label' => t('Select calendar'), - '$calendar_optiopns_label' => [t('Channel Calendars'), t('CalDAV Calendars')], - '$delete' => t('Delete'), - '$delete_all' => t('Delete all'), - '$cancel' => t('Cancel'), - '$create' => t('Create'), - '$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.'), - '$channel_hash' => $channel['channel_hash'], - '$acl' => $acl, - '$lockstate' => (($accesslist->is_private()) ? 'lock' : 'unlock'), - '$allow_cid' => acl2json($permissions['allow_cid']), - '$allow_gid' => acl2json($permissions['allow_gid']), - '$deny_cid' => acl2json($permissions['deny_cid']), - '$deny_gid' => acl2json($permissions['deny_gid']), - '$catsenabled' => $catsenabled, - '$categories_label' => t('Categories'), - '$resource' => json_encode($resource), - '$categories' => $categories - ]); - - return $o; - - } - - // Provide json data for calendar - if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'json' && intval(argv(3)) && intval(argv(4))) { - - $events = []; - - $id = [argv(3), argv(4)]; - - if (! cdav_perms($id[0],$calendars)) { - json_return_and_die($events); - } - - if (x($_GET,'start')) { - $start = new DateTime($_GET['start']); - } - if (x($_GET,'end')) { - $end = new DateTime($_GET['end']); - } - - $filters['name'] = 'VCALENDAR'; - $filters['prop-filters'][0]['name'] = 'VEVENT'; - $filters['comp-filters'][0]['name'] = 'VEVENT'; - $filters['comp-filters'][0]['time-range']['start'] = $start; - $filters['comp-filters'][0]['time-range']['end'] = $end; - - $uris = $caldavBackend->calendarQuery($id, $filters); - - if ($uris) { - $objects = $caldavBackend->getMultipleCalendarObjects($id, $uris); - foreach ($objects as $object) { - - $vcalendar = Reader::read($object['calendardata']); - - if (isset($vcalendar->VEVENT->RRULE)) { - // expanding recurrent events seems to loose timezone info - // save it here so we can add it later - $recurrent_timezone = (string)$vcalendar->VEVENT->DTSTART['TZID']; - $vcalendar = $vcalendar->expand($start, $end); - } - - foreach ($vcalendar->VEVENT as $vevent) { - $title = (string)$vevent->SUMMARY; - $dtstart = (string)$vevent->DTSTART; - $dtend = (string)$vevent->DTEND; - $description = (string)$vevent->DESCRIPTION; - $location = (string)$vevent->LOCATION; - $timezone = (string)$vevent->DTSTART['TZID']; - $rw = ((cdav_perms($id[0],$calendars,true)) ? true : false); - $editable = $rw ? true : false; - $recurrent = ((isset($vevent->{'RECURRENCE-ID'})) ? true : false); - - if ($recurrent) { - $editable = false; - $timezone = $recurrent_timezone; - } - - $allDay = false; - - // allDay event rules - if (!strpos($dtstart, 'T') && !strpos($dtend, 'T')) { - $allDay = true; - } - if (strpos($dtstart, 'T000000') && strpos($dtend, 'T000000')) { - $allDay = true; - } - - $events[] = [ - 'calendar_id' => $id, - 'uri' => $object['uri'], - 'title' => $title, - 'start' => datetime_convert($timezone, $timezone, $dtstart, 'c'), - 'end' => (($dtend) ? datetime_convert($timezone, $timezone, $dtend, 'c') : ''), - 'description' => $description, - 'location' => $location, - 'allDay' => $allDay, - 'editable' => $editable, - 'recurrent' => $recurrent, - 'rw' => $rw - ]; - } - } - } - json_return_and_die($events); - } - - // enable/disable calendars - if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && argv(3) && (argv(4) == 1 || argv(4) == 0)) { - $id = argv(3); - - if (! cdav_perms($id,$calendars)) { - killme(); - } - - set_pconfig(local_channel(), 'cdav_calendar' , argv(3), argv(4)); - killme(); - } - - // drop calendar - if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'drop' && intval(argv(3)) && intval(argv(4))) { - $id = [argv(3), argv(4)]; - - if (! cdav_perms($id[0],$calendars)) { - killme(); - } - - $caldavBackend->deleteCalendar($id); - killme(); - } - - // drop sharee - if (argc() == 6 && argv(1) === 'calendar' && argv(2) === 'dropsharee' && intval(argv(3)) && intval(argv(4))) { - - $id = [argv(3), argv(4)]; - $hash = argv(5); - - if (! cdav_perms($id[0],$calendars)) { - killme(); - } - - $sharee_arr = channelx_by_hash($hash); - - $sharee = new Sharee(); - - $sharee->href = 'mailto:' . $sharee_arr['xchan_addr']; - $sharee->principal = 'principals/' . $sharee_arr['channel_address']; - $sharee->access = 4; - $caldavBackend->updateInvites($id, [$sharee]); - - killme(); - } - - - if (argv(1) === 'addressbook') { - nav_set_selected('CardDAV'); - $carddavBackend = new PDO($pdo); - $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); - } - - // Display Adressbook here - if (argc() == 3 && argv(1) === 'addressbook' && intval(argv(2))) { - - $id = argv(2); - - $displayname = cdav_perms($id,$addressbooks); - - if (! $displayname) { - return; - } - - head_add_css('cdav_addressbook.css'); - - $o = ''; - - $sabrecards = $carddavBackend->getCards($id); - foreach ($sabrecards as $sabrecard) { - $uris[] = $sabrecard['uri']; - } - - if ($uris) { - $objects = $carddavBackend->getMultipleCards($id, $uris); - - foreach ($objects as $object) { - $vcard = Reader::read($object['carddata']); - - $photo = ''; - if ($vcard->PHOTO) { - $photo_value = strtolower($vcard->PHOTO->getValueType()); // binary or uri - if ($photo_value === 'binary') { - $photo_type = strtolower($vcard->PHOTO['TYPE']); // mime jpeg, png or gif - $photo = 'data:image/' . $photo_type . ';base64,' . base64_encode((string)$vcard->PHOTO); - } - else { - $url = parse_url((string)$vcard->PHOTO); - $photo = 'data:' . $url['path']; - } - } - - $fn = ''; - if ($vcard->FN) { - $fn = (string)$vcard->FN; - } - - $org = ''; - if ($vcard->ORG) { - $org = (string)$vcard->ORG; - } - - $title = ''; - if ($vcard->TITLE) { - $title = (string)$vcard->TITLE; - } - - $tels = []; - if ($vcard->TEL) { - foreach ($vcard->TEL as $tel) { - $type = (($tel['TYPE']) ? translate_type((string)$tel['TYPE']) : ''); - $tels[] = [ - 'type' => $type, - 'nr' => (string)$tel - ]; - } - } - - $emails = []; - if ($vcard->EMAIL) { - foreach ($vcard->EMAIL as $email) { - $type = (($email['TYPE']) ? translate_type((string)$email['TYPE']) : ''); - $emails[] = [ - 'type' => $type, - 'address' => (string)$email - ]; - } - } - - $impps = []; - if ($vcard->IMPP) { - foreach ($vcard->IMPP as $impp) { - $type = (($impp['TYPE']) ? translate_type((string)$impp['TYPE']) : ''); - $impps[] = [ - 'type' => $type, - 'address' => (string)$impp - ]; - } - } - - $urls = []; - if ($vcard->URL) { - foreach ($vcard->URL as $url) { - $type = (($url['TYPE']) ? translate_type((string)$url['TYPE']) : ''); - $urls[] = [ - 'type' => $type, - 'address' => (string)$url - ]; - } - } - - $adrs = []; - if ($vcard->ADR) { - foreach ($vcard->ADR as $adr) { - $type = (($adr['TYPE']) ? translate_type((string)$adr['TYPE']) : ''); - $adrs[] = [ - 'type' => $type, - 'address' => $adr->getParts() - ]; - } - } - - $note = ''; - if ($vcard->NOTE) { - $note = (string)$vcard->NOTE; - } - - $cards[] = [ - 'id' => $object['id'], - 'uri' => $object['uri'], - 'photo' => $photo, - 'fn' => $fn, - 'org' => $org, - 'title' => $title, - 'tels' => $tels, - 'emails' => $emails, - 'impps' => $impps, - 'urls' => $urls, - 'adrs' => $adrs, - 'note' => $note - ]; - } - - usort($cards, function($a, $b) { return strcasecmp($a['fn'], $b['fn']); }); - } - - $o .= replace_macros(get_markup_template('cdav_addressbook.tpl'), [ - '$id' => $id, - '$cards' => $cards, - '$displayname' => $displayname, - '$name_label' => t('Name'), - '$org_label' => t('Organisation'), - '$title_label' => t('Title'), - '$tel_label' => t('Phone'), - '$email_label' => t('Email'), - '$impp_label' => t('Instant messenger'), - '$url_label' => t('Website'), - '$adr_label' => t('Address'), - '$note_label' => t('Note'), - '$mobile' => t('Mobile'), - '$home' => t('Home'), - '$work' => t('Work'), - '$other' => t('Other'), - '$add_card' => t('Add Contact'), - '$add_field' => t('Add Field'), - '$create' => t('Create'), - '$update' => t('Update'), - '$delete' => t('Delete'), - '$cancel' => t('Cancel'), - '$po_box' => t('P.O. Box'), - '$extra' => t('Additional'), - '$street' => t('Street'), - '$locality' => t('Locality'), - '$region' => t('Region'), - '$zip_code' => t('ZIP Code'), - '$country' => t('Country') - ]); - - return $o; - } - - // delete addressbook - if (argc() > 3 && argv(1) === 'addressbook' && argv(2) === 'drop' && intval(argv(3))) { - $id = argv(3); - - if (! cdav_perms($id,$addressbooks)) { - return; - } - - $carddavBackend->deleteAddressBook($id); - killme(); - } - - } - - function activate($pdo, $channel) { - - if (! $channel) { - return; - } - - $uri = 'principals/' . $channel['channel_address']; - - - $r = q("select * from principals where uri = '%s' limit 1", - dbesc($uri) - ); - if($r) { - $r = q("update principals set email = '%s', displayname = '%s' where uri = '%s' ", - dbesc($channel['xchan_addr']), - dbesc($channel['channel_name']), - dbesc($uri) - ); - } - else { - $r = q("insert into principals ( uri, email, displayname ) values('%s','%s','%s') ", - dbesc($uri), - dbesc($channel['xchan_addr']), - dbesc($channel['channel_name']) - ); - - // create default calendar - $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); - $properties = [ - '{DAV:}displayname' => t('Default Calendar'), - '{http://apple.com/ns/ical/}calendar-color' => '#6cad39', - '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] - ]; - - $id = $caldavBackend->createCalendar($uri, 'default', $properties); - set_pconfig(local_channel(), 'cdav_calendar' , $id[0], 1); - set_pconfig(local_channel(), 'cdav_calendar' , 'calendar', 1); - - // create default addressbook - $carddavBackend = new PDO($pdo); - $properties = ['{DAV:}displayname' => t('Default Addressbook')]; - $carddavBackend->createAddressBook($uri, 'default', $properties); - - } - } + } + + if ($calendar['share-access'] != 2) { + $writable_calendars[] = [ + 'displayname' => $calendar['{DAV:}displayname'], + 'sharer' => $sharer, + 'id' => $calendar['id'] + ]; + } + } + + $sources = rtrim($sources, ', '); + + $first_day = feature_enabled(local_channel(), 'cal_first_day'); + $first_day = (($first_day) ? $first_day : 0); + + $title = ['title', t('Event title')]; + $dtstart = ['dtstart', t('Start date and time')]; + $dtend = ['dtend', t('End date and time')]; + $description = ['description', t('Description')]; + $location = ['location', t('Location')]; + + $catsenabled = Apps::system_app_installed(local_channel(), 'Categories'); + + require_once('include/acl_selectors.php'); + + $accesslist = new AccessControl($channel); + $perm_defaults = $accesslist->get(); + + $acl = populate_acl($perm_defaults, false, PermissionDescription::fromGlobalPermission('view_stream')); + + $permissions = $perm_defaults; + + $o .= replace_macros(get_markup_template('cdav_calendar.tpl'), [ + '$sources' => $sources, + '$color' => $color, + '$lang' => App::$language, + '$timezone' => App::$timezone, + '$first_day' => $first_day, + '$prev' => t('Previous'), + '$next' => t('Next'), + '$today' => t('Today'), + '$month' => t('Month'), + '$week' => t('Week'), + '$day' => t('Day'), + '$list_month' => t('List month'), + '$list_week' => t('List week'), + '$list_day' => t('List day'), + '$title' => $title, + '$calendars' => $calendars, + '$writable_calendars' => $writable_calendars, + '$dtstart' => $dtstart, + '$dtend' => $dtend, + '$description' => $description, + '$location' => $location, + '$more' => t('More'), + '$less' => t('Less'), + '$update' => t('Update'), + '$calendar_select_label' => t('Select calendar'), + '$calendar_optiopns_label' => [t('Channel Calendars'), t('CalDAV Calendars')], + '$delete' => t('Delete'), + '$delete_all' => t('Delete all'), + '$cancel' => t('Cancel'), + '$create' => t('Create'), + '$recurrence_warning' => t('Sorry! Editing of recurrent events is not yet implemented.'), + '$channel_hash' => $channel['channel_hash'], + '$acl' => $acl, + '$lockstate' => (($accesslist->is_private()) ? 'lock' : 'unlock'), + '$allow_cid' => acl2json($permissions['allow_cid']), + '$allow_gid' => acl2json($permissions['allow_gid']), + '$deny_cid' => acl2json($permissions['deny_cid']), + '$deny_gid' => acl2json($permissions['deny_gid']), + '$catsenabled' => $catsenabled, + '$categories_label' => t('Categories'), + '$resource' => json_encode($resource), + '$categories' => $categories + ]); + + return $o; + + } + + // Provide json data for calendar + if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'json' && intval(argv(3)) && intval(argv(4))) { + + $events = []; + + $id = [argv(3), argv(4)]; + + if (!cdav_perms($id[0], $calendars)) { + json_return_and_die($events); + } + + if (x($_GET, 'start')) { + $start = new DateTime($_GET['start']); + } + if (x($_GET, 'end')) { + $end = new DateTime($_GET['end']); + } + + $filters['name'] = 'VCALENDAR'; + $filters['prop-filters'][0]['name'] = 'VEVENT'; + $filters['comp-filters'][0]['name'] = 'VEVENT'; + $filters['comp-filters'][0]['time-range']['start'] = $start; + $filters['comp-filters'][0]['time-range']['end'] = $end; + + $uris = $caldavBackend->calendarQuery($id, $filters); + + if ($uris) { + $objects = $caldavBackend->getMultipleCalendarObjects($id, $uris); + foreach ($objects as $object) { + + $vcalendar = Reader::read($object['calendardata']); + + if (isset($vcalendar->VEVENT->RRULE)) { + // expanding recurrent events seems to loose timezone info + // save it here so we can add it later + $recurrent_timezone = (string)$vcalendar->VEVENT->DTSTART['TZID']; + $vcalendar = $vcalendar->expand($start, $end); + } + + foreach ($vcalendar->VEVENT as $vevent) { + $title = (string)$vevent->SUMMARY; + $dtstart = (string)$vevent->DTSTART; + $dtend = (string)$vevent->DTEND; + $description = (string)$vevent->DESCRIPTION; + $location = (string)$vevent->LOCATION; + $timezone = (string)$vevent->DTSTART['TZID']; + $rw = ((cdav_perms($id[0], $calendars, true)) ? true : false); + $editable = $rw ? true : false; + $recurrent = ((isset($vevent->{'RECURRENCE-ID'})) ? true : false); + + if ($recurrent) { + $editable = false; + $timezone = $recurrent_timezone; + } + + $allDay = false; + + // allDay event rules + if (!strpos($dtstart, 'T') && !strpos($dtend, 'T')) { + $allDay = true; + } + if (strpos($dtstart, 'T000000') && strpos($dtend, 'T000000')) { + $allDay = true; + } + + $events[] = [ + 'calendar_id' => $id, + 'uri' => $object['uri'], + 'title' => $title, + 'start' => datetime_convert($timezone, $timezone, $dtstart, 'c'), + 'end' => (($dtend) ? datetime_convert($timezone, $timezone, $dtend, 'c') : ''), + 'description' => $description, + 'location' => $location, + 'allDay' => $allDay, + 'editable' => $editable, + 'recurrent' => $recurrent, + 'rw' => $rw + ]; + } + } + } + json_return_and_die($events); + } + + // enable/disable calendars + if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'switch' && argv(3) && (argv(4) == 1 || argv(4) == 0)) { + $id = argv(3); + + if (!cdav_perms($id, $calendars)) { + killme(); + } + + set_pconfig(local_channel(), 'cdav_calendar', argv(3), argv(4)); + killme(); + } + + // drop calendar + if (argc() == 5 && argv(1) === 'calendar' && argv(2) === 'drop' && intval(argv(3)) && intval(argv(4))) { + $id = [argv(3), argv(4)]; + + if (!cdav_perms($id[0], $calendars)) { + killme(); + } + + $caldavBackend->deleteCalendar($id); + killme(); + } + + // drop sharee + if (argc() == 6 && argv(1) === 'calendar' && argv(2) === 'dropsharee' && intval(argv(3)) && intval(argv(4))) { + + $id = [argv(3), argv(4)]; + $hash = argv(5); + + if (!cdav_perms($id[0], $calendars)) { + killme(); + } + + $sharee_arr = channelx_by_hash($hash); + + $sharee = new Sharee(); + + $sharee->href = 'mailto:' . $sharee_arr['xchan_addr']; + $sharee->principal = 'principals/' . $sharee_arr['channel_address']; + $sharee->access = 4; + $caldavBackend->updateInvites($id, [$sharee]); + + killme(); + } + + + if (argv(1) === 'addressbook') { + nav_set_selected('CardDAV'); + $carddavBackend = new PDO($pdo); + $addressbooks = $carddavBackend->getAddressBooksForUser($principalUri); + } + + // Display Adressbook here + if (argc() == 3 && argv(1) === 'addressbook' && intval(argv(2))) { + + $id = argv(2); + + $displayname = cdav_perms($id, $addressbooks); + + if (!$displayname) { + return; + } + + head_add_css('cdav_addressbook.css'); + + $o = ''; + + $sabrecards = $carddavBackend->getCards($id); + foreach ($sabrecards as $sabrecard) { + $uris[] = $sabrecard['uri']; + } + + if ($uris) { + $objects = $carddavBackend->getMultipleCards($id, $uris); + + foreach ($objects as $object) { + $vcard = Reader::read($object['carddata']); + + $photo = ''; + if ($vcard->PHOTO) { + $photo_value = strtolower($vcard->PHOTO->getValueType()); // binary or uri + if ($photo_value === 'binary') { + $photo_type = strtolower($vcard->PHOTO['TYPE']); // mime jpeg, png or gif + $photo = 'data:image/' . $photo_type . ';base64,' . base64_encode((string)$vcard->PHOTO); + } else { + $url = parse_url((string)$vcard->PHOTO); + $photo = 'data:' . $url['path']; + } + } + + $fn = ''; + if ($vcard->FN) { + $fn = (string)$vcard->FN; + } + + $org = ''; + if ($vcard->ORG) { + $org = (string)$vcard->ORG; + } + + $title = ''; + if ($vcard->TITLE) { + $title = (string)$vcard->TITLE; + } + + $tels = []; + if ($vcard->TEL) { + foreach ($vcard->TEL as $tel) { + $type = (($tel['TYPE']) ? translate_type((string)$tel['TYPE']) : ''); + $tels[] = [ + 'type' => $type, + 'nr' => (string)$tel + ]; + } + } + + $emails = []; + if ($vcard->EMAIL) { + foreach ($vcard->EMAIL as $email) { + $type = (($email['TYPE']) ? translate_type((string)$email['TYPE']) : ''); + $emails[] = [ + 'type' => $type, + 'address' => (string)$email + ]; + } + } + + $impps = []; + if ($vcard->IMPP) { + foreach ($vcard->IMPP as $impp) { + $type = (($impp['TYPE']) ? translate_type((string)$impp['TYPE']) : ''); + $impps[] = [ + 'type' => $type, + 'address' => (string)$impp + ]; + } + } + + $urls = []; + if ($vcard->URL) { + foreach ($vcard->URL as $url) { + $type = (($url['TYPE']) ? translate_type((string)$url['TYPE']) : ''); + $urls[] = [ + 'type' => $type, + 'address' => (string)$url + ]; + } + } + + $adrs = []; + if ($vcard->ADR) { + foreach ($vcard->ADR as $adr) { + $type = (($adr['TYPE']) ? translate_type((string)$adr['TYPE']) : ''); + $adrs[] = [ + 'type' => $type, + 'address' => $adr->getParts() + ]; + } + } + + $note = ''; + if ($vcard->NOTE) { + $note = (string)$vcard->NOTE; + } + + $cards[] = [ + 'id' => $object['id'], + 'uri' => $object['uri'], + 'photo' => $photo, + 'fn' => $fn, + 'org' => $org, + 'title' => $title, + 'tels' => $tels, + 'emails' => $emails, + 'impps' => $impps, + 'urls' => $urls, + 'adrs' => $adrs, + 'note' => $note + ]; + } + + usort($cards, function ($a, $b) { + return strcasecmp($a['fn'], $b['fn']); + }); + } + + $o .= replace_macros(get_markup_template('cdav_addressbook.tpl'), [ + '$id' => $id, + '$cards' => $cards, + '$displayname' => $displayname, + '$name_label' => t('Name'), + '$org_label' => t('Organisation'), + '$title_label' => t('Title'), + '$tel_label' => t('Phone'), + '$email_label' => t('Email'), + '$impp_label' => t('Instant messenger'), + '$url_label' => t('Website'), + '$adr_label' => t('Address'), + '$note_label' => t('Note'), + '$mobile' => t('Mobile'), + '$home' => t('Home'), + '$work' => t('Work'), + '$other' => t('Other'), + '$add_card' => t('Add Contact'), + '$add_field' => t('Add Field'), + '$create' => t('Create'), + '$update' => t('Update'), + '$delete' => t('Delete'), + '$cancel' => t('Cancel'), + '$po_box' => t('P.O. Box'), + '$extra' => t('Additional'), + '$street' => t('Street'), + '$locality' => t('Locality'), + '$region' => t('Region'), + '$zip_code' => t('ZIP Code'), + '$country' => t('Country') + ]); + + return $o; + } + + // delete addressbook + if (argc() > 3 && argv(1) === 'addressbook' && argv(2) === 'drop' && intval(argv(3))) { + $id = argv(3); + + if (!cdav_perms($id, $addressbooks)) { + return; + } + + $carddavBackend->deleteAddressBook($id); + killme(); + } + + } + + public function activate($pdo, $channel) + { + + if (!$channel) { + return; + } + + $uri = 'principals/' . $channel['channel_address']; + + + $r = q("select * from principals where uri = '%s' limit 1", + dbesc($uri) + ); + if ($r) { + $r = q("update principals set email = '%s', displayname = '%s' where uri = '%s' ", + dbesc($channel['xchan_addr']), + dbesc($channel['channel_name']), + dbesc($uri) + ); + } else { + $r = q("insert into principals ( uri, email, displayname ) values('%s','%s','%s') ", + dbesc($uri), + dbesc($channel['xchan_addr']), + dbesc($channel['channel_name']) + ); + + // create default calendar + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $properties = [ + '{DAV:}displayname' => t('Default Calendar'), + '{http://apple.com/ns/ical/}calendar-color' => '#6cad39', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => $channel['channel_name'] + ]; + + $id = $caldavBackend->createCalendar($uri, 'default', $properties); + set_pconfig(local_channel(), 'cdav_calendar', $id[0], 1); + set_pconfig(local_channel(), 'cdav_calendar', 'calendar', 1); + + // create default addressbook + $carddavBackend = new PDO($pdo); + $properties = ['{DAV:}displayname' => t('Default Addressbook')]; + $carddavBackend->createAddressBook($uri, 'default', $properties); + + } + } } diff --git a/Zotlabs/Module/Changeaddr.php b/Zotlabs/Module/Changeaddr.php index 3ab6495b0..e79b6f9bc 100644 --- a/Zotlabs/Module/Changeaddr.php +++ b/Zotlabs/Module/Changeaddr.php @@ -10,103 +10,106 @@ use Zotlabs\Web\Controller; * Provided for those situations which require it. * Must be manually configured by the admin before use. */ - - -class Changeaddr extends Controller { - - function post() { - - if (! get_config('system','allow_nick_change')) { - return; - } - - if (! local_channel()) { - return; - } - - if (isset($_SESSION['delegate']) && $_SESSION['delegate']) { - return; - } - - if ((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password'])))) - return; - - if ((! x($_POST,'verify')) || (! strlen(trim($_POST['verify'])))) - return; - - if ($_POST['verify'] !== $_SESSION['remove_account_verify']) - return; - - - $account = App::get_account(); - $channel = App::get_channel(); - - $x = account_verify_password($account['account_email'],$_POST['qxz_password']); - if (! ($x && $x['account'])) { - return; - } - - if ($account['account_password_changed'] > NULL_DATE) { - $d1 = datetime_convert('UTC','UTC','now - 48 hours'); - if ($account['account_password_changed'] > $d1) { - notice( t('Channel name changes are not allowed within 48 hours of changing the account password.') . EOL); - return; - } - } - - $new_address = trim($_POST['newname']); - - if ($new_address === $channel['channel_address']) - return; - - if ($new_address === 'sys') { - notice( t('Reserved nickname. Please choose another.') . EOL); - return; - } - - if (check_webbie(array($new_address)) !== $new_address) { - notice( t('Nickname has unsupported characters or is already being used on this site.') . EOL); - return $ret; - } - - channel_change_address($channel,$new_address); - - goaway(z_root() . '/changeaddr'); - - } - - - function get() { - - if (! get_config('system','allow_nick_change')) { - notice(t('Feature has been disabled') . EOL); - return; - } - if (! local_channel()) { - goaway(z_root()); - } - - $channel = App::get_channel(); +class Changeaddr extends Controller +{ + + public function post() + { + + if (!get_config('system', 'allow_nick_change')) { + return; + } + + if (!local_channel()) { + return; + } + + if (isset($_SESSION['delegate']) && $_SESSION['delegate']) { + return; + } + + if ((!x($_POST, 'qxz_password')) || (!strlen(trim($_POST['qxz_password'])))) + return; + + if ((!x($_POST, 'verify')) || (!strlen(trim($_POST['verify'])))) + return; + + if ($_POST['verify'] !== $_SESSION['remove_account_verify']) + return; + + + $account = App::get_account(); + $channel = App::get_channel(); + + $x = account_verify_password($account['account_email'], $_POST['qxz_password']); + if (!($x && $x['account'])) { + return; + } + + if ($account['account_password_changed'] > NULL_DATE) { + $d1 = datetime_convert('UTC', 'UTC', 'now - 48 hours'); + if ($account['account_password_changed'] > $d1) { + notice(t('Channel name changes are not allowed within 48 hours of changing the account password.') . EOL); + return; + } + } + + $new_address = trim($_POST['newname']); + + if ($new_address === $channel['channel_address']) + return; + + if ($new_address === 'sys') { + notice(t('Reserved nickname. Please choose another.') . EOL); + return; + } + + if (check_webbie(array($new_address)) !== $new_address) { + notice(t('Nickname has unsupported characters or is already being used on this site.') . EOL); + return $ret; + } + + channel_change_address($channel, $new_address); + + goaway(z_root() . '/changeaddr'); + + } + + + public function get() + { + + if (!get_config('system', 'allow_nick_change')) { + notice(t('Feature has been disabled') . EOL); + return; + } + + + if (!local_channel()) { + goaway(z_root()); + } + + $channel = App::get_channel(); + + $hash = random_string(); + + $_SESSION['remove_account_verify'] = $hash; + + $tpl = get_markup_template('channel_rename.tpl'); + $o .= replace_macros($tpl, [ + '$basedir' => z_root(), + '$hash' => $hash, + '$title' => t('Change channel nickname/address'), + '$desc' => array(t('WARNING: '), t('Any/all connections on other networks will be lost!')), + '$passwd' => t('Please enter your password for verification:'), + '$newname' => ['newname', t('New channel address'), $channel['channel_address'], ''], + '$submit' => t('Rename Channel') + ]); + + return $o; + + } - $hash = random_string(); - - $_SESSION['remove_account_verify'] = $hash; - - $tpl = get_markup_template('channel_rename.tpl'); - $o .= replace_macros($tpl, [ - '$basedir' => z_root(), - '$hash' => $hash, - '$title' => t('Change channel nickname/address'), - '$desc' => array(t('WARNING: '), t('Any/all connections on other networks will be lost!')), - '$passwd' => t('Please enter your password for verification:'), - '$newname' => [ 'newname', t('New channel address'),$channel['channel_address'], ''], - '$submit' => t('Rename Channel') - ]); - - return $o; - - } - } diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php index c4f9b37f9..8cd0994cf 100644 --- a/Zotlabs/Module/Channel.php +++ b/Zotlabs/Module/Channel.php @@ -26,605 +26,591 @@ require_once('include/acl_selectors.php'); * @brief Channel Controller * */ +class Channel extends Controller +{ -class Channel extends Controller { + // State passed in from the Update module. - // State passed in from the Update module. - - public $profile_uid = 0; - public $loading = 0; - public $updating = 0; + public $profile_uid = 0; + public $loading = 0; + public $updating = 0; - function init() { + public function init() + { - if (isset($_GET['search']) && (in_array(substr($_GET['search'],0,1),[ '@', '!', '?']) || strpos($_GET['search'],'https://') === 0)) { - goaway(z_root() . '/search' . '?f=&search=' . urlencode($_GET['search'])); - } + if (isset($_GET['search']) && (in_array(substr($_GET['search'], 0, 1), ['@', '!', '?']) || strpos($_GET['search'], 'https://') === 0)) { + goaway(z_root() . '/search' . '?f=&search=' . urlencode($_GET['search'])); + } - $which = null; - if (argc() > 1) { - $which = argv(1); - } - if (! $which) { - if (local_channel()) { - $channel = App::get_channel(); - if ($channel && $channel['channel_address']) { - $which = $channel['channel_address']; - } - } - } - if (! $which) { - notice( t('You must be logged in to see this page.') . EOL ); - return; - } + $which = null; + if (argc() > 1) { + $which = argv(1); + } + if (!$which) { + if (local_channel()) { + $channel = App::get_channel(); + if ($channel && $channel['channel_address']) { + $which = $channel['channel_address']; + } + } + } + if (!$which) { + notice(t('You must be logged in to see this page.') . EOL); + return; + } - $profile = 0; - $channel = App::get_channel(); + $profile = 0; + $channel = App::get_channel(); - if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { - $which = $channel['channel_address']; - $profile = argv(1); - } + if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + } - $channel = channelx_by_nick($which, true); - if (! $channel) { - http_status_exit(404, 'Not found'); - } - if ($channel['channel_removed']) { - http_status_exit(410,'Gone'); - } + $channel = channelx_by_nick($which, true); + if (!$channel) { + http_status_exit(404, 'Not found'); + } + if ($channel['channel_removed']) { + http_status_exit(410, 'Gone'); + } - if (get_pconfig($channel['channel_id'],'system','noindex')) { - App::$meta->set('robots', 'noindex, noarchive'); - } + if (get_pconfig($channel['channel_id'], 'system', 'noindex')) { + App::$meta->set('robots', 'noindex, noarchive'); + } - head_add_link( [ - 'rel' => 'alternate', - 'type' => 'application/atom+xml', - 'title' => t('Only posts'), - 'href' => z_root() . '/feed/' . $which - ]); - - - - // An ActivityStreams actor record is more or less required for ActivityStreams compliance - // unless the actor object is inlined into every activity/object. This implies that it - // is more or less required for the Zot6 protocol, which uses ActivityStreams as a content - // serialisation and which doesn't always include the full actor record with every - // activity/object. - - // "more or less" means it isn't spelled out in the ActivityStreams spec, but a number of - // things will break in subtle ways if it isn't provided. - - // The ActivityPub protocol requires an 'inbox', which will not be present in this record - // if/when the ActivityPub protocol is disabled. This will be the case when using the Redmatrix - // fork of Zap; which disables ActivityPub connectivity by default. - - if (ActivityStreams::is_as_request()) { - - // Somebody may attempt an ActivityStreams fetch on one of our message permalinks - // Make it do the right thing. - - $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : ''); - $mid = unpack_link_id($mid); - - if ($mid) { - $obj = null; - if (strpos($mid, z_root() . '/item/') === 0) { - App::$argc = 2; - App::$argv = [ 'item', basename($mid) ]; - $obj = new Item(); - } - if (strpos($mid, z_root() . '/activity/') === 0) { - App::$argc = 2; - App::$argv = [ 'activity', basename($mid) ]; - $obj = new Activity(); - } - if ($obj) { - $obj->init(); - } - } - if (intval($channel['channel_system'])) { - goaway(z_root()); - } - as_return_and_die(Activity::encode_person($channel,true,true),$channel); - } - - // handle zot6 channel discovery - - if(Libzot::is_zot_request()) { - - $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); - - if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { - $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer'] ])); - $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($sigdata['signer']) - ); - - if($s && $s[0]['hubloc_sitekey'] && $s[0]['site_crypto']) { - $data = json_encode(Crypto::encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto']))); - } - } - else { - $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'] ])); - } - - $headers = [ - 'Content-Type' => 'application/x-zot+json', - 'Digest' => HTTPSig::generate_digest_header($data), - '(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'] - ]; - $h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel)); - HTTPSig::set_headers($h); - echo $data; - killme(); - } + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/atom+xml', + 'title' => t('Only posts'), + 'href' => z_root() . '/feed/' . $which + ]); - // Run Libprofile::load() here to make sure the theme is set before - // we start loading content + // An ActivityStreams actor record is more or less required for ActivityStreams compliance + // unless the actor object is inlined into every activity/object. This implies that it + // is more or less required for the Zot6 protocol, which uses ActivityStreams as a content + // serialisation and which doesn't always include the full actor record with every + // activity/object. - Libprofile::load($which,$profile); + // "more or less" means it isn't spelled out in the ActivityStreams spec, but a number of + // things will break in subtle ways if it isn't provided. - if (! $_REQUEST['mid']) { + // The ActivityPub protocol requires an 'inbox', which will not be present in this record + // if/when the ActivityPub protocol is disabled. This will be the case when using the Redmatrix + // fork of Zap; which disables ActivityPub connectivity by default. - App::$meta->set('og:title', $channel['channel_name']); - App::$meta->set('og:image', $channel['xchan_photo_l']); - App::$meta->set('og:type','webpage'); - App::$meta->set('og:url:secure_url', channel_url($channel)); - if(App::$profile['about'] && perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_profile')) { - App::$meta->set('og:description', App::$profile['about']); - } - else { - App::$meta->set('og:description', sprintf( t('This is the home page of %s.'), $channel['channel_name'])); - } - } - } + if (ActivityStreams::is_as_request()) { - function get() { + // Somebody may attempt an ActivityStreams fetch on one of our message permalinks + // Make it do the right thing. - $noscript_content = get_config('system', 'noscript_content', '1'); + $mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : ''); + $mid = unpack_link_id($mid); - $category = $datequery = $datequery2 = ''; + if ($mid) { + $obj = null; + if (strpos($mid, z_root() . '/item/') === 0) { + App::$argc = 2; + App::$argv = ['item', basename($mid)]; + $obj = new Item(); + } + if (strpos($mid, z_root() . '/activity/') === 0) { + App::$argc = 2; + App::$argv = ['activity', basename($mid)]; + $obj = new Activity(); + } + if ($obj) { + $obj->init(); + } + } + if (intval($channel['channel_system'])) { + goaway(z_root()); + } + as_return_and_die(Activity::encode_person($channel, true, true), $channel); + } - $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : ''); - $mid = unpack_link_id($mid); + // handle zot6 channel discovery - $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); - $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); + if (Libzot::is_zot_request()) { - if(observer_prohibited(true)) { - return login(); - } + $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); - $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); - $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : ''); - $order = ((x($_GET,'order')) ? notags($_GET['order']) : 'post'); - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - $search = ((x($_GET,'search')) ? $_GET['search'] : EMPTY_STR); + if ($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { + $data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer']])); + $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($sigdata['signer']) + ); - $groups = []; + if ($s && $s[0]['hubloc_sitekey'] && $s[0]['site_crypto']) { + $data = json_encode(Crypto::encapsulate($data, $s[0]['hubloc_sitekey'], Libzot::best_algorithm($s[0]['site_crypto']))); + } + } else { + $data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash']])); + } - $o = ''; - - if($this->updating) { - // Ensure we've got a profile owner if updating. - App::$profile['profile_uid'] = App::$profile_uid = $this->profile_uid; - } - - $is_owner = (((local_channel()) && (App::$profile['profile_uid'] == local_channel())) ? true : false); - - $channel = App::get_channel(); - $observer = App::get_observer(); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - - $perms = get_all_perms(App::$profile['profile_uid'],$ob_hash); + $headers = [ + 'Content-Type' => 'application/x-zot+json', + 'Digest' => HTTPSig::generate_digest_header($data), + '(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'] + ]; + $h = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel)); + HTTPSig::set_headers($h); + echo $data; + killme(); + } - if ($this->loading && ! $mid) { + // Run Libprofile::load() here to make sure the theme is set before + // we start loading content - $_SESSION['loadtime_channel'] = datetime_convert(); - if ($is_owner) { - PConfig::Set(local_channel(),'system','loadtime_channel',$_SESSION['loadtime_channel']); - } - } + Libprofile::load($which, $profile); + + if (!$_REQUEST['mid']) { + + App::$meta->set('og:title', $channel['channel_name']); + App::$meta->set('og:image', $channel['xchan_photo_l']); + App::$meta->set('og:type', 'webpage'); + App::$meta->set('og:url:secure_url', channel_url($channel)); + if (App::$profile['about'] && perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_profile')) { + App::$meta->set('og:description', App::$profile['about']); + } else { + App::$meta->set('og:description', sprintf(t('This is the home page of %s.'), $channel['channel_name'])); + } + } + } + + public function get() + { + + $noscript_content = get_config('system', 'noscript_content', '1'); + + $category = $datequery = $datequery2 = ''; + + $mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : ''); + $mid = unpack_link_id($mid); + + $datequery = ((x($_GET, 'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); + $datequery2 = ((x($_GET, 'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); + + if (observer_prohibited(true)) { + return login(); + } + + $category = ((x($_REQUEST, 'cat')) ? $_REQUEST['cat'] : ''); + $hashtags = ((x($_REQUEST, 'tag')) ? $_REQUEST['tag'] : ''); + $order = ((x($_GET, 'order')) ? notags($_GET['order']) : 'post'); + $static = ((array_key_exists('static', $_REQUEST)) ? intval($_REQUEST['static']) : 0); + $search = ((x($_GET, 'search')) ? $_GET['search'] : EMPTY_STR); + + $groups = []; + + $o = ''; + + if ($this->updating) { + // Ensure we've got a profile owner if updating. + App::$profile['profile_uid'] = App::$profile_uid = $this->profile_uid; + } + + $is_owner = (((local_channel()) && (App::$profile['profile_uid'] == local_channel())) ? true : false); + + $channel = App::get_channel(); + $observer = App::get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms(App::$profile['profile_uid'], $ob_hash); + if ($this->loading && !$mid) { - if(! $perms['view_stream']) { - // We may want to make the target of this redirect configurable - if($perms['view_profile']) { - notice( t('Insufficient permissions. Request redirected to profile page.') . EOL); - goaway (z_root() . "/profile/" . App::$profile['channel_address']); - } - notice( t('Permission denied.') . EOL); - return; - } + $_SESSION['loadtime_channel'] = datetime_convert(); + if ($is_owner) { + PConfig::Set(local_channel(), 'system', 'loadtime_channel', $_SESSION['loadtime_channel']); + } + } - if(! $this->updating) { - - nav_set_selected('Channel Home'); - - $static = channel_manual_conv_update(App::$profile['profile_uid']); - - // search terms header - if($search) { - $o .= replace_macros(get_markup_template("section_title.tpl"),array( - '$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8') - )); - } - - $role = get_pconfig(App::$profile['profile_uid'],'system','permissions_role'); - if ($role === 'social_restricted' && (! $ob_hash)) { - // provide warning that content is probably hidden ? - } - - if($channel && $is_owner) { - $channel_acl = array( - 'allow_cid' => $channel['channel_allow_cid'], - 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ); - } - else { - $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; - } + if (!$perms['view_stream']) { + // We may want to make the target of this redirect configurable + if ($perms['view_profile']) { + notice(t('Insufficient permissions. Request redirected to profile page.') . EOL); + goaway(z_root() . "/profile/" . App::$profile['channel_address']); + } + notice(t('Permission denied.') . EOL); + return; + } - if($perms['post_wall']) { + if (!$this->updating) { - $x = array( - 'is_owner' => $is_owner, - 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(App::$profile['profile_uid'],'system','use_browser_location')))) ? true : false), - 'default_location' => (($is_owner) ? App::$profile['channel_location'] : ''), - 'nickname' => App::$profile['channel_address'], - 'lockstate' => (((strlen(App::$profile['channel_allow_cid'])) || (strlen(App::$profile['channel_allow_gid'])) || (strlen(App::$profile['channel_deny_cid'])) || (strlen(App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'), - 'acl' => (($is_owner) ? populate_acl($channel_acl,true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''), - 'permissions' => $channel_acl, - 'showacl' => (($is_owner) ? 'yes' : ''), - 'bang' => '', - 'visitor' => (($is_owner || $observer) ? true : false), - 'profile_uid' => App::$profile['profile_uid'], - 'editor_autocomplete' => true, - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true, - 'jotnets' => true, - 'reset' => t('Reset form') - ); + nav_set_selected('Channel Home'); - $o .= status_editor($x); - } + $static = channel_manual_conv_update(App::$profile['profile_uid']); - if (! $mid && ! $search) { - $obj = new Pinned; - $o .= $obj->widget([]); - } - } + // search terms header + if ($search) { + $o .= replace_macros(get_markup_template("section_title.tpl"), array( + '$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT, 'UTF-8') + )); + } + + $role = get_pconfig(App::$profile['profile_uid'], 'system', 'permissions_role'); + if ($role === 'social_restricted' && (!$ob_hash)) { + // provide warning that content is probably hidden ? + } + + if ($channel && $is_owner) { + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + } else { + $channel_acl = ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']; + } - /** - * Get permissions SQL - */ - - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0 + if ($perms['post_wall']) { + + $x = array( + 'is_owner' => $is_owner, + 'allow_location' => ((($is_owner || $observer) && (intval(get_pconfig(App::$profile['profile_uid'], 'system', 'use_browser_location')))) ? true : false), + 'default_location' => (($is_owner) ? App::$profile['channel_location'] : ''), + 'nickname' => App::$profile['channel_address'], + 'lockstate' => (((strlen(App::$profile['channel_allow_cid'])) || (strlen(App::$profile['channel_allow_gid'])) || (strlen(App::$profile['channel_deny_cid'])) || (strlen(App::$profile['channel_deny_gid']))) ? 'lock' : 'unlock'), + 'acl' => (($is_owner) ? populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post') : ''), + 'permissions' => $channel_acl, + 'showacl' => (($is_owner) ? 'yes' : ''), + 'bang' => '', + 'visitor' => (($is_owner || $observer) ? true : false), + 'profile_uid' => App::$profile['profile_uid'], + 'editor_autocomplete' => true, + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true, + 'jotnets' => true, + 'reset' => t('Reset form') + ); + + $o .= status_editor($x); + } + + if (!$mid && !$search) { + $obj = new Pinned(); + $o .= $obj->widget([]); + } + } + + + /** + * Get permissions SQL + */ + + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_pending_remove = 0 and item.item_blocked = 0 "; - if (! $is_owner) - $item_normal .= "and item.item_delayed = 0 "; - $item_normal_update = item_normal_update(); - $sql_extra = item_permissions_sql(App::$profile['profile_uid']); + if (!$is_owner) + $item_normal .= "and item.item_delayed = 0 "; + $item_normal_update = item_normal_update(); + $sql_extra = item_permissions_sql(App::$profile['profile_uid']); - if (get_pconfig(App::$profile['profile_uid'],'system','channel_list_mode') && (! $mid)) { - $page_mode = 'list'; - } - else { - $page_mode = 'client'; - } - - $abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " "; + if (get_pconfig(App::$profile['profile_uid'], 'system', 'channel_list_mode') && (!$mid)) { + $page_mode = 'list'; + } else { + $page_mode = 'client'; + } - $simple_update = (($this->updating) ? " AND item_unseen = 1 " : ''); + $abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " "; - if ($search) { - $search = escape_tags($search); - if(strpos($search,'#') === 0) { - $sql_extra .= term_query('item',substr($search,1),TERM_HASHTAG,TERM_COMMUNITYTAG); - } - else { - $sql_extra .= sprintf(" AND (item.body like '%s' OR item.title like '%s') ", - dbesc(protect_sprintf('%' . $search . '%')), - dbesc(protect_sprintf('%' . $search . '%')) - ); - } - } + $simple_update = (($this->updating) ? " AND item_unseen = 1 " : ''); + + if ($search) { + $search = escape_tags($search); + if (strpos($search, '#') === 0) { + $sql_extra .= term_query('item', substr($search, 1), TERM_HASHTAG, TERM_COMMUNITYTAG); + } else { + $sql_extra .= sprintf(" AND (item.body like '%s' OR item.title like '%s') ", + dbesc(protect_sprintf('%' . $search . '%')), + dbesc(protect_sprintf('%' . $search . '%')) + ); + } + } - head_add_link([ - 'rel' => 'alternate', - 'type' => 'application/json+oembed', - 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), - 'title' => 'oembed' - ]); + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), + 'title' => 'oembed' + ]); - if ($this->updating && isset($_SESSION['loadtime_channel'])) { - $simple_update = " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime_channel']) . "' "; - } - if ($this->loading) { - $simple_update = ''; - } - - if ($static && $simple_update) { - $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - } - - if (($this->updating) && (! $this->loading)) { - if ($mid) { - $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal_update + if ($this->updating && isset($_SESSION['loadtime_channel'])) { + $simple_update = " AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime_channel']) . "' "; + } + if ($this->loading) { + $simple_update = ''; + } + + if ($static && $simple_update) { + $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + } + + if (($this->updating) && (!$this->loading)) { + if ($mid) { + $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal_update AND item_wall = 1 $simple_update $sql_extra limit 1", - dbesc($mid . '%'), - intval(App::$profile['profile_uid']) - ); - } - else { - $r = q("SELECT parent AS item_id from item + dbesc($mid . '%'), + intval(App::$profile['profile_uid']) + ); + } else { + $r = q("SELECT parent AS item_id from item left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) WHERE uid = %d $item_normal_update AND item_wall = 1 $simple_update AND (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra ORDER BY created DESC", - intval(App::$profile['profile_uid']) - ); - } - } - else { + intval(App::$profile['profile_uid']) + ); + } + } else { - if (x($category)) { - $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $category, TERM_CATEGORY)); - } - if (x($hashtags)) { - $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'],'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); - } + if (x($category)) { + $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $category, TERM_CATEGORY)); + } + if (x($hashtags)) { + $sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); + } - if ($datequery) { - $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery)))); - $order = 'post'; - } - if ($datequery2) { - $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2)))); - } + if ($datequery) { + $sql_extra2 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery)))); + $order = 'post'; + } + if ($datequery2) { + $sql_extra2 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery2)))); + } - if ($datequery || $datequery2) { - $sql_extra2 .= " and item.item_thread_top != 0 "; - } + if ($datequery || $datequery2) { + $sql_extra2 .= " and item.item_thread_top != 0 "; + } - if ($order === 'post') { - $ordering = "created"; - } - else { - $ordering = "commented"; - } + if ($order === 'post') { + $ordering = "created"; + } else { + $ordering = "commented"; + } - $itemspage = get_pconfig(local_channel(),'system','itemspage'); - App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + $itemspage = get_pconfig(local_channel(), 'system', 'itemspage'); + App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - if ($noscript_content || $this->loading) { - if ($mid) { - $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal + if ($noscript_content || $this->loading) { + if ($mid) { + $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal AND item_wall = 1 $sql_extra limit 1", - dbesc($mid . '%'), - intval(App::$profile['profile_uid']) - ); - if (! $r) { - notice( t('Permission denied.') . EOL); - } - } - else { - $r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item + dbesc($mid . '%'), + intval(App::$profile['profile_uid']) + ); + if (!$r) { + notice(t('Permission denied.') . EOL); + } + } else { + $r = q("SELECT DISTINCT item.parent AS item_id, $ordering FROM item left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids ) WHERE true and item.uid = %d $item_normal AND (abook.abook_blocked = 0 or abook.abook_flags is null) AND item.item_wall = 1 AND item.item_thread_top = 1 $sql_extra $sql_extra2 ORDER BY $ordering DESC $pager_sql ", - intval(App::$profile['profile_uid']) - ); - } - } - else { - $r = []; - } - } - if ($r) { + intval(App::$profile['profile_uid']) + ); + } + } else { + $r = []; + } + } + if ($r) { - $parents_str = ids_to_querystr($r,'item_id'); + $parents_str = ids_to_querystr($r, 'item_id'); - $items = q("SELECT item.*, item.id AS item_id + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.uid = %d $item_normal AND item.parent IN ( %s ) $sql_extra ", - intval(App::$profile['profile_uid']), - dbesc($parents_str) - ); + intval(App::$profile['profile_uid']), + dbesc($parents_str) + ); - xchan_query($items); - $items = fetch_post_tags($items, true); - $items = conv_sort($items,$ordering); + xchan_query($items); + $items = fetch_post_tags($items, true); + $items = conv_sort($items, $ordering); - if ($this->loading && $mid && (! count($items))) { - // This will happen if we don't have sufficient permissions - // to view the parent item (or the item itself if it is toplevel) - notice( t('Permission denied.') . EOL); - } + if ($this->loading && $mid && (!count($items))) { + // This will happen if we don't have sufficient permissions + // to view the parent item (or the item itself if it is toplevel) + notice(t('Permission denied.') . EOL); + } - } - else { - $items = []; - } + } else { + $items = []; + } - if ((! $this->updating) && (! $this->loading)) { + if ((!$this->updating) && (!$this->loading)) { - // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, - // because browser prefetching might change it on us. We have to deliver it with the page. + // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, + // because browser prefetching might change it on us. We have to deliver it with the page. - $maxheight = get_pconfig(App::$profile['profile_uid'],'system','channel_divmore_height'); - if(! $maxheight) - $maxheight = 400; + $maxheight = get_pconfig(App::$profile['profile_uid'], 'system', 'channel_divmore_height'); + if (!$maxheight) + $maxheight = 400; - $o .= '
        ' . "\r\n"; - $o .= "\r\n"; + $o .= '
        ' . "\r\n"; + $o .= "\r\n"; - App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( - '$baseurl' => z_root(), - '$pgtype' => 'channel', - '$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'), - '$gid' => '0', - '$cid' => '0', - '$cmin' => '(-1)', - '$cmax' => '(-1)', - '$star' => '0', - '$liked' => '0', - '$conv' => '0', - '$spam' => '0', - '$nouveau' => '0', - '$wall' => '1', - '$draft' => '0', - '$fh' => '0', - '$dm' => '0', - '$static' => $static, - '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), - '$search' => $search, - '$xchan' => '', - '$order' => (($order) ? urlencode($order) : ''), - '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), - '$file' => '', - '$cats' => (($category) ? urlencode($category) : ''), - '$tags' => (($hashtags) ? urlencode($hashtags) : ''), - '$mid' => (($mid) ? urlencode($mid) : ''), - '$verb' => '', - '$net' => '', - '$dend' => $datequery, - '$dbegin' => $datequery2 - )); + App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), array( + '$baseurl' => z_root(), + '$pgtype' => 'channel', + '$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '(-1)', + '$cmax' => '(-1)', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$nouveau' => '0', + '$wall' => '1', + '$draft' => '0', + '$fh' => '0', + '$dm' => '0', + '$static' => $static, + '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), + '$search' => $search, + '$xchan' => '', + '$order' => (($order) ? urlencode($order) : ''), + '$list' => ((x($_REQUEST, 'list')) ? intval($_REQUEST['list']) : 0), + '$file' => '', + '$cats' => (($category) ? urlencode($category) : ''), + '$tags' => (($hashtags) ? urlencode($hashtags) : ''), + '$mid' => (($mid) ? urlencode($mid) : ''), + '$verb' => '', + '$net' => '', + '$dend' => $datequery, + '$dbegin' => $datequery2 + )); - } + } - $update_unseen = ''; + $update_unseen = ''; - if ($page_mode === 'list') { + if ($page_mode === 'list') { - /** - * in "list mode", only mark the parent item and any like activities as "seen". - * We won't distinguish between comment likes and post likes. The important thing - * is that the number of unseen comments will be accurate. The SQL to separate the - * comment likes could also get somewhat hairy. - */ + /** + * in "list mode", only mark the parent item and any like activities as "seen". + * We won't distinguish between comment likes and post likes. The important thing + * is that the number of unseen comments will be accurate. The SQL to separate the + * comment likes could also get somewhat hairy. + */ - if (isset($parents_str) && $parents_str) { - $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; - $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; - } - } - else { - if (isset($parents_str) && $parents_str) { - $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; - } - } + if (isset($parents_str) && $parents_str) { + $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; + $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; + } + } else { + if (isset($parents_str) && $parents_str) { + $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; + } + } - if ($is_owner && $update_unseen && (! $_SESSION['sudo'])) { - $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ]; - call_hooks('update_unseen',$x); - if ($x['update'] === 'unset' || intval($x['update'])) { - $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen", - intval(local_channel()) - ); - } + if ($is_owner && $update_unseen && (!$_SESSION['sudo'])) { + $x = ['channel_id' => local_channel(), 'update' => 'unset']; + call_hooks('update_unseen', $x); + if ($x['update'] === 'unset' || intval($x['update'])) { + $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen", + intval(local_channel()) + ); + } - $ids = ids_to_array($items,'item_id'); - $seen = PConfig::Get(local_channel(),'system','seen_items'); - if (! $seen) { - $seen = []; - } - $seen = array_merge($ids,$seen); - PConfig::Set(local_channel(),'system','seen_items',$seen); - } + $ids = ids_to_array($items, 'item_id'); + $seen = PConfig::Get(local_channel(), 'system', 'seen_items'); + if (!$seen) { + $seen = []; + } + $seen = array_merge($ids, $seen); + PConfig::Set(local_channel(), 'system', 'seen_items', $seen); + } - $mode = (($search) ? 'search' : 'channel'); + $mode = (($search) ? 'search' : 'channel'); - if($this->updating) { - $o .= conversation($items,$mode,$this->updating,$page_mode); - } - else { + if ($this->updating) { + $o .= conversation($items, $mode, $this->updating, $page_mode); + } else { - $o .= ''; + $o .= ''; - $o .= conversation($items,$mode,$this->updating,$page_mode); + $o .= conversation($items, $mode, $this->updating, $page_mode); - if ($mid && $items[0]['title']) - App::$page['title'] = $items[0]['title'] . " - " . App::$page['title']; + if ($mid && $items[0]['title']) + App::$page['title'] = $items[0]['title'] . " - " . App::$page['title']; - } + } - // We reset $channel so that info can be obtained for unlogged visitors - $channel = channelx_by_n(App::$profile['profile_uid']); + // We reset $channel so that info can be obtained for unlogged visitors + $channel = channelx_by_n(App::$profile['profile_uid']); - if (isset($_REQUEST['mid']) && $_REQUEST['mid']) { + if (isset($_REQUEST['mid']) && $_REQUEST['mid']) { - if(preg_match("/\[[zi]mg(.*?)\]([^\[]+)/is", $items[0]['body'], $matches)) { - $ogimage = $matches[2]; - // Will we use og:image:type someday? We keep this just in case - // $ogimagetype = guess_image_type($ogimage); - } + if (preg_match("/\[[zi]mg(.*?)\]([^\[]+)/is", $items[0]['body'], $matches)) { + $ogimage = $matches[2]; + // Will we use og:image:type someday? We keep this just in case + // $ogimagetype = guess_image_type($ogimage); + } - // some work on post content to generate a description - // almost fully based on work done on Hubzilla by Max Kostikov - $ogdesc = $items[0]['body']; + // some work on post content to generate a description + // almost fully based on work done on Hubzilla by Max Kostikov + $ogdesc = $items[0]['body']; - $ogdesc = str_replace("#^[", "[", $ogdesc); + $ogdesc = str_replace("#^[", "[", $ogdesc); - $ogdesc = bbcode($ogdesc, [ 'tryoembed' => false ]); - $ogdesc = trim(html2plain($ogdesc, 0, true)); - $ogdesc = html_entity_decode($ogdesc, ENT_QUOTES, 'UTF-8'); + $ogdesc = bbcode($ogdesc, ['tryoembed' => false]); + $ogdesc = trim(html2plain($ogdesc, 0, true)); + $ogdesc = html_entity_decode($ogdesc, ENT_QUOTES, 'UTF-8'); - // remove all URLs - $ogdesc = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $ogdesc); + // remove all URLs + $ogdesc = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $ogdesc); - // shorten description - $ogdesc = substr($ogdesc, 0, 300); - $ogdesc = str_replace("\n", " ", $ogdesc); - while (strpos($ogdesc, " ") !== false) - $ogdesc = str_replace(" ", " ", $ogdesc); - $ogdesc = (strlen($ogdesc) < 298 ? $ogdesc : rtrim(substr($ogdesc, 0, strrpos($ogdesc, " ")), "?.,:;!-") . "..."); + // shorten description + $ogdesc = substr($ogdesc, 0, 300); + $ogdesc = str_replace("\n", " ", $ogdesc); + while (strpos($ogdesc, " ") !== false) + $ogdesc = str_replace(" ", " ", $ogdesc); + $ogdesc = (strlen($ogdesc) < 298 ? $ogdesc : rtrim(substr($ogdesc, 0, strrpos($ogdesc, " ")), "?.,:;!-") . "..."); - // we can now start loading content + // we can now start loading content - App::$meta->set('og:title', ($items[0]['title'] ? $items[0]['title'] : $channel['channel_name'])); - App::$meta->set('og:image', ($ogimage ? $ogimage : $channel['xchan_photo_l'])); - App::$meta->set('og:type', 'article'); - App::$meta->set('og:url:secure_url', channel_url($channel)); - App::$meta->set('og:description', ($ogdesc ? $ogdesc : sprintf( t('This post was published on the home page of %s.'), $channel['channel_name']))); - } + App::$meta->set('og:title', ($items[0]['title'] ? $items[0]['title'] : $channel['channel_name'])); + App::$meta->set('og:image', ($ogimage ? $ogimage : $channel['xchan_photo_l'])); + App::$meta->set('og:type', 'article'); + App::$meta->set('og:url:secure_url', channel_url($channel)); + App::$meta->set('og:description', ($ogdesc ? $ogdesc : sprintf(t('This post was published on the home page of %s.'), $channel['channel_name']))); + } - if ($mid) { - $o .= '
        '; - } + if ($mid) { + $o .= '
        '; + } - return $o; - } + return $o; + } } diff --git a/Zotlabs/Module/Chanview.php b/Zotlabs/Module/Chanview.php index d55397545..4d77a81bd 100644 --- a/Zotlabs/Module/Chanview.php +++ b/Zotlabs/Module/Chanview.php @@ -7,171 +7,170 @@ use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Webfinger; use Zotlabs\Lib\Activity; -class Chanview extends Controller { +class Chanview extends Controller +{ - function get() { - - $observer = App::get_observer(); - $xchan = null; - - $r = null; - - if ($_REQUEST['hash']) { - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($_REQUEST['hash']) - ); - } - if ($_REQUEST['address']) { - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc(punify($_REQUEST['address'])) - ); - } - elseif (local_channel() && intval($_REQUEST['cid'])) { - $r = q("SELECT abook.*, xchan.* + public function get() + { + + $observer = App::get_observer(); + $xchan = null; + + $r = null; + + if ($_REQUEST['hash']) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($_REQUEST['hash']) + ); + } + if ($_REQUEST['address']) { + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc(punify($_REQUEST['address'])) + ); + } elseif (local_channel() && intval($_REQUEST['cid'])) { + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_channel()), - intval($_REQUEST['cid']) - ); - } - elseif ($_REQUEST['url']) { - - // if somebody re-installed they will have more than one xchan, use the most recent name date as this is - // the most useful consistently ascending table item we have. - - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_url = '%s' or hubloc_id_url = '%s' order by xchan_name_date desc limit 1", - dbesc($_REQUEST['url']), - dbesc($_REQUEST['url']) - ); - } - if ($r) { - App::$poi = array_shift($r); - } - - // Here, let's see if we have an xchan. If we don't, how we proceed is determined by what - // info we do have. If it's a URL, we can offer to visit it directly. If it's a webbie or - // address, we can and should try to import it. If it's just a hash, we can't continue, but we - // probably wouldn't have a hash if we don't already have an xchan for this channel. - - if (! App::$poi) { - logger('mod_chanview: fallback'); - // This is hackish - construct a zot address from the url - if ($_REQUEST['url']) { - if (preg_match('/https?\:\/\/(.*?)(\/channel\/|\/profile\/)(.*?)$/ism',$_REQUEST['url'],$matches)) { - $_REQUEST['address'] = $matches[3] . '@' . $matches[1]; - } - logger('mod_chanview: constructed address ' . print_r($matches,true)); - } + intval(local_channel()), + intval($_REQUEST['cid']) + ); + } elseif ($_REQUEST['url']) { - $r = null; + // if somebody re-installed they will have more than one xchan, use the most recent name date as this is + // the most useful consistently ascending table item we have. - if ($_REQUEST['address']) { - $href = Webfinger::zot_url(punify($url)); - if ($href) { - $zf = Zotfinger::exec($href,$channel); - } - if (is_array($zf) && array_path_exists('signature/signer',$zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { - $xc = Libzot::import_xchan($zf['data']); - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc($_REQUEST['address']) - ); - if ($r) { - App::$poi = $r[0]; - } - } - if (! $r) { - if (discover_by_webbie($_REQUEST['address'])) { - $r = q("select * from xchan where xchan_addr = '%s' limit 1", - dbesc($_REQUEST['address']) - ); - if ($r) { - App::$poi = $r[0]; - } - } - } - } - } - - if (! App::$poi) { - notice( t('Channel not found.') . EOL); - return; - } + $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_url = '%s' or hubloc_id_url = '%s' order by xchan_name_date desc limit 1", + dbesc($_REQUEST['url']), + dbesc($_REQUEST['url']) + ); + } + if ($r) { + App::$poi = array_shift($r); + } - $is_zot = false; - $connected = false; - - $url = App::$poi['xchan_url']; - if (App::$poi['xchan_network'] === 'zot6') { - $is_zot = true; - } - if (local_channel()) { - $c = q("select abook_id, abook_pending from abook where abook_channel = %d and abook_xchan = '%s' limit 1", - intval(local_channel()), - dbesc(App::$poi['xchan_hash']) - ); - - // if somebody followed us and we want to find out more, start - // by viewing their publicly accessible information. - // Otherwise the primary use of this page is to provide a connect - // button for anybody in the fediverse - which doesn't have to ask - // you who you are. - - if ($c && intval($c[0]['abook_pending']) === 0) { - $connected = true; - } - } + // Here, let's see if we have an xchan. If we don't, how we proceed is determined by what + // info we do have. If it's a URL, we can offer to visit it directly. If it's a webbie or + // address, we can and should try to import it. If it's just a hash, we can't continue, but we + // probably wouldn't have a hash if we don't already have an xchan for this channel. - if ($is_zot && $observer) { - $url = zid($url); - } + if (!App::$poi) { + logger('mod_chanview: fallback'); + // This is hackish - construct a zot address from the url + if ($_REQUEST['url']) { + if (preg_match('/https?\:\/\/(.*?)(\/channel\/|\/profile\/)(.*?)$/ism', $_REQUEST['url'], $matches)) { + $_REQUEST['address'] = $matches[3] . '@' . $matches[1]; + } + logger('mod_chanview: constructed address ' . print_r($matches, true)); + } - // If we are already connected, just go to the profile. - - if ($connected) { - goaway($url); - } - else { + $r = null; - $about = false; - $xprof = q("select * from xprof where xprof_hash = '%s'", - dbesc(App::$poi['xchan_hash']) - ); - if ($xprof) { - $about = zidify_links(bbcode($xprof[0]['xprof_about'])); - } + if ($_REQUEST['address']) { + $href = Webfinger::zot_url(punify($url)); + if ($href) { + $zf = Zotfinger::exec($href, $channel); + } + if (is_array($zf) && array_path_exists('signature/signer', $zf) && $zf['signature']['signer'] === $href && intval($zf['signature']['header_valid'])) { + $xc = Libzot::import_xchan($zf['data']); + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc($_REQUEST['address']) + ); + if ($r) { + App::$poi = $r[0]; + } + } + if (!$r) { + if (discover_by_webbie($_REQUEST['address'])) { + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc($_REQUEST['address']) + ); + if ($r) { + App::$poi = $r[0]; + } + } + } + } + } - $followers = t('Not available'); - $following = t('Not available'); + if (!App::$poi) { + notice(t('Channel not found.') . EOL); + return; + } - $f = get_xconfig(App::$poi['xchan_hash'],'activitypub','collections'); - if ($f && isset($f['followers'])) { - $m = Activity::fetch($f['followers']); - if (is_array($m) && isset($m['totalItems'])) { - $followers = intval($m['totalItems']); - } - } - if ($f && isset($f['following'])) { - $m = Activity::fetch($f['following']); - if (is_array($m) && isset($m['totalItems'])) { - $following = intval($m['totalItems']); - } - } + $is_zot = false; + $connected = false; + + $url = App::$poi['xchan_url']; + if (App::$poi['xchan_network'] === 'zot6') { + $is_zot = true; + } + if (local_channel()) { + $c = q("select abook_id, abook_pending from abook where abook_channel = %d and abook_xchan = '%s' limit 1", + intval(local_channel()), + dbesc(App::$poi['xchan_hash']) + ); + + // if somebody followed us and we want to find out more, start + // by viewing their publicly accessible information. + // Otherwise the primary use of this page is to provide a connect + // button for anybody in the fediverse - which doesn't have to ask + // you who you are. + + if ($c && intval($c[0]['abook_pending']) === 0) { + $connected = true; + } + } + + if ($is_zot && $observer) { + $url = zid($url); + } + + // If we are already connected, just go to the profile. + + if ($connected) { + goaway($url); + } else { + + $about = false; + $xprof = q("select * from xprof where xprof_hash = '%s'", + dbesc(App::$poi['xchan_hash']) + ); + if ($xprof) { + $about = zidify_links(bbcode($xprof[0]['xprof_about'])); + } + + $followers = t('Not available'); + $following = t('Not available'); + + $f = get_xconfig(App::$poi['xchan_hash'], 'activitypub', 'collections'); + if ($f && isset($f['followers'])) { + $m = Activity::fetch($f['followers']); + if (is_array($m) && isset($m['totalItems'])) { + $followers = intval($m['totalItems']); + } + } + if ($f && isset($f['following'])) { + $m = Activity::fetch($f['following']); + if (is_array($m) && isset($m['totalItems'])) { + $following = intval($m['totalItems']); + } + } + + $o = replace_macros(get_markup_template('chanview.tpl'), [ + '$url' => $url, + '$photo' => get_xconfig(App::$poi['xchan_hash'], 'system', 'cover_photo'), + '$alt' => t('Cover photo for this channel'), + '$about' => $about, + '$followers_txt' => t('Followers'), + '$following_txt' => t('Following'), + '$followers' => $followers, + '$following' => $following, + '$visit' => t('Visit'), + '$full' => t('toggle full screen mode') + ]); + + return $o; + } + } - $o = replace_macros(get_markup_template('chanview.tpl'), [ - '$url' => $url, - '$photo' => get_xconfig(App::$poi['xchan_hash'],'system','cover_photo'), - '$alt' => t('Cover photo for this channel'), - '$about' => $about, - '$followers_txt' => t('Followers'), - '$following_txt' => t('Following'), - '$followers' => $followers, - '$following' => $following, - '$visit' => t('Visit'), - '$full' => t('toggle full screen mode') - ]); - - return $o; - } - } - } diff --git a/Zotlabs/Module/Chat.php b/Zotlabs/Module/Chat.php index 22ed3958b..633e790aa 100644 --- a/Zotlabs/Module/Chat.php +++ b/Zotlabs/Module/Chat.php @@ -10,82 +10,86 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Lib\Libprofile; use Zotlabs\Access\AccessControl; -class Chat extends Controller { +class Chat extends Controller +{ - function init() { - - $which = ((argc() > 1) ? argv(1) : null); - if (local_channel() && (! $which)) { - $channel = App::get_channel(); - if ($channel && $channel['channel_address']) { - $which = $channel['channel_address']; - } - } + public function init() + { - if (! $which) { - notice( t('You must be logged in to see this page.') . EOL ); - return; - } - - $profile = 0; - - // Run Libprofile::load() here to make sure the theme is set before - // we start loading content - - Libprofile::load($which,$profile); - - } - - function post() { - - if ($_POST['room_name']) { - $room = strip_tags(trim($_POST['room_name'])); - } - - if ((! $room) || (! local_channel())) { - return; - } - - $channel = App::get_channel(); - - if ($_POST['action'] === 'drop') { - logger('delete chatroom'); - Chatroom::destroy($channel, [ 'cr_name' => $room ] ); - goaway(z_root() . '/chat/' . $channel['channel_address']); - } - - $acl = new AccessControl($channel); - $acl->set_from_array($_REQUEST); - - $arr = $acl->get(); - $arr['name'] = $room; - $arr['expire'] = intval($_POST['chat_expire']); - if (intval($arr['expire']) < 0) { - $arr['expire'] = 0; - } - - Chatroom::create($channel,$arr); - - $x = q("select * from chatroom where cr_name = '%s' and cr_uid = %d limit 1", - dbesc($room), - intval(local_channel()) - ); - - Libsync::build_sync_packet(0, array('chatroom' => $x)); - - if ($x) { - goaway(z_root() . '/chat/' . $channel['channel_address'] . '/' . $x[0]['cr_id']); - } - - // that failed. Try again perhaps? - - goaway(z_root() . '/chat/' . $channel['channel_address'] . '/new'); - - - } - - - function get() { + $which = ((argc() > 1) ? argv(1) : null); + if (local_channel() && (!$which)) { + $channel = App::get_channel(); + if ($channel && $channel['channel_address']) { + $which = $channel['channel_address']; + } + } + + if (!$which) { + notice(t('You must be logged in to see this page.') . EOL); + return; + } + + $profile = 0; + + // Run Libprofile::load() here to make sure the theme is set before + // we start loading content + + Libprofile::load($which, $profile); + + } + + public function post() + { + + if ($_POST['room_name']) { + $room = strip_tags(trim($_POST['room_name'])); + } + + if ((!$room) || (!local_channel())) { + return; + } + + $channel = App::get_channel(); + + if ($_POST['action'] === 'drop') { + logger('delete chatroom'); + Chatroom::destroy($channel, ['cr_name' => $room]); + goaway(z_root() . '/chat/' . $channel['channel_address']); + } + + $acl = new AccessControl($channel); + $acl->set_from_array($_REQUEST); + + $arr = $acl->get(); + $arr['name'] = $room; + $arr['expire'] = intval($_POST['chat_expire']); + if (intval($arr['expire']) < 0) { + $arr['expire'] = 0; + } + + Chatroom::create($channel, $arr); + + $x = q("select * from chatroom where cr_name = '%s' and cr_uid = %d limit 1", + dbesc($room), + intval(local_channel()) + ); + + Libsync::build_sync_packet(0, array('chatroom' => $x)); + + if ($x) { + goaway(z_root() . '/chat/' . $channel['channel_address'] . '/' . $x[0]['cr_id']); + } + + // that failed. Try again perhaps? + + goaway(z_root() . '/chat/' . $channel['channel_address'] . '/new'); + + + } + + + public function get() + { // if(! Apps::system_app_installed(App::$profile_uid, 'Chatrooms')) { // // Do not display any associated widgets at this point @@ -95,171 +99,170 @@ class Chat extends Controller { // $o .= t('Access Controlled Chatrooms'); // return $o; // } - - if (local_channel()) { - $channel = App::get_channel(); - nav_set_selected('Chatrooms'); - } - $ob = App::get_observer(); - $observer = get_observer_hash(); - if (! $observer) { - notice( t('Permission denied.') . EOL); - return; - } - - if (! perm_is_allowed(App::$profile['profile_uid'],$observer,'chat')) { - notice( t('Permission denied.') . EOL); - return; - } - - if ((argc() > 3) && intval(argv(2)) && (argv(3) === 'leave')) { - Chatroom::leave($observer,argv(2),$_SERVER['REMOTE_ADDR']); - goaway(z_root() . '/channel/' . argv(1)); - } - - - if ((argc() > 3) && intval(argv(2)) && (argv(3) === 'status')) { - $ret = [ 'success' => false ]; - $room_id = intval(argv(2)); - if (! $room_id || ! $observer) { - return; - } - - $r = q("select * from chatroom where cr_id = %d limit 1", - intval($room_id) - ); - if (! $r) { - json_return_and_die($ret); - } - require_once('include/security.php'); - $sql_extra = permissions_sql($r[0]['cr_uid']); - - $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", - intval($room_id), - intval($r[0]['cr_uid']) - ); - if (! $x) { - json_return_and_die($ret); - } - $y = q("select count(*) as total from chatpresence where cp_room = %d", - intval($room_id) - ); - if ($y) { - $ret['success'] = true; - $ret['chatroom'] = $r[0]['cr_name']; - $ret['inroom'] = $y[0]['total']; - } - - // figure out how to present a timestamp of the last activity, since we don't know the observer's timezone. - - $z = q("select created from chat where chat_room = %d order by created desc limit 1", - intval($room_id) - ); - if ($z) { - $ret['last'] = $z[0]['created']; - } - json_return_and_die($ret); - } - - - if (argc() > 2 && intval(argv(2))) { - - $room_id = intval(argv(2)); - - $x = Chatroom::enter($observer,$room_id,'online',$_SERVER['REMOTE_ADDR']); - if (! $x) { - return; - } - $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", - intval($room_id), - intval(App::$profile['profile_uid']) - ); - - if ($x) { - $acl = new AccessControl(false); - $acl->set($x[0]); - - $private = $acl->is_private(); - $room_name = $x[0]['cr_name']; - } - else { - notice( t('Room not found') . EOL); - return; - } + if (local_channel()) { + $channel = App::get_channel(); + nav_set_selected('Chatrooms'); + } - $cipher = get_pconfig(local_channel(),'system','default_cipher'); - if (! $cipher) { - $cipher = 'AES-128-CCM'; - } + $ob = App::get_observer(); + $observer = get_observer_hash(); + if (!$observer) { + notice(t('Permission denied.') . EOL); + return; + } - - $o = replace_macros(get_markup_template('chat.tpl'), [ - '$is_owner' => ((local_channel() && local_channel() == $x[0]['cr_uid']) ? true : false), - '$room_name' => $room_name, - '$room_id' => $room_id, - '$baseurl' => z_root(), - '$nickname' => argv(1), - '$submit' => t('Submit'), - '$leave' => t('Leave Room'), - '$drop' => t('Delete Room'), - '$away' => t('I am away right now'), - '$online' => t('I am online'), - '$feature_encrypt' => ((Apps::system_app_installed(local_channel(),'Secrets')) ? true : false), - '$cipher' => $cipher, - '$linkurl' => t('Please enter a link URL:'), - '$encrypt' => t('Encrypt text'), - '$insert' => t('Insert web link') - ]); - return $o; - } + if (!perm_is_allowed(App::$profile['profile_uid'], $observer, 'chat')) { + notice(t('Permission denied.') . EOL); + return; + } - require_once('include/conversation.php'); - - $o = ''; + if ((argc() > 3) && intval(argv(2)) && (argv(3) === 'leave')) { + Chatroom::leave($observer, argv(2), $_SERVER['REMOTE_ADDR']); + goaway(z_root() . '/channel/' . argv(1)); + } - $acl = new AccessControl($channel); - $channel_acl = $acl->get(); - $lockstate = (($channel_acl['allow_cid'] || $channel_acl['allow_gid'] || $channel_acl['deny_cid'] || $channel_acl['deny_gid']) ? 'lock' : 'unlock'); - require_once('include/acl_selectors.php'); + if ((argc() > 3) && intval(argv(2)) && (argv(3) === 'status')) { + $ret = ['success' => false]; + $room_id = intval(argv(2)); + if (!$room_id || !$observer) { + return; + } - $chatroom_new = ''; - if (local_channel()) { - $chatroom_new = replace_macros(get_markup_template('chatroom_new.tpl'),array( - '$header' => t('New Chatroom'), - '$name' => array('room_name',t('Chatroom name'),'', ''), - '$chat_expire' => array('chat_expire',t('Expiration of chats (minutes)'),120,''), - '$permissions' => t('Permissions'), - '$acl' => populate_acl($channel_acl,false), - '$allow_cid' => acl2json($channel_acl['allow_cid']), - '$allow_gid' => acl2json($channel_acl['allow_gid']), - '$deny_cid' => acl2json($channel_acl['deny_cid']), - '$deny_gid' => acl2json($channel_acl['deny_gid']), - '$lockstate' => $lockstate, - '$submit' => t('Submit') - - )); - } + $r = q("select * from chatroom where cr_id = %d limit 1", + intval($room_id) + ); + if (!$r) { + json_return_and_die($ret); + } + require_once('include/security.php'); + $sql_extra = permissions_sql($r[0]['cr_uid']); + + $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", + intval($room_id), + intval($r[0]['cr_uid']) + ); + if (!$x) { + json_return_and_die($ret); + } + $y = q("select count(*) as total from chatpresence where cp_room = %d", + intval($room_id) + ); + if ($y) { + $ret['success'] = true; + $ret['chatroom'] = $r[0]['cr_name']; + $ret['inroom'] = $y[0]['total']; + } + + // figure out how to present a timestamp of the last activity, since we don't know the observer's timezone. + + $z = q("select created from chat where chat_room = %d order by created desc limit 1", + intval($room_id) + ); + if ($z) { + $ret['last'] = $z[0]['created']; + } + json_return_and_die($ret); + } + + + if (argc() > 2 && intval(argv(2))) { + + $room_id = intval(argv(2)); + + $x = Chatroom::enter($observer, $room_id, 'online', $_SERVER['REMOTE_ADDR']); + if (!$x) { + return; + } + $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", + intval($room_id), + intval(App::$profile['profile_uid']) + ); + + if ($x) { + $acl = new AccessControl(false); + $acl->set($x[0]); + + $private = $acl->is_private(); + $room_name = $x[0]['cr_name']; + } else { + notice(t('Room not found') . EOL); + return; + } + + $cipher = get_pconfig(local_channel(), 'system', 'default_cipher'); + if (!$cipher) { + $cipher = 'AES-128-CCM'; + } + + + $o = replace_macros(get_markup_template('chat.tpl'), [ + '$is_owner' => ((local_channel() && local_channel() == $x[0]['cr_uid']) ? true : false), + '$room_name' => $room_name, + '$room_id' => $room_id, + '$baseurl' => z_root(), + '$nickname' => argv(1), + '$submit' => t('Submit'), + '$leave' => t('Leave Room'), + '$drop' => t('Delete Room'), + '$away' => t('I am away right now'), + '$online' => t('I am online'), + '$feature_encrypt' => ((Apps::system_app_installed(local_channel(), 'Secrets')) ? true : false), + '$cipher' => $cipher, + '$linkurl' => t('Please enter a link URL:'), + '$encrypt' => t('Encrypt text'), + '$insert' => t('Insert web link') + ]); + return $o; + } + + require_once('include/conversation.php'); + + $o = ''; + + $acl = new AccessControl($channel); + $channel_acl = $acl->get(); + + $lockstate = (($channel_acl['allow_cid'] || $channel_acl['allow_gid'] || $channel_acl['deny_cid'] || $channel_acl['deny_gid']) ? 'lock' : 'unlock'); + require_once('include/acl_selectors.php'); + + $chatroom_new = ''; + if (local_channel()) { + $chatroom_new = replace_macros(get_markup_template('chatroom_new.tpl'), array( + '$header' => t('New Chatroom'), + '$name' => array('room_name', t('Chatroom name'), '', ''), + '$chat_expire' => array('chat_expire', t('Expiration of chats (minutes)'), 120, ''), + '$permissions' => t('Permissions'), + '$acl' => populate_acl($channel_acl, false), + '$allow_cid' => acl2json($channel_acl['allow_cid']), + '$allow_gid' => acl2json($channel_acl['allow_gid']), + '$deny_cid' => acl2json($channel_acl['deny_cid']), + '$deny_gid' => acl2json($channel_acl['deny_gid']), + '$lockstate' => $lockstate, + '$submit' => t('Submit') + + )); + } + + $rooms = Chatroom::roomlist(App::$profile['profile_uid']); + + $o .= replace_macros(get_markup_template('chatrooms.tpl'), [ + '$header' => sprintf(t('%1$s\'s Chatrooms'), App::$profile['fullname']), + '$name' => t('Name'), + '$baseurl' => z_root(), + '$nickname' => App::$profile['channel_address'], + '$rooms' => $rooms, + '$norooms' => t('No chatrooms available'), + '$newroom' => t('Create New'), + '$is_owner' => ((local_channel() && local_channel() == App::$profile['profile_uid']) ? 1 : 0), + '$chatroom_new' => $chatroom_new, + '$expire' => t('Expiration'), + '$expire_unit' => t('min') //minutes + ]); + + return $o; + + } - $rooms = Chatroom::roomlist(App::$profile['profile_uid']); - - $o .= replace_macros(get_markup_template('chatrooms.tpl'), [ - '$header' => sprintf( t('%1$s\'s Chatrooms'), App::$profile['fullname']), - '$name' => t('Name'), - '$baseurl' => z_root(), - '$nickname' => App::$profile['channel_address'], - '$rooms' => $rooms, - '$norooms' => t('No chatrooms available'), - '$newroom' => t('Create New'), - '$is_owner' => ((local_channel() && local_channel() == App::$profile['profile_uid']) ? 1 : 0), - '$chatroom_new' => $chatroom_new, - '$expire' => t('Expiration'), - '$expire_unit' => t('min') //minutes - ]); - - return $o; - - } - } diff --git a/Zotlabs/Module/Chatsvc.php b/Zotlabs/Module/Chatsvc.php index 67a9f1d66..a832247bc 100644 --- a/Zotlabs/Module/Chatsvc.php +++ b/Zotlabs/Module/Chatsvc.php @@ -8,179 +8,183 @@ use App; use Zotlabs\Lib as Zlib; use Zotlabs\Web\Controller; -class Chatsvc extends Controller { +class Chatsvc extends Controller +{ - function init() { - - //logger('chatsvc'); - - $ret = array('success' => false); - - App::$data['chat']['room_id'] = intval($_REQUEST['room_id']); - $x = q("select cr_uid from chatroom where cr_id = %d and cr_id != 0 limit 1", - intval(App::$data['chat']['room_id']) - ); - if(! $x) - json_return_and_die($ret); - - App::$data['chat']['uid'] = $x[0]['cr_uid']; - - if(! perm_is_allowed(App::$data['chat']['uid'],get_observer_hash(),'chat')) { - json_return_and_die($ret); - } - - } - - function post() { - - $ret = array('success' => false); - - $room_id = App::$data['chat']['room_id']; - $text = escape_tags($_REQUEST['chat_text']); - if(! $text) - return; - - $sql_extra = permissions_sql(App::$data['chat']['uid']); - - $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", - intval(App::$data['chat']['uid']), - intval(App::$data['chat']['room_id']) - ); - if(! $r) - json_return_and_die($ret); - - $arr = array( - 'chat_room' => App::$data['chat']['room_id'], - 'chat_xchan' => get_observer_hash(), - 'chat_text' => $text - ); - - call_hooks('chat_post',$arr); - - $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text ) + public function init() + { + + //logger('chatsvc'); + + $ret = array('success' => false); + + App::$data['chat']['room_id'] = intval($_REQUEST['room_id']); + $x = q("select cr_uid from chatroom where cr_id = %d and cr_id != 0 limit 1", + intval(App::$data['chat']['room_id']) + ); + if (!$x) + json_return_and_die($ret); + + App::$data['chat']['uid'] = $x[0]['cr_uid']; + + if (!perm_is_allowed(App::$data['chat']['uid'], get_observer_hash(), 'chat')) { + json_return_and_die($ret); + } + + } + + public function post() + { + + $ret = array('success' => false); + + $room_id = App::$data['chat']['room_id']; + $text = escape_tags($_REQUEST['chat_text']); + if (!$text) + return; + + $sql_extra = permissions_sql(App::$data['chat']['uid']); + + $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", + intval(App::$data['chat']['uid']), + intval(App::$data['chat']['room_id']) + ); + if (!$r) + json_return_and_die($ret); + + $arr = array( + 'chat_room' => App::$data['chat']['room_id'], + 'chat_xchan' => get_observer_hash(), + 'chat_text' => $text + ); + + call_hooks('chat_post', $arr); + + $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text ) values( %d, '%s', '%s', '%s' )", - intval(App::$data['chat']['room_id']), - dbesc(get_observer_hash()), - dbesc(datetime_convert()), - dbesc(str_rot47(base64url_encode($arr['chat_text']))) - ); - - $ret['success'] = true; - json_return_and_die($ret); - } - - function get() { - - $status = strip_tags($_REQUEST['status']); - $room_id = intval(App::$data['chat']['room_id']); - $stopped = ((x($_REQUEST,'stopped') && intval($_REQUEST['stopped'])) ? true : false); - - if($status && $room_id) { - - $x = q("select channel_address from channel where channel_id = %d limit 1", - intval(App::$data['chat']['uid']) - ); - - $r = q("update chatpresence set cp_status = '%s', cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'", - dbesc($status), - dbesc(datetime_convert()), - intval($room_id), - dbesc(get_observer_hash()), - dbesc($_SERVER['REMOTE_ADDR']) - ); - - goaway(z_root() . '/chat/' . $x[0]['channel_address'] . '/' . $room_id); - } - - if(! $stopped) { - - $lastseen = intval($_REQUEST['last']); - - $ret = array('success' => false); - - $sql_extra = permissions_sql(App::$data['chat']['uid']); - - $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", - intval(App::$data['chat']['uid']), - intval(App::$data['chat']['room_id']) - ); - if(! $r) - json_return_and_die($ret); - - $inroom = []; - - $r = q("select * from chatpresence left join xchan on xchan_hash = cp_xchan where cp_room = %d order by xchan_name", - intval(App::$data['chat']['room_id']) - ); - if($r) { - foreach($r as $rv) { - if(! $rv['xchan_name']) { - $rv['xchan_hash'] = $rv['cp_xchan']; - $rv['xchan_name'] = substr($rv['cp_xchan'],strrpos($rv['cp_xchan'],'.')+1); - $rv['xchan_addr'] = ''; - $rv['xchan_network'] = 'unknown'; - $rv['xchan_url'] = z_root(); - $rv['xchan_hidden'] = 1; - $rv['xchan_photo_mimetype'] = 'image/png'; - $rv['xchan_photo_l'] = z_root() . '/' . get_default_profile_photo(300); - $rv['xchan_photo_m'] = z_root() . '/' . get_default_profile_photo(80); - $rv['xchan_photo_s'] = z_root() . '/' . get_default_profile_photo(48); + intval(App::$data['chat']['room_id']), + dbesc(get_observer_hash()), + dbesc(datetime_convert()), + dbesc(str_rot47(base64url_encode($arr['chat_text']))) + ); + + $ret['success'] = true; + json_return_and_die($ret); + } + + public function get() + { + + $status = strip_tags($_REQUEST['status']); + $room_id = intval(App::$data['chat']['room_id']); + $stopped = ((x($_REQUEST, 'stopped') && intval($_REQUEST['stopped'])) ? true : false); + + if ($status && $room_id) { + + $x = q("select channel_address from channel where channel_id = %d limit 1", + intval(App::$data['chat']['uid']) + ); + + $r = q("update chatpresence set cp_status = '%s', cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'", + dbesc($status), + dbesc(datetime_convert()), + intval($room_id), + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + + goaway(z_root() . '/chat/' . $x[0]['channel_address'] . '/' . $room_id); + } + + if (!$stopped) { + + $lastseen = intval($_REQUEST['last']); + + $ret = array('success' => false); + + $sql_extra = permissions_sql(App::$data['chat']['uid']); + + $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", + intval(App::$data['chat']['uid']), + intval(App::$data['chat']['room_id']) + ); + if (!$r) + json_return_and_die($ret); + + $inroom = []; + + $r = q("select * from chatpresence left join xchan on xchan_hash = cp_xchan where cp_room = %d order by xchan_name", + intval(App::$data['chat']['room_id']) + ); + if ($r) { + foreach ($r as $rv) { + if (!$rv['xchan_name']) { + $rv['xchan_hash'] = $rv['cp_xchan']; + $rv['xchan_name'] = substr($rv['cp_xchan'], strrpos($rv['cp_xchan'], '.') + 1); + $rv['xchan_addr'] = ''; + $rv['xchan_network'] = 'unknown'; + $rv['xchan_url'] = z_root(); + $rv['xchan_hidden'] = 1; + $rv['xchan_photo_mimetype'] = 'image/png'; + $rv['xchan_photo_l'] = z_root() . '/' . get_default_profile_photo(300); + $rv['xchan_photo_m'] = z_root() . '/' . get_default_profile_photo(80); + $rv['xchan_photo_s'] = z_root() . '/' . get_default_profile_photo(48); + + } + + switch ($rv['cp_status']) { + case 'away': + $status = t('Away'); + $status_class = 'away'; + break; + case 'online': + default: + $status = t('Online'); + $status_class = 'online'; + break; + } + + $inroom[] = array('img' => zid($rv['xchan_photo_m']), 'img_type' => $rv['xchan_photo_mimetype'], 'name' => $rv['xchan_name'], 'status' => $status, 'status_class' => $status_class); + } + } + + $chats = []; + + $r = q("select * from chat left join xchan on chat_xchan = xchan_hash where chat_room = %d and chat_id > %d order by created", + intval(App::$data['chat']['room_id']), + intval($lastseen) + ); + if ($r) { + foreach ($r as $rr) { + $chats[] = array( + 'id' => $rr['chat_id'], + 'img' => zid($rr['xchan_photo_m']), + 'img_type' => $rr['xchan_photo_mimetype'], + 'name' => $rr['xchan_name'], + 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'c'), + 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'r'), + 'text' => zidify_links(smilies(bbcode(base64url_decode(str_rot47($rr['chat_text']))))), + 'self' => ((get_observer_hash() == $rr['chat_xchan']) ? 'self' : '') + ); + } + } + } + + $r = q("update chatpresence set cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'", + dbesc(datetime_convert()), + intval(App::$data['chat']['room_id']), + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + + $ret['success'] = true; + if (!$stopped) { + $ret['inroom'] = $inroom; + $ret['chats'] = $chats; + } + json_return_and_die($ret); + + } - } - switch($rv['cp_status']) { - case 'away': - $status = t('Away'); - $status_class = 'away'; - break; - case 'online': - default: - $status = t('Online'); - $status_class = 'online'; - break; - } - - $inroom[] = array('img' => zid($rv['xchan_photo_m']), 'img_type' => $rv['xchan_photo_mimetype'],'name' => $rv['xchan_name'], 'status' => $status, 'status_class' => $status_class); - } - } - - $chats = []; - - $r = q("select * from chat left join xchan on chat_xchan = xchan_hash where chat_room = %d and chat_id > %d order by created", - intval(App::$data['chat']['room_id']), - intval($lastseen) - ); - if($r) { - foreach($r as $rr) { - $chats[] = array( - 'id' => $rr['chat_id'], - 'img' => zid($rr['xchan_photo_m']), - 'img_type' => $rr['xchan_photo_mimetype'], - 'name' => $rr['xchan_name'], - 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'c'), - 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'r'), - 'text' => zidify_links(smilies(bbcode(base64url_decode(str_rot47($rr['chat_text']))))), - 'self' => ((get_observer_hash() == $rr['chat_xchan']) ? 'self' : '') - ); - } - } - } - - $r = q("update chatpresence set cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'", - dbesc(datetime_convert()), - intval(App::$data['chat']['room_id']), - dbesc(get_observer_hash()), - dbesc($_SERVER['REMOTE_ADDR']) - ); - - $ret['success'] = true; - if(! $stopped) { - $ret['inroom'] = $inroom; - $ret['chats'] = $chats; - } - json_return_and_die($ret); - - } - - } diff --git a/Zotlabs/Module/Clients.php b/Zotlabs/Module/Clients.php index 7cf8facd4..da2fa5480 100644 --- a/Zotlabs/Module/Clients.php +++ b/Zotlabs/Module/Clients.php @@ -6,18 +6,20 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Clients extends Controller { +class Clients extends Controller +{ - function get() { + public function get() + { $desc = t('This app allows you to authorize mobile apps using OAuth and OpenID to access your channel.'); - if(! Apps::system_app_installed(local_channel(),'Clients')) { - return ''; - } - goaway(z_root() . '/settings/oauth2'); - } + if (!Apps::system_app_installed(local_channel(), 'Clients')) { + return ''; + } + goaway(z_root() . '/settings/oauth2'); + } } diff --git a/Zotlabs/Module/Cloud.php b/Zotlabs/Module/Cloud.php index 2293b8cd7..5709464cf 100644 --- a/Zotlabs/Module/Cloud.php +++ b/Zotlabs/Module/Cloud.php @@ -27,124 +27,123 @@ require_once('include/attach.php'); * @brief Cloud Module. * */ +class Cloud extends Controller +{ -class Cloud extends Controller { + /** + * @brief Fires up the SabreDAV server. + * + */ + public function init() + { - /** - * @brief Fires up the SabreDAV server. - * - */ - function init() { + if (!is_dir('store')) { + os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false); + } - if (! is_dir('store')) { - os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false); - } - - $which = null; - if (argc() > 1) { - $which = argv(1); - } - $profile = 0; + $which = null; + if (argc() > 1) { + $which = argv(1); + } + $profile = 0; - if ($which) { - Libprofile::load( $which, $profile); - } + if ($which) { + Libprofile::load($which, $profile); + } - $auth = new BasicAuth(); + $auth = new BasicAuth(); - $ob_hash = get_observer_hash(); + $ob_hash = get_observer_hash(); - if ($ob_hash) { - if (local_channel()) { - $channel = App::get_channel(); - $auth->setCurrentUser($channel['channel_address']); - $auth->channel_id = $channel['channel_id']; - $auth->channel_hash = $channel['channel_hash']; - $auth->channel_account_id = $channel['channel_account_id']; - if ($channel['channel_timezone']) { - $auth->setTimezone($channel['channel_timezone']); - } - } - $auth->observer = $ob_hash; - } + if ($ob_hash) { + if (local_channel()) { + $channel = App::get_channel(); + $auth->setCurrentUser($channel['channel_address']); + $auth->channel_id = $channel['channel_id']; + $auth->channel_hash = $channel['channel_hash']; + $auth->channel_account_id = $channel['channel_account_id']; + if ($channel['channel_timezone']) { + $auth->setTimezone($channel['channel_timezone']); + } + } + $auth->observer = $ob_hash; + } - // if we arrived at this path with any query parameters in the url, build a clean url without - // them and redirect. + // if we arrived at this path with any query parameters in the url, build a clean url without + // them and redirect. - if (! array_key_exists('cloud_sort',$_SESSION)) { - $_SESSION['cloud_sort'] = 'name'; - } + if (!array_key_exists('cloud_sort', $_SESSION)) { + $_SESSION['cloud_sort'] = 'name'; + } - $_SESSION['cloud_sort'] = (($_REQUEST['sort']) ? trim(notags($_REQUEST['sort'])) : $_SESSION['cloud_sort']); + $_SESSION['cloud_sort'] = (($_REQUEST['sort']) ? trim(notags($_REQUEST['sort'])) : $_SESSION['cloud_sort']); - $x = clean_query_string(); - if ($x !== App::$query_string) { - goaway(z_root() . '/' . $x); - } + $x = clean_query_string(); + if ($x !== App::$query_string) { + goaway(z_root() . '/' . $x); + } - $rootDirectory = new Directory('/', $auth); + $rootDirectory = new Directory('/', $auth); - // A SabreDAV server-object - $server = new SDAV\Server($rootDirectory); - // prevent overwriting changes each other with a lock backend - $lockBackend = new SDAV\Locks\Backend\File('cache/locks'); - $lockPlugin = new SDAV\Locks\Plugin($lockBackend); + // A SabreDAV server-object + $server = new SDAV\Server($rootDirectory); + // prevent overwriting changes each other with a lock backend + $lockBackend = new SDAV\Locks\Backend\File('cache/locks'); + $lockPlugin = new SDAV\Locks\Plugin($lockBackend); - $server->addPlugin($lockPlugin); + $server->addPlugin($lockPlugin); - $is_readable = false; + $is_readable = false; - // provide a directory view for the cloud in Hubzilla - $browser = new Browser($auth); - $auth->setBrowserPlugin($browser); + // provide a directory view for the cloud in Hubzilla + $browser = new Browser($auth); + $auth->setBrowserPlugin($browser); - $server->addPlugin($browser); + $server->addPlugin($browser); - // Experimental QuotaPlugin - // require_once('\Zotlabs\Storage/QuotaPlugin.php'); - // $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth)); + // Experimental QuotaPlugin + // require_once('\Zotlabs\Storage/QuotaPlugin.php'); + // $server->addPlugin(new \Zotlabs\Storage\\QuotaPlugin($auth)); - // over-ride the default XML output on thrown exceptions + // over-ride the default XML output on thrown exceptions - $server->on('exception', [ $this, 'DAVException' ]); + $server->on('exception', [$this, 'DAVException']); - // All we need to do now, is to fire up the server + // All we need to do now, is to fire up the server - $server->exec(); + $server->exec(); - if ($browser->build_page) { - construct_page(); - } - - killme(); - } + if ($browser->build_page) { + construct_page(); + } + + killme(); + } - function DAVException($err) { - - if ($err instanceof NotFound) { - notice( t('Not found') . EOL); - } - elseif ($err instanceof Forbidden) { - notice( t('Permission denied') . EOL); - } - elseif ($err instanceof NotImplemented) { - notice( t('Please refresh page') . EOL); - // It would be nice to do the following on remote authentication - // which provides an unexpected page query param, but we do not - // because if the exception has a different cause, it will loop. - // goaway(z_root() . '/' . App::$query_string); - } - else { - notice( t('Unknown error') . EOL); - } + public function DAVException($err) + { - construct_page(); - - killme(); - } + if ($err instanceof NotFound) { + notice(t('Not found') . EOL); + } elseif ($err instanceof Forbidden) { + notice(t('Permission denied') . EOL); + } elseif ($err instanceof NotImplemented) { + notice(t('Please refresh page') . EOL); + // It would be nice to do the following on remote authentication + // which provides an unexpected page query param, but we do not + // because if the exception has a different cause, it will loop. + // goaway(z_root() . '/' . App::$query_string); + } else { + notice(t('Unknown error') . EOL); + } + + construct_page(); + + killme(); + } } diff --git a/Zotlabs/Module/Cloud_tiles.php b/Zotlabs/Module/Cloud_tiles.php index 1a91f0d36..5d6ae07a2 100644 --- a/Zotlabs/Module/Cloud_tiles.php +++ b/Zotlabs/Module/Cloud_tiles.php @@ -4,20 +4,22 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Cloud_tiles extends Controller { +class Cloud_tiles extends Controller +{ - function init() { + public function init() + { - if(intval($_SESSION['cloud_tiles'])) - $_SESSION['cloud_tiles'] = 0; - else - $_SESSION['cloud_tiles'] = 1; + if (intval($_SESSION['cloud_tiles'])) + $_SESSION['cloud_tiles'] = 0; + else + $_SESSION['cloud_tiles'] = 1; - if(local_channel()) { - set_pconfig(local_channel(),'system','cloud_tiles',$_SESSION['cloud_tiles']); - } + if (local_channel()) { + set_pconfig(local_channel(), 'system', 'cloud_tiles', $_SESSION['cloud_tiles']); + } - goaway(z_root() . '/' . hex2bin(argv(1))); + goaway(z_root() . '/' . hex2bin(argv(1))); - } + } } \ No newline at end of file diff --git a/Zotlabs/Module/Comment_control.php b/Zotlabs/Module/Comment_control.php index 884096e09..075719bd1 100644 --- a/Zotlabs/Module/Comment_control.php +++ b/Zotlabs/Module/Comment_control.php @@ -6,23 +6,25 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Comment_control extends Controller { +class Comment_control extends Controller +{ - function get() { + public function get() + { $desc = t('This app allows you to select the comment audience and set a length of time that comments on a particular post will be accepted.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Comment Control'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Comment Control'))) { return $text; } - $desc = t('This app is installed. A button to control comments may be found below the post editor.'); + $desc = t('This app is installed. A button to control comments may be found below the post editor.'); - $text = ''; + $text = ''; - return $text; + return $text; - } + } } diff --git a/Zotlabs/Module/Common.php b/Zotlabs/Module/Common.php index f975ed426..7f816bfa4 100644 --- a/Zotlabs/Module/Common.php +++ b/Zotlabs/Module/Common.php @@ -8,69 +8,72 @@ use Zotlabs\Web\Controller; require_once('include/socgraph.php'); -class Common extends Controller { +class Common extends Controller +{ - function init() { - - if(argc() > 1 && intval(argv(1))) - $channel_id = intval(argv(1)); - else { - notice( t('No channel.') . EOL ); - App::$error = 404; - return; - } - - $x = q("select channel_address from channel where channel_id = %d limit 1", - intval($channel_id) - ); - - if($x) - Libprofile::load($x[0]['channel_address'],0); - - } - - function get() { - - $o = ''; - - if(! App::$profile['profile_uid']) - return; - - $observer_hash = get_observer_hash(); - - if(! perm_is_allowed(App::$profile['profile_uid'],$observer_hash,'view_contacts')) { - notice( t('Permission denied.') . EOL); - return; - } - - $t = count_common_friends(App::$profile['profile_uid'],$observer_hash); - - if(! $t) { - notice( t('No connections in common.') . EOL); - return; - } - - $r = common_friends(App::$profile['profile_uid'],$observer_hash); - - if($r) { - foreach($r as $rr) { - $items[] = [ - 'url' => $rr['xchan_url'], - 'name' => $rr['xchan_name'], - 'photo' => $rr['xchan_photo_m'], - 'tags' => '' - ]; - } - } + public function init() + { - $tpl = get_markup_template('common_friends.tpl'); + if (argc() > 1 && intval(argv(1))) + $channel_id = intval(argv(1)); + else { + notice(t('No channel.') . EOL); + App::$error = 404; + return; + } + + $x = q("select channel_address from channel where channel_id = %d limit 1", + intval($channel_id) + ); + + if ($x) + Libprofile::load($x[0]['channel_address'], 0); + + } + + public function get() + { + + $o = ''; + + if (!App::$profile['profile_uid']) + return; + + $observer_hash = get_observer_hash(); + + if (!perm_is_allowed(App::$profile['profile_uid'], $observer_hash, 'view_contacts')) { + notice(t('Permission denied.') . EOL); + return; + } + + $t = count_common_friends(App::$profile['profile_uid'], $observer_hash); + + if (!$t) { + notice(t('No connections in common.') . EOL); + return; + } + + $r = common_friends(App::$profile['profile_uid'], $observer_hash); + + if ($r) { + foreach ($r as $rr) { + $items[] = [ + 'url' => $rr['xchan_url'], + 'name' => $rr['xchan_name'], + 'photo' => $rr['xchan_photo_m'], + 'tags' => '' + ]; + } + } + + $tpl = get_markup_template('common_friends.tpl'); + + $o = replace_macros($tpl, [ + '$title' => t('View Common Connections'), + '$items' => $items + ]); + + return $o; + } - $o = replace_macros($tpl, [ - '$title' => t('View Common Connections'), - '$items' => $items - ]); - - return $o; - } - } diff --git a/Zotlabs/Module/Connac.php b/Zotlabs/Module/Connac.php index 233054536..51a575608 100644 --- a/Zotlabs/Module/Connac.php +++ b/Zotlabs/Module/Connac.php @@ -9,25 +9,27 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Connac extends Controller { +class Connac extends Controller +{ - function init() { + public function init() + { - $ret = []; - - if (! local_channel()) { - json_return_and_die($ret); - } + $ret = []; - - $r = q("select xchan_addr from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and xchan_network = 'zot6'", - intval(local_channel()) - ); - if ($r) { - foreach ($r as $rv) { - $ret[] = $rv['xchan_addr']; - } - } - json_return_and_die($ret); - } + if (!local_channel()) { + json_return_and_die($ret); + } + + + $r = q("select xchan_addr from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and xchan_network = 'zot6'", + intval(local_channel()) + ); + if ($r) { + foreach ($r as $rv) { + $ret[] = $rv['xchan_addr']; + } + } + json_return_and_die($ret); + } } diff --git a/Zotlabs/Module/Connect.php b/Zotlabs/Module/Connect.php index 7526b2b59..ac41a2c11 100644 --- a/Zotlabs/Module/Connect.php +++ b/Zotlabs/Module/Connect.php @@ -8,117 +8,118 @@ use Zotlabs\Daemon\Run; use Zotlabs\Lib\Libprofile; -class Connect extends Controller { +class Connect extends Controller +{ - function init() { - if(argc() > 1) { - App::$data['channel'] = channelx_by_nick(argv(1)); - Libprofile::load(argv(1),EMPTY_STR); - } - else { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } - } - - function post() { - - if(! array_key_exists('channel', App::$data)) - return; - - $edit = ((local_channel() && (local_channel() == App::$data['channel']['channel_id'])) ? true : false); - - if($edit) { - $has_premium = ((App::$data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? 1 : 0); - $premium = (($_POST['premium']) ? intval($_POST['premium']) : 0); - $text = escape_tags($_POST['text']); - - if($has_premium != $premium) { - $r = q("update channel set channel_pageflags = ( channel_pageflags %s %d ) where channel_id = %d", - db_getfunc('^'), - intval(PAGE_PREMIUM), - intval(local_channel()) - ); - - Run::Summon( [ 'Notifier','refresh_all',App::$data['channel']['channel_id'] ] ); - } - set_pconfig(App::$data['channel']['channel_id'],'system','selltext',$text); - // reload the page completely to get fresh data - goaway(z_root() . '/' . App::$query_string); - - } - - $url = EMPTY_STR; - $observer = App::get_observer(); - if(($observer) && ($_POST['submit'] === t('Continue'))) { - if($observer['xchan_follow']) - $url = sprintf($observer['xchan_follow'],urlencode(channel_reddress(App::$data['channel']))); - if(! $url) { - $r = q("select * from hubloc where hubloc_hash = '%s' order by hubloc_id desc limit 1", - dbesc($observer['xchan_hash']) - ); - if($r) - $url = $r[0]['hubloc_url'] . '/follow?f=&url=' . urlencode(channel_reddress(App::$data['channel'])); - } - } - if($url) - goaway($url . '&confirm=1'); - else - notice('Unable to connect to your home hub location.'); - - } - - - - function get() { - - $edit = ((local_channel() && (local_channel() == App::$data['channel']['channel_id'])) ? true : false); - - $text = get_pconfig(App::$data['channel']['channel_id'],'system','selltext'); - - if($edit) { - - $o = replace_macros(get_markup_template('sellpage_edit.tpl'),array( - '$header' => t('Premium Channel Setup'), - '$address' => App::$data['channel']['channel_address'], - '$premium' => array('premium', t('Enable premium channel connection restrictions'),((App::$data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? '1' : ''),''), - '$lbl_about' => t('Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc.'), - '$text' => $text, - '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), - '$lbl2' => t('Potential connections will then see the following text before proceeding:'), - '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), - '$submit' => t('Submit'), - - - )); - return $o; - } - else { - if(! $text) - $text = t('(No specific instructions have been provided by the channel owner.)'); - - $submit = replace_macros(get_markup_template('sellpage_submit.tpl'), array( - '$continue' => t('Continue'), - '$address' => App::$data['channel']['channel_address'] - )); - - $o = replace_macros(get_markup_template('sellpage_view.tpl'),array( - '$header' => t('Restricted or Premium Channel'), - '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), - '$text' => prepare_text($text), - - '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), - '$submit' => $submit, - - )); - - $arr = array('channel' => App::$data['channel'],'observer' => App::get_observer(), 'sellpage' => $o, 'submit' => $submit); - call_hooks('connect_premium', $arr); - $o = $arr['sellpage']; - - } - - return $o; - } + public function init() + { + if (argc() > 1) { + App::$data['channel'] = channelx_by_nick(argv(1)); + Libprofile::load(argv(1), EMPTY_STR); + } else { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } + } + + public function post() + { + + if (!array_key_exists('channel', App::$data)) + return; + + $edit = ((local_channel() && (local_channel() == App::$data['channel']['channel_id'])) ? true : false); + + if ($edit) { + $has_premium = ((App::$data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? 1 : 0); + $premium = (($_POST['premium']) ? intval($_POST['premium']) : 0); + $text = escape_tags($_POST['text']); + + if ($has_premium != $premium) { + $r = q("update channel set channel_pageflags = ( channel_pageflags %s %d ) where channel_id = %d", + db_getfunc('^'), + intval(PAGE_PREMIUM), + intval(local_channel()) + ); + + Run::Summon(['Notifier', 'refresh_all', App::$data['channel']['channel_id']]); + } + set_pconfig(App::$data['channel']['channel_id'], 'system', 'selltext', $text); + // reload the page completely to get fresh data + goaway(z_root() . '/' . App::$query_string); + + } + + $url = EMPTY_STR; + $observer = App::get_observer(); + if (($observer) && ($_POST['submit'] === t('Continue'))) { + if ($observer['xchan_follow']) + $url = sprintf($observer['xchan_follow'], urlencode(channel_reddress(App::$data['channel']))); + if (!$url) { + $r = q("select * from hubloc where hubloc_hash = '%s' order by hubloc_id desc limit 1", + dbesc($observer['xchan_hash']) + ); + if ($r) + $url = $r[0]['hubloc_url'] . '/follow?f=&url=' . urlencode(channel_reddress(App::$data['channel'])); + } + } + if ($url) + goaway($url . '&confirm=1'); + else + notice('Unable to connect to your home hub location.'); + + } + + + public function get() + { + + $edit = ((local_channel() && (local_channel() == App::$data['channel']['channel_id'])) ? true : false); + + $text = get_pconfig(App::$data['channel']['channel_id'], 'system', 'selltext'); + + if ($edit) { + + $o = replace_macros(get_markup_template('sellpage_edit.tpl'), array( + '$header' => t('Premium Channel Setup'), + '$address' => App::$data['channel']['channel_address'], + '$premium' => array('premium', t('Enable premium channel connection restrictions'), ((App::$data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? '1' : ''), ''), + '$lbl_about' => t('Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc.'), + '$text' => $text, + '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), + '$lbl2' => t('Potential connections will then see the following text before proceeding:'), + '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), + '$submit' => t('Submit'), + + + )); + return $o; + } else { + if (!$text) + $text = t('(No specific instructions have been provided by the channel owner.)'); + + $submit = replace_macros(get_markup_template('sellpage_submit.tpl'), array( + '$continue' => t('Continue'), + '$address' => App::$data['channel']['channel_address'] + )); + + $o = replace_macros(get_markup_template('sellpage_view.tpl'), array( + '$header' => t('Restricted or Premium Channel'), + '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), + '$text' => prepare_text($text), + + '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), + '$submit' => $submit, + + )); + + $arr = array('channel' => App::$data['channel'], 'observer' => App::get_observer(), 'sellpage' => $o, 'submit' => $submit); + call_hooks('connect_premium', $arr); + $o = $arr['sellpage']; + + } + + return $o; + } } diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php index 4671fbbf7..e54664180 100644 --- a/Zotlabs/Module/Connections.php +++ b/Zotlabs/Module/Connections.php @@ -8,248 +8,249 @@ use Zotlabs\Lib\LibBlock; require_once('include/socgraph.php'); -class Connections extends Controller { +class Connections extends Controller +{ - function init() { - - if (! local_channel()) { - return; - } - - $channel = App::get_channel(); - if ($channel) { - head_set_icon($channel['xchan_photo_s']); - } - - } - - function get() { - - $sort_type = 0; - $o = ''; - - - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return login(); - } + public function init() + { - nav_set_selected('Connections'); - - $active = false; - $blocked = false; - $hidden = false; - $ignored = false; - $archived = false; - $unblocked = false; - $pending = false; - $unconnected = false; - $all = false; - - if (! (isset($_REQUEST['aj']) && $_REQUEST['aj'])) { - $_SESSION['return_url'] = App::$query_string; - } - - $search_flags = ""; - $head = ''; - - if (argc() == 2) { - switch (argv(1)) { - case 'active': - $search_flags = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 AND abook_not_here = 0 "; - $head = t('Active'); - $active = true; - break; - case 'blocked': - $search_flags = " and abook_blocked = 1 "; - $head = t('Blocked'); - $blocked = true; - break; - case 'ignored': - $search_flags = " and abook_ignored = 1 "; - $head = t('Ignored'); - $ignored = true; - break; - case 'hidden': - $search_flags = " and abook_hidden = 1 "; - $head = t('Hidden'); - $hidden = true; - break; - case 'archived': - $search_flags = " and ( abook_archived = 1 OR abook_not_here = 1) "; - $head = t('Archived/Unreachable'); - $archived = true; - break; - case 'all': - $search_flags = ''; - $head = t('All'); - $all = true; - break; - case 'pending': - $search_flags = " and abook_pending = 1 "; - $head = t('New'); - $pending = true; - break; - case 'ifpending': - case intval(argv(1)): - $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", - intval(local_channel()) - ); - if ($r && $r[0]['total']) { - $search_flags = " and abook_pending = 1 "; - if(intval(argv(1))) { - $search_flags .= " and abook_id = " . intval(argv(1)) . " "; - } - $head = t('New'); - $pending = true; - App::$argv[1] = 'pending'; - } - else { - $head = t('All'); - $search_flags = ''; - $all = true; - App::$argc = 1; - unset(App::$argv[1]); - } - break; - - default: - $search_flags = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 and abook_not_here = 0 "; - $active = true; - $head = t('Active'); - break; - - } - - $sql_extra = $search_flags; - if (argv(1) === 'pending') { - $sql_extra .= " and abook_ignored = 0 "; - } - } - else { - $sql_extra = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 and abook_not_here = 0 "; - $active = true; - $head = t('Active'); - } - - $search = ((x($_REQUEST,'search')) ? notags(trim($_REQUEST['search'])) : ''); - - $tabs = array( - - 'active' => array( - 'label' => t('Active Connections'), - 'url' => z_root() . '/connections/active', - 'sel' => ($active) ? 'active' : '', - 'title' => t('Show active connections'), - ), + if (!local_channel()) { + return; + } - 'pending' => array( - 'label' => t('New Connections'), - 'url' => z_root() . '/connections/pending', - 'sel' => ($pending) ? 'active' : '', - 'title' => t('Show pending (new) connections'), - ), - - 'blocked' => array( - 'label' => t('Blocked'), - 'url' => z_root() . '/connections/blocked', - 'sel' => ($blocked) ? 'active' : '', - 'title' => t('Only show blocked connections'), - ), - - 'ignored' => array( - 'label' => t('Ignored'), - 'url' => z_root() . '/connections/ignored', - 'sel' => ($ignored) ? 'active' : '', - 'title' => t('Only show ignored connections'), - ), - - 'archived' => array( - 'label' => t('Archived/Unreachable'), - 'url' => z_root() . '/connections/archived', - 'sel' => ($archived) ? 'active' : '', - 'title' => t('Only show archived/unreachable connections'), - ), - - 'hidden' => array( - 'label' => t('Hidden'), - 'url' => z_root() . '/connections/hidden', - 'sel' => ($hidden) ? 'active' : '', - 'title' => t('Only show hidden connections'), - ), - - 'all' => array( - 'label' => t('All Connections'), - 'url' => z_root() . '/connections/all', - 'sel' => ($all) ? 'active' : '', - 'title' => t('Show all connections'), - ), - - ); - - $searching = false; - if($search) { - $search_hdr = $search; - $search_txt = dbesc(protect_sprintf($search)); - $searching = true; - } - $sql_extra .= (($searching) ? " AND ( xchan_name like '%%$search_txt%%' OR abook_alias like '%%$search_txt%%' ) " : ""); - - if (isset($_REQUEST['gid']) && intval($_REQUEST['gid'])) { - $sql_extra .= " and xchan_hash in ( select xchan from pgrp_member where gid = " . intval($_REQUEST['gid']) . " and uid = " . intval(local_channel()) . " ) "; - } - - $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash + $channel = App::get_channel(); + if ($channel) { + head_set_icon($channel['xchan_photo_s']); + } + + } + + public function get() + { + + $sort_type = 0; + $o = ''; + + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return login(); + } + + nav_set_selected('Connections'); + + $active = false; + $blocked = false; + $hidden = false; + $ignored = false; + $archived = false; + $unblocked = false; + $pending = false; + $unconnected = false; + $all = false; + + if (!(isset($_REQUEST['aj']) && $_REQUEST['aj'])) { + $_SESSION['return_url'] = App::$query_string; + } + + $search_flags = ""; + $head = ''; + + if (argc() == 2) { + switch (argv(1)) { + case 'active': + $search_flags = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 AND abook_not_here = 0 "; + $head = t('Active'); + $active = true; + break; + case 'blocked': + $search_flags = " and abook_blocked = 1 "; + $head = t('Blocked'); + $blocked = true; + break; + case 'ignored': + $search_flags = " and abook_ignored = 1 "; + $head = t('Ignored'); + $ignored = true; + break; + case 'hidden': + $search_flags = " and abook_hidden = 1 "; + $head = t('Hidden'); + $hidden = true; + break; + case 'archived': + $search_flags = " and ( abook_archived = 1 OR abook_not_here = 1) "; + $head = t('Archived/Unreachable'); + $archived = true; + break; + case 'all': + $search_flags = ''; + $head = t('All'); + $all = true; + break; + case 'pending': + $search_flags = " and abook_pending = 1 "; + $head = t('New'); + $pending = true; + break; + case 'ifpending': + case intval(argv(1)): + $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", + intval(local_channel()) + ); + if ($r && $r[0]['total']) { + $search_flags = " and abook_pending = 1 "; + if (intval(argv(1))) { + $search_flags .= " and abook_id = " . intval(argv(1)) . " "; + } + $head = t('New'); + $pending = true; + App::$argv[1] = 'pending'; + } else { + $head = t('All'); + $search_flags = ''; + $all = true; + App::$argc = 1; + unset(App::$argv[1]); + } + break; + + default: + $search_flags = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 and abook_not_here = 0 "; + $active = true; + $head = t('Active'); + break; + + } + + $sql_extra = $search_flags; + if (argv(1) === 'pending') { + $sql_extra .= " and abook_ignored = 0 "; + } + } else { + $sql_extra = " and abook_blocked = 0 and abook_ignored = 0 and abook_hidden = 0 and abook_archived = 0 and abook_not_here = 0 "; + $active = true; + $head = t('Active'); + } + + $search = ((x($_REQUEST, 'search')) ? notags(trim($_REQUEST['search'])) : ''); + + $tabs = array( + + 'active' => array( + 'label' => t('Active Connections'), + 'url' => z_root() . '/connections/active', + 'sel' => ($active) ? 'active' : '', + 'title' => t('Show active connections'), + ), + + 'pending' => array( + 'label' => t('New Connections'), + 'url' => z_root() . '/connections/pending', + 'sel' => ($pending) ? 'active' : '', + 'title' => t('Show pending (new) connections'), + ), + + 'blocked' => array( + 'label' => t('Blocked'), + 'url' => z_root() . '/connections/blocked', + 'sel' => ($blocked) ? 'active' : '', + 'title' => t('Only show blocked connections'), + ), + + 'ignored' => array( + 'label' => t('Ignored'), + 'url' => z_root() . '/connections/ignored', + 'sel' => ($ignored) ? 'active' : '', + 'title' => t('Only show ignored connections'), + ), + + 'archived' => array( + 'label' => t('Archived/Unreachable'), + 'url' => z_root() . '/connections/archived', + 'sel' => ($archived) ? 'active' : '', + 'title' => t('Only show archived/unreachable connections'), + ), + + 'hidden' => array( + 'label' => t('Hidden'), + 'url' => z_root() . '/connections/hidden', + 'sel' => ($hidden) ? 'active' : '', + 'title' => t('Only show hidden connections'), + ), + + 'all' => array( + 'label' => t('All Connections'), + 'url' => z_root() . '/connections/all', + 'sel' => ($all) ? 'active' : '', + 'title' => t('Show all connections'), + ), + + ); + + $searching = false; + if ($search) { + $search_hdr = $search; + $search_txt = dbesc(protect_sprintf($search)); + $searching = true; + } + $sql_extra .= (($searching) ? " AND ( xchan_name like '%%$search_txt%%' OR abook_alias like '%%$search_txt%%' ) " : ""); + + if (isset($_REQUEST['gid']) && intval($_REQUEST['gid'])) { + $sql_extra .= " and xchan_hash in ( select xchan from pgrp_member where gid = " . intval($_REQUEST['gid']) . " and uid = " . intval(local_channel()) . " ) "; + } + + $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ", - intval(local_channel()) - ); - if($r) { - App::set_pager_total($r[0]['total']); - $total = $r[0]['total']; - } + intval(local_channel()) + ); + if ($r) { + App::set_pager_total($r[0]['total']); + $total = $r[0]['total']; + } - $order_q = 'xchan_name'; - if (isset($_REQUEST['order'])) { - switch ($_REQUEST['order']) { - case 'date': - $order_q = 'abook_created desc'; - break; - case 'created': - $order_q = 'abook_created'; - break; - case 'cmax': - $order_q = 'abook_closeness'; - break; - case 'name': - default: - $order_q = 'xchan_name'; - break; - } - } + $order_q = 'xchan_name'; + if (isset($_REQUEST['order'])) { + switch ($_REQUEST['order']) { + case 'date': + $order_q = 'abook_created desc'; + break; + case 'created': + $order_q = 'abook_created'; + break; + case 'cmax': + $order_q = 'abook_closeness'; + break; + case 'name': + default: + $order_q = 'xchan_name'; + break; + } + } - $order = array( - - 'name' => array( - 'label' => t('Name'), - 'url' => z_root() . '/connections' . ((argv(1)) ? '/' . argv(1) : '') . '?order=name', - 'sel' => ((isset($_REQUEST['order']) && $_REQUEST['order'] !== 'name') ? 'active' : ''), - 'title' => t('Order by name'), - ), + $order = array( - 'date' => array( - 'label' => t('Recent'), - 'url' => z_root() . '/connections' . ((argv(1)) ? '/' . argv(1) : '') . '?order=date', - 'sel' => ((isset($_REQUEST['order']) && $_REQUEST['order'] === 'date') ? 'active' : ''), - 'title' => t('Order by recent'), - ), + 'name' => array( + 'label' => t('Name'), + 'url' => z_root() . '/connections' . ((argv(1)) ? '/' . argv(1) : '') . '?order=name', + 'sel' => ((isset($_REQUEST['order']) && $_REQUEST['order'] !== 'name') ? 'active' : ''), + 'title' => t('Order by name'), + ), - 'created' => array( - 'label' => t('Created'), - 'url' => z_root() . '/connections' . ((argv(1)) ? '/' . argv(1) : '') . '?order=created', - 'sel' => ((isset($_REQUEST['order']) && $_REQUEST['order'] === 'created') ? 'active' : ''), - 'title' => t('Order by date'), - ), + 'date' => array( + 'label' => t('Recent'), + 'url' => z_root() . '/connections' . ((argv(1)) ? '/' . argv(1) : '') . '?order=date', + 'sel' => ((isset($_REQUEST['order']) && $_REQUEST['order'] === 'date') ? 'active' : ''), + 'title' => t('Order by recent'), + ), + + 'created' => array( + 'label' => t('Created'), + 'url' => z_root() . '/connections' . ((argv(1)) ? '/' . argv(1) : '') . '?order=created', + 'sel' => ((isset($_REQUEST['order']) && $_REQUEST['order'] === 'created') ? 'active' : ''), + 'title' => t('Order by date'), + ), // reserved for cmax // 'date' => array( // 'label' => t(''), @@ -258,137 +259,133 @@ class Connections extends Controller { // 'title' => t('Order by recent'), // ), - ); + ); - - - $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra ORDER BY $order_q LIMIT %d OFFSET %d ", - intval(local_channel()), - intval(App::$pager['itemspage']), - intval(App::$pager['start']) - ); - - $contacts = []; - - if($r) { + intval(local_channel()), + intval(App::$pager['itemspage']), + intval(App::$pager['start']) + ); - vcard_query($r); + $contacts = []; + + if ($r) { + + vcard_query($r); - foreach($r as $rr) { - if ((! $blocked) && LibBlock::fetch_by_entity(local_channel(),$rr['xchan_hash'])) { - continue; - } - if($rr['xchan_url']) { + foreach ($r as $rr) { + if ((!$blocked) && LibBlock::fetch_by_entity(local_channel(), $rr['xchan_hash'])) { + continue; + } + if ($rr['xchan_url']) { - if((isset($rr['vcard']) && $rr['vcard']) && is_array($rr['vcard']['tels']) && $rr['vcard']['tels'][0]['nr']) - $phone = $rr['vcard']['tels'][0]['nr']; - else - $phone = ''; - - $status_str = ''; - $status = array( - ((isset($rr['abook_active']) && intval($rr['abook_active'])) ? t('Active') : ''), - ((intval($rr['abook_pending'])) ? t('Pending approval') : ''), - ((intval($rr['abook_archived'])) ? t('Archived') : ''), - ((intval($rr['abook_hidden'])) ? t('Hidden') : ''), - ((intval($rr['abook_ignored'])) ? t('Ignored') : ''), - ((intval($rr['abook_blocked'])) ? t('Blocked') : ''), - ((intval($rr['abook_not_here'])) ? t('Not connected at this location') : '') - ); + if ((isset($rr['vcard']) && $rr['vcard']) && is_array($rr['vcard']['tels']) && $rr['vcard']['tels'][0]['nr']) + $phone = $rr['vcard']['tels'][0]['nr']; + else + $phone = ''; + + $status_str = ''; + $status = array( + ((isset($rr['abook_active']) && intval($rr['abook_active'])) ? t('Active') : ''), + ((intval($rr['abook_pending'])) ? t('Pending approval') : ''), + ((intval($rr['abook_archived'])) ? t('Archived') : ''), + ((intval($rr['abook_hidden'])) ? t('Hidden') : ''), + ((intval($rr['abook_ignored'])) ? t('Ignored') : ''), + ((intval($rr['abook_blocked'])) ? t('Blocked') : ''), + ((intval($rr['abook_not_here'])) ? t('Not connected at this location') : '') + ); + + $oneway = false; + if (!their_perms_contains(local_channel(), $rr['xchan_hash'], 'post_comments')) { + $oneway = true; + } + + foreach ($status as $str) { + if (!$str) + continue; + $status_str .= $str; + $status_str .= ', '; + } + $status_str = rtrim($status_str, ', '); + + $contacts[] = array( + 'img_hover' => sprintf(t('%1$s [%2$s]'), $rr['xchan_name'], $rr['xchan_url']), + 'edit_hover' => t('Edit connection'), + 'edit' => t('Edit'), + 'delete_hover' => t('Delete connection'), + 'id' => $rr['abook_id'], + 'thumb' => $rr['xchan_photo_m'], + 'name' => $rr['xchan_name'] . (($rr['abook_alias']) ? ' <' . $rr['abook_alias'] . '>' : ''), + 'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''), + 'link' => z_root() . '/connedit/' . $rr['abook_id'], + 'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop', + 'delete' => t('Delete'), + 'url' => chanlink_hash($rr['xchan_hash']), + 'webbie_label' => t('Channel address'), + 'webbie' => $rr['xchan_addr'], + 'network_label' => t('Network'), + 'network' => network_to_name($rr['xchan_network']), + 'channel_type' => intval($rr['xchan_type']), + 'call' => t('Call'), + 'phone' => $phone, + 'status_label' => t('Status'), + 'status' => $status_str, + 'connected_label' => t('Connected'), + 'connected' => datetime_convert('UTC', date_default_timezone_get(), $rr['abook_created'], 'c'), + 'approve_hover' => t('Approve connection'), + 'approve' => (($rr['abook_pending']) ? t('Approve') : false), + 'ignore_hover' => t('Ignore connection'), + 'ignore' => ((!$rr['abook_ignored']) ? t('Ignore') : false), + 'recent_label' => t('Recent activity'), + 'recentlink' => z_root() . '/stream/?f=&cid=' . intval($rr['abook_id']), + 'oneway' => $oneway, + 'allow_delete' => ($rr['abook_pending'] || get_pconfig(local_channel(), 'system', 'connections_quick_delete')), + ); + } + } + } + + + if ($_REQUEST['aj']) { + if ($contacts) { + $o = replace_macros(get_markup_template('contactsajax.tpl'), array( + '$contacts' => $contacts, + '$edit' => t('Edit'), + )); + } else { + $o = '
        '; + } + echo $o; + killme(); + } else { + $o .= ""; + $o .= replace_macros(get_markup_template('connections.tpl'), array( + '$header' => t('Connections') . (($head) ? ': ' . $head : ''), + '$tabs' => $tabs, + '$order' => $order, + '$sort' => t('Filter by'), + '$sortorder' => t('Sort by'), + '$total' => $total, + '$search' => ((isset($search_hdr)) ? $search_hdr : EMPTY_STR), + '$label' => t('Search'), + '$desc' => t('Search your connections'), + '$finding' => (($searching) ? t('Connections search') . ": '" . $search . "'" : ""), + '$submit' => t('Find'), + '$edit' => t('Edit'), + '$cmd' => App::$cmd, + '$contacts' => $contacts, + '$paginate' => paginate($a), + + )); + } + + if (!$contacts) + $o .= '
        '; + + return $o; + } - $oneway = false; - if(! their_perms_contains(local_channel(),$rr['xchan_hash'],'post_comments')) { - $oneway = true; - } - - foreach($status as $str) { - if(!$str) - continue; - $status_str .= $str; - $status_str .= ', '; - } - $status_str = rtrim($status_str, ', '); - - $contacts[] = array( - 'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']), - 'edit_hover' => t('Edit connection'), - 'edit' => t('Edit'), - 'delete_hover' => t('Delete connection'), - 'id' => $rr['abook_id'], - 'thumb' => $rr['xchan_photo_m'], - 'name' => $rr['xchan_name'] . (($rr['abook_alias']) ? ' <' . $rr['abook_alias'] . '>' : ''), - 'classes' => ((intval($rr['abook_archived']) || intval($rr['abook_not_here'])) ? 'archived' : ''), - 'link' => z_root() . '/connedit/' . $rr['abook_id'], - 'deletelink' => z_root() . '/connedit/' . intval($rr['abook_id']) . '/drop', - 'delete' => t('Delete'), - 'url' => chanlink_hash($rr['xchan_hash']), - 'webbie_label' => t('Channel address'), - 'webbie' => $rr['xchan_addr'], - 'network_label' => t('Network'), - 'network' => network_to_name($rr['xchan_network']), - 'channel_type' => intval($rr['xchan_type']), - 'call' => t('Call'), - 'phone' => $phone, - 'status_label' => t('Status'), - 'status' => $status_str, - 'connected_label' => t('Connected'), - 'connected' => datetime_convert('UTC',date_default_timezone_get(),$rr['abook_created'], 'c'), - 'approve_hover' => t('Approve connection'), - 'approve' => (($rr['abook_pending']) ? t('Approve') : false), - 'ignore_hover' => t('Ignore connection'), - 'ignore' => ((! $rr['abook_ignored']) ? t('Ignore') : false), - 'recent_label' => t('Recent activity'), - 'recentlink' => z_root() . '/stream/?f=&cid=' . intval($rr['abook_id']), - 'oneway' => $oneway, - 'allow_delete' => ($rr['abook_pending'] || get_pconfig(local_channel(),'system','connections_quick_delete')), - ); - } - } - } - - - if($_REQUEST['aj']) { - if($contacts) { - $o = replace_macros(get_markup_template('contactsajax.tpl'),array( - '$contacts' => $contacts, - '$edit' => t('Edit'), - )); - } - else { - $o = '
        '; - } - echo $o; - killme(); - } - else { - $o .= ""; - $o .= replace_macros(get_markup_template('connections.tpl'),array( - '$header' => t('Connections') . (($head) ? ': ' . $head : ''), - '$tabs' => $tabs, - '$order' => $order, - '$sort' => t('Filter by'), - '$sortorder' => t('Sort by'), - '$total' => $total, - '$search' => ((isset($search_hdr)) ? $search_hdr : EMPTY_STR), - '$label' => t('Search'), - '$desc' => t('Search your connections'), - '$finding' => (($searching) ? t('Connections search') . ": '" . $search . "'" : ""), - '$submit' => t('Find'), - '$edit' => t('Edit'), - '$cmd' => App::$cmd, - '$contacts' => $contacts, - '$paginate' => paginate($a), - - )); - } - - if(! $contacts) - $o .= '
        '; - - return $o; - } - } diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php index 98e61b296..40dda220f 100644 --- a/Zotlabs/Module/Connedit.php +++ b/Zotlabs/Module/Connedit.php @@ -26,863 +26,860 @@ require_once('include/socgraph.php'); require_once('include/photos.php'); -class Connedit extends Controller { +class Connedit extends Controller +{ - /** - * @brief Initialize the connection-editor - */ + /** + * @brief Initialize the connection-editor + */ - function init() { - - if (! local_channel()) { - return; - } - - if ((argc() >= 2) && intval(argv(1))) { - $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash + public function init() + { + + if (!local_channel()) { + return; + } + + if ((argc() >= 2) && intval(argv(1))) { + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_channel()), - intval(argv(1)) - ); - // Set the person-of-interest for use by widgets that operate on a single pre-defined channel - if ($r) { - App::$poi = array_shift($r); - } - } - - $channel = App::get_channel(); - if ($channel) { - head_set_icon($channel['xchan_photo_s']); - } - } + intval(local_channel()), + intval(argv(1)) + ); + // Set the person-of-interest for use by widgets that operate on a single pre-defined channel + if ($r) { + App::$poi = array_shift($r); + } + } - - /** - * @brief Evaluate posted values and set changes - */ - - function post() { - - if (! local_channel()) { - return; - } - - $contact_id = intval(argv(1)); - if (! $contact_id) { - return; - } - - $channel = App::get_channel(); - - $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", - intval($contact_id), - intval(local_channel()) - ); - - if (! $orig_record) { - notice( t('Could not access contact record.') . EOL); - goaway(z_root() . '/connections'); - } + $channel = App::get_channel(); + if ($channel) { + head_set_icon($channel['xchan_photo_s']); + } + } - $orig_record = array_shift($orig_record); - call_hooks('contact_edit_post', $_POST); - - $vc = get_abconfig(local_channel(),$orig_record['abook_xchan'],'system','vcard'); - $vcard = (($vc) ? Reader::read($vc) : null); - $serialised_vcard = update_vcard($_REQUEST,$vcard); - if ($serialised_vcard) { - set_abconfig(local_channel(),$orig_record['abook_xchan'],'system','vcard',$serialised_vcard); - } + /** + * @brief Evaluate posted values and set changes + */ - $autoperms = null; - $is_self = false; + public function post() + { - if (intval($orig_record['abook_self'])) { - $autoperms = intval($_POST['autoperms']); - $is_self = true; - } - - $profile_id = ((array_key_exists('profile_assign',$_POST)) ? $_POST['profile_assign'] : $orig_record['abook_profile']); + if (!local_channel()) { + return; + } - if ($profile_id) { - $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND uid = %d LIMIT 1", - dbesc($profile_id), - intval(local_channel()) - ); - if (! $r) { - notice( t('Could not locate selected profile.') . EOL); - return; - } - } - - $abook_incl = ((array_key_exists('abook_incl',$_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record['abook_incl']); - $abook_excl = ((array_key_exists('abook_excl',$_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record['abook_excl']); - $abook_alias = ((array_key_exists('abook_alias',$_POST)) ? escape_tags(trim($_POST['abook_alias'])) : $orig_record['abook_alias']); + $contact_id = intval(argv(1)); + if (!$contact_id) { + return; + } - $block_announce = ((array_key_exists('block_announce',$_POST)) ? intval($_POST['block_announce']) : 0); - - set_abconfig($channel['channel_id'],$orig_record['abook_xchan'],'system','block_announce',$block_announce); + $channel = App::get_channel(); - $hidden = intval($_POST['hidden']); - - $priority = intval($_POST['poll']); - if ($priority > 5 || $priority < 0) { - $priority = 0; - } - - if (! array_key_exists('closeness',$_POST)) { - $_POST['closeness'] = 80; - } - $closeness = intval($_POST['closeness']); - if ($closeness < 0 || $closeness > 99) { - $closeness = 80; - } - - $all_perms = Permissions::Perms(); + $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + intval($contact_id), + intval(local_channel()) + ); - $p = EMPTY_STR; + if (!$orig_record) { + notice(t('Could not access contact record.') . EOL); + goaway(z_root() . '/connections'); + } - if ($all_perms) { - foreach ($all_perms as $perm => $desc) { - if (array_key_exists('perms_' . $perm, $_POST)) { - if ($p) { - $p .= ','; - } - $p .= $perm; - } - } - set_abconfig($channel['channel_id'],$orig_record['abook_xchan'],'system','my_perms',$p); - if ($autoperms) { - set_pconfig($channel['channel_id'],'system','autoperms',$p); - } - } + $orig_record = array_shift($orig_record); - $new_friend = false; - - if (($_REQUEST['pending']) && intval($orig_record['abook_pending'])) { + call_hooks('contact_edit_post', $_POST); - $new_friend = true; - - // @fixme it won't be common, but when you accept a new connection request - // the permissions will now be that of your permissions role and ignore - // any you may have set manually on the form. We'll probably see a bug if somebody - // tries to set the permissions *and* approve the connection in the same - // request. The workaround is to approve the connection, then go back and - // adjust permissions as desired. - - $p = Permissions::connect_perms(local_channel()); - $my_perms = Permissions::serialise($p['perms']); - if ($my_perms) { - set_abconfig($channel['channel_id'],$orig_record['abook_xchan'],'system','my_perms',$my_perms); - } - } + $vc = get_abconfig(local_channel(), $orig_record['abook_xchan'], 'system', 'vcard'); + $vcard = (($vc) ? Reader::read($vc) : null); + $serialised_vcard = update_vcard($_REQUEST, $vcard); + if ($serialised_vcard) { + set_abconfig(local_channel(), $orig_record['abook_xchan'], 'system', 'vcard', $serialised_vcard); + } - $abook_pending = (($new_friend) ? 0 : $orig_record['abook_pending']); + $autoperms = null; + $is_self = false; - $r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d, + if (intval($orig_record['abook_self'])) { + $autoperms = intval($_POST['autoperms']); + $is_self = true; + } + + $profile_id = ((array_key_exists('profile_assign', $_POST)) ? $_POST['profile_assign'] : $orig_record['abook_profile']); + + if ($profile_id) { + $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND uid = %d LIMIT 1", + dbesc($profile_id), + intval(local_channel()) + ); + if (!$r) { + notice(t('Could not locate selected profile.') . EOL); + return; + } + } + + $abook_incl = ((array_key_exists('abook_incl', $_POST)) ? escape_tags($_POST['abook_incl']) : $orig_record['abook_incl']); + $abook_excl = ((array_key_exists('abook_excl', $_POST)) ? escape_tags($_POST['abook_excl']) : $orig_record['abook_excl']); + $abook_alias = ((array_key_exists('abook_alias', $_POST)) ? escape_tags(trim($_POST['abook_alias'])) : $orig_record['abook_alias']); + + $block_announce = ((array_key_exists('block_announce', $_POST)) ? intval($_POST['block_announce']) : 0); + + set_abconfig($channel['channel_id'], $orig_record['abook_xchan'], 'system', 'block_announce', $block_announce); + + $hidden = intval($_POST['hidden']); + + $priority = intval($_POST['poll']); + if ($priority > 5 || $priority < 0) { + $priority = 0; + } + + if (!array_key_exists('closeness', $_POST)) { + $_POST['closeness'] = 80; + } + $closeness = intval($_POST['closeness']); + if ($closeness < 0 || $closeness > 99) { + $closeness = 80; + } + + $all_perms = Permissions::Perms(); + + $p = EMPTY_STR; + + if ($all_perms) { + foreach ($all_perms as $perm => $desc) { + if (array_key_exists('perms_' . $perm, $_POST)) { + if ($p) { + $p .= ','; + } + $p .= $perm; + } + } + set_abconfig($channel['channel_id'], $orig_record['abook_xchan'], 'system', 'my_perms', $p); + if ($autoperms) { + set_pconfig($channel['channel_id'], 'system', 'autoperms', $p); + } + } + + $new_friend = false; + + if (($_REQUEST['pending']) && intval($orig_record['abook_pending'])) { + + $new_friend = true; + + // @fixme it won't be common, but when you accept a new connection request + // the permissions will now be that of your permissions role and ignore + // any you may have set manually on the form. We'll probably see a bug if somebody + // tries to set the permissions *and* approve the connection in the same + // request. The workaround is to approve the connection, then go back and + // adjust permissions as desired. + + $p = Permissions::connect_perms(local_channel()); + $my_perms = Permissions::serialise($p['perms']); + if ($my_perms) { + set_abconfig($channel['channel_id'], $orig_record['abook_xchan'], 'system', 'my_perms', $my_perms); + } + } + + $abook_pending = (($new_friend) ? 0 : $orig_record['abook_pending']); + + $r = q("UPDATE abook SET abook_profile = '%s', abook_closeness = %d, abook_pending = %d, abook_incl = '%s', abook_excl = '%s', abook_alias = '%s' where abook_id = %d AND abook_channel = %d", - dbesc($profile_id), - intval($closeness), - intval($abook_pending), - dbesc($abook_incl), - dbesc($abook_excl), - dbesc($abook_alias), - intval($contact_id), - intval(local_channel()) - ); - - if ($r) { - info( t('Connection updated.') . EOL); - } - else { - notice( t('Failed to update connection record.') . EOL); - } - - if (! intval(App::$poi['abook_self'])) { - if ($new_friend) { - Run::Summon( [ 'Notifier', 'permissions_accept', $contact_id ] ); - } + dbesc($profile_id), + intval($closeness), + intval($abook_pending), + dbesc($abook_incl), + dbesc($abook_excl), + dbesc($abook_alias), + intval($contact_id), + intval(local_channel()) + ); - Run::Summon( [ - 'Notifier', - (($new_friend) ? 'permissions_create' : 'permissions_update'), - $contact_id - ]); - } - - if ($new_friend) { - $default_group = $channel['channel_default_group']; - if ($default_group) { - $g = AccessList::rec_byhash(local_channel(),$default_group); - if ($g) { - AccessList::member_add(local_channel(),'',App::$poi['abook_xchan'],$g['id']); - } - } - - // Check if settings permit ("post new friend activity" is allowed, and - // friends in general or this friend in particular aren't hidden) - // and send out a new friend activity - - $pr = q("select * from profile where uid = %d and is_default = 1 and hide_friends = 0", - intval($channel['channel_id']) - ); - if (($pr) && (! intval($orig_record['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'],'system','post_newfriend')))) { - $xarr = []; + if ($r) { + info(t('Connection updated.') . EOL); + } else { + notice(t('Failed to update connection record.') . EOL); + } - $xarr['item_wall'] = 1; - $xarr['item_origin'] = 1; - $xarr['item_thread_top'] = 1; - $xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash']; - $xarr['allow_cid'] = $channel['channel_allow_cid']; - $xarr['allow_gid'] = $channel['channel_allow_gid']; - $xarr['deny_cid'] = $channel['channel_deny_cid']; - $xarr['deny_gid'] = $channel['channel_deny_gid']; - $xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0); - - $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]'; - - $xarr['body'] .= "\n\n\n" . '[zrl=' . App::$poi['xchan_url'] . '][zmg=80x80]' . App::$poi['xchan_photo_m'] . '[/zmg][/zrl]'; - - post_activity_item($xarr); - - } - - // pull in a bit of content if there is any to pull in - Run::Summon( [ 'Onepoll', $contact_id ]); - } - - // Refresh the structure in memory with the new data - - $r = q("SELECT abook.*, xchan.* + if (!intval(App::$poi['abook_self'])) { + if ($new_friend) { + Run::Summon(['Notifier', 'permissions_accept', $contact_id]); + } + + Run::Summon([ + 'Notifier', + (($new_friend) ? 'permissions_create' : 'permissions_update'), + $contact_id + ]); + } + + if ($new_friend) { + $default_group = $channel['channel_default_group']; + if ($default_group) { + $g = AccessList::rec_byhash(local_channel(), $default_group); + if ($g) { + AccessList::member_add(local_channel(), '', App::$poi['abook_xchan'], $g['id']); + } + } + + // Check if settings permit ("post new friend activity" is allowed, and + // friends in general or this friend in particular aren't hidden) + // and send out a new friend activity + + $pr = q("select * from profile where uid = %d and is_default = 1 and hide_friends = 0", + intval($channel['channel_id']) + ); + if (($pr) && (!intval($orig_record['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'], 'system', 'post_newfriend')))) { + $xarr = []; + + $xarr['item_wall'] = 1; + $xarr['item_origin'] = 1; + $xarr['item_thread_top'] = 1; + $xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash']; + $xarr['allow_cid'] = $channel['channel_allow_cid']; + $xarr['allow_gid'] = $channel['channel_allow_gid']; + $xarr['deny_cid'] = $channel['channel_deny_cid']; + $xarr['deny_gid'] = $channel['channel_deny_gid']; + $xarr['item_private'] = (($xarr['allow_cid'] || $xarr['allow_gid'] || $xarr['deny_cid'] || $xarr['deny_gid']) ? 1 : 0); + + $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . App::$poi['xchan_url'] . ']' . App::$poi['xchan_name'] . '[/zrl]'; + + $xarr['body'] .= "\n\n\n" . '[zrl=' . App::$poi['xchan_url'] . '][zmg=80x80]' . App::$poi['xchan_photo_m'] . '[/zmg][/zrl]'; + + post_activity_item($xarr); + + } + + // pull in a bit of content if there is any to pull in + Run::Summon(['Onepoll', $contact_id]); + } + + // Refresh the structure in memory with the new data + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_channel()), - intval($contact_id) - ); - if ($r) { - App::$poi = array_shift($r); - } - - if ($new_friend) { - $arr = [ 'channel_id' => local_channel(), 'abook' => App::$poi ]; - call_hooks('accept_follow', $arr); - } - - $this->connedit_clone($a); - - if (($_REQUEST['pending']) && (!$_REQUEST['done'])) { - goaway(z_root() . '/connections/ifpending'); - } - - return; - - } - - /* @brief Clone connection - * - * - */ - - function connedit_clone(&$a) { - - if (! App::$poi) { - return; - } - - $channel = App::get_channel(); - - $r = q("SELECT abook.*, xchan.* + intval(local_channel()), + intval($contact_id) + ); + if ($r) { + App::$poi = array_shift($r); + } + + if ($new_friend) { + $arr = ['channel_id' => local_channel(), 'abook' => App::$poi]; + call_hooks('accept_follow', $arr); + } + + $this->connedit_clone($a); + + if (($_REQUEST['pending']) && (!$_REQUEST['done'])) { + goaway(z_root() . '/connections/ifpending'); + } + + return; + + } + + /* @brief Clone connection + * + * + */ + + public function connedit_clone(&$a) + { + + if (!App::$poi) { + return; + } + + $channel = App::get_channel(); + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_channel()), - intval(App::$poi['abook_id']) - ); - if (! $r) { - return; - } + intval(local_channel()), + intval(App::$poi['abook_id']) + ); + if (!$r) { + return; + } - App::$poi = array_shift($r); - $clone = App::$poi; - - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); - - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if ($abconfig) { - $clone['abconfig'] = $abconfig; - } - Libsync::build_sync_packet($channel['channel_id'], [ 'abook' => [ $clone ] ] ); - } - - /** - * @brief Generate content of connection edit page - */ - - function get() { - - $sort_type = 0; - $o = EMPTY_STR; - - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return login(); - } - - $section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : ''); - $channel = App::get_channel(); - - $yes_no = [ t('No'), t('Yes') ]; - - $connect_perms = Permissions::connect_perms(local_channel()); + App::$poi = array_shift($r); + $clone = App::$poi; - $o .= "\n"; - - if (argc() == 3) { - - $contact_id = intval(argv(1)); - if (! $contact_id) { - return; - } - - $cmd = argv(2); - - $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash + foreach ($connect_perms['perms'] as $p => $v) { + if ($v) { + $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n"; + } + } + $o .= " }\n\n"; + + if (argc() == 3) { + + $contact_id = intval(argv(1)); + if (!$contact_id) { + return; + } + + $cmd = argv(2); + + $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1", - intval($contact_id), - intval(local_channel()) - ); - - if (! $orig_record) { - notice( t('Could not access address book record.') . EOL); - goaway(z_root() . '/connections'); - } + intval($contact_id), + intval(local_channel()) + ); - $orig_record = array_shift($orig_record); + if (!$orig_record) { + notice(t('Could not access address book record.') . EOL); + goaway(z_root() . '/connections'); + } - if ($cmd === 'update') { - // pull feed and consume it, which should subscribe to the hub. - Run::Summon( [ 'Poller', $contact_id ]); - goaway(z_root() . '/connedit/' . $contact_id); - } + $orig_record = array_shift($orig_record); - if ($cmd === 'fetchvc') { - $url = str_replace('/channel/','/profile/',$orig_record['xchan_url']) . '/vcard'; - $recurse = 0; - $x = z_fetch_url(zid($url),false,$recurse,['session' => true]); - if ($x['success']) { - $h = new HTTPHeaders($x['header']); - $fields = $h->fetcharr(); - if ($fields && array_key_exists('content-type',$fields)) { - $type = explode(';',trim($fields['content-type'])); - if ($type && $type[0] === 'text/vcard' && $x['body']) { - $vc = Reader::read($x['body']); - $vcard = $vc->serialize(); - if ($vcard) { - set_abconfig(local_channel(),$orig_record['abook_xchan'],'system','vcard',$vcard); - $this->connedit_clone($a); - } - } - } - } - goaway(z_root() . '/connedit/' . $contact_id); - } + if ($cmd === 'update') { + // pull feed and consume it, which should subscribe to the hub. + Run::Summon(['Poller', $contact_id]); + goaway(z_root() . '/connedit/' . $contact_id); + } + + if ($cmd === 'fetchvc') { + $url = str_replace('/channel/', '/profile/', $orig_record['xchan_url']) . '/vcard'; + $recurse = 0; + $x = z_fetch_url(zid($url), false, $recurse, ['session' => true]); + if ($x['success']) { + $h = new HTTPHeaders($x['header']); + $fields = $h->fetcharr(); + if ($fields && array_key_exists('content-type', $fields)) { + $type = explode(';', trim($fields['content-type'])); + if ($type && $type[0] === 'text/vcard' && $x['body']) { + $vc = Reader::read($x['body']); + $vcard = $vc->serialize(); + if ($vcard) { + set_abconfig(local_channel(), $orig_record['abook_xchan'], 'system', 'vcard', $vcard); + $this->connedit_clone($a); + } + } + } + } + goaway(z_root() . '/connedit/' . $contact_id); + } - if ($cmd === 'resetphoto') { - q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s'", - dbesc($orig_record['xchan_hash']) - ); - $cmd = 'refresh'; - } + if ($cmd === 'resetphoto') { + q("update xchan set xchan_photo_date = '2001-01-01 00:00:00' where xchan_hash = '%s'", + dbesc($orig_record['xchan_hash']) + ); + $cmd = 'refresh'; + } - if ($cmd === 'refresh') { - if($orig_record['xchan_network'] === 'zot6') { - if (! Libzot::refresh($orig_record, App::get_channel())) { - notice( t('Refresh failed - channel is currently unavailable.') ); - } - } - else { - if ($orig_record['xchan_network'] === 'activitypub') { - ActivityPub::discover($orig_record['xchan_hash'],true); - } - // if they are on a different network we'll force a refresh of the connection basic info - Run::Summon( [ 'Notifier', 'permissions_update', $contact_id ]); - } - goaway(z_root() . '/connedit/' . $contact_id); - } + if ($cmd === 'refresh') { + if ($orig_record['xchan_network'] === 'zot6') { + if (!Libzot::refresh($orig_record, App::get_channel())) { + notice(t('Refresh failed - channel is currently unavailable.')); + } + } else { + if ($orig_record['xchan_network'] === 'activitypub') { + ActivityPub::discover($orig_record['xchan_hash'], true); + } + // if they are on a different network we'll force a refresh of the connection basic info + Run::Summon(['Notifier', 'permissions_update', $contact_id]); + } + goaway(z_root() . '/connedit/' . $contact_id); + } - switch ($cmd) { - case 'block': - if (intval($orig_record['abook_blocked'])) { - LibBlock::remove(local_channel(),$orig_record['abook_xchan']); - $sync = [ - 'block_channel_id' => local_channel(), - 'block_entity' => $orig_record['abook_xchan'], - 'block_type' => BLOCKTYPE_CHANNEL, - 'deleted' => true, - ]; - } - else { - LibBlock::store( [ - 'block_channel_id' => local_channel(), - 'block_entity' => $orig_record['abook_xchan'], - 'block_type' => BLOCKTYPE_CHANNEL, - 'block_comment' => t('Added by Connedit') - ]); - $z = q("insert into xign ( uid, xchan ) values ( %d , '%s' ) ", - intval(local_channel()), - dbesc($orig_record['abook_xchan']) - ); - $sync = LibBlock::fetch_by_entity(local_channel(),$orig_record['abook_xchan']); - } - $ignored = [ 'uid' => local_channel(), 'xchan' => $orig_record['abook_xchan'] ]; - Libsync::build_sync_packet(0, [ 'xign' => [ $ignored ], 'block' => [ $sync ]] ); - $flag_result = abook_toggle_flag($orig_record,ABOOK_FLAG_BLOCKED); - break; - case 'ignore': - $flag_result = abook_toggle_flag($orig_record,ABOOK_FLAG_IGNORED); - break; - case 'censor': - $flag_result = abook_toggle_flag($orig_record,ABOOK_FLAG_CENSORED); - break; - case 'archive': - $flag_result = abook_toggle_flag($orig_record,ABOOK_FLAG_ARCHIVED); - break; - case 'hide': - $flag_result = abook_toggle_flag($orig_record,ABOOK_FLAG_HIDDEN); - break; - case 'approve': - if(intval($orig_record['abook_pending'])) { - $flag_result = abook_toggle_flag($orig_record,ABOOK_FLAG_PENDING); - } - break; - default: - break; - } + switch ($cmd) { + case 'block': + if (intval($orig_record['abook_blocked'])) { + LibBlock::remove(local_channel(), $orig_record['abook_xchan']); + $sync = [ + 'block_channel_id' => local_channel(), + 'block_entity' => $orig_record['abook_xchan'], + 'block_type' => BLOCKTYPE_CHANNEL, + 'deleted' => true, + ]; + } else { + LibBlock::store([ + 'block_channel_id' => local_channel(), + 'block_entity' => $orig_record['abook_xchan'], + 'block_type' => BLOCKTYPE_CHANNEL, + 'block_comment' => t('Added by Connedit') + ]); + $z = q("insert into xign ( uid, xchan ) values ( %d , '%s' ) ", + intval(local_channel()), + dbesc($orig_record['abook_xchan']) + ); + $sync = LibBlock::fetch_by_entity(local_channel(), $orig_record['abook_xchan']); + } + $ignored = ['uid' => local_channel(), 'xchan' => $orig_record['abook_xchan']]; + Libsync::build_sync_packet(0, ['xign' => [$ignored], 'block' => [$sync]]); + $flag_result = abook_toggle_flag($orig_record, ABOOK_FLAG_BLOCKED); + break; + case 'ignore': + $flag_result = abook_toggle_flag($orig_record, ABOOK_FLAG_IGNORED); + break; + case 'censor': + $flag_result = abook_toggle_flag($orig_record, ABOOK_FLAG_CENSORED); + break; + case 'archive': + $flag_result = abook_toggle_flag($orig_record, ABOOK_FLAG_ARCHIVED); + break; + case 'hide': + $flag_result = abook_toggle_flag($orig_record, ABOOK_FLAG_HIDDEN); + break; + case 'approve': + if (intval($orig_record['abook_pending'])) { + $flag_result = abook_toggle_flag($orig_record, ABOOK_FLAG_PENDING); + } + break; + default: + break; + } - if (isset($flag_result)) { - if ($flag_result) { - $this->connedit_clone($a); - } - else { - notice(t('Unable to set address book parameters.') . EOL); - } - goaway(z_root() . '/connedit/' . $contact_id); - } - - if ($cmd === 'drop') { - if ($orig_record['xchan_network'] === 'activitypub') { - ActivityPub::contact_remove(local_channel(), $orig_record); - } - contact_remove(local_channel(), $orig_record['abook_id'], true); + if (isset($flag_result)) { + if ($flag_result) { + $this->connedit_clone($a); + } else { + notice(t('Unable to set address book parameters.') . EOL); + } + goaway(z_root() . '/connedit/' . $contact_id); + } - // The purge notification is sent to the xchan_hash as the abook record will have just been removed - - Run::Summon( [ 'Notifier' , 'purge', $orig_record['xchan_hash'] ] ); - - Libsync::build_sync_packet(0, [ 'abook' => [ [ 'abook_xchan' => $orig_record['abook_xchan'], 'entry_deleted' => true ] ] ] ); - - info( t('Connection has been removed.') . EOL ); - if (isset($_SESSION['return_url']) && $_SESSION['return_url']) { - goaway(z_root() . '/' . $_SESSION['return_url']); - } - goaway(z_root() . '/contacts'); - } - } - - if (App::$poi) { - - $abook_prev = 0; - $abook_next = 0; + if ($cmd === 'drop') { + if ($orig_record['xchan_network'] === 'activitypub') { + ActivityPub::contact_remove(local_channel(), $orig_record); + } + contact_remove(local_channel(), $orig_record['abook_id'], true); - $contact_id = App::$poi['abook_id']; - $contact = App::$poi; + // The purge notification is sent to the xchan_hash as the abook record will have just been removed - $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name", - intval(local_channel()) - ); + Run::Summon(['Notifier', 'purge', $orig_record['xchan_hash']]); - if ($cn) { - // store previous/next ids for navigation - $pntotal = count($cn); + Libsync::build_sync_packet(0, ['abook' => [['abook_xchan' => $orig_record['abook_xchan'], 'entry_deleted' => true]]]); - for ($x = 0; $x < $pntotal; $x ++) { - if ($cn[$x]['abook_id'] == $contact_id) { - if ($x === 0) { - $abook_prev = 0; - } - else { - $abook_prev = $cn[$x - 1]['abook_id']; - } - if ($x === $pntotal) { - $abook_next = 0; - } - else { - $abook_next = $cn[$x +1]['abook_id']; - } - } - } - } + info(t('Connection has been removed.') . EOL); + if (isset($_SESSION['return_url']) && $_SESSION['return_url']) { + goaway(z_root() . '/' . $_SESSION['return_url']); + } + goaway(z_root() . '/contacts'); + } + } - $tools = array( - - 'view' => array( - 'label' => t('View Profile'), - 'url' => chanlink_cid($contact['abook_id']), - 'sel' => '', - 'title' => sprintf( t('View %s\'s profile'), $contact['xchan_name']), - ), - - 'refresh' => array( - 'label' => t('Refresh Permissions'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh', - 'sel' => '', - 'title' => t('Fetch updated permissions'), - ), + if (App::$poi) { - 'rephoto' => array( - 'label' => t('Refresh Photo'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/resetphoto', - 'sel' => '', - 'title' => t('Fetch updated photo'), - ), - - 'recent' => array( - 'label' => t('Recent Activity'), - 'url' => z_root() . '/stream/?f=&cid=' . $contact['abook_id'], - 'sel' => '', - 'title' => t('View recent posts and comments'), - ), - - 'block' => array( - 'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', - 'sel' => (intval($contact['abook_blocked']) ? 'active' : ''), - 'title' => t('Block (or Unblock) all communications with this connection'), - 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked') : ''), - ), - - 'ignore' => array( - 'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', - 'sel' => (intval($contact['abook_ignored']) ? 'active' : ''), - 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), - 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored') : ''), - ), + $abook_prev = 0; + $abook_next = 0; - 'censor' => array( - 'label' => (intval($contact['abook_censor']) ? t('Uncensor') : t('Censor')), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor', - 'sel' => (intval($contact['abook_censor']) ? 'active' : ''), - 'title' => t('Censor (or Uncensor) images from this connection'), - 'info' => (intval($contact['abook_censor']) ? t('This connection is censored') : ''), - ), + $contact_id = App::$poi['abook_id']; + $contact = App::$poi; - 'archive' => array( - 'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', - 'sel' => (intval($contact['abook_archived']) ? 'active' : ''), - 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), - 'info' => (intval($contact['abook_archived']) ? t('This connection is archived') : ''), - ), - - 'hide' => array( - 'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', - 'sel' => (intval($contact['abook_hidden']) ? 'active' : ''), - 'title' => t('Hide or Unhide this connection from your other connections'), - 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden') : ''), - ), - - 'delete' => array( - 'label' => t('Delete'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop', - 'sel' => '', - 'title' => t('Delete this connection'), - ), - - ); + $cn = q("SELECT abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 order by xchan_name", + intval(local_channel()) + ); + + if ($cn) { + // store previous/next ids for navigation + $pntotal = count($cn); + + for ($x = 0; $x < $pntotal; $x++) { + if ($cn[$x]['abook_id'] == $contact_id) { + if ($x === 0) { + $abook_prev = 0; + } else { + $abook_prev = $cn[$x - 1]['abook_id']; + } + if ($x === $pntotal) { + $abook_next = 0; + } else { + $abook_next = $cn[$x + 1]['abook_id']; + } + } + } + } + + $tools = array( + + 'view' => array( + 'label' => t('View Profile'), + 'url' => chanlink_cid($contact['abook_id']), + 'sel' => '', + 'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name']), + ), + + 'refresh' => array( + 'label' => t('Refresh Permissions'), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh', + 'sel' => '', + 'title' => t('Fetch updated permissions'), + ), + + 'rephoto' => array( + 'label' => t('Refresh Photo'), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/resetphoto', + 'sel' => '', + 'title' => t('Fetch updated photo'), + ), + + 'recent' => array( + 'label' => t('Recent Activity'), + 'url' => z_root() . '/stream/?f=&cid=' . $contact['abook_id'], + 'sel' => '', + 'title' => t('View recent posts and comments'), + ), + + 'block' => array( + 'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', + 'sel' => (intval($contact['abook_blocked']) ? 'active' : ''), + 'title' => t('Block (or Unblock) all communications with this connection'), + 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked') : ''), + ), + + 'ignore' => array( + 'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', + 'sel' => (intval($contact['abook_ignored']) ? 'active' : ''), + 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), + 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored') : ''), + ), + + 'censor' => array( + 'label' => (intval($contact['abook_censor']) ? t('Uncensor') : t('Censor')), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor', + 'sel' => (intval($contact['abook_censor']) ? 'active' : ''), + 'title' => t('Censor (or Uncensor) images from this connection'), + 'info' => (intval($contact['abook_censor']) ? t('This connection is censored') : ''), + ), + + 'archive' => array( + 'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', + 'sel' => (intval($contact['abook_archived']) ? 'active' : ''), + 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), + 'info' => (intval($contact['abook_archived']) ? t('This connection is archived') : ''), + ), + + 'hide' => array( + 'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', + 'sel' => (intval($contact['abook_hidden']) ? 'active' : ''), + 'title' => t('Hide or Unhide this connection from your other connections'), + 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden') : ''), + ), + + 'delete' => array( + 'label' => t('Delete'), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop', + 'sel' => '', + 'title' => t('Delete this connection'), + ), + + ); - if($contact['xchan_network'] === 'zot6') { - $tools['fetchvc'] = [ - 'label' => t('Fetch Vcard'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/fetchvc', - 'sel' => '', - 'title' => t('Fetch electronic calling card for this connection') - ]; - } + if ($contact['xchan_network'] === 'zot6') { + $tools['fetchvc'] = [ + 'label' => t('Fetch Vcard'), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/fetchvc', + 'sel' => '', + 'title' => t('Fetch electronic calling card for this connection') + ]; + } - $sections = []; + $sections = []; - $sections['perms'] = [ - 'label' => t('Permissions'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=perms', - 'sel' => '', - 'title' => t('Open Individual Permissions section by default'), - ]; - - $self = false; - - if(intval($contact['abook_self'])) { - $self = true; - $abook_prev = $abook_next = 0; - } - - $vc = get_abconfig(local_channel(),$contact['abook_xchan'],'system','vcard'); + $sections['perms'] = [ + 'label' => t('Permissions'), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=perms', + 'sel' => '', + 'title' => t('Open Individual Permissions section by default'), + ]; - $vctmp = (($vc) ? Reader::read($vc) : null); - $vcard = (($vctmp) ? get_vcard_array($vctmp,$contact['abook_id']) : [] ); - if(! $vcard) - $vcard['fn'] = $contact['xchan_name']; + $self = false; + + if (intval($contact['abook_self'])) { + $self = true; + $abook_prev = $abook_next = 0; + } + + $vc = get_abconfig(local_channel(), $contact['abook_xchan'], 'system', 'vcard'); + + $vctmp = (($vc) ? Reader::read($vc) : null); + $vcard = (($vctmp) ? get_vcard_array($vctmp, $contact['abook_id']) : []); + if (!$vcard) + $vcard['fn'] = $contact['xchan_name']; - $tpl = get_markup_template("abook_edit.tpl"); - - if(Apps::system_app_installed(local_channel(),'Friend Zoom')) { + $tpl = get_markup_template("abook_edit.tpl"); - $sections['affinity'] = [ - 'label' => t('Friend Zoom'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=affinity', - 'sel' => '', - 'title' => t('Open Friend Zoom section by default'), - ]; - - $labels = [ - 0 => t('Me'), - 20 => t('Family'), - 40 => t('Friends'), - 60 => t('Peers'), - 80 => t('Connections'), - 99 => t('All') - ]; - call_hooks('affinity_labels',$labels); - - $slider_tpl = get_markup_template('contact_slider.tpl'); - - $slideval = intval($contact['abook_closeness']); - - $slide = replace_macros($slider_tpl,array( - '$min' => 1, - '$val' => $slideval, - '$labels' => $labels, - )); - } + if (Apps::system_app_installed(local_channel(), 'Friend Zoom')) { - if(Apps::system_app_installed(local_channel(),'Content Filter')) { - $sections['filter'] = [ - 'label' => t('Filter'), - 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=filter', - 'sel' => '', - 'title' => t('Open Custom Filter section by default'), - ]; - } - - $rating_val = 0; - $rating_text = ''; - - $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", - dbesc($channel['channel_hash']), - dbesc($contact['xchan_hash']) - ); - - if($xl) { - $rating_val = intval($xl[0]['xlink_rating']); - $rating_text = $xl[0]['xlink_rating_text']; - } - - $rating_enabled = get_config('system','rating_enabled'); - - if($rating_enabled) { - $rating = replace_macros(get_markup_template('rating_slider.tpl'),array( - '$min' => -10, - '$val' => $rating_val - )); - } - else { - $rating = false; - } - - - $perms = []; - $channel = App::get_channel(); - - $global_perms = Permissions::Perms(); + $sections['affinity'] = [ + 'label' => t('Friend Zoom'), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=affinity', + 'sel' => '', + 'title' => t('Open Friend Zoom section by default'), + ]; - $existing = get_all_perms(local_channel(),$contact['abook_xchan'],false); - - $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'),t('Yes'))); - - $multiprofs = ((feature_enabled(local_channel(),'multi_profiles')) ? true : false); - - if($slide && !$multiprofs) - $affinity = t('Set Friend Zoom'); - - if(!$slide && $multiprofs) - $affinity = t('Set Profile'); - - if($slide && $multiprofs) - $affinity = t('Set Friend Zoom & Profile'); - - - $theirs = get_abconfig(local_channel(),$contact['abook_xchan'],'system','their_perms',EMPTY_STR); + $labels = [ + 0 => t('Me'), + 20 => t('Family'), + 40 => t('Friends'), + 60 => t('Peers'), + 80 => t('Connections'), + 99 => t('All') + ]; + call_hooks('affinity_labels', $labels); - $their_perms = Permissions::FilledPerms(explode(',',$theirs)); - foreach($global_perms as $k => $v) { - if(! array_key_exists($k,$their_perms)) - $their_perms[$k] = 1; - } + $slider_tpl = get_markup_template('contact_slider.tpl'); - $my_perms = explode(',',get_abconfig(local_channel(),$contact['abook_xchan'],'system','my_perms',EMPTY_STR)); + $slideval = intval($contact['abook_closeness']); - foreach($global_perms as $k => $v) { - $thisperm = ((in_array($k,$my_perms)) ? 1 : 0); - - $checkinherited = PermissionLimits::Get(local_channel(),$k); - - // For auto permissions (when $self is true) we don't want to look at existing - // permissions because they are enabled for the channel owner - if((! $self) && ($existing[$k])) - $thisperm = "1"; + $slide = replace_macros($slider_tpl, array( + '$min' => 1, + '$val' => $slideval, + '$labels' => $labels, + )); + } - $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); - } - - $pcat = new Permcat(local_channel()); - $pcatlist = $pcat->listing(); - $permcats = []; - if($pcatlist) { - foreach($pcatlist as $pc) { - $permcats[$pc['name']] = $pc['localname']; - } - } + if (Apps::system_app_installed(local_channel(), 'Content Filter')) { + $sections['filter'] = [ + 'label' => t('Filter'), + 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/?f=§ion=filter', + 'sel' => '', + 'title' => t('Open Custom Filter section by default'), + ]; + } - $locstr = locations_by_netid($contact['xchan_hash']); - if(! $locstr) - $locstr = unpunify($contact['xchan_url']); - - $clone_warn = ''; - $clonable = (in_array($contact['xchan_network'],['zot6','zot','rss']) ? true : false); - if(! $clonable) { - $clone_warn = ''; - $clone_warn .= ((intval($contact['abook_not_here'])) - ? t('This connection is unreachable from this location.') - : t('This connection may be unreachable from other channel locations.') - ); - $clone_warn .= '
        ' . t('Location independence is not supported by their network.'); - } - + $rating_val = 0; + $rating_text = ''; + + $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", + dbesc($channel['channel_hash']), + dbesc($contact['xchan_hash']) + ); + + if ($xl) { + $rating_val = intval($xl[0]['xlink_rating']); + $rating_text = $xl[0]['xlink_rating_text']; + } + + $rating_enabled = get_config('system', 'rating_enabled'); + + if ($rating_enabled) { + $rating = replace_macros(get_markup_template('rating_slider.tpl'), array( + '$min' => -10, + '$val' => $rating_val + )); + } else { + $rating = false; + } - if(intval($contact['abook_not_here']) && $unclonable) - $not_here = t('This connection is unreachable from this location. Location independence is not supported by their network.'); - - $o .= replace_macros($tpl, [ - '$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name']) . (($contact['abook_alias']) ? ' <' . $contact['abook_alias'] . '>' : '')), - '$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no), - '$permcat' => [ 'permcat', t('Permission role'), '', '',$permcats ], - '$permcat_new' => t('Add permission role'), - '$permcat_enable' => feature_enabled(local_channel(),'permcats'), - '$addr' => unpunify($contact['xchan_addr']), - '$primeurl' => unpunify($contact['xchan_url']), - '$block_announce' => [ 'block_announce', t('Ignore shares and repeats this connection posts'), get_abconfig(local_channel(),$contact['xchan_hash'],'system','block_announce',false),t('Note: This is not recommended for Groups.'), [ t('No'), t('Yes') ] ], - '$section' => $section, - '$sections' => $sections, - '$vcard' => $vcard, - '$addr_text' => t('This connection\'s primary address is'), - '$loc_text' => t('Available locations:'), - '$locstr' => $locstr, - '$unclonable' => $clone_warn, - '$notself' => (($self) ? '' : '1'), - '$self' => (($self) ? '1' : ''), - '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), - '$tools_label' => t('Connection Tools'), - '$tools' => (($self) ? '' : $tools), - '$lbl_slider' => t('Slide to adjust your degree of friendship'), - '$lbl_rating' => t('Rating'), - '$lbl_rating_label' => t('Slide to adjust your rating'), - '$lbl_rating_txt' => t('Optionally explain your rating'), - '$connfilter' => Apps::system_app_installed(local_channel(),'Content Filter'), - '$connfilter_label' => t('Custom Filter'), - '$incl' => array('abook_incl',t('Only import posts with this text'), $contact['abook_incl'],t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')), - '$excl' => array('abook_excl',t('Do not import posts with this text'), $contact['abook_excl'],t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')), - '$alias' => array('abook_alias',t('Nickname'), $contact['abook_alias'],t('optional - allows you to search by a name that you have chosen')), - '$rating_text' => array('rating_text', t('Optionally explain your rating'),$rating_text,''), - '$rating_info' => t('This information is public!'), - '$rating' => $rating, - '$rating_val' => $rating_val, - '$slide' => $slide, - '$affinity' => $affinity, - '$pending_label' => t('Connection Pending Approval'), - '$is_pending' => (intval($contact['abook_pending']) ? 1 : ''), - '$unapproved' => $unapproved, - '$inherited' => t('inherited'), - '$submit' => t('Submit'), - '$lbl_vis2' => sprintf( t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), - '$close' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 80), - '$them' => t('Their Settings'), - '$me' => t('My Settings'), - '$perms' => $perms, - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), - '$permnote_self' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes.'), - '$lastupdtext' => t('Last update:'), - '$last_update' => relative_date($contact['abook_connected']), - '$profile_select' => contact_profile_assign($contact['abook_profile']), - '$multiprofs' => $multiprofs, - '$contact_id' => $contact['abook_id'], - '$name' => $contact['xchan_name'], - '$abook_prev' => $abook_prev, - '$abook_next' => $abook_next, - '$vcard_label' => t('Details'), - '$displayname' => $displayname, - '$name_label' => t('Name'), - '$org_label' => t('Organisation'), - '$title_label' => t('Title'), - '$tel_label' => t('Phone'), - '$email_label' => t('Email'), - '$impp_label' => t('Instant messenger'), - '$url_label' => t('Website'), - '$adr_label' => t('Address'), - '$note_label' => t('Note'), - '$mobile' => t('Mobile'), - '$home' => t('Home'), - '$work' => t('Work'), - '$other' => t('Other'), - '$add_card' => t('Add Contact'), - '$add_field' => t('Add Field'), - '$create' => t('Create'), - '$update' => t('Update'), - '$delete' => t('Delete'), - '$cancel' => t('Cancel'), - '$po_box' => t('P.O. Box'), - '$extra' => t('Additional'), - '$street' => t('Street'), - '$locality' => t('Locality'), - '$region' => t('Region'), - '$zip_code' => t('ZIP Code'), - '$country' => t('Country') - ]); - - $arr = array('contact' => $contact,'output' => $o); - - call_hooks('contact_edit', $arr); - - return $arr['output']; - - } - } + $perms = []; + $channel = App::get_channel(); + + $global_perms = Permissions::Perms(); + + $existing = get_all_perms(local_channel(), $contact['abook_xchan'], false); + + $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'), t('Yes'))); + + $multiprofs = ((feature_enabled(local_channel(), 'multi_profiles')) ? true : false); + + if ($slide && !$multiprofs) + $affinity = t('Set Friend Zoom'); + + if (!$slide && $multiprofs) + $affinity = t('Set Profile'); + + if ($slide && $multiprofs) + $affinity = t('Set Friend Zoom & Profile'); + + + $theirs = get_abconfig(local_channel(), $contact['abook_xchan'], 'system', 'their_perms', EMPTY_STR); + + $their_perms = Permissions::FilledPerms(explode(',', $theirs)); + foreach ($global_perms as $k => $v) { + if (!array_key_exists($k, $their_perms)) + $their_perms[$k] = 1; + } + + $my_perms = explode(',', get_abconfig(local_channel(), $contact['abook_xchan'], 'system', 'my_perms', EMPTY_STR)); + + foreach ($global_perms as $k => $v) { + $thisperm = ((in_array($k, $my_perms)) ? 1 : 0); + + $checkinherited = PermissionLimits::Get(local_channel(), $k); + + // For auto permissions (when $self is true) we don't want to look at existing + // permissions because they are enabled for the channel owner + if ((!$self) && ($existing[$k])) + $thisperm = "1"; + + $perms[] = array('perms_' . $k, $v, ((array_key_exists($k, $their_perms)) ? intval($their_perms[$k]) : ''), $thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); + } + + $pcat = new Permcat(local_channel()); + $pcatlist = $pcat->listing(); + $permcats = []; + if ($pcatlist) { + foreach ($pcatlist as $pc) { + $permcats[$pc['name']] = $pc['localname']; + } + } + + $locstr = locations_by_netid($contact['xchan_hash']); + if (!$locstr) + $locstr = unpunify($contact['xchan_url']); + + $clone_warn = ''; + $clonable = (in_array($contact['xchan_network'], ['zot6', 'zot', 'rss']) ? true : false); + if (!$clonable) { + $clone_warn = ''; + $clone_warn .= ((intval($contact['abook_not_here'])) + ? t('This connection is unreachable from this location.') + : t('This connection may be unreachable from other channel locations.') + ); + $clone_warn .= '
        ' . t('Location independence is not supported by their network.'); + } + + + if (intval($contact['abook_not_here']) && $unclonable) + $not_here = t('This connection is unreachable from this location. Location independence is not supported by their network.'); + + $o .= replace_macros($tpl, [ + '$header' => (($self) ? t('Connection Default Permissions') : sprintf(t('Connection: %s'), $contact['xchan_name']) . (($contact['abook_alias']) ? ' <' . $contact['abook_alias'] . '>' : '')), + '$autoperms' => array('autoperms', t('Apply these permissions automatically'), ((get_pconfig(local_channel(), 'system', 'autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no), + '$permcat' => ['permcat', t('Permission role'), '', '', $permcats], + '$permcat_new' => t('Add permission role'), + '$permcat_enable' => feature_enabled(local_channel(), 'permcats'), + '$addr' => unpunify($contact['xchan_addr']), + '$primeurl' => unpunify($contact['xchan_url']), + '$block_announce' => ['block_announce', t('Ignore shares and repeats this connection posts'), get_abconfig(local_channel(), $contact['xchan_hash'], 'system', 'block_announce', false), t('Note: This is not recommended for Groups.'), [t('No'), t('Yes')]], + '$section' => $section, + '$sections' => $sections, + '$vcard' => $vcard, + '$addr_text' => t('This connection\'s primary address is'), + '$loc_text' => t('Available locations:'), + '$locstr' => $locstr, + '$unclonable' => $clone_warn, + '$notself' => (($self) ? '' : '1'), + '$self' => (($self) ? '1' : ''), + '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), + '$tools_label' => t('Connection Tools'), + '$tools' => (($self) ? '' : $tools), + '$lbl_slider' => t('Slide to adjust your degree of friendship'), + '$lbl_rating' => t('Rating'), + '$lbl_rating_label' => t('Slide to adjust your rating'), + '$lbl_rating_txt' => t('Optionally explain your rating'), + '$connfilter' => Apps::system_app_installed(local_channel(), 'Content Filter'), + '$connfilter_label' => t('Custom Filter'), + '$incl' => array('abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')), + '$excl' => array('abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')), + '$alias' => array('abook_alias', t('Nickname'), $contact['abook_alias'], t('optional - allows you to search by a name that you have chosen')), + '$rating_text' => array('rating_text', t('Optionally explain your rating'), $rating_text, ''), + '$rating_info' => t('This information is public!'), + '$rating' => $rating, + '$rating_val' => $rating_val, + '$slide' => $slide, + '$affinity' => $affinity, + '$pending_label' => t('Connection Pending Approval'), + '$is_pending' => (intval($contact['abook_pending']) ? 1 : ''), + '$unapproved' => $unapproved, + '$inherited' => t('inherited'), + '$submit' => t('Submit'), + '$lbl_vis2' => sprintf(t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), + '$close' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 80), + '$them' => t('Their Settings'), + '$me' => t('My Settings'), + '$perms' => $perms, + '$permlbl' => t('Individual Permissions'), + '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), + '$permnote_self' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes.'), + '$lastupdtext' => t('Last update:'), + '$last_update' => relative_date($contact['abook_connected']), + '$profile_select' => contact_profile_assign($contact['abook_profile']), + '$multiprofs' => $multiprofs, + '$contact_id' => $contact['abook_id'], + '$name' => $contact['xchan_name'], + '$abook_prev' => $abook_prev, + '$abook_next' => $abook_next, + '$vcard_label' => t('Details'), + '$displayname' => $displayname, + '$name_label' => t('Name'), + '$org_label' => t('Organisation'), + '$title_label' => t('Title'), + '$tel_label' => t('Phone'), + '$email_label' => t('Email'), + '$impp_label' => t('Instant messenger'), + '$url_label' => t('Website'), + '$adr_label' => t('Address'), + '$note_label' => t('Note'), + '$mobile' => t('Mobile'), + '$home' => t('Home'), + '$work' => t('Work'), + '$other' => t('Other'), + '$add_card' => t('Add Contact'), + '$add_field' => t('Add Field'), + '$create' => t('Create'), + '$update' => t('Update'), + '$delete' => t('Delete'), + '$cancel' => t('Cancel'), + '$po_box' => t('P.O. Box'), + '$extra' => t('Additional'), + '$street' => t('Street'), + '$locality' => t('Locality'), + '$region' => t('Region'), + '$zip_code' => t('ZIP Code'), + '$country' => t('Country') + ]); + + $arr = array('contact' => $contact, 'output' => $o); + + call_hooks('contact_edit', $arr); + + return $arr['output']; + + } + } } diff --git a/Zotlabs/Module/Contactgroup.php b/Zotlabs/Module/Contactgroup.php index 79b743ac8..b6fd42cd0 100644 --- a/Zotlabs/Module/Contactgroup.php +++ b/Zotlabs/Module/Contactgroup.php @@ -15,42 +15,43 @@ use Zotlabs\Lib\AccessList; */ -class Contactgroup extends Controller { +class Contactgroup extends Controller +{ - function get() { - - if (! local_channel()) { - killme(); - } - - if ((argc() > 2) && (intval(argv(1))) && (argv(2))) { - $r = abook_by_hash(local_channel(), base64url_decode(argv(2))); - if ($r) { - $change = $r['abook_xchan']; - } - } - - if ((argc() > 1) && (intval(argv(1)))) { - - $group = AccessList::by_id(local_channel(),argv(1)); + public function get() + { - if (! $group) { - killme(); - } - - $members = AccessList::members(local_channel(),$group['id']); - $preselected = ids_to_array($members,'xchan_hash'); - - if ($change) { - if (in_array($change,$preselected)) { - AccessList::member_remove(local_channel(),$group['gname'],$change); - } - else { - AccessList::member_add(local_channel(),$group['gname'],$change); - } - } - } - - killme(); - } + if (!local_channel()) { + killme(); + } + + if ((argc() > 2) && (intval(argv(1))) && (argv(2))) { + $r = abook_by_hash(local_channel(), base64url_decode(argv(2))); + if ($r) { + $change = $r['abook_xchan']; + } + } + + if ((argc() > 1) && (intval(argv(1)))) { + + $group = AccessList::by_id(local_channel(), argv(1)); + + if (!$group) { + killme(); + } + + $members = AccessList::members(local_channel(), $group['id']); + $preselected = ids_to_array($members, 'xchan_hash'); + + if ($change) { + if (in_array($change, $preselected)) { + AccessList::member_remove(local_channel(), $group['gname'], $change); + } else { + AccessList::member_add(local_channel(), $group['gname'], $change); + } + } + } + + killme(); + } } diff --git a/Zotlabs/Module/Content_filter.php b/Zotlabs/Module/Content_filter.php index c6d1afc40..8da4a26a1 100644 --- a/Zotlabs/Module/Content_filter.php +++ b/Zotlabs/Module/Content_filter.php @@ -6,69 +6,72 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Content_filter extends Controller { +class Content_filter extends Controller +{ - function post() { + public function post() + { - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Content Filter'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Content Filter'))) { return; } - if($_POST['content_filter-submit']) { + if ($_POST['content_filter-submit']) { - $incl = ((x($_POST['message_filter_incl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_incl']),ENT_QUOTES) : ''); - $excl = ((x($_POST['message_filter_excl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_excl']),ENT_QUOTES) : ''); - - set_pconfig(local_channel(),'system','message_filter_incl',$incl); - set_pconfig(local_channel(),'system','message_filter_excl',$excl); + $incl = ((x($_POST['message_filter_incl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_incl']), ENT_QUOTES) : ''); + $excl = ((x($_POST['message_filter_excl'])) ? htmlspecialchars_decode(trim($_POST['message_filter_excl']), ENT_QUOTES) : ''); - info( t('Content Filter settings updated.') . EOL); + set_pconfig(local_channel(), 'system', 'message_filter_incl', $incl); + set_pconfig(local_channel(), 'system', 'message_filter_excl', $excl); - } - - Libsync::build_sync_packet(); + info(t('Content Filter settings updated.') . EOL); - } + } + + Libsync::build_sync_packet(); + + } - function get() { + public function get() + { $desc = t('This app (when installed) allows you to filter incoming content from all sources or from specific connections. The filtering may be based on words, tags, regular expressions, or language'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Content Filter'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Content Filter'))) { return $text; } - $text .= EOL . t('The settings on this page apply to all incoming content. To edit the settings for individual connetions, see the similar settings on the Connection Edit page for that connection.') . EOL . EOL; + $text .= EOL . t('The settings on this page apply to all incoming content. To edit the settings for individual connetions, see the similar settings on the Connection Edit page for that connection.') . EOL . EOL; - $setting_fields = $text; + $setting_fields = $text; - $setting_fields .= replace_macros(get_markup_template('field_textarea.tpl'), array( - '$field' => [ - 'message_filter_incl', - t('Only import posts with this text'), - get_pconfig(local_channel(),'system','message_filter_incl',''), - t('words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts') - ] - )); - $setting_fields .= replace_macros(get_markup_template('field_textarea.tpl'), array( - '$field' => [ - 'message_filter_excl', - t('Do not import posts with this text'), - get_pconfig(local_channel(),'system','message_filter_excl',''), - t('words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts') - ] - )); + $setting_fields .= replace_macros(get_markup_template('field_textarea.tpl'), array( + '$field' => [ + 'message_filter_incl', + t('Only import posts with this text'), + get_pconfig(local_channel(), 'system', 'message_filter_incl', ''), + t('words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts') + ] + )); + $setting_fields .= replace_macros(get_markup_template('field_textarea.tpl'), array( + '$field' => [ + 'message_filter_excl', + t('Do not import posts with this text'), + get_pconfig(local_channel(), 'system', 'message_filter_excl', ''), + t('words one per line or #tags, $categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts') + ] + )); - $s .= replace_macros(get_markup_template('generic_app_settings.tpl'), array( - '$addon' => array('content_filter', '' . t('Content Filter Settings'), '', t('Submit')), - '$content' => $setting_fields - )); + $s .= replace_macros(get_markup_template('generic_app_settings.tpl'), array( + '$addon' => array('content_filter', '' . t('Content Filter Settings'), '', t('Submit')), + '$content' => $setting_fields + )); - return $s; - } + return $s; + } } \ No newline at end of file diff --git a/Zotlabs/Module/Conversation.php b/Zotlabs/Module/Conversation.php index d685bba4b..d7395693b 100644 --- a/Zotlabs/Module/Conversation.php +++ b/Zotlabs/Module/Conversation.php @@ -10,153 +10,155 @@ use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\ThreadListener; use App; -class Conversation extends Controller { +class Conversation extends Controller +{ - function init() { + public function init() + { - if (ActivityStreams::is_as_request()) { + if (ActivityStreams::is_as_request()) { - $item_id = argv(1); + $item_id = argv(1); - if (! $item_id) - http_status_exit(404, 'Not found'); + if (!$item_id) + http_status_exit(404, 'Not found'); - $portable_id = EMPTY_STR; + $portable_id = EMPTY_STR; - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) "; + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) "; - $i = null; + $i = null; - // do we have the item (at all)? + // do we have the item (at all)? - $r = q("select * from item where mid = '%s' $item_normal limit 1", - dbesc(z_root() . '/activity/' . $item_id) - ); + $r = q("select * from item where mid = '%s' $item_normal limit 1", + dbesc(z_root() . '/activity/' . $item_id) + ); - if (! $r) { - $r = q("select * from item where mid = '%s' $item_normal limit 1", - dbesc(z_root() . '/item/' . $item_id) - ); - if (! $r) { - http_status_exit(404,'Not found'); - } - } + if (!$r) { + $r = q("select * from item where mid = '%s' $item_normal limit 1", + dbesc(z_root() . '/item/' . $item_id) + ); + if (!$r) { + http_status_exit(404, 'Not found'); + } + } - // process an authenticated fetch + // process an authenticated fetch - $sigdata = HTTPSig::verify(EMPTY_STR); - if($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - observer_auth($portable_id); + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + observer_auth($portable_id); - // first see if we have a copy of this item's parent owned by the current signer - // include xchans for all zot-like networks - these will have the same guid and public key + // first see if we have a copy of this item's parent owned by the current signer + // include xchans for all zot-like networks - these will have the same guid and public key - $x = q("select * from xchan where xchan_hash = '%s'", - dbesc($sigdata['portable_id']) - ); + $x = q("select * from xchan where xchan_hash = '%s'", + dbesc($sigdata['portable_id']) + ); - if ($x) { - $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ", - dbesc($sigdata['portable_id']), - dbesc($x[0]['xchan_guid']), - dbesc($x[0]['xchan_pubkey']) - ); + if ($x) { + $xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ", + dbesc($sigdata['portable_id']), + dbesc($x[0]['xchan_guid']), + dbesc($x[0]['xchan_pubkey']) + ); - if ($xchans) { - $hashes = ids_to_querystr($xchans,'xchan_hash',true); - $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1", - dbesc($r[0]['parent_mid']) - ); - } - } - } + if ($xchans) { + $hashes = ids_to_querystr($xchans, 'xchan_hash', true); + $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan in ( " . protect_sprintf($hashes) . " ) limit 1", + dbesc($r[0]['parent_mid']) + ); + } + } + } - // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access - // with a bias towards those items owned by channels on this site (item_wall = 1) + // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access + // with a bias towards those items owned by channels on this site (item_wall = 1) - $sql_extra = item_permissions_sql(0); + $sql_extra = item_permissions_sql(0); - if (! $i) { - $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", - dbesc($r[0]['parent_mid']) - ); - } + if (!$i) { + $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", + dbesc($r[0]['parent_mid']) + ); + } - if(! $i) { - http_status_exit(403,'Forbidden'); - } + if (!$i) { + http_status_exit(403, 'Forbidden'); + } - $parents_str = ids_to_querystr($i,'item_id'); + $parents_str = ids_to_querystr($i, 'item_id'); - $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ", - dbesc($parents_str) - ); + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal ", + dbesc($parents_str) + ); - if(! $items) { - http_status_exit(404, 'Not found'); - } + if (!$items) { + http_status_exit(404, 'Not found'); + } - xchan_query($items,true); - $items = fetch_post_tags($items,true); + xchan_query($items, true); + $items = fetch_post_tags($items, true); - $observer = App::get_observer(); - $parent = $items[0]; - $recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'],'activitypub','recips', []) : []); - $to = (($recips && array_key_exists('to',$recips) && is_array($recips['to'])) ? $recips['to'] : null); - $nitems = []; - foreach($items as $i) { + $observer = App::get_observer(); + $parent = $items[0]; + $recips = (($parent['owner']['xchan_network'] === 'activitypub') ? get_iconfig($parent['id'], 'activitypub', 'recips', []) : []); + $to = (($recips && array_key_exists('to', $recips) && is_array($recips['to'])) ? $recips['to'] : null); + $nitems = []; + foreach ($items as $i) { - $mids = []; + $mids = []; - if(intval($i['item_private'])) { - if(! $observer) { - continue; - } - // ignore private reshare, possibly from hubzilla - if($i['verb'] === 'Announce') { - if(! in_array($i['thr_parent'],$mids)) { - $mids[] = $i['thr_parent']; - } - continue; - } - // also ignore any children of the private reshares - if(in_array($i['thr_parent'],$mids)) { - continue; - } + if (intval($i['item_private'])) { + if (!$observer) { + continue; + } + // ignore private reshare, possibly from hubzilla + if ($i['verb'] === 'Announce') { + if (!in_array($i['thr_parent'], $mids)) { + $mids[] = $i['thr_parent']; + } + continue; + } + // also ignore any children of the private reshares + if (in_array($i['thr_parent'], $mids)) { + continue; + } - if((! $to) || (! in_array($observer['xchan_url'],$to))) { - continue; - } + if ((!$to) || (!in_array($observer['xchan_url'], $to))) { + continue; + } - } - $nitems[] = $i; - } + } + $nitems[] = $i; + } - if(! $nitems) - http_status_exit(404, 'Not found'); + if (!$nitems) + http_status_exit(404, 'Not found'); - $chan = channelx_by_n($nitems[0]['uid']); + $chan = channelx_by_n($nitems[0]['uid']); - if(! $chan) - http_status_exit(404, 'Not found'); + if (!$chan) + http_status_exit(404, 'Not found'); - if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) - http_status_exit(403, 'Forbidden'); + if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) + http_status_exit(403, 'Forbidden'); - $i = ZlibActivity::encode_item_collection($nitems,'conversation/' . $item_id,'OrderedCollection',true, count($nitems)); - if ($portable_id && (! intval($items[0]['item_private']))) { - ThreadListener::store(z_root() . '/activity/' . $item_id,$portable_id); - } + $i = ZlibActivity::encode_item_collection($nitems, 'conversation/' . $item_id, 'OrderedCollection', true, count($nitems)); + if ($portable_id && (!intval($items[0]['item_private']))) { + ThreadListener::store(z_root() . '/activity/' . $item_id, $portable_id); + } - if(! $i) - http_status_exit(404, 'Not found'); + if (!$i) + http_status_exit(404, 'Not found'); - $channel = channelx_by_n($items[0]['uid']); - as_return_and_die($i,$channel); + $channel = channelx_by_n($items[0]['uid']); + as_return_and_die($i, $channel); - } - - goaway(z_root() . '/item/' . argv(1)); - } + } + + goaway(z_root() . '/item/' . argv(1)); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php index cac6c43f3..5fab638cb 100644 --- a/Zotlabs/Module/Cover_photo.php +++ b/Zotlabs/Module/Cover_photo.php @@ -25,472 +25,468 @@ require_once('include/photos.php'); * @return void * */ +class Cover_photo extends Controller +{ + + public function init() + { + if (!local_channel()) { + return; + } + + $channel = App::get_channel(); + Libprofile::load($channel['channel_address']); + } + + /** + * @brief Evaluate posted values + * + * @return void + * + */ + + public function post() + { + + if (!local_channel()) { + return; + } + + $channel = App::get_channel(); + + check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); + + if ((array_key_exists('cropfinal', $_POST)) && ($_POST['cropfinal'] == 1)) { + + // phase 2 - we have finished cropping + + if (argc() != 2) { + notice(t('Image uploaded but image cropping failed.') . EOL); + return; + } + + $image_id = argv(1); + + if (substr($image_id, -2, 1) == '-') { + $scale = substr($image_id, -1, 1); + $image_id = substr($image_id, 0, -2); + } -class Cover_photo extends Controller { + $srcX = intval($_POST['xstart']); + $srcY = intval($_POST['ystart']); + $srcW = intval($_POST['xfinal']) - $srcX; + $srcH = intval($_POST['yfinal']) - $srcY; - function init() { - if (! local_channel()) { - return; - } - - $channel = App::get_channel(); - Libprofile::load($channel['channel_address']); - } - - /** - * @brief Evaluate posted values - * - * @return void - * - */ - - function post() { - - if (! local_channel()) { - return; - } - - $channel = App::get_channel(); - - check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); - - if ((array_key_exists('cropfinal',$_POST)) && ($_POST['cropfinal'] == 1)) { - - // phase 2 - we have finished cropping - - if (argc() != 2) { - notice( t('Image uploaded but image cropping failed.') . EOL ); - return; - } - - $image_id = argv(1); - - if (substr($image_id,-2,1) == '-') { - $scale = substr($image_id,-1,1); - $image_id = substr($image_id,0,-2); - } - + $r = q("select gender from profile where uid = %d and is_default = 1 limit 1", + intval(local_channel()) + ); + if ($r) { + $profile = array_shift($r); + } + + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1", + dbesc($image_id), + intval(local_channel()) + ); + + if ($r) { + + $max_thumb = intval(get_config('system', 'max_thumbnail', 1600)); + $iscaled = false; + if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) { + $imagick_path = get_config('system', 'imagick_convert_path'); + if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) { + + $fname = dbunescbin($r[0]['content']); + $tmp_name = $fname . '-001'; + $newsize = photo_calculate_scale(array_merge(getimagesize($fname), ['max' => $max_thumb])); + $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name); + // logger('imagick thumbnail command: ' . $cmd); + for ($x = 0; $x < 4; $x++) { + exec($cmd); + if (file_exists($tmp_name)) { + break; + } + } + if (file_exists($tmp_name)) { + $base_image = $r[0]; + $gis = getimagesize($tmp_name); + logger('gis: ' . print_r($gis, true)); + $base_image['width'] = $gis[0]; + $base_image['height'] = $gis[1]; + $base_image['content'] = @file_get_contents($tmp_name); + $iscaled = true; + @unlink($tmp_name); + } + } + } + if (!$iscaled) { + $base_image = $r[0]; + $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); + } + + $im = photo_factory($base_image['content'], $base_image['mimetype']); + if ($im && $im->is_valid()) { + + // We are scaling and cropping the relative pixel locations to the original photo instead of the + // scaled photo we operated on. + + // First load the scaled photo to check its size. (Should probably pass this in the post form and save + // a query.) + + $g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3", + dbesc($image_id), + intval(local_channel()) + ); - $srcX = intval($_POST['xstart']); - $srcY = intval($_POST['ystart']); - $srcW = intval($_POST['xfinal']) - $srcX; - $srcH = intval($_POST['yfinal']) - $srcY; - - $r = q("select gender from profile where uid = %d and is_default = 1 limit 1", - intval(local_channel()) - ); - if ($r) { - $profile = array_shift($r); - } - - $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale > 0 order by imgscale asc LIMIT 1", - dbesc($image_id), - intval(local_channel()) - ); - - if ($r) { + $scaled_width = $g[0]['width']; + $scaled_height = $g[0]['height']; - $max_thumb = intval(get_config('system','max_thumbnail',1600)); - $iscaled = false; - if (intval($r[0]['height']) > $max_thumb || intval($r[0]['width']) > $max_thumb) { - $imagick_path = get_config('system','imagick_convert_path'); - if ($imagick_path && @file_exists($imagick_path) && intval($r[0]['os_storage'])) { + if ((!$scaled_width) || (!$scaled_height)) { + logger('potential divide by zero scaling cover photo'); + return; + } - $fname = dbunescbin($r[0]['content']); - $tmp_name = $fname . '-001'; - $newsize = photo_calculate_scale(array_merge(getimagesize($fname),['max' => $max_thumb])); - $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $fname) . ' -resize ' . $newsize . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmp_name); - // logger('imagick thumbnail command: ' . $cmd); - for ($x = 0; $x < 4; $x ++) { - exec($cmd); - if (file_exists($tmp_name)) { - break; - } - } - if (file_exists($tmp_name)) { - $base_image = $r[0]; - $gis = getimagesize($tmp_name); -logger('gis: ' . print_r($gis,true)); - $base_image['width'] = $gis[0]; - $base_image['height'] = $gis[1]; - $base_image['content'] = @file_get_contents($tmp_name); - $iscaled = true; - @unlink($tmp_name); - } - } - } - if (! $iscaled) { - $base_image = $r[0]; - $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); - } + // unset all other cover photos - $im = photo_factory($base_image['content'], $base_image['mimetype']); - if ($im && $im->is_valid()) { - - // We are scaling and cropping the relative pixel locations to the original photo instead of the - // scaled photo we operated on. - - // First load the scaled photo to check its size. (Should probably pass this in the post form and save - // a query.) - - $g = q("select width, height from photo where resource_id = '%s' and uid = %d and imgscale = 3", - dbesc($image_id), - intval(local_channel()) - ); - - - $scaled_width = $g[0]['width']; - $scaled_height = $g[0]['height']; - - if ((! $scaled_width) || (! $scaled_height)) { - logger('potential divide by zero scaling cover photo'); - return; - } - - // unset all other cover photos - - q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_COVER), - intval(local_channel()) - ); - - $orig_srcx = ( $base_image['width'] / $scaled_width ) * $srcX; - $orig_srcy = ( $base_image['height'] / $scaled_height ) * $srcY; - $orig_srcw = ( $srcW / $scaled_width ) * $base_image['width']; - $orig_srch = ( $srcH / $scaled_height ) * $base_image['height']; - - $im->cropImageRect(1200,435,$orig_srcx, $orig_srcy, $orig_srcw, $orig_srch); - - $aid = get_account_id(); - - $p = [ - 'aid' => $aid, - 'uid' => local_channel(), - 'resource_id' => $base_image['resource_id'], - 'filename' => $base_image['filename'], - 'album' => t('Cover Photos'), - 'os_path' => $base_image['os_path'], - 'display_path' => $base_image['display_path'], - 'created' => $base_image['created'], - 'edited' => $base_image['edited'] - ]; - - $p['imgscale'] = 7; - $p['photo_usage'] = PHOTO_COVER; - - $r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200); + q("update photo set photo_usage = %d where photo_usage = %d and uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_COVER), + intval(local_channel()) + ); - $im->doScaleImage(850,310); - $p['imgscale'] = 8; + $orig_srcx = ($base_image['width'] / $scaled_width) * $srcX; + $orig_srcy = ($base_image['height'] / $scaled_height) * $srcY; + $orig_srcw = ($srcW / $scaled_width) * $base_image['width']; + $orig_srch = ($srcH / $scaled_height) * $base_image['height']; - $r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850); - - $im->doScaleImage(425,160); - $p['imgscale'] = 9; - - $r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425); - - if ($r1 === false || $r2 === false || $r3 === false) { - // if one failed, delete them all so we can start over. - notice( t('Image resize failed.') . EOL ); - $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ", - dbesc($base_image['resource_id']), - local_channel() - ); - return; - } - - $channel = App::get_channel(); - $this->send_cover_photo_activity($channel,$base_image,$profile); - - - } - else - notice( t('Unable to process image') . EOL); - } - - goaway(z_root() . '/channel/' . $channel['channel_address']); - - } - - - $hash = photo_new_resource(); - $smallest = 0; - - $matches = []; - $partial = false; + $im->cropImageRect(1200, 435, $orig_srcx, $orig_srcy, $orig_srcw, $orig_srch); - if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { - $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); - if ($pm) { - logger('Content-Range: ' . print_r($matches,true)); - $partial = true; - } - } + $aid = get_account_id(); - if ($partial) { - $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + $p = [ + 'aid' => $aid, + 'uid' => local_channel(), + 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], + 'album' => t('Cover Photos'), + 'os_path' => $base_image['os_path'], + 'display_path' => $base_image['display_path'], + 'created' => $base_image['created'], + 'edited' => $base_image['edited'] + ]; - if ($x['partial']) { - header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($x); - } - else { - header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + $p['imgscale'] = 7; + $p['photo_usage'] = PHOTO_COVER; - $_FILES['userfile'] = [ - 'name' => $x['name'], - 'type' => $x['type'], - 'tmp_name' => $x['tmp_name'], - 'error' => $x['error'], - 'size' => $x['size'] - ]; - } - } - else { - if (! array_key_exists('userfile',$_FILES)) { - $_FILES['userfile'] = [ - 'name' => $_FILES['files']['name'], - 'type' => $_FILES['files']['type'], - 'tmp_name' => $_FILES['files']['tmp_name'], - 'error' => $_FILES['files']['error'], - 'size' => $_FILES['files']['size'] - ]; - } - } + $r1 = $im->storeThumbnail($p, PHOTO_RES_COVER_1200); - $res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash)); - - logger('attach_store: ' . print_r($res,true),LOGGER_DEBUG); + $im->doScaleImage(850, 310); + $p['imgscale'] = 8; - json_return_and_die([ 'message' => $hash ]); - - } - - function send_cover_photo_activity($channel,$photo,$profile) { - - $arr = []; - $arr['item_thread_top'] = 1; - $arr['item_origin'] = 1; - $arr['item_wall'] = 1; - $arr['uuid'] = new_uuid(); - $arr['mid'] = z_root() . '/item/' . $arr['uuid']; - $arr['obj_type'] = ACTIVITY_OBJ_NOTE; - $arr['verb'] = ACTIVITY_CREATE; - - if ($profile && stripos($profile['gender'],t('female')) !== false) { - $t = t('%1$s updated her %2$s'); - } - elseif ($profile && stripos($profile['gender'],t('male')) !== false) { - $t = t('%1$s updated his %2$s'); - } - else { - $t = t('%1$s updated their %2$s'); - } - - $ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]'; - - $ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]'; - - $arr['body'] = sprintf($t,$channel['channel_name'],$ptext) . "\n\n" . $ltext; + $r2 = $im->storeThumbnail($p, PHOTO_RES_COVER_850); - $arr['obj'] = [ - 'type' => ACTIVITY_OBJ_NOTE, - 'published' => datetime_convert('UTC','UTC',$photo['created'],ATOM_TIME), - 'updated' => datetime_convert('UTC','UTC',$photo['edited'],ATOM_TIME), - 'id' => $arr['mid'], - 'url' => [ 'type' => 'Link', 'mediaType' => $photo['mimetype'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7' ], - 'source' => [ 'content' => $arr['body'], 'mediaType' => 'text/bbcode' ], - 'content' => bbcode($arr['body']), - 'actor' => Activity::encode_person($channel,false), - ]; + $im->doScaleImage(425, 160); + $p['imgscale'] = 9; - $acl = new AccessControl($channel); - $x = $acl->get(); - $arr['allow_cid'] = $x['allow_cid']; - - $arr['allow_gid'] = $x['allow_gid']; - $arr['deny_cid'] = $x['deny_cid']; - $arr['deny_gid'] = $x['deny_gid']; - - $arr['uid'] = $channel['channel_id']; - $arr['aid'] = $channel['channel_account_id']; - - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['author_xchan'] = $channel['channel_hash']; - - post_activity_item($arr); - - - } - - - /** - * @brief Generate content of profile-photo view - * - * @return string - * - */ - - - function get() { - - if (! local_channel()) { - notice( t('Permission denied.') . EOL ); - return; - } - - $channel = App::get_channel(); - - $newuser = false; - - if (argc() == 2 && argv(1) === 'new') - $newuser = true; - - if (argv(1) === 'use') { - if (argc() < 3) { - notice( t('Permission denied.') . EOL ); - return; - } + $r3 = $im->storeThumbnail($p, PHOTO_RES_COVER_425); + + if ($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice(t('Image resize failed.') . EOL); + $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale >= 7 ", + dbesc($base_image['resource_id']), + local_channel() + ); + return; + } + + $channel = App::get_channel(); + $this->send_cover_photo_activity($channel, $base_image, $profile); + + + } else + notice(t('Unable to process image') . EOL); + } + + goaway(z_root() . '/channel/' . $channel['channel_address']); + + } + + + $hash = photo_new_resource(); + $smallest = 0; + + $matches = []; + $partial = false; + + if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches, true)); + $partial = true; + } + } + + if ($partial) { + $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]); + + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($x); + } else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } else { + if (!array_key_exists('userfile', $_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Cover Photos'), 'hash' => $hash)); + + logger('attach_store: ' . print_r($res, true), LOGGER_DEBUG); + + json_return_and_die(['message' => $hash]); + + } + + public function send_cover_photo_activity($channel, $photo, $profile) + { + + $arr = []; + $arr['item_thread_top'] = 1; + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['uuid'] = new_uuid(); + $arr['mid'] = z_root() . '/item/' . $arr['uuid']; + $arr['obj_type'] = ACTIVITY_OBJ_NOTE; + $arr['verb'] = ACTIVITY_CREATE; + + if ($profile && stripos($profile['gender'], t('female')) !== false) { + $t = t('%1$s updated her %2$s'); + } elseif ($profile && stripos($profile['gender'], t('male')) !== false) { + $t = t('%1$s updated his %2$s'); + } else { + $t = t('%1$s updated their %2$s'); + } + + $ptext = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $photo['resource_id'] . ']' . t('cover photo') . '[/zrl]'; + + $ltext = '[zrl=' . z_root() . '/profile/' . $channel['channel_address'] . ']' . '[zmg]' . z_root() . '/photo/' . $photo['resource_id'] . '-8[/zmg][/zrl]'; + + $arr['body'] = sprintf($t, $channel['channel_name'], $ptext) . "\n\n" . $ltext; + + $arr['obj'] = [ + 'type' => ACTIVITY_OBJ_NOTE, + 'published' => datetime_convert('UTC', 'UTC', $photo['created'], ATOM_TIME), + 'updated' => datetime_convert('UTC', 'UTC', $photo['edited'], ATOM_TIME), + 'id' => $arr['mid'], + 'url' => ['type' => 'Link', 'mediaType' => $photo['mimetype'], 'href' => z_root() . '/photo/' . $photo['resource_id'] . '-7'], + 'source' => ['content' => $arr['body'], 'mediaType' => 'text/bbcode'], + 'content' => bbcode($arr['body']), + 'actor' => Activity::encode_person($channel, false), + ]; + + $acl = new AccessControl($channel); + $x = $acl->get(); + $arr['allow_cid'] = $x['allow_cid']; + + $arr['allow_gid'] = $x['allow_gid']; + $arr['deny_cid'] = $x['deny_cid']; + $arr['deny_gid'] = $x['deny_gid']; + + $arr['uid'] = $channel['channel_id']; + $arr['aid'] = $channel['channel_account_id']; + + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $channel['channel_hash']; + + post_activity_item($arr); + + + } + + + /** + * @brief Generate content of profile-photo view + * + * @return string + * + */ + + + public function get() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + $channel = App::get_channel(); + + $newuser = false; + + if (argc() == 2 && argv(1) === 'new') + $newuser = true; + + if (argv(1) === 'use') { + if (argc() < 3) { + notice(t('Permission denied.') . EOL); + return; + } // check_form_security_token_redirectOnErr('/cover_photo', 'cover_photo'); - - $resource_id = argv(2); - - $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC", - intval(local_channel()), - dbesc($resource_id) - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - $havescale = false; - foreach ($r as $rr) { - if ($rr['imgscale'] == 7) { - $havescale = true; - } - } - - $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", - intval($r[0]['id']), - intval(local_channel()) - - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - - if (intval($r[0]['os_storage'])) { - $data = @file_get_contents(dbunescbin($r[0]['content'])); - } - else { - $data = dbunescbin($r[0]['content']); - } - - $ph = photo_factory($data, $r[0]['mimetype']); - $smallest = 0; - if ($ph && $ph->is_valid()) { - // go ahead as if we have just uploaded a new photo to crop - $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0", - dbesc($r[0]['resource_id']), - intval(local_channel()) - ); - - if ($i) { - $hash = $i[0]['resource_id']; - foreach ($i as $ii) { - $smallest = intval($ii['imgscale']); - } - } - } - - $this->cover_photo_crop_ui_head($ph, $hash, $smallest); - } - - - if(! array_key_exists('imagecrop',App::$data)) { - - $o .= replace_macros(get_markup_template('cover_photo.tpl'), [ - '$user' => App::$channel['channel_address'], - '$info' => t('Your cover photo may be visible to anybody on the internet'), - '$existing' => get_cover_photo(local_channel(),'array',PHOTO_RES_COVER_850), - '$lbl_upfile' => t('Upload File:'), - '$lbl_profiles' => t('Select a profile:'), - '$title' => t('Change Cover Photo'), - '$submit' => t('Upload'), - '$profiles' => $profiles, - '$embedPhotos' => t('Use a photo from your albums'), - '$embedPhotosModalTitle' => t('Use a photo from your albums'), - '$embedPhotosModalCancel' => t('Cancel'), - '$embedPhotosModalOK' => t('OK'), - '$modalchooseimages' => t('Choose images to embed'), - '$modalchoosealbum' => t('Choose an album'), - '$modaldiffalbum' => t('Choose a different album'), - '$modalerrorlist' => t('Error getting album list'), - '$modalerrorlink' => t('Error getting photo link'), - '$modalerroralbum' => t('Error getting album'), - '$form_security_token' => get_form_security_token("cover_photo"), - '$select' => t('Select previously uploaded photo'), - ]); - - call_hooks('cover_photo_content_end', $o); - - return $o; - } - else { - $filename = App::$data['imagecrop'] . '-3'; - $resolution = 3; + $resource_id = argv(2); + + $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' and imgscale > 0 ORDER BY imgscale ASC", + intval(local_channel()), + dbesc($resource_id) + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + $havescale = false; + foreach ($r as $rr) { + if ($rr['imgscale'] == 7) { + $havescale = true; + } + } + + $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval(local_channel()) + + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + + if (intval($r[0]['os_storage'])) { + $data = @file_get_contents(dbunescbin($r[0]['content'])); + } else { + $data = dbunescbin($r[0]['content']); + } + + $ph = photo_factory($data, $r[0]['mimetype']); + $smallest = 0; + if ($ph && $ph->is_valid()) { + // go ahead as if we have just uploaded a new photo to crop + $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d and imgscale = 0", + dbesc($r[0]['resource_id']), + intval(local_channel()) + ); + + if ($i) { + $hash = $i[0]['resource_id']; + foreach ($i as $ii) { + $smallest = intval($ii['imgscale']); + } + } + } + + $this->cover_photo_crop_ui_head($ph, $hash, $smallest); + } + + + if (!array_key_exists('imagecrop', App::$data)) { + + $o .= replace_macros(get_markup_template('cover_photo.tpl'), [ + '$user' => App::$channel['channel_address'], + '$info' => t('Your cover photo may be visible to anybody on the internet'), + '$existing' => get_cover_photo(local_channel(), 'array', PHOTO_RES_COVER_850), + '$lbl_upfile' => t('Upload File:'), + '$lbl_profiles' => t('Select a profile:'), + '$title' => t('Change Cover Photo'), + '$submit' => t('Upload'), + '$profiles' => $profiles, + '$embedPhotos' => t('Use a photo from your albums'), + '$embedPhotosModalTitle' => t('Use a photo from your albums'), + '$embedPhotosModalCancel' => t('Cancel'), + '$embedPhotosModalOK' => t('OK'), + '$modalchooseimages' => t('Choose images to embed'), + '$modalchoosealbum' => t('Choose an album'), + '$modaldiffalbum' => t('Choose a different album'), + '$modalerrorlist' => t('Error getting album list'), + '$modalerrorlink' => t('Error getting photo link'), + '$modalerroralbum' => t('Error getting album'), + '$form_security_token' => get_form_security_token("cover_photo"), + '$select' => t('Select previously uploaded photo'), + + ]); + + call_hooks('cover_photo_content_end', $o); + + return $o; + } else { + $filename = App::$data['imagecrop'] . '-3'; + $resolution = 3; + + $o .= replace_macros(get_markup_template('cropcover.tpl'), [ + '$filename' => $filename, + '$profile' => intval($_REQUEST['profile']), + '$resource' => App::$data['imagecrop'] . '-3', + '$image_url' => z_root() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), + '$form_security_token' => get_form_security_token("cover_photo"), + '$done' => t('Done Editing') + ]); + return $o; + } + } + + /* @brief Generate the UI for photo-cropping + * + * @param $a Current application + * @param $ph Photo-Factory + * @return void + * + */ + + public function cover_photo_crop_ui_head($ph, $hash, $smallest) + { + + $max_length = get_config('system', 'max_image_length', MAX_IMAGE_LENGTH); + if ($max_length > 0) { + $ph->scaleImage($max_length); + } + + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + if ($width < 300 || $height < 300) { + $ph->scaleImageUp(240); + $width = $ph->getWidth(); + $height = $ph->getHeight(); + } + + + App::$data['imagecrop'] = $hash; + App::$data['imagecrop_resolution'] = $smallest; + App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); + return; + } + - $o .= replace_macros(get_markup_template('cropcover.tpl'), [ - '$filename' => $filename, - '$profile' => intval($_REQUEST['profile']), - '$resource' => App::$data['imagecrop'] . '-3', - '$image_url' => z_root() . '/photo/' . $filename, - '$title' => t('Crop Image'), - '$desc' => t('Please adjust the image cropping for optimum viewing.'), - '$form_security_token' => get_form_security_token("cover_photo"), - '$done' => t('Done Editing') - ]); - return $o; - } - } - - /* @brief Generate the UI for photo-cropping - * - * @param $a Current application - * @param $ph Photo-Factory - * @return void - * - */ - - function cover_photo_crop_ui_head($ph, $hash, $smallest){ - - $max_length = get_config('system','max_image_length', MAX_IMAGE_LENGTH); - if ($max_length > 0) { - $ph->scaleImage($max_length); - } - - $width = $ph->getWidth(); - $height = $ph->getHeight(); - - if ($width < 300 || $height < 300) { - $ph->scaleImageUp(240); - $width = $ph->getWidth(); - $height = $ph->getHeight(); - } - - - App::$data['imagecrop'] = $hash; - App::$data['imagecrop_resolution'] = $smallest; - App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); - return; - } - - } diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php index efea8476d..e406bc3dd 100644 --- a/Zotlabs/Module/Dav.php +++ b/Zotlabs/Module/Dav.php @@ -25,118 +25,120 @@ require_once('include/auth.php'); require_once('include/security.php'); -class Dav extends Controller { +class Dav extends Controller +{ - /** - * @brief Fires up the SabreDAV server. - * - */ - function init() { + /** + * @brief Fires up the SabreDAV server. + * + */ + public function init() + { - foreach ([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) { + foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $head) { - /* Basic authentication */ + /* Basic authentication */ - if (array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,5) === 'Basic') { - $userpass = @base64_decode(substr(trim($_SERVER[$head]),6)) ; - if (strlen($userpass)) { - list($name, $password) = explode(':', $userpass); - $_SERVER['PHP_AUTH_USER'] = $name; - $_SERVER['PHP_AUTH_PW'] = $password; - } - break; - } + if (array_key_exists($head, $_SERVER) && substr(trim($_SERVER[$head]), 0, 5) === 'Basic') { + $userpass = @base64_decode(substr(trim($_SERVER[$head]), 6)); + if (strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + break; + } - /* Signature authentication */ + /* Signature authentication */ - if (array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') { - if ($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } + if (array_key_exists($head, $_SERVER) && substr(trim($_SERVER[$head]), 0, 9) === 'Signature') { + if ($head !== 'HTTP_AUTHORIZATION') { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; + continue; + } - $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); - if ($sigblock) { - $keyId = str_replace('acct:','',$sigblock['keyId']); - if ($keyId) { - $r = q("select * from hubloc where ( hubloc_addr = '%s' OR hubloc_id_url = '%s' OR hubloc_hash = '%s') limit 1", - dbesc($keyId), - dbesc($keyId), - dbesc($keyId) - ); - if ($r) { - $c = channelx_by_hash($r[0]['hubloc_hash']); - if ($c) { - $a = q("select * from account where account_id = %d limit 1", - intval($c['channel_account_id']) - ); - if ($a) { - $record = [ 'channel' => $c, 'account' => $a[0] ]; - $channel_login = $c['channel_id']; - } - } - } - if (! $record) { - continue; - } + $sigblock = HTTPSig::parse_sigheader($_SERVER[$head]); + if ($sigblock) { + $keyId = str_replace('acct:', '', $sigblock['keyId']); + if ($keyId) { + $r = q("select * from hubloc where ( hubloc_addr = '%s' OR hubloc_id_url = '%s' OR hubloc_hash = '%s') limit 1", + dbesc($keyId), + dbesc($keyId), + dbesc($keyId) + ); + if ($r) { + $c = channelx_by_hash($r[0]['hubloc_hash']); + if ($c) { + $a = q("select * from account where account_id = %d limit 1", + intval($c['channel_account_id']) + ); + if ($a) { + $record = ['channel' => $c, 'account' => $a[0]]; + $channel_login = $c['channel_id']; + } + } + } + if (!$record) { + continue; + } - if ($record) { - $verified = HTTPSig::verify('',$record['channel']['channel_pubkey']); - if (! ($verified && $verified['header_signed'] && $verified['header_valid'])) { - $record = null; - } - if ($record['account']) { - authenticate_success($record['account']); - if ($channel_login) { - change_channel($channel_login); - } - } - break; - } - } - } - } - } + if ($record) { + $verified = HTTPSig::verify('', $record['channel']['channel_pubkey']); + if (!($verified && $verified['header_signed'] && $verified['header_valid'])) { + $record = null; + } + if ($record['account']) { + authenticate_success($record['account']); + if ($channel_login) { + change_channel($channel_login); + } + } + break; + } + } + } + } + } - if (! is_dir('store')) - os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false); + if (!is_dir('store')) + os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, false); - if (argc() > 1) - Libprofile::load(argv(1),0); + if (argc() > 1) + Libprofile::load(argv(1), 0); - $auth = new BasicAuth(); + $auth = new BasicAuth(); // $auth->observer = get_observer_hash(); - $auth->setRealm(ucfirst(System::get_platform_name()) . ' ' . 'WebDAV'); + $auth->setRealm(ucfirst(System::get_platform_name()) . ' ' . 'WebDAV'); - $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); + $rootDirectory = new \Zotlabs\Storage\Directory('/', $auth); - // A SabreDAV server-object - $server = new SDAV\Server($rootDirectory); + // A SabreDAV server-object + $server = new SDAV\Server($rootDirectory); - $authPlugin = new Plugin($auth); - $server->addPlugin($authPlugin); + $authPlugin = new Plugin($auth); + $server->addPlugin($authPlugin); - // prevent overwriting changes each other with a lock backend - $lockBackend = new SDAV\Locks\Backend\File('cache/locks'); - $lockPlugin = new SDAV\Locks\Plugin($lockBackend); + // prevent overwriting changes each other with a lock backend + $lockBackend = new SDAV\Locks\Backend\File('cache/locks'); + $lockPlugin = new SDAV\Locks\Plugin($lockBackend); - $server->addPlugin($lockPlugin); + $server->addPlugin($lockPlugin); - // provide a directory view for the cloud in Hubzilla - $browser = new Browser($auth); - $auth->setBrowserPlugin($browser); + // provide a directory view for the cloud in Hubzilla + $browser = new Browser($auth); + $auth->setBrowserPlugin($browser); - // Experimental QuotaPlugin - // $server->addPlugin(new \Zotlabs\Storage\QuotaPlugin($auth)); + // Experimental QuotaPlugin + // $server->addPlugin(new \Zotlabs\Storage\QuotaPlugin($auth)); - // All we need to do now, is to fire up the server - $server->exec(); + // All we need to do now, is to fire up the server + $server->exec(); - killme(); - } + killme(); + } } diff --git a/Zotlabs/Module/Defperms.php b/Zotlabs/Module/Defperms.php index 9255bbb6a..95b9b406c 100644 --- a/Zotlabs/Module/Defperms.php +++ b/Zotlabs/Module/Defperms.php @@ -13,257 +13,261 @@ require_once('include/socgraph.php'); require_once('include/photos.php'); -class Defperms extends Controller { +class Defperms extends Controller +{ - /* @brief Initialize the connection-editor - * - * - */ + /* @brief Initialize the connection-editor + * + * + */ - function init() { - - if (! local_channel()) { - return; - } - - $r = q("SELECT abook.*, xchan.* + public function init() + { + + if (!local_channel()) { + return; + } + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_self = 1 and abook_channel = %d LIMIT 1", - intval(local_channel()) - ); - if ($r) { - App::$poi = array_shift($r); - } + intval(local_channel()) + ); + if ($r) { + App::$poi = array_shift($r); + } - $channel = App::get_channel(); - if ($channel) { - head_set_icon($channel['xchan_photo_s']); - } - } + $channel = App::get_channel(); + if ($channel) { + head_set_icon($channel['xchan_photo_s']); + } + } - - /* @brief Evaluate posted values and set changes - * - */ - - function post() { - - if (! local_channel()) { - return; - } - - $contact_id = intval(argv(1)); - if (! $contact_id) { - return; - } - - $channel = App::get_channel(); - - $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", - intval($contact_id), - intval(local_channel()) - ); - - if (! $orig_record) { - notice( t('Could not access contact record.') . EOL); - goaway(z_root() . '/connections'); - } - - if (intval($orig_record[0]['abook_self'])) { - $autoperms = intval($_POST['autoperms']); - $is_self = true; - } - else { - $autoperms = null; - $is_self = false; - } - - $all_perms = Permissions::Perms(); + /* @brief Evaluate posted values and set changes + * + */ - $p = EMPTY_STR; + public function post() + { - if ($all_perms) { - foreach ($all_perms as $perm => $desc) { - if (array_key_exists('perms_' . $perm, $_POST)) { - if ($p) { - $p .= ','; - } - $p .= $perm; - } - } - set_abconfig($channel['channel_id'],$orig_record[0]['abook_xchan'],'system','my_perms',$p); - if ($autoperms) { - set_pconfig($channel['channel_id'],'system','autoperms',$p); - } - } - - notice( t('Settings updated.') . EOL); + if (!local_channel()) { + return; + } - - // Refresh the structure in memory with the new data - - $r = q("SELECT abook.*, xchan.* + $contact_id = intval(argv(1)); + if (!$contact_id) { + return; + } + + $channel = App::get_channel(); + + $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + intval($contact_id), + intval(local_channel()) + ); + + if (!$orig_record) { + notice(t('Could not access contact record.') . EOL); + goaway(z_root() . '/connections'); + } + + + if (intval($orig_record[0]['abook_self'])) { + $autoperms = intval($_POST['autoperms']); + $is_self = true; + } else { + $autoperms = null; + $is_self = false; + } + + $all_perms = Permissions::Perms(); + + $p = EMPTY_STR; + + if ($all_perms) { + foreach ($all_perms as $perm => $desc) { + if (array_key_exists('perms_' . $perm, $_POST)) { + if ($p) { + $p .= ','; + } + $p .= $perm; + } + } + set_abconfig($channel['channel_id'], $orig_record[0]['abook_xchan'], 'system', 'my_perms', $p); + if ($autoperms) { + set_pconfig($channel['channel_id'], 'system', 'autoperms', $p); + } + } + + notice(t('Settings updated.') . EOL); + + + // Refresh the structure in memory with the new data + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_channel()), - intval($contact_id) - ); - if ($r) { - App::$poi = $r[0]; - } - - $this->defperms_clone($a); - - goaway(z_root() . '/defperms'); - - return; - - } - - /* @brief Clone connection - * - * - */ - - function defperms_clone(&$a) { - - if (! App::$poi) { - return; - } - - $channel = App::get_channel(); - - $r = q("SELECT abook.*, xchan.* + intval(local_channel()), + intval($contact_id) + ); + if ($r) { + App::$poi = $r[0]; + } + + $this->defperms_clone($a); + + goaway(z_root() . '/defperms'); + + return; + + } + + /* @brief Clone connection + * + * + */ + + public function defperms_clone(&$a) + { + + if (!App::$poi) { + return; + } + + $channel = App::get_channel(); + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_id = %d LIMIT 1", - intval(local_channel()), - intval(App::$poi['abook_id']) - ); - if ($r) { - App::$poi = array_shift($r); - } - - $clone = App::$poi; - - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); - - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if ($abconfig) { - $clone['abconfig'] = $abconfig; - } - Libsync::build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone))); - } - - /* @brief Generate content of connection default permissions page - * - * - */ - - function get() { - - $sort_type = 0; - $o = ''; - - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return login(); - } + intval(local_channel()), + intval(App::$poi['abook_id']) + ); + if ($r) { + App::$poi = array_shift($r); + } - $role = get_pconfig(local_channel(),'system','permissions_role'); - if ($role) { - notice( t('Permission denied.') . EOL); - return; - } + $clone = App::$poi; - $section = ((array_key_exists('section',$_REQUEST)) ? $_REQUEST['section'] : ''); - $channel = App::get_channel(); - - $yes_no = [ t('No'),t('Yes') ]; - - $connect_perms = Permissions::connect_perms(local_channel()); + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); - $o .= "\n"; - - if (App::$poi) { - - $sections = []; + foreach ($connect_perms['perms'] as $p => $v) { + if ($v) { + $o .= "\$('#me_id_perms_" . $p . "').prop('checked', true); \n"; + } + } + $o .= " }\n\n"; - $self = false; - - $tpl = get_markup_template('defperms.tpl'); - - $perms = []; - $channel = App::get_channel(); + if (App::$poi) { - $contact = App::$poi; - - $global_perms = Permissions::Perms(); + $sections = []; - $hidden_perms = []; - - foreach ($global_perms as $k => $v) { - $thisperm = get_abconfig(local_channel(),$contact['abook_xchan'],'my_perms',$k); - - $checkinherited = PermissionLimits::Get(local_channel(),$k); + $self = false; - $inherited = (($checkinherited & PERMS_SPECIFIC) ? false : true); + $tpl = get_markup_template('defperms.tpl'); - $perms[] = [ 'perms_' . $k, $v, intval($thisperm), '', $yes_no, (($inherited) ? ' disabled="disabled" ' : '') ]; - if ($inherited) { - $hidden_perms[] = [ 'perms_' . $k, intval($thisperm) ]; - } - } - - $pcat = new Permcat(local_channel()); - $pcatlist = $pcat->listing(); - $permcats = []; - if ($pcatlist) { - foreach ($pcatlist as $pc) { - $permcats[$pc['name']] = $pc['localname']; - } - } + $perms = []; + $channel = App::get_channel(); - $o .= replace_macros($tpl, [ - '$header' => t('Connection Default Permissions'), - '$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no), - '$permcat' => [ 'permcat', t('Permission role'), '', '',$permcats ], - '$permcat_new' => t('Add permission role'), - '$permcat_enable' => feature_enabled(local_channel(),'permcats'), - '$section' => $section, - '$sections' => $sections, - '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), - '$autoapprove' => t('Automatic approval settings'), - '$unapproved' => $unapproved, - '$inherited' => t('inherited'), - '$submit' => t('Submit'), - '$me' => t('My Settings'), - '$perms' => $perms, - '$hidden_perms' => $hidden_perms, - '$permlbl' => t('Individual Permissions'), - '$permnote_self' => t('Some individual permissions may have been preset or locked based on your channel type and privacy settings.'), - '$contact_id' => $contact['abook_id'], - '$name' => $contact['xchan_name'], - ]); - - $arr = array('contact' => $contact,'output' => $o); - - call_hooks('contact_edit', $arr); - - return $arr['output']; - - } - } + $contact = App::$poi; + + $global_perms = Permissions::Perms(); + + $hidden_perms = []; + + foreach ($global_perms as $k => $v) { + $thisperm = get_abconfig(local_channel(), $contact['abook_xchan'], 'my_perms', $k); + + $checkinherited = PermissionLimits::Get(local_channel(), $k); + + $inherited = (($checkinherited & PERMS_SPECIFIC) ? false : true); + + $perms[] = ['perms_' . $k, $v, intval($thisperm), '', $yes_no, (($inherited) ? ' disabled="disabled" ' : '')]; + if ($inherited) { + $hidden_perms[] = ['perms_' . $k, intval($thisperm)]; + } + } + + $pcat = new Permcat(local_channel()); + $pcatlist = $pcat->listing(); + $permcats = []; + if ($pcatlist) { + foreach ($pcatlist as $pc) { + $permcats[$pc['name']] = $pc['localname']; + } + } + + $o .= replace_macros($tpl, [ + '$header' => t('Connection Default Permissions'), + '$autoperms' => array('autoperms', t('Apply these permissions automatically'), ((get_pconfig(local_channel(), 'system', 'autoperms')) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no), + '$permcat' => ['permcat', t('Permission role'), '', '', $permcats], + '$permcat_new' => t('Add permission role'), + '$permcat_enable' => feature_enabled(local_channel(), 'permcats'), + '$section' => $section, + '$sections' => $sections, + '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), + '$autoapprove' => t('Automatic approval settings'), + '$unapproved' => $unapproved, + '$inherited' => t('inherited'), + '$submit' => t('Submit'), + '$me' => t('My Settings'), + '$perms' => $perms, + '$hidden_perms' => $hidden_perms, + '$permlbl' => t('Individual Permissions'), + '$permnote_self' => t('Some individual permissions may have been preset or locked based on your channel type and privacy settings.'), + '$contact_id' => $contact['abook_id'], + '$name' => $contact['xchan_name'], + ]); + + $arr = array('contact' => $contact, 'output' => $o); + + call_hooks('contact_edit', $arr); + + return $arr['output']; + + } + } } diff --git a/Zotlabs/Module/Dircensor.php b/Zotlabs/Module/Dircensor.php index 0dab52cb6..ac1e71096 100644 --- a/Zotlabs/Module/Dircensor.php +++ b/Zotlabs/Module/Dircensor.php @@ -6,47 +6,48 @@ use App; use Zotlabs\Web\Controller; -class Dircensor extends Controller { +class Dircensor extends Controller +{ - function get() { - if(! is_site_admin()) { - return; - } + public function get() + { + if (!is_site_admin()) { + return; + } - $dirmode = intval(get_config('system','directory_mode')); + $dirmode = intval(get_config('system', 'directory_mode')); - if (! ($dirmode == DIRECTORY_MODE_PRIMARY || $dirmode == DIRECTORY_MODE_STANDALONE)) { - return; - } + if (!($dirmode == DIRECTORY_MODE_PRIMARY || $dirmode == DIRECTORY_MODE_STANDALONE)) { + return; + } - $xchan = argv(1); - if(! $xchan) { - return; - } + $xchan = argv(1); + if (!$xchan) { + return; + } - $r = q("select * from xchan where xchan_hash = '%s'", - dbesc($xchan) - ); + $r = q("select * from xchan where xchan_hash = '%s'", + dbesc($xchan) + ); - if(! $r) { - return; - } + if (!$r) { + return; + } - $val = (($r[0]['xchan_censored']) ? 0 : 1); + $val = (($r[0]['xchan_censored']) ? 0 : 1); - q("update xchan set xchan_censored = $val where xchan_hash = '%s'", - dbesc($xchan) - ); + q("update xchan set xchan_censored = $val where xchan_hash = '%s'", + dbesc($xchan) + ); - if( $val) { - info( t('Entry censored') . EOL); - } - else { - info( t('Entry uncensored') . EOL); - } - - goaway(z_root() . '/directory'); + if ($val) { + info(t('Entry censored') . EOL); + } else { + info(t('Entry uncensored') . EOL); + } - } + goaway(z_root() . '/directory'); + + } } \ No newline at end of file diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php index e7ba468c3..426f2f6e7 100644 --- a/Zotlabs/Module/Directory.php +++ b/Zotlabs/Module/Directory.php @@ -14,534 +14,530 @@ require_once('include/html2plain.php'); define( 'DIRECTORY_PAGESIZE', 60); -class Directory extends Controller { +class Directory extends Controller +{ - function init() { - App::set_pager_itemspage(DIRECTORY_PAGESIZE); - - if (x($_GET,'ignore') && local_channel()) { - q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ", - intval(local_channel()), - dbesc($_GET['ignore']) - ); - - Libsync::build_sync_packet(local_channel(), [ 'xign' => [ [ 'uid' => local_channel(), 'xchan' => $_GET['ignore'] ]]] ); - if ($_REQUEST['return']) { - goaway(z_root() . '/' . base64_decode($_REQUEST['return'])); - } - goaway(z_root() . '/directory?f=&suggest=1'); - } - - $observer = get_observer_hash(); - $global_changed = false; - $safe_changed = false; - $type_changed = false; - $active_changed = false; - - if (array_key_exists('global',$_REQUEST)) { - $globaldir = intval($_REQUEST['global']); - if (get_config('system','localdir_hide')) { - $globaldir = 1; - } - $global_changed = true; - } - if ($global_changed) { - $_SESSION['globaldir'] = $globaldir; - if ($observer) { - set_xconfig($observer,'directory','globaldir',$globaldir); - } - } - - if (array_key_exists('safe',$_REQUEST)) { - $safemode = intval($_REQUEST['safe']); - $safe_changed = true; - } - if ($safe_changed) { - $_SESSION['safemode'] = $safemode; - if ($observer) { - set_xconfig($observer,'directory','safemode',$safemode); - } - } - - if (array_key_exists('type',$_REQUEST)) { - $type = intval($_REQUEST['type']); - $type_changed = true; - } - if ($type_changed) { - $_SESSION['chantype'] = $type; - if ($observer) { - set_xconfig($observer,'directory','chantype',$type); - } - } + public function init() + { + App::set_pager_itemspage(DIRECTORY_PAGESIZE); - if (array_key_exists('active',$_REQUEST)) { - $active = intval($_REQUEST['active']); - $active_changed = true; - } - if ($active_changed) { - $_SESSION['activedir'] = $active; - if ($observer) { - set_xconfig($observer,'directory','activedir',$active); - } - } + if (x($_GET, 'ignore') && local_channel()) { + q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ", + intval(local_channel()), + dbesc($_GET['ignore']) + ); - } - - function get() { - - if (observer_prohibited()) { - notice( t('Public access denied.') . EOL); - return; - } + Libsync::build_sync_packet(local_channel(), ['xign' => [['uid' => local_channel(), 'xchan' => $_GET['ignore']]]]); + if ($_REQUEST['return']) { + goaway(z_root() . '/' . base64_decode($_REQUEST['return'])); + } + goaway(z_root() . '/directory?f=&suggest=1'); + } - $observer = get_observer_hash(); + $observer = get_observer_hash(); + $global_changed = false; + $safe_changed = false; + $type_changed = false; + $active_changed = false; - if (get_config('system','block_public_directory',true) && (! $observer)) { - notice( t('Public access denied.') . EOL); - return login(false); - } - - $globaldir = Libzotdir::get_directory_setting($observer, 'globaldir'); + if (array_key_exists('global', $_REQUEST)) { + $globaldir = intval($_REQUEST['global']); + if (get_config('system', 'localdir_hide')) { + $globaldir = 1; + } + $global_changed = true; + } + if ($global_changed) { + $_SESSION['globaldir'] = $globaldir; + if ($observer) { + set_xconfig($observer, 'directory', 'globaldir', $globaldir); + } + } - // override your personal global search pref if we're doing a navbar search of the directory - if (intval($_REQUEST['navsearch'])) { - $globaldir = 1; - } - - $safe_mode = Libzotdir::get_directory_setting($observer, 'safemode'); - - $type = Libzotdir::get_directory_setting($observer, 'chantype'); + if (array_key_exists('safe', $_REQUEST)) { + $safemode = intval($_REQUEST['safe']); + $safe_changed = true; + } + if ($safe_changed) { + $_SESSION['safemode'] = $safemode; + if ($observer) { + set_xconfig($observer, 'directory', 'safemode', $safemode); + } + } - $active = Libzotdir::get_directory_setting($observer, 'activedir'); + if (array_key_exists('type', $_REQUEST)) { + $type = intval($_REQUEST['type']); + $type_changed = true; + } + if ($type_changed) { + $_SESSION['chantype'] = $type; + if ($observer) { + set_xconfig($observer, 'directory', 'chantype', $type); + } + } - $o = ''; - nav_set_selected('Directory'); - - if (x($_POST,'search')) { - $search = notags(trim($_POST['search'])); - } - else { - $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); - } - - if (strpos($search,'=')) { - $advanced = $search; - } - - $keywords = (($_GET['keywords']) ? $_GET['keywords'] : ''); - - // Suggest channels if no search terms or keywords are given - $suggest = (local_channel() && x($_REQUEST,'suggest')) ? $_REQUEST['suggest'] : ''; - - if ($suggest) { + if (array_key_exists('active', $_REQUEST)) { + $active = intval($_REQUEST['active']); + $active_changed = true; + } + if ($active_changed) { + $_SESSION['activedir'] = $active; + if ($observer) { + set_xconfig($observer, 'directory', 'activedir', $active); + } + } - // the directory options have no effect in suggestion mode - - $globaldir = 1; - $safe_mode = 1; - $active = 1; - $type = 0; + } - // only return DIRECTORY_PAGESIZE suggestions as the suggestion sorting - // only works if the suggestion query and the directory query have the - // same number of results + public function get() + { - App::set_pager_itemspage(60); - $r = suggestion_query(local_channel(),get_observer_hash(),App::$pager['start'],DIRECTORY_PAGESIZE); + if (observer_prohibited()) { + notice(t('Public access denied.') . EOL); + return; + } - if (! $r) { - if ($_REQUEST['aj']) { - echo '
        '; - killme(); - } + $observer = get_observer_hash(); - notice( t('No default suggestions were found.') . EOL); - return; - } - - // Remember in which order the suggestions were - $addresses = []; - $common = []; - $index = 0; - foreach ($r as $rr) { - $common[$rr['xchan_hash']] = ((intval($rr['total']) > 0) ? intval($rr['total']) - 1 : 0); - $addresses[$rr['xchan_hash']] = $index++; - } - - // Build query to get info about suggested people - $advanced = ''; - foreach (array_keys($addresses) as $address) { - $advanced .= "xhash=\"$address\" "; - } - // Remove last space in the advanced query - $advanced = rtrim($advanced); - - } - - $tpl = get_markup_template('directory_header.tpl'); - - $dirmode = intval(get_config('system','directory_mode')); + if (get_config('system', 'block_public_directory', true) && (!$observer)) { + notice(t('Public access denied.') . EOL); + return login(false); + } - $directory_admin = false; + $globaldir = Libzotdir::get_directory_setting($observer, 'globaldir'); - $url = z_root() . '/dirsearch'; - if (is_site_admin()) { - $directory_admin = true; - } - - $contacts = []; - - if (local_channel()) { - $x = q("select abook_xchan from abook where abook_channel = %d", - intval(local_channel()) - ); - if ($x) { - foreach ($x as $xx) { - $contacts[] = $xx['abook_xchan']; - } - } - } - - if ($url) { - - $numtags = get_config('system','directorytags'); - - $kw = ((intval($numtags) > 0) ? intval($numtags) : 50); - - if (get_config('system','disable_directory_keywords')) { - $kw = 0; - } - - $query = $url . '?f=&kw=' . $kw . (($safe_mode != 1) ? '&safe=' . $safe_mode : ''); - - if ($token) { - $query .= '&t=' . $token; - } - - if (! $globaldir) { - $query .= '&hub=' . App::get_hostname(); - } - if ($search) { - $query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search); - } - if (strpos($search,'@')) { - $query .= '&address=' . urlencode($search); - } - if (strpos($search,'http') === 0) { - $query .= '&url=' . urlencode($search); - } - if ($keywords) { - $query .= '&keywords=' . urlencode($keywords); - } - if ($advanced) { - $query .= '&query=' . urlencode($advanced); - } - if (! is_null($type)) { - $query .= '&type=' . intval($type); - } - $directory_sort_order = get_config('system','directory_sort_order'); - if (! $directory_sort_order) { - $directory_sort_order = 'date'; - } - - $sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : $directory_sort_order); - - if ($sort_order) { - $query .= '&order=' . urlencode($sort_order); - } - - if (App::$pager['page'] != 1) { - $query .= '&p=' . App::$pager['page']; - } + // override your personal global search pref if we're doing a navbar search of the directory + if (intval($_REQUEST['navsearch'])) { + $globaldir = 1; + } - if (isset($active)) { - $query .= '&active=' . intval($active); - } + $safe_mode = Libzotdir::get_directory_setting($observer, 'safemode'); + + $type = Libzotdir::get_directory_setting($observer, 'chantype'); + + $active = Libzotdir::get_directory_setting($observer, 'activedir'); + + $o = ''; + nav_set_selected('Directory'); + + if (x($_POST, 'search')) { + $search = notags(trim($_POST['search'])); + } else { + $search = ((x($_GET, 'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); + } + + if (strpos($search, '=')) { + $advanced = $search; + } + + $keywords = (($_GET['keywords']) ? $_GET['keywords'] : ''); + + // Suggest channels if no search terms or keywords are given + $suggest = (local_channel() && x($_REQUEST, 'suggest')) ? $_REQUEST['suggest'] : ''; + + if ($suggest) { + + // the directory options have no effect in suggestion mode + + $globaldir = 1; + $safe_mode = 1; + $active = 1; + $type = 0; + + // only return DIRECTORY_PAGESIZE suggestions as the suggestion sorting + // only works if the suggestion query and the directory query have the + // same number of results + + App::set_pager_itemspage(60); + $r = suggestion_query(local_channel(), get_observer_hash(), App::$pager['start'], DIRECTORY_PAGESIZE); + + if (!$r) { + if ($_REQUEST['aj']) { + echo '
        '; + killme(); + } + + notice(t('No default suggestions were found.') . EOL); + return; + } + + // Remember in which order the suggestions were + $addresses = []; + $common = []; + $index = 0; + foreach ($r as $rr) { + $common[$rr['xchan_hash']] = ((intval($rr['total']) > 0) ? intval($rr['total']) - 1 : 0); + $addresses[$rr['xchan_hash']] = $index++; + } + + // Build query to get info about suggested people + $advanced = ''; + foreach (array_keys($addresses) as $address) { + $advanced .= "xhash=\"$address\" "; + } + // Remove last space in the advanced query + $advanced = rtrim($advanced); + + } + + $tpl = get_markup_template('directory_header.tpl'); + + $dirmode = intval(get_config('system', 'directory_mode')); + + $directory_admin = false; + + $url = z_root() . '/dirsearch'; + if (is_site_admin()) { + $directory_admin = true; + } + + $contacts = []; + + if (local_channel()) { + $x = q("select abook_xchan from abook where abook_channel = %d", + intval(local_channel()) + ); + if ($x) { + foreach ($x as $xx) { + $contacts[] = $xx['abook_xchan']; + } + } + } + + if ($url) { + + $numtags = get_config('system', 'directorytags'); + + $kw = ((intval($numtags) > 0) ? intval($numtags) : 50); + + if (get_config('system', 'disable_directory_keywords')) { + $kw = 0; + } + + $query = $url . '?f=&kw=' . $kw . (($safe_mode != 1) ? '&safe=' . $safe_mode : ''); + + if ($token) { + $query .= '&t=' . $token; + } + + if (!$globaldir) { + $query .= '&hub=' . App::get_hostname(); + } + if ($search) { + $query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search); + } + if (strpos($search, '@')) { + $query .= '&address=' . urlencode($search); + } + if (strpos($search, 'http') === 0) { + $query .= '&url=' . urlencode($search); + } + if ($keywords) { + $query .= '&keywords=' . urlencode($keywords); + } + if ($advanced) { + $query .= '&query=' . urlencode($advanced); + } + if (!is_null($type)) { + $query .= '&type=' . intval($type); + } + $directory_sort_order = get_config('system', 'directory_sort_order'); + if (!$directory_sort_order) { + $directory_sort_order = 'date'; + } + + $sort_order = ((x($_REQUEST, 'order')) ? $_REQUEST['order'] : $directory_sort_order); + + if ($sort_order) { + $query .= '&order=' . urlencode($sort_order); + } + + if (App::$pager['page'] != 1) { + $query .= '&p=' . App::$pager['page']; + } + + if (isset($active)) { + $query .= '&active=' . intval($active); + } - // logger('mod_directory: query: ' . $query); - - $x = z_fetch_url($query); - // logger('directory: return from upstream: ' . print_r($x,true), LOGGER_DATA); - - if ($x['success']) { - $t = 0; - $j = json_decode($x['body'],true); - if ($j) { - - if ($j['results']) { + // logger('mod_directory: query: ' . $query); - $results = $j['results']; - if ($suggest) { - // change order to "number of common friends descending" - $results = self::reorder_results($results,$addresses); - } + $x = z_fetch_url($query); + // logger('directory: return from upstream: ' . print_r($x,true), LOGGER_DATA); - $entries = []; - - $photo = 'thumb'; - - foreach ($results as $rr) { - - $profile_link = chanlink_url($rr['url']); - - $pdesc = (($rr['description']) ? $rr['description'] . '
        ' : ''); - $connect_link = ((local_channel()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : ''); - - // Checking status is disabled ATM until someone checks the performance impact more carefully - //$online = remote_online_status($rr['address']); - $online = ''; - - if (in_array($rr['hash'],$contacts)) { - $connect_link = ''; - } - - $location = ''; - if (strlen($rr['locale'])) { - $location .= $rr['locale']; - } - if (strlen($rr['region'])) { - if (strlen($rr['locale'])) { - $location .= ', '; - } - $location .= $rr['region']; - } - if (strlen($rr['country'])) { - if (strlen($location)) { - $location .= ', '; - } - $location .= $rr['country']; - } - - $age = ''; - if (strlen($rr['birthday'])) { - if (($years = age($rr['birthday'],'UTC','')) > 0) { - $age = $years; - } - } - - $page_type = ''; - - $total_ratings = ''; - - $profile = $rr; - - $gender = ((x($profile,'gender') == 1) ? t('Gender: ') . $profile['gender']: False); - $marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False); - $homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') : False); - $homepageurl = ((x($profile,'homepage') == 1) ? html2plain($profile['homepage']) : ''); - $hometown = ((x($profile,'hometown') == 1) ? html2plain($profile['hometown']) : False); - $about = ((x($profile,'about') == 1) ? zidify_links(bbcode($profile['about'])) : False); - - $keywords = ((x($profile,'keywords')) ? $profile['keywords'] : ''); - - $out = ''; - - if ($keywords) { - $keywords = str_replace(',',' ', $keywords); - $keywords = str_replace(' ',' ', $keywords); - $karr = explode(' ', $keywords); - - if ($karr) { - if (local_channel()) { - $pk = q("select keywords from profile where uid = %d and is_default = 1 limit 1", - intval(local_channel()) - ); - if ($pk) { - $keywords = str_replace(',',' ', $pk[0]['keywords']); - $keywords = str_replace(' ',' ', $keywords); - $marr = explode(' ', $keywords); - } - } - foreach ($karr as $k) { - if (strlen($out)) { - $out .= ', '; - } - if ($marr && in_arrayi($k,$marr)) { - $out .= '' . $k . ''; - } - else { - $out .= '' . $k . ''; - } - } - } - } - - $entry = [ - 'id' => ++ $t, - 'profile_link' => $profile_link, - 'type' => $rr['type'], - 'photo' => $rr['photo'], - 'hash' => $rr['hash'], - 'alttext' => $rr['name'] . ((local_channel() || remote_channel()) ? ' ' . $rr['address'] : ''), - 'name' => $rr['name'], - 'age' => $age, - 'age_label' => t('Age:'), - 'profile' => $profile, - 'address' => $rr['address'], - 'nickname' => substr($rr['address'],0,strpos($rr['address'],'@')), - 'location' => $location, - 'location_label' => t('Location:'), - 'gender' => $gender, - 'total_ratings' => $total_ratings, - 'viewrate' => true, - 'canrate' => (($rating_enabled && local_channel()) ? true : false), - // 'network' => network_to_name($rr['network']), - // 'network_label' => t('Network:'), - 'pdesc' => $pdesc, - 'pdesc_label' => t('Description:'), - 'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] : ''), - 'censor_label' => (($rr['censored']) ? t('Uncensor') : t('Censor')), - 'marital' => $marital, - 'homepage' => $homepage, - 'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)), - 'hometown' => $hometown, - 'hometown_label' => t('Hometown:'), - 'about' => $about, - 'about_label' => t('About:'), - 'conn_label' => t('Connect'), - 'forum_label' => t('Group'), - 'collections_label' => t('Collection'), - 'connect' => $connect_link, - 'online' => $online, - 'kw' => (($out) ? t('Keywords: ') : ''), - 'keywords' => $out, - 'ignlink' => $suggest ? z_root() . '/directory?ignore=' . $rr['hash'] : '', - 'ignore_label' => t('Don\'t suggest'), - 'common_friends' => (($common[$rr['hash']]) ? intval($common[$rr['hash']]) : ''), - 'common_label' => t('Suggestion ranking:'), - 'common_count' => intval($common[$rr['hash']]), - 'safe' => $safe_mode - ]; + if ($x['success']) { + $t = 0; + $j = json_decode($x['body'], true); + if ($j) { + + if ($j['results']) { + + $results = $j['results']; + if ($suggest) { + // change order to "number of common friends descending" + $results = self::reorder_results($results, $addresses); + } + + $entries = []; + + $photo = 'thumb'; + + foreach ($results as $rr) { + + $profile_link = chanlink_url($rr['url']); + + $pdesc = (($rr['description']) ? $rr['description'] . '
        ' : ''); + $connect_link = ((local_channel()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : ''); + + // Checking status is disabled ATM until someone checks the performance impact more carefully + //$online = remote_online_status($rr['address']); + $online = ''; + + if (in_array($rr['hash'], $contacts)) { + $connect_link = ''; + } + + $location = ''; + if (strlen($rr['locale'])) { + $location .= $rr['locale']; + } + if (strlen($rr['region'])) { + if (strlen($rr['locale'])) { + $location .= ', '; + } + $location .= $rr['region']; + } + if (strlen($rr['country'])) { + if (strlen($location)) { + $location .= ', '; + } + $location .= $rr['country']; + } + + $age = ''; + if (strlen($rr['birthday'])) { + if (($years = age($rr['birthday'], 'UTC', '')) > 0) { + $age = $years; + } + } + + $page_type = ''; + + $total_ratings = ''; + + $profile = $rr; + + $gender = ((x($profile, 'gender') == 1) ? t('Gender: ') . $profile['gender'] : False); + $marital = ((x($profile, 'marital') == 1) ? t('Status: ') . $profile['marital'] : False); + $homepage = ((x($profile, 'homepage') == 1) ? t('Homepage: ') : False); + $homepageurl = ((x($profile, 'homepage') == 1) ? html2plain($profile['homepage']) : ''); + $hometown = ((x($profile, 'hometown') == 1) ? html2plain($profile['hometown']) : False); + $about = ((x($profile, 'about') == 1) ? zidify_links(bbcode($profile['about'])) : False); + + $keywords = ((x($profile, 'keywords')) ? $profile['keywords'] : ''); + + $out = ''; + + if ($keywords) { + $keywords = str_replace(',', ' ', $keywords); + $keywords = str_replace(' ', ' ', $keywords); + $karr = explode(' ', $keywords); + + if ($karr) { + if (local_channel()) { + $pk = q("select keywords from profile where uid = %d and is_default = 1 limit 1", + intval(local_channel()) + ); + if ($pk) { + $keywords = str_replace(',', ' ', $pk[0]['keywords']); + $keywords = str_replace(' ', ' ', $keywords); + $marr = explode(' ', $keywords); + } + } + foreach ($karr as $k) { + if (strlen($out)) { + $out .= ', '; + } + if ($marr && in_arrayi($k, $marr)) { + $out .= '' . $k . ''; + } else { + $out .= '' . $k . ''; + } + } + } + } + + $entry = [ + 'id' => ++$t, + 'profile_link' => $profile_link, + 'type' => $rr['type'], + 'photo' => $rr['photo'], + 'hash' => $rr['hash'], + 'alttext' => $rr['name'] . ((local_channel() || remote_channel()) ? ' ' . $rr['address'] : ''), + 'name' => $rr['name'], + 'age' => $age, + 'age_label' => t('Age:'), + 'profile' => $profile, + 'address' => $rr['address'], + 'nickname' => substr($rr['address'], 0, strpos($rr['address'], '@')), + 'location' => $location, + 'location_label' => t('Location:'), + 'gender' => $gender, + 'total_ratings' => $total_ratings, + 'viewrate' => true, + 'canrate' => (($rating_enabled && local_channel()) ? true : false), + // 'network' => network_to_name($rr['network']), + // 'network_label' => t('Network:'), + 'pdesc' => $pdesc, + 'pdesc_label' => t('Description:'), + 'censor' => (($directory_admin) ? 'dircensor/' . $rr['hash'] : ''), + 'censor_label' => (($rr['censored']) ? t('Uncensor') : t('Censor')), + 'marital' => $marital, + 'homepage' => $homepage, + 'homepageurl' => (($safe_mode) ? $homepageurl : linkify($homepageurl)), + 'hometown' => $hometown, + 'hometown_label' => t('Hometown:'), + 'about' => $about, + 'about_label' => t('About:'), + 'conn_label' => t('Connect'), + 'forum_label' => t('Group'), + 'collections_label' => t('Collection'), + 'connect' => $connect_link, + 'online' => $online, + 'kw' => (($out) ? t('Keywords: ') : ''), + 'keywords' => $out, + 'ignlink' => $suggest ? z_root() . '/directory?ignore=' . $rr['hash'] : '', + 'ignore_label' => t('Don\'t suggest'), + 'common_friends' => (($common[$rr['hash']]) ? intval($common[$rr['hash']]) : ''), + 'common_label' => t('Suggestion ranking:'), + 'common_count' => intval($common[$rr['hash']]), + 'safe' => $safe_mode + ]; - $blocked = LibBlock::fetch($channel['channel_id'],BLOCKTYPE_SERVER); + $blocked = LibBlock::fetch($channel['channel_id'], BLOCKTYPE_SERVER); - $found_block = false; - if ($blocked) { - foreach ($blocked as $b) { - if (strpos($rr['site_url'],$b['block_entity']) !== false) { - $found_block = true; - break; - } - } - if ($found_block) { - continue; - } - } + $found_block = false; + if ($blocked) { + foreach ($blocked as $b) { + if (strpos($rr['site_url'], $b['block_entity']) !== false) { + $found_block = true; + break; + } + } + if ($found_block) { + continue; + } + } - if (LibBlock::fetch_by_entity(local_channel(), $entry['hash'])) { - continue; - } + if (LibBlock::fetch_by_entity(local_channel(), $entry['hash'])) { + continue; + } - $arr = array('contact' => $rr, 'entry' => $entry); - - call_hooks('directory_item', $arr); - - unset($profile); - unset($location); - - if (! $arr['entry']) { - continue; - } - - if ($sort_order == '' && $suggest) { - $entries[$addresses[$rr['address']]] = $arr['entry']; // Use the same indexes as originally to get the best suggestion first - } - else { - $entries[] = $arr['entry']; - } - } - - ksort($entries); // Sort array by key so that foreach-constructs work as expected - - if ($j['keywords']) { - App::$data['directory_keywords'] = $j['keywords']; - } - - // logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA); - - - if ($_REQUEST['aj']) { - if ($entries) { - $o = replace_macros(get_markup_template('directajax.tpl'), [ '$entries' => $entries ] ); - } - else { - $o = '
        '; - } - echo $o; - killme(); - } - else { - $maxheight = 94; - - $dirtitle = (($globaldir) ? t('Directory') : t('Local Directory')); - - $o .= ""; - $o .= replace_macros($tpl, [ - '$search' => $search, - '$desc' => t('Find'), - '$finddsc' => t('Finding:'), - '$safetxt' => htmlspecialchars($search,ENT_QUOTES,'UTF-8'), - '$entries' => $entries, - '$dirlbl' => $suggest ? t('Channel Suggestions') : $dirtitle, - '$submit' => t('Find'), - '$next' => alt_pager($j['records'], t('next page'), t('previous page')), - '$sort' => t('Sort options'), - '$normal' => t('Alphabetic'), - '$reverse' => t('Reverse Alphabetic'), - '$date' => t('Newest to Oldest'), - '$reversedate' => t('Oldest to Newest'), - '$suggest' => $suggest ? '&suggest=1' : '' - ]); - } - } - else { - if ($_REQUEST['aj']) { - $o = '
        '; - echo $o; - killme(); - } - if ($search && App::$pager['page'] == 1 && $j['records'] == 0) { - if (strpos($search,'@')) { - goaway(z_root() . '/chanview/?f=&address=' . $search); - } - elseif(strpos($search,'http') === 0) { - goaway(z_root() . '/chanview/?f=&url=' . $search); - } - else { - $r = q("select xchan_hash from xchan where xchan_name = '%s' limit 1", - dbesc($search) - ); - if ($r) { - goaway(z_root() . '/chanview/?f=&hash=' . urlencode($r[0]['xchan_hash'])); - } - } - } - info( t("No entries (some entries may be hidden).") . EOL); - } - } - } - } - return $o; - } + $arr = array('contact' => $rr, 'entry' => $entry); + + call_hooks('directory_item', $arr); + + unset($profile); + unset($location); + + if (!$arr['entry']) { + continue; + } + + if ($sort_order == '' && $suggest) { + $entries[$addresses[$rr['address']]] = $arr['entry']; // Use the same indexes as originally to get the best suggestion first + } else { + $entries[] = $arr['entry']; + } + } + + ksort($entries); // Sort array by key so that foreach-constructs work as expected + + if ($j['keywords']) { + App::$data['directory_keywords'] = $j['keywords']; + } + + // logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA); - static public function reorder_results($results,$suggests) { - if (! $suggests) { - return $results; - } + if ($_REQUEST['aj']) { + if ($entries) { + $o = replace_macros(get_markup_template('directajax.tpl'), ['$entries' => $entries]); + } else { + $o = '
        '; + } + echo $o; + killme(); + } else { + $maxheight = 94; + + $dirtitle = (($globaldir) ? t('Directory') : t('Local Directory')); + + $o .= ""; + $o .= replace_macros($tpl, [ + '$search' => $search, + '$desc' => t('Find'), + '$finddsc' => t('Finding:'), + '$safetxt' => htmlspecialchars($search, ENT_QUOTES, 'UTF-8'), + '$entries' => $entries, + '$dirlbl' => $suggest ? t('Channel Suggestions') : $dirtitle, + '$submit' => t('Find'), + '$next' => alt_pager($j['records'], t('next page'), t('previous page')), + '$sort' => t('Sort options'), + '$normal' => t('Alphabetic'), + '$reverse' => t('Reverse Alphabetic'), + '$date' => t('Newest to Oldest'), + '$reversedate' => t('Oldest to Newest'), + '$suggest' => $suggest ? '&suggest=1' : '' + ]); + } + } else { + if ($_REQUEST['aj']) { + $o = '
        '; + echo $o; + killme(); + } + if ($search && App::$pager['page'] == 1 && $j['records'] == 0) { + if (strpos($search, '@')) { + goaway(z_root() . '/chanview/?f=&address=' . $search); + } elseif (strpos($search, 'http') === 0) { + goaway(z_root() . '/chanview/?f=&url=' . $search); + } else { + $r = q("select xchan_hash from xchan where xchan_name = '%s' limit 1", + dbesc($search) + ); + if ($r) { + goaway(z_root() . '/chanview/?f=&hash=' . urlencode($r[0]['xchan_hash'])); + } + } + } + info(t("No entries (some entries may be hidden).") . EOL); + } + } + } + } + return $o; + } + + + public static function reorder_results($results, $suggests) + { + if (!$suggests) { + return $results; + } + + $out = []; + foreach ($suggests as $k => $v) { + foreach ($results as $rv) { + if ($k == $rv['hash']) { + $out[intval($v)] = $rv; + break; + } + } + } + return $out; + } - $out = []; - foreach ($suggests as $k => $v) { - foreach ($results as $rv) { - if ($k == $rv['hash']) { - $out[intval($v)] = $rv; - break; - } - } - } - return $out; - } - } diff --git a/Zotlabs/Module/Dirsearch.php b/Zotlabs/Module/Dirsearch.php index 7ee5d79b3..8f6cae2e3 100644 --- a/Zotlabs/Module/Dirsearch.php +++ b/Zotlabs/Module/Dirsearch.php @@ -7,455 +7,454 @@ use Zotlabs\Web\Controller; // This is the primary endpoint for communicating with Zot directory services. -class Dirsearch extends Controller { +class Dirsearch extends Controller +{ - function init() { - App::set_pager_itemspage(60); - } - - function get() { - - $ret = [ 'success' => false ]; - - // logger('request: ' . print_r($_REQUEST,true)); - + public function init() + { + App::set_pager_itemspage(60); + } - if (argc() > 1 && argv(1) === 'sites') { - $ret = $this->list_public_sites(); - json_return_and_die($ret); - } + public function get() + { - $dirmode = intval(get_config('system','directory_mode')); + $ret = ['success' => false]; + + // logger('request: ' . print_r($_REQUEST,true)); - $network = EMPTY_STR; + if (argc() > 1 && argv(1) === 'sites') { + $ret = $this->list_public_sites(); + json_return_and_die($ret); + } - $sql_extra = ''; - - $tables = [ 'name', 'address', 'xhash', 'locale', 'region', 'postcode', - 'country', 'gender', 'marital', 'sexual', 'keywords' ]; - - // parse advanced query if present - - if ($_REQUEST['query']) { - $advanced = $this->dir_parse_query($_REQUEST['query']); - if ($advanced) { - foreach ($advanced as $adv) { - if (in_array($adv['field'],$tables)) { - if ($adv['field'] === 'name') - $sql_extra .= $this->dir_query_build($adv['logic'],'xchan_name',$adv['value']); - elseif ($adv['field'] === 'address') - $sql_extra .= $this->dir_query_build($adv['logic'],'xchan_addr',$adv['value']); - elseif ($adv['field'] === 'xhash') - $sql_extra .= $this->dir_query_build($adv['logic'],'xchan_hash',$adv['value']); - else - $sql_extra .= $this->dir_query_build($adv['logic'],'xprof_' . $adv['field'],$adv['value']); - } - } - } - } - - $hash = ((x($_REQUEST['hash'])) ? $_REQUEST['hash'] : ''); - $name = ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''); - $url = ((x($_REQUEST,'url')) ? $_REQUEST['url'] : ''); - $hub = ((x($_REQUEST,'hub')) ? $_REQUEST['hub'] : ''); - $address = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : ''); - $locale = ((x($_REQUEST,'locale')) ? $_REQUEST['locale'] : ''); - $region = ((x($_REQUEST,'region')) ? $_REQUEST['region'] : ''); - $postcode = ((x($_REQUEST,'postcode')) ? $_REQUEST['postcode'] : ''); - $country = ((x($_REQUEST,'country')) ? $_REQUEST['country'] : ''); - $gender = ((x($_REQUEST,'gender')) ? $_REQUEST['gender'] : ''); - $marital = ((x($_REQUEST,'marital')) ? $_REQUEST['marital'] : ''); - $sexual = ((x($_REQUEST,'sexual')) ? $_REQUEST['sexual'] : ''); - $keywords = ((x($_REQUEST,'keywords')) ? $_REQUEST['keywords'] : ''); - $agege = ((x($_REQUEST,'agege')) ? intval($_REQUEST['agege']) : 0 ); - $agele = ((x($_REQUEST,'agele')) ? intval($_REQUEST['agele']) : 0 ); - $kw = ((x($_REQUEST,'kw')) ? intval($_REQUEST['kw']) : 0 ); - $active = ((x($_REQUEST,'active')) ? intval($_REQUEST['active']) : 0 ); - $type = ((array_key_exists('type',$_REQUEST)) ? intval($_REQUEST['type']) : 0); - - // allow a site to disable the directory's keyword list - if (get_config('system','disable_directory_keywords')) - $kw = 0; - - // by default use a safe search - $safe = ((x($_REQUEST,'safe'))); - if ($safe === false) { - $safe = 1; - } - - // Directory mirrors will request sync packets, which are lists - // of records that have changed since the sync datetime. - - if (array_key_exists('sync',$_REQUEST)) { - if ($_REQUEST['sync']) - $sync = datetime_convert('UTC','UTC',$_REQUEST['sync']); - else - $sync = datetime_convert('UTC','UTC','2010-01-01 01:01:00'); - } - else - $sync = false; - - if (($dirmode == DIRECTORY_MODE_STANDALONE) && (! $hub)) { - $hub = App::get_hostname(); - } - - if ($hub) { - $hub_query = " and xchan_hash in (select hubloc_hash from hubloc where hubloc_host = '" . protect_sprintf(dbesc($hub)) . "') "; - } - else { - $hub_query = ''; - } - - if ($url) { - $r = q("select xchan_name from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_url = '%s' or hubloc_id_url = '%s'", - dbesc($url), - dbesc($url) - ); - if ($r && $r[0]['xchan_name']) { - $name = $r[0]['xchan_name']; - } - } - - // The order identifier is validated further below - - $sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : ''); + $dirmode = intval(get_config('system', 'directory_mode')); - // parse and assemble the query for advanced searches - - $joiner = ' OR '; + $network = EMPTY_STR; - if($_REQUEST['and']) - $joiner = ' AND '; - - if ($name) { - $sql_extra .= $this->dir_query_build($joiner,'xchan_name',$name); - } - if ($address) { - $sql_extra .= $this->dir_query_build($joiner,'xchan_addr',$address); - } - if ($hash) { - $sql_extra .= $this->dir_query_build($joiner,'xchan_hash',$hash); - } - if ($locale) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_locale',$locale); - } - if ($region) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_region',$region); - } - if ($postcode) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_postcode',$postcode); - } - if ($country) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_country',$country); - } - if ($gender) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_gender',$gender); - } - if ($marital) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_marital',$marital); - } - if ($sexual) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_sexual',$sexual); - } - if ($keywords) { - $sql_extra .= $this->dir_query_build($joiner,'xprof_keywords',$keywords); - } - - // we only support an age range currently. You must set both agege - // (greater than or equal) and agele (less than or equal) - - if($agele && $agege) { - $sql_extra .= " $joiner ( xprof_age <= " . intval($agele) . " "; - $sql_extra .= " AND xprof_age >= " . intval($agege) . ") "; - } - - - $perpage = (($_REQUEST['n']) ? $_REQUEST['n'] : 60); - $page = (($_REQUEST['p']) ? intval($_REQUEST['p'] - 1) : 0); - $startrec = (($page+1) * $perpage) - $perpage; - $limit = (($_REQUEST['limit']) ? intval($_REQUEST['limit']) : 0); - $return_total = ((x($_REQUEST,'return_total')) ? intval($_REQUEST['return_total']) : 0); - - // mtime is not currently working - - $mtime = ((x($_REQUEST,'mtime')) ? datetime_convert('UTC','UTC',$_REQUEST['mtime']) : ''); - - // merge them into xprof - - $ret['success'] = true; - - // If &limit=n, return at most n entries - // If &return_total=1, we count matching entries and return that as 'total_items' for use in pagination. - // By default we return one page (default 60 items maximum) and do not count total entries - - $logic = ((strlen($sql_extra)) ? 'false' : 'true'); - - if ($hash) { - $logic = 'true'; - } - - if ($dirmode == DIRECTORY_MODE_STANDALONE) { - $sql_extra .= " and xchan_addr like '%%" . App::get_hostname() . "' "; - } - - $safesql = (($safe > 0) ? " and xchan_censored = 0 and xchan_selfcensored = 0 " : ''); - if ($safe < 0) { - $safesql = " and ( xchan_censored = 1 OR xchan_selfcensored = 1 ) "; - } - - if ($type) { - $safesql .= " and xchan_type = " . intval($type); - } + $sql_extra = ''; - $activesql = EMPTY_STR; - - if ($active) { - $activesql = "and xchan_updated > '" . datetime_convert(date_default_timezone_get(),'UTC','now - 60 days') . "' "; - } + $tables = ['name', 'address', 'xhash', 'locale', 'region', 'postcode', + 'country', 'gender', 'marital', 'sexual', 'keywords']; - if ($limit) { - $qlimit = " LIMIT $limit "; - } - else { - $qlimit = " LIMIT " . intval($perpage) . " OFFSET " . intval($startrec); - if ($return_total) { - $r = q("SELECT COUNT(xchan_hash) AS total FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra $network and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql $activesql "); - if ($r) { - $ret['total_items'] = $r[0]['total']; - } - } - } - - if ($sort_order == 'normal') { - $order = " order by xchan_name asc "; - - // Start the alphabetic search at 'A' - // This will make a handful of channels whose names begin with - // punctuation un-searchable in this mode - - $safesql .= " and ascii(substring(xchan_name FROM 1 FOR 1)) > 64 "; - } - elseif ($sort_order == 'reverse') - $order = " order by xchan_name desc "; - elseif ($sort_order == 'reversedate') - $order = " order by xchan_name_date asc "; - else - $order = " order by xchan_name_date desc "; - - - // normal directory query + // parse advanced query if present - $r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash + if ($_REQUEST['query']) { + $advanced = $this->dir_parse_query($_REQUEST['query']); + if ($advanced) { + foreach ($advanced as $adv) { + if (in_array($adv['field'], $tables)) { + if ($adv['field'] === 'name') + $sql_extra .= $this->dir_query_build($adv['logic'], 'xchan_name', $adv['value']); + elseif ($adv['field'] === 'address') + $sql_extra .= $this->dir_query_build($adv['logic'], 'xchan_addr', $adv['value']); + elseif ($adv['field'] === 'xhash') + $sql_extra .= $this->dir_query_build($adv['logic'], 'xchan_hash', $adv['value']); + else + $sql_extra .= $this->dir_query_build($adv['logic'], 'xprof_' . $adv['field'], $adv['value']); + } + } + } + } + + $hash = ((x($_REQUEST['hash'])) ? $_REQUEST['hash'] : ''); + $name = ((x($_REQUEST, 'name')) ? $_REQUEST['name'] : ''); + $url = ((x($_REQUEST, 'url')) ? $_REQUEST['url'] : ''); + $hub = ((x($_REQUEST, 'hub')) ? $_REQUEST['hub'] : ''); + $address = ((x($_REQUEST, 'address')) ? $_REQUEST['address'] : ''); + $locale = ((x($_REQUEST, 'locale')) ? $_REQUEST['locale'] : ''); + $region = ((x($_REQUEST, 'region')) ? $_REQUEST['region'] : ''); + $postcode = ((x($_REQUEST, 'postcode')) ? $_REQUEST['postcode'] : ''); + $country = ((x($_REQUEST, 'country')) ? $_REQUEST['country'] : ''); + $gender = ((x($_REQUEST, 'gender')) ? $_REQUEST['gender'] : ''); + $marital = ((x($_REQUEST, 'marital')) ? $_REQUEST['marital'] : ''); + $sexual = ((x($_REQUEST, 'sexual')) ? $_REQUEST['sexual'] : ''); + $keywords = ((x($_REQUEST, 'keywords')) ? $_REQUEST['keywords'] : ''); + $agege = ((x($_REQUEST, 'agege')) ? intval($_REQUEST['agege']) : 0); + $agele = ((x($_REQUEST, 'agele')) ? intval($_REQUEST['agele']) : 0); + $kw = ((x($_REQUEST, 'kw')) ? intval($_REQUEST['kw']) : 0); + $active = ((x($_REQUEST, 'active')) ? intval($_REQUEST['active']) : 0); + $type = ((array_key_exists('type', $_REQUEST)) ? intval($_REQUEST['type']) : 0); + + // allow a site to disable the directory's keyword list + if (get_config('system', 'disable_directory_keywords')) + $kw = 0; + + // by default use a safe search + $safe = ((x($_REQUEST, 'safe'))); + if ($safe === false) { + $safe = 1; + } + + // Directory mirrors will request sync packets, which are lists + // of records that have changed since the sync datetime. + + if (array_key_exists('sync', $_REQUEST)) { + if ($_REQUEST['sync']) + $sync = datetime_convert('UTC', 'UTC', $_REQUEST['sync']); + else + $sync = datetime_convert('UTC', 'UTC', '2010-01-01 01:01:00'); + } else + $sync = false; + + if (($dirmode == DIRECTORY_MODE_STANDALONE) && (!$hub)) { + $hub = App::get_hostname(); + } + + if ($hub) { + $hub_query = " and xchan_hash in (select hubloc_hash from hubloc where hubloc_host = '" . protect_sprintf(dbesc($hub)) . "') "; + } else { + $hub_query = ''; + } + + if ($url) { + $r = q("select xchan_name from hubloc left join xchan on hubloc_hash = xchan_hash where hubloc_url = '%s' or hubloc_id_url = '%s'", + dbesc($url), + dbesc($url) + ); + if ($r && $r[0]['xchan_name']) { + $name = $r[0]['xchan_name']; + } + } + + // The order identifier is validated further below + + $sort_order = ((x($_REQUEST, 'order')) ? $_REQUEST['order'] : ''); + + + // parse and assemble the query for advanced searches + + $joiner = ' OR '; + + if ($_REQUEST['and']) + $joiner = ' AND '; + + if ($name) { + $sql_extra .= $this->dir_query_build($joiner, 'xchan_name', $name); + } + if ($address) { + $sql_extra .= $this->dir_query_build($joiner, 'xchan_addr', $address); + } + if ($hash) { + $sql_extra .= $this->dir_query_build($joiner, 'xchan_hash', $hash); + } + if ($locale) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_locale', $locale); + } + if ($region) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_region', $region); + } + if ($postcode) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_postcode', $postcode); + } + if ($country) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_country', $country); + } + if ($gender) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_gender', $gender); + } + if ($marital) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_marital', $marital); + } + if ($sexual) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_sexual', $sexual); + } + if ($keywords) { + $sql_extra .= $this->dir_query_build($joiner, 'xprof_keywords', $keywords); + } + + // we only support an age range currently. You must set both agege + // (greater than or equal) and agele (less than or equal) + + if ($agele && $agege) { + $sql_extra .= " $joiner ( xprof_age <= " . intval($agele) . " "; + $sql_extra .= " AND xprof_age >= " . intval($agege) . ") "; + } + + + $perpage = (($_REQUEST['n']) ? $_REQUEST['n'] : 60); + $page = (($_REQUEST['p']) ? intval($_REQUEST['p'] - 1) : 0); + $startrec = (($page + 1) * $perpage) - $perpage; + $limit = (($_REQUEST['limit']) ? intval($_REQUEST['limit']) : 0); + $return_total = ((x($_REQUEST, 'return_total')) ? intval($_REQUEST['return_total']) : 0); + + // mtime is not currently working + + $mtime = ((x($_REQUEST, 'mtime')) ? datetime_convert('UTC', 'UTC', $_REQUEST['mtime']) : ''); + + // merge them into xprof + + $ret['success'] = true; + + // If &limit=n, return at most n entries + // If &return_total=1, we count matching entries and return that as 'total_items' for use in pagination. + // By default we return one page (default 60 items maximum) and do not count total entries + + $logic = ((strlen($sql_extra)) ? 'false' : 'true'); + + if ($hash) { + $logic = 'true'; + } + + if ($dirmode == DIRECTORY_MODE_STANDALONE) { + $sql_extra .= " and xchan_addr like '%%" . App::get_hostname() . "' "; + } + + $safesql = (($safe > 0) ? " and xchan_censored = 0 and xchan_selfcensored = 0 " : ''); + if ($safe < 0) { + $safesql = " and ( xchan_censored = 1 OR xchan_selfcensored = 1 ) "; + } + + if ($type) { + $safesql .= " and xchan_type = " . intval($type); + } + + $activesql = EMPTY_STR; + + if ($active) { + $activesql = "and xchan_updated > '" . datetime_convert(date_default_timezone_get(), 'UTC', 'now - 60 days') . "' "; + } + + if ($limit) { + $qlimit = " LIMIT $limit "; + } else { + $qlimit = " LIMIT " . intval($perpage) . " OFFSET " . intval($startrec); + if ($return_total) { + $r = q("SELECT COUNT(xchan_hash) AS total FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra $network and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql $activesql "); + if ($r) { + $ret['total_items'] = $r[0]['total']; + } + } + } + + if ($sort_order == 'normal') { + $order = " order by xchan_name asc "; + + // Start the alphabetic search at 'A' + // This will make a handful of channels whose names begin with + // punctuation un-searchable in this mode + + $safesql .= " and ascii(substring(xchan_name FROM 1 FOR 1)) > 64 "; + } elseif ($sort_order == 'reverse') + $order = " order by xchan_name desc "; + elseif ($sort_order == 'reversedate') + $order = " order by xchan_name_date asc "; + else + $order = " order by xchan_name_date desc "; + + + // normal directory query + + $r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash where ( $logic $sql_extra ) $hub_query $network and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql $activesql $order $qlimit " - ); + ); - $ret['page'] = $page + 1; - $ret['records'] = count($r); - - if ($r) { - - $entries = []; - $dups = []; - $isdup = EMPTY_STR; + $ret['page'] = $page + 1; + $ret['records'] = count($r); - // Collect activitypub identities and query which also have zot6 identities. - // Do this once per page fetch rather than once per entry. + if ($r) { - foreach ($r as $rv) { - if ($rv['xchan_network'] === 'activitypub') { - if ($isdup) { - $isdup .= ','; - } - $isdup .= "'" . dbesc($rv['xchan_url']) . "'"; - } - if ($isdup) { - $isdup = protect_sprintf($isdup); - $z = q("select xchan_url, xchan_hash from xchan where xchan_url in ( $isdup ) and xchan_network = 'zot6'"); - if ($z) { - foreach($z as $zv) { - $dups[$zv['xchan_url']] = $zv['xchan_hash']; - } - } - } - } - - foreach ($r as $rr) { + $entries = []; + $dups = []; + $isdup = EMPTY_STR; - // If it's an activitypub record and the channel also has a zot6 address, don't return it. - - if (array_key_exists($rr['xchan_url'],$dups)) { - continue; - } + // Collect activitypub identities and query which also have zot6 identities. + // Do this once per page fetch rather than once per entry. - if (! check_siteallowed($rr['xchan_url'])) { - continue; - } + foreach ($r as $rv) { + if ($rv['xchan_network'] === 'activitypub') { + if ($isdup) { + $isdup .= ','; + } + $isdup .= "'" . dbesc($rv['xchan_url']) . "'"; + } + if ($isdup) { + $isdup = protect_sprintf($isdup); + $z = q("select xchan_url, xchan_hash from xchan where xchan_url in ( $isdup ) and xchan_network = 'zot6'"); + if ($z) { + foreach ($z as $zv) { + $dups[$zv['xchan_url']] = $zv['xchan_hash']; + } + } + } + } - if (! check_channelallowed($rr['xchan_hash'])) { - continue; - } + foreach ($r as $rr) { + + // If it's an activitypub record and the channel also has a zot6 address, don't return it. + + if (array_key_exists($rr['xchan_url'], $dups)) { + continue; + } + + if (!check_siteallowed($rr['xchan_url'])) { + continue; + } + + if (!check_channelallowed($rr['xchan_hash'])) { + continue; + } - $entry = []; - - $entry['name'] = $rr['xchan_name']; - $entry['hash'] = $rr['xchan_hash']; - $entry['censored'] = $rr['xchan_censored']; - $entry['selfcensored'] = $rr['xchan_selfcensored']; - $entry['type'] = $rr['xchan_type']; - $entry['url'] = $rr['xchan_url']; - $entry['photo_l'] = $rr['xchan_photo_l']; - $entry['photo'] = $rr['xchan_photo_m']; - $entry['address'] = $rr['xchan_addr']; - $entry['network'] = $rr['xchan_network']; - $entry['description'] = $rr['xprof_desc']; - $entry['locale'] = $rr['xprof_locale']; - $entry['region'] = $rr['xprof_region']; - $entry['postcode'] = $rr['xprof_postcode']; - $entry['country'] = $rr['xprof_country']; - $entry['birthday'] = $rr['xprof_dob']; - $entry['age'] = $rr['xprof_age']; - $entry['gender'] = $rr['xprof_gender']; - $entry['marital'] = $rr['xprof_marital']; - $entry['sexual'] = $rr['xprof_sexual']; - $entry['about'] = $rr['xprof_about']; - $entry['homepage'] = $rr['xprof_homepage']; - $entry['hometown'] = $rr['xprof_hometown']; - $entry['keywords'] = $rr['xprof_keywords']; - - $entries[] = $entry; - - } - - $ret['results'] = $entries; - if ($kw) { - $k = dir_tagadelic($kw, $hub, $type,$safesql); - if ($k) { - $ret['keywords'] = []; - foreach ($k as $kv) { - $ret['keywords'][] = [ 'term' => $kv[0], 'weight' => $kv[1], 'normalise' => $kv[2] ]; - } - } - } - } - json_return_and_die($ret); - } - - function dir_query_build($joiner,$field,$s) { - $ret = ''; - if (trim($s)) - $ret .= dbesc($joiner) . " " . dbesc($field) . " like '" . protect_sprintf( '%' . dbesc($s) . '%' ) . "' "; - return $ret; - } - - function dir_flag_build($joiner,$field,$bit,$s) { - return dbesc($joiner) . " ( " . dbesc($field) . " & " . intval($bit) . " ) " . ((intval($s)) ? '>' : '=' ) . " 0 "; - } - - - function dir_parse_query($s) { - - $ret = []; - $curr = []; - $all = explode(' ',$s); - $quoted_string = false; - - if ($all) { - foreach ($all as $q) { - if ($quoted_string === false) { - if ($q === 'and') { - $curr['logic'] = 'and'; - continue; - } - if ($q === 'or') { - $curr['logic'] = 'or'; - continue; - } - if ($q === 'not') { - $curr['logic'] .= ' not'; - continue; - } - if (strpos($q,'=')) { - if (! isset($curr['logic'])) - $curr['logic'] = 'or'; - $curr['field'] = trim(substr($q,0,strpos($q,'='))); - $curr['value'] = trim(substr($q,strpos($q,'=')+1)); - if ($curr['value'][0] == '"' && $curr['value'][strlen($curr['value'])-1] != '"') { - $quoted_string = true; - $curr['value'] = substr($curr['value'],1); - continue; - } - elseif ($curr['value'][0] == '"' && $curr['value'][strlen($curr['value'])-1] == '"') { - $curr['value'] = substr($curr['value'],1,strlen($curr['value'])-2); - $ret[] = $curr; - $curr = []; - continue; - } - else { - $ret[] = $curr; - $curr = []; - continue; - } - } - } - else { - if ($q[strlen($q)-1] == '"') { - $curr['value'] .= ' ' . str_replace('"','',trim($q)); - $ret[] = $curr; - $curr = []; - $quoted_string = false; - } - else - $curr['value'] .= ' ' . trim($q); - } - } - } - logger('dir_parse_query:' . print_r($ret,true),LOGGER_DATA); - return $ret; - } - - - function list_public_sites() { - - $rand = db_getfunc('rand'); - $realm = get_directory_realm(); + $entry = []; - $r = q("select * from site where site_type = %d and site_dead = 0", - intval(SITE_TYPE_ZOT) - ); - - $ret = array('success' => false); - - if ($r) { - $ret['success'] = true; - $ret['sites'] = []; - - foreach ($r as $rr) { - - if ($rr['site_access'] == ACCESS_FREE) - $access = 'free'; - elseif ($rr['site_access'] == ACCESS_PAID) - $access = 'paid'; - elseif ($rr['site_access'] == ACCESS_TIERED) - $access = 'tiered'; - else - $access = 'private'; - - if ($rr['site_register'] == REGISTER_OPEN) - $register = 'open'; - elseif ($rr['site_register'] == REGISTER_APPROVE) - $register = 'approve'; - else - $register = 'closed'; - - $ret['sites'][] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location'], 'project' => $rr['site_project'], 'version' => $rr['site_version']); + $entry['name'] = $rr['xchan_name']; + $entry['hash'] = $rr['xchan_hash']; + $entry['censored'] = $rr['xchan_censored']; + $entry['selfcensored'] = $rr['xchan_selfcensored']; + $entry['type'] = $rr['xchan_type']; + $entry['url'] = $rr['xchan_url']; + $entry['photo_l'] = $rr['xchan_photo_l']; + $entry['photo'] = $rr['xchan_photo_m']; + $entry['address'] = $rr['xchan_addr']; + $entry['network'] = $rr['xchan_network']; + $entry['description'] = $rr['xprof_desc']; + $entry['locale'] = $rr['xprof_locale']; + $entry['region'] = $rr['xprof_region']; + $entry['postcode'] = $rr['xprof_postcode']; + $entry['country'] = $rr['xprof_country']; + $entry['birthday'] = $rr['xprof_dob']; + $entry['age'] = $rr['xprof_age']; + $entry['gender'] = $rr['xprof_gender']; + $entry['marital'] = $rr['xprof_marital']; + $entry['sexual'] = $rr['xprof_sexual']; + $entry['about'] = $rr['xprof_about']; + $entry['homepage'] = $rr['xprof_homepage']; + $entry['hometown'] = $rr['xprof_hometown']; + $entry['keywords'] = $rr['xprof_keywords']; - } - } - return $ret; - } + $entries[] = $entry; + + } + + $ret['results'] = $entries; + if ($kw) { + $k = dir_tagadelic($kw, $hub, $type, $safesql); + if ($k) { + $ret['keywords'] = []; + foreach ($k as $kv) { + $ret['keywords'][] = ['term' => $kv[0], 'weight' => $kv[1], 'normalise' => $kv[2]]; + } + } + } + } + json_return_and_die($ret); + } + + public function dir_query_build($joiner, $field, $s) + { + $ret = ''; + if (trim($s)) + $ret .= dbesc($joiner) . " " . dbesc($field) . " like '" . protect_sprintf('%' . dbesc($s) . '%') . "' "; + return $ret; + } + + public function dir_flag_build($joiner, $field, $bit, $s) + { + return dbesc($joiner) . " ( " . dbesc($field) . " & " . intval($bit) . " ) " . ((intval($s)) ? '>' : '=') . " 0 "; + } + + + public function dir_parse_query($s) + { + + $ret = []; + $curr = []; + $all = explode(' ', $s); + $quoted_string = false; + + if ($all) { + foreach ($all as $q) { + if ($quoted_string === false) { + if ($q === 'and') { + $curr['logic'] = 'and'; + continue; + } + if ($q === 'or') { + $curr['logic'] = 'or'; + continue; + } + if ($q === 'not') { + $curr['logic'] .= ' not'; + continue; + } + if (strpos($q, '=')) { + if (!isset($curr['logic'])) + $curr['logic'] = 'or'; + $curr['field'] = trim(substr($q, 0, strpos($q, '='))); + $curr['value'] = trim(substr($q, strpos($q, '=') + 1)); + if ($curr['value'][0] == '"' && $curr['value'][strlen($curr['value']) - 1] != '"') { + $quoted_string = true; + $curr['value'] = substr($curr['value'], 1); + continue; + } elseif ($curr['value'][0] == '"' && $curr['value'][strlen($curr['value']) - 1] == '"') { + $curr['value'] = substr($curr['value'], 1, strlen($curr['value']) - 2); + $ret[] = $curr; + $curr = []; + continue; + } else { + $ret[] = $curr; + $curr = []; + continue; + } + } + } else { + if ($q[strlen($q) - 1] == '"') { + $curr['value'] .= ' ' . str_replace('"', '', trim($q)); + $ret[] = $curr; + $curr = []; + $quoted_string = false; + } else + $curr['value'] .= ' ' . trim($q); + } + } + } + logger('dir_parse_query:' . print_r($ret, true), LOGGER_DATA); + return $ret; + } + + + public function list_public_sites() + { + + $rand = db_getfunc('rand'); + $realm = get_directory_realm(); + + $r = q("select * from site where site_type = %d and site_dead = 0", + intval(SITE_TYPE_ZOT) + ); + + $ret = array('success' => false); + + if ($r) { + $ret['success'] = true; + $ret['sites'] = []; + + foreach ($r as $rr) { + + if ($rr['site_access'] == ACCESS_FREE) + $access = 'free'; + elseif ($rr['site_access'] == ACCESS_PAID) + $access = 'paid'; + elseif ($rr['site_access'] == ACCESS_TIERED) + $access = 'tiered'; + else + $access = 'private'; + + if ($rr['site_register'] == REGISTER_OPEN) + $register = 'open'; + elseif ($rr['site_register'] == REGISTER_APPROVE) + $register = 'approve'; + else + $register = 'closed'; + + $ret['sites'][] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location'], 'project' => $rr['site_project'], 'version' => $rr['site_version']); + + } + } + return $ret; + } } diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php index 36519828c..819f0f945 100644 --- a/Zotlabs/Module/Display.php +++ b/Zotlabs/Module/Display.php @@ -15,510 +15,498 @@ require_once('include/conversation.php'); require_once('include/acl_selectors.php'); -class Display extends Controller { +class Display extends Controller +{ - // State passed in from the Update module. - - public $profile_uid = 0; - public $loading = 0; - public $updating = 0; + // State passed in from the Update module. + + public $profile_uid = 0; + public $loading = 0; + public $updating = 0; - function get() { + public function get() + { - $noscript_content = (get_config('system', 'noscript_content', '1') && (! $this->updating)); + $noscript_content = (get_config('system', 'noscript_content', '1') && (!$this->updating)); - $module_format = 'html'; + $module_format = 'html'; - if(argc() > 1) { - $module_format = substr(argv(1),strrpos(argv(1),'.') + 1); - if(! in_array($module_format,['atom','zot','json'])) - $module_format = 'html'; - } + if (argc() > 1) { + $module_format = substr(argv(1), strrpos(argv(1), '.') + 1); + if (!in_array($module_format, ['atom', 'zot', 'json'])) + $module_format = 'html'; + } - if($this->loading) - $_SESSION['loadtime_display'] = datetime_convert(); - - if(observer_prohibited()) { - notice( t('Public access denied.') . EOL); - return; - } - - if(argc() > 1) { - $item_hash = argv(1); - if($module_format !== 'html') { - $item_hash = substr($item_hash,0,strrpos($item_hash,'.')); - } - } - - if($_REQUEST['mid']) - $item_hash = $_REQUEST['mid']; + if ($this->loading) + $_SESSION['loadtime_display'] = datetime_convert(); - if(! $item_hash) { - App::$error = 404; - notice( t('Item not found.') . EOL); - return; - } - - $observer_is_owner = false; - $updateable = false; + if (observer_prohibited()) { + notice(t('Public access denied.') . EOL); + return; + } - if(local_channel() && (! $this->updating)) { - - $channel = App::get_channel(); + if (argc() > 1) { + $item_hash = argv(1); + if ($module_format !== 'html') { + $item_hash = substr($item_hash, 0, strrpos($item_hash, '.')); + } + } - $channel_acl = array( - 'allow_cid' => $channel['channel_allow_cid'], - 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ); + if ($_REQUEST['mid']) + $item_hash = $_REQUEST['mid']; - $x = array( - 'is_owner' => true, - 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), - 'default_location' => $channel['channel_location'], - 'nickname' => $channel['channel_address'], - 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => populate_acl($channel_acl,true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), - 'permissions' => $channel_acl, - 'bang' => '', - 'visitor' => true, - 'profile_uid' => local_channel(), - 'return_path' => 'channel/' . $channel['channel_address'], - 'expanded' => true, - 'editor_autocomplete' => true, - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true, - 'jotnets' => true, - 'reset' => t('Reset form') - ); - - $o = '
        '; - $o .= status_editor($x); - $o .= '
        '; - } - - // This page can be viewed by anybody so the query could be complicated - // First we'll see if there is a copy of the item which is owned by us - if we're logged in locally. - // If that fails (or we aren't logged in locally), - // query an item in which the observer (if logged in remotely) has cid or gid rights - // and if that fails, look for a copy of the post that has no privacy restrictions. - // If we find the post, but we don't find a copy that we're allowed to look at, this fact needs to be reported. - - // find a copy of the item somewhere - - $target_item = null; + if (!$item_hash) { + App::$error = 404; + notice(t('Item not found.') . EOL); + return; + } - $item_hash = unpack_link_id($item_hash); + $observer_is_owner = false; + $updateable = false; - $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid like '%s' limit 1", - dbesc($item_hash . '%') - ); - - if($r) { - $target_item = $r[0]; - } + if (local_channel() && (!$this->updating)) { - $x = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($target_item['author_xchan']) - ); - if($x) { + $channel = App::get_channel(); + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $x = array( + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), + 'permissions' => $channel_acl, + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_channel(), + 'return_path' => 'channel/' . $channel['channel_address'], + 'expanded' => true, + 'editor_autocomplete' => true, + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true, + 'jotnets' => true, + 'reset' => t('Reset form') + ); + + $o = '
        '; + $o .= status_editor($x); + $o .= '
        '; + } + + // This page can be viewed by anybody so the query could be complicated + // First we'll see if there is a copy of the item which is owned by us - if we're logged in locally. + // If that fails (or we aren't logged in locally), + // query an item in which the observer (if logged in remotely) has cid or gid rights + // and if that fails, look for a copy of the post that has no privacy restrictions. + // If we find the post, but we don't find a copy that we're allowed to look at, this fact needs to be reported. + + // find a copy of the item somewhere + + $target_item = null; + + $item_hash = unpack_link_id($item_hash); + + $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid like '%s' limit 1", + dbesc($item_hash . '%') + ); + + if ($r) { + $target_item = $r[0]; + } + + $x = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($target_item['author_xchan']) + ); + if ($x) { // not yet ready for prime time // \App::$poi = $x[0]; - } + } - // if the item is to be moderated redirect to /moderate - if($target_item['item_blocked'] == ITEM_MODERATED) { - goaway(z_root() . '/moderate/' . $target_item['id']); - } - - $r = null; - - if($target_item['item_type'] == ITEM_TYPE_WEBPAGE) { - $x = q("select * from channel where channel_id = %d limit 1", - intval($target_item['uid']) - ); - $y = q("select * from iconfig left join item on iconfig.iid = item.id + // if the item is to be moderated redirect to /moderate + if ($target_item['item_blocked'] == ITEM_MODERATED) { + goaway(z_root() . '/moderate/' . $target_item['id']); + } + + $r = null; + + if ($target_item['item_type'] == ITEM_TYPE_WEBPAGE) { + $x = q("select * from channel where channel_id = %d limit 1", + intval($target_item['uid']) + ); + $y = q("select * from iconfig left join item on iconfig.iid = item.id where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item.id = %d limit 1", - intval($target_item['uid']), - intval($target_item['parent']) - ); - if($x && $y) { - goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['v']); - } - else { - notice( t('Page not found.') . EOL); - return ''; - } - } - if($target_item['item_type'] == ITEM_TYPE_ARTICLE) { - $x = q("select * from channel where channel_id = %d limit 1", - intval($target_item['uid']) - ); - $y = q("select * from iconfig left join item on iconfig.iid = item.id + intval($target_item['uid']), + intval($target_item['parent']) + ); + if ($x && $y) { + goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['v']); + } else { + notice(t('Page not found.') . EOL); + return ''; + } + } + if ($target_item['item_type'] == ITEM_TYPE_ARTICLE) { + $x = q("select * from channel where channel_id = %d limit 1", + intval($target_item['uid']) + ); + $y = q("select * from iconfig left join item on iconfig.iid = item.id where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and item.id = %d limit 1", - intval($target_item['uid']), - intval($target_item['parent']) - ); - if($x && $y) { - goaway(z_root() . '/articles/' . $x[0]['channel_address'] . '/' . $y[0]['v']); - } - else { - notice( t('Page not found.') . EOL); - return ''; - } - } - if($target_item['item_type'] == ITEM_TYPE_CARD) { - $x = q("select * from channel where channel_id = %d limit 1", - intval($target_item['uid']) - ); - $y = q("select * from iconfig left join item on iconfig.iid = item.id + intval($target_item['uid']), + intval($target_item['parent']) + ); + if ($x && $y) { + goaway(z_root() . '/articles/' . $x[0]['channel_address'] . '/' . $y[0]['v']); + } else { + notice(t('Page not found.') . EOL); + return ''; + } + } + if ($target_item['item_type'] == ITEM_TYPE_CARD) { + $x = q("select * from channel where channel_id = %d limit 1", + intval($target_item['uid']) + ); + $y = q("select * from iconfig left join item on iconfig.iid = item.id where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'CARD' and item.id = %d limit 1", - intval($target_item['uid']), - intval($target_item['parent']) - ); - if($x && $y) { - goaway(z_root() . '/cards/' . $x[0]['channel_address'] . '/' . $y[0]['v']); - } - else { - notice( t('Page not found.') . EOL); - return ''; - } - } - if ($target_item['item_type'] == ITEM_TYPE_CUSTOM) { - call_hooks('item_custom_display',$target_item); - notice( t('Page not found.') . EOL); - return ''; - } + intval($target_item['uid']), + intval($target_item['parent']) + ); + if ($x && $y) { + goaway(z_root() . '/cards/' . $x[0]['channel_address'] . '/' . $y[0]['v']); + } else { + notice(t('Page not found.') . EOL); + return ''; + } + } + if ($target_item['item_type'] == ITEM_TYPE_CUSTOM) { + call_hooks('item_custom_display', $target_item); + notice(t('Page not found.') . EOL); + return ''; + } - - - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - - - $simple_update = (($this->updating) ? " AND item_unseen = 1 " : ''); - - if($this->updating && $_SESSION['loadtime_display']) - $simple_update = " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime_display']) . "' "; - if($this->loading) - $simple_update = ''; - - if($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - - if((! $this->updating) && (! $this->loading)) { - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); + $static = ((array_key_exists('static', $_REQUEST)) ? intval($_REQUEST['static']) : 0); - // if the target item is not a post (eg a like) we want to address its thread parent - $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']); + $simple_update = (($this->updating) ? " AND item_unseen = 1 " : ''); - // if we received a decoded hash originally we must encode it again before handing to javascript + if ($this->updating && $_SESSION['loadtime_display']) + $simple_update = " AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime_display']) . "' "; + if ($this->loading) + $simple_update = ''; - $mid = gen_link_id($mid); + if ($static && $simple_update) + $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - $o .= '
        ' . "\r\n"; - $o .= "\r\n"; - - App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( - '$baseurl' => z_root(), - '$pgtype' => 'display', - '$uid' => '0', - '$gid' => '0', - '$cid' => '0', - '$cmin' => '(-1)', - '$cmax' => '(-1)', - '$star' => '0', - '$liked' => '0', - '$conv' => '0', - '$spam' => '0', - '$fh' => '0', - '$dm' => '0', - '$nouveau' => '0', - '$wall' => '0', - '$draft' => '0', - '$static' => $static, - '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), - '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), - '$search' => '', - '$xchan' => '', - '$order' => '', - '$file' => '', - '$cats' => '', - '$tags' => '', - '$dend' => '', - '$dbegin' => '', - '$verb' => '', - '$net' => '', - '$mid' => (($mid) ? urlencode($mid) : '') - )); + if ((!$this->updating) && (!$this->loading)) { - head_add_link([ - 'rel' => 'alternate', - 'type' => 'application/json+oembed', - 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), - 'title' => 'oembed' - ]); + $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); - } + // if the target item is not a post (eg a like) we want to address its thread parent - $observer_hash = get_observer_hash(); - $item_normal = item_normal(); - $item_normal_update = item_normal_update(); + $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']); - $sql_extra = ((local_channel()) ? EMPTY_STR : item_permissions_sql(0, $observer_hash)); + // if we received a decoded hash originally we must encode it again before handing to javascript - if($noscript_content || $this->loading) { + $mid = gen_link_id($mid); - $r = null; + $o .= '
        ' . "\r\n"; + $o .= "\r\n"; - require_once('include/channel.php'); - $sys = get_sys_channel(); - $sysid = $sys['channel_id']; + App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), array( + '$baseurl' => z_root(), + '$pgtype' => 'display', + '$uid' => '0', + '$gid' => '0', + '$cid' => '0', + '$cmin' => '(-1)', + '$cmax' => '(-1)', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '0', + '$dm' => '0', + '$nouveau' => '0', + '$wall' => '0', + '$draft' => '0', + '$static' => $static, + '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), + '$list' => ((x($_REQUEST, 'list')) ? intval($_REQUEST['list']) : 0), + '$search' => '', + '$xchan' => '', + '$order' => '', + '$file' => '', + '$cats' => '', + '$tags' => '', + '$dend' => '', + '$dbegin' => '', + '$verb' => '', + '$net' => '', + '$mid' => (($mid) ? urlencode($mid) : '') + )); - if(local_channel()) { - $r = q("SELECT item.id as item_id from item WHERE uid = %d and mid = '%s' $item_normal limit 1", - intval(local_channel()), - dbesc($target_item['parent_mid']) - ); - if($r) { - $updateable = true; - } - } + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), + 'title' => 'oembed' + ]); - if (! (is_array($r) && count($r))) { - $r = q("SELECT item.id as item_id from item WHERE mid = '%s' $sql_extra $item_normal limit 1", - dbesc($target_item['parent_mid']) - ); - } - } - elseif ($this->updating && !$this->loading) { - $r = null; + } - require_once('include/channel.php'); - $sys = get_sys_channel(); - $sysid = $sys['channel_id']; + $observer_hash = get_observer_hash(); + $item_normal = item_normal(); + $item_normal_update = item_normal_update(); - if (local_channel()) { - $r = q("SELECT item.parent AS item_id from item WHERE uid = %d and parent_mid = '%s' $item_normal_update $simple_update limit 1", - intval(local_channel()), - dbesc($target_item['parent_mid']) - ); - if($r) { - $updateable = true; - } - } + $sql_extra = ((local_channel()) ? EMPTY_STR : item_permissions_sql(0, $observer_hash)); - if(! $r) { - $r = q("SELECT item.parent AS item_id from item WHERE parent_mid = '%s' $sql_extra $item_normal_update $simple_update limit 1", - dbesc($target_item['parent_mid']) - ); - } - } - - else { - $r = []; - } + if ($noscript_content || $this->loading) { - if($r) { - $parents_str = ids_to_querystr($r,'item_id'); - if($parents_str) { - $items = q("SELECT item.*, item.id AS item_id + $r = null; + + require_once('include/channel.php'); + $sys = get_sys_channel(); + $sysid = $sys['channel_id']; + + if (local_channel()) { + $r = q("SELECT item.id as item_id from item WHERE uid = %d and mid = '%s' $item_normal limit 1", + intval(local_channel()), + dbesc($target_item['parent_mid']) + ); + if ($r) { + $updateable = true; + } + } + + if (!(is_array($r) && count($r))) { + $r = q("SELECT item.id as item_id from item WHERE mid = '%s' $sql_extra $item_normal limit 1", + dbesc($target_item['parent_mid']) + ); + } + } elseif ($this->updating && !$this->loading) { + $r = null; + + require_once('include/channel.php'); + $sys = get_sys_channel(); + $sysid = $sys['channel_id']; + + if (local_channel()) { + $r = q("SELECT item.parent AS item_id from item WHERE uid = %d and parent_mid = '%s' $item_normal_update $simple_update limit 1", + intval(local_channel()), + dbesc($target_item['parent_mid']) + ); + if ($r) { + $updateable = true; + } + } + + if (!$r) { + $r = q("SELECT item.parent AS item_id from item WHERE parent_mid = '%s' $sql_extra $item_normal_update $simple_update limit 1", + dbesc($target_item['parent_mid']) + ); + } + } else { + $r = []; + } + + if ($r) { + $parents_str = ids_to_querystr($r, 'item_id'); + if ($parents_str) { + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE parent in ( %s ) $item_normal $sql_extra ", - dbesc($parents_str) - ); - xchan_query($items); - $items = fetch_post_tags($items,true); - $items = conv_sort($items,'created'); - } - } - else { - $items = []; - } + dbesc($parents_str) + ); + xchan_query($items); + $items = fetch_post_tags($items, true); + $items = conv_sort($items, 'created'); + } + } else { + $items = []; + } - // see if the top-level post owner chose to block search engines - - if ($items && get_pconfig($items[0]['uid'],'system','noindex')) { - App::$meta->set('robots', 'noindex, noarchive'); - } + // see if the top-level post owner chose to block search engines - foreach ($items as $item) { - if ($item['mid'] === $item_hash) { + if ($items && get_pconfig($items[0]['uid'], 'system', 'noindex')) { + App::$meta->set('robots', 'noindex, noarchive'); + } + + foreach ($items as $item) { + if ($item['mid'] === $item_hash) { - if(preg_match("/\[[zi]mg(.*?)\]([^\[]+)/is", $items[0]['body'], $matches)) { - $ogimage = $matches[2]; - // Will we use og:image:type someday? We keep this just in case - // $ogimagetype = guess_image_type($ogimage); - } + if (preg_match("/\[[zi]mg(.*?)\]([^\[]+)/is", $items[0]['body'], $matches)) { + $ogimage = $matches[2]; + // Will we use og:image:type someday? We keep this just in case + // $ogimagetype = guess_image_type($ogimage); + } - // some work on post content to generate a description - // almost fully based on work done on Hubzilla by Max Kostikov - $ogdesc = $item['body']; + // some work on post content to generate a description + // almost fully based on work done on Hubzilla by Max Kostikov + $ogdesc = $item['body']; - $ogdesc = bbcode($ogdesc, [ 'export' => true ]); - $ogdesc = trim(html2plain($ogdesc, 0, true)); - $ogdesc = html_entity_decode($ogdesc, ENT_QUOTES, 'UTF-8'); + $ogdesc = bbcode($ogdesc, ['export' => true]); + $ogdesc = trim(html2plain($ogdesc, 0, true)); + $ogdesc = html_entity_decode($ogdesc, ENT_QUOTES, 'UTF-8'); - // remove all URLs - $ogdesc = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $ogdesc); + // remove all URLs + $ogdesc = preg_replace("/https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,\@]+/", "", $ogdesc); - // shorten description - $ogdesc = substr($ogdesc, 0, 300); - $ogdesc = str_replace("\n", " ", $ogdesc); - while (strpos($ogdesc, " ") !== false) - $ogdesc = str_replace(" ", " ", $ogdesc); - $ogdesc = (strlen($ogdesc) < 298 ? $ogdesc : rtrim(substr($ogdesc, 0, strrpos($ogdesc, " ")), "?.,:;!-") . "..."); + // shorten description + $ogdesc = substr($ogdesc, 0, 300); + $ogdesc = str_replace("\n", " ", $ogdesc); + while (strpos($ogdesc, " ") !== false) + $ogdesc = str_replace(" ", " ", $ogdesc); + $ogdesc = (strlen($ogdesc) < 298 ? $ogdesc : rtrim(substr($ogdesc, 0, strrpos($ogdesc, " ")), "?.,:;!-") . "..."); - $ogsite = (System::get_site_name()) ? escape_tags(System::get_site_name()) : System::get_platform_name(); + $ogsite = (System::get_site_name()) ? escape_tags(System::get_site_name()) : System::get_platform_name(); - // we can now start loading content - if ($item['mid'] == $item['parent_mid']) { - App::$meta->set('og:title', ($items[0]['title'] - ? sprintf( t('"%1$s", shared by %2$s with %3$s'),$items[0]['title'],$item['author']['xchan_name'],$ogsite) - : sprintf( t('%1$s shared this post with %2$s'),$item['author']['xchan_name'],$ogsite))); - App::$meta->set('og:image', (isset($ogimage) ? $ogimage : System::get_site_icon())); - App::$meta->set('og:type', 'article'); - App::$meta->set('og:url:secure_url', $item['llink']); - App::$meta->set('og:description', ($ogdesc ? $ogdesc : sprintf( t('Not much to read, click to see the post.')))); - } - else { - if (($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) { - App::$meta->set('og:title', ($items[0]['title'] - ? sprintf( t('%1$s shared a reaction to "%2$s"'),$item['author']['xchan_name'],$items[0]['title']) - : sprintf( t('%s shared a reaction to this post/conversation'),$item['author']['xchan_name']))); - App::$meta->set('og:image', (isset($ogimage) ? $ogimage : System::get_site_icon())); - App::$meta->set('og:type', 'article'); - App::$meta->set('og:url:secure_url', $item['llink']); - App::$meta->set('og:description', $ogdesc); - } - else { - App::$meta->set('og:title', ($items[0]['title'] - ? sprintf( t('%1$s commented "%2$s"'),$item['author']['xchan_name'],$items[0]['title']) - : sprintf( t('%s shared a comment of this post/conversation'),$item['author']['xchan_name']))); - App::$meta->set('og:image', (isset($ogimage) ? $ogimage : System::get_site_icon())); - App::$meta->set('og:type', 'article'); - App::$meta->set('og:url:secure_url', $item['llink']); - App::$meta->set('og:description', sprintf( t('%1$s wrote this: "%2$s"'),$item['author']['xchan_name'],$ogdesc)); - } - } - } - } + // we can now start loading content + if ($item['mid'] == $item['parent_mid']) { + App::$meta->set('og:title', ($items[0]['title'] + ? sprintf(t('"%1$s", shared by %2$s with %3$s'), $items[0]['title'], $item['author']['xchan_name'], $ogsite) + : sprintf(t('%1$s shared this post with %2$s'), $item['author']['xchan_name'], $ogsite))); + App::$meta->set('og:image', (isset($ogimage) ? $ogimage : System::get_site_icon())); + App::$meta->set('og:type', 'article'); + App::$meta->set('og:url:secure_url', $item['llink']); + App::$meta->set('og:description', ($ogdesc ? $ogdesc : sprintf(t('Not much to read, click to see the post.')))); + } else { + if (($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) { + App::$meta->set('og:title', ($items[0]['title'] + ? sprintf(t('%1$s shared a reaction to "%2$s"'), $item['author']['xchan_name'], $items[0]['title']) + : sprintf(t('%s shared a reaction to this post/conversation'), $item['author']['xchan_name']))); + App::$meta->set('og:image', (isset($ogimage) ? $ogimage : System::get_site_icon())); + App::$meta->set('og:type', 'article'); + App::$meta->set('og:url:secure_url', $item['llink']); + App::$meta->set('og:description', $ogdesc); + } else { + App::$meta->set('og:title', ($items[0]['title'] + ? sprintf(t('%1$s commented "%2$s"'), $item['author']['xchan_name'], $items[0]['title']) + : sprintf(t('%s shared a comment of this post/conversation'), $item['author']['xchan_name']))); + App::$meta->set('og:image', (isset($ogimage) ? $ogimage : System::get_site_icon())); + App::$meta->set('og:type', 'article'); + App::$meta->set('og:url:secure_url', $item['llink']); + App::$meta->set('og:description', sprintf(t('%1$s wrote this: "%2$s"'), $item['author']['xchan_name'], $ogdesc)); + } + } + } + } - if (local_channel() && $items) { - $ids = ids_to_array($items,'item_id'); - $seen = PConfig::Get(local_channel(),'system','seen_items'); - if (! $seen) { - $seen = []; - } - $seen = array_unique(array_merge($ids,$seen)); - PConfig::Set(local_channel(),'system','seen_items',$seen); - } + if (local_channel() && $items) { + $ids = ids_to_array($items, 'item_id'); + $seen = PConfig::Get(local_channel(), 'system', 'seen_items'); + if (!$seen) { + $seen = []; + } + $seen = array_unique(array_merge($ids, $seen)); + PConfig::Set(local_channel(), 'system', 'seen_items', $seen); + } - switch($module_format) { - - case 'html': + switch ($module_format) { - if ($this->updating) { - $o .= conversation($items, 'display', $this->updating, 'client'); - } - else { - $o .= ''; + case 'html': - App::$page['title'] = (($items[0]['title']) ? $items[0]['title'] . " - " . App::$page['title'] : App::$page['title']); + if ($this->updating) { + $o .= conversation($items, 'display', $this->updating, 'client'); + } else { + $o .= ''; - $o .= conversation($items, 'display', $this->updating, 'client'); - } + App::$page['title'] = (($items[0]['title']) ? $items[0]['title'] . " - " . App::$page['title'] : App::$page['title']); - break; + $o .= conversation($items, 'display', $this->updating, 'client'); + } - case 'atom': + break; - $atom = replace_macros(get_markup_template('atom_feed.tpl'), array( - '$version' => xmlify(System::get_project_version()), - '$generator' => xmlify(System::get_platform_name()), - '$generator_uri' => 'https://hubzilla.org', - '$feed_id' => xmlify(App::$cmd), - '$feed_title' => xmlify(t('Article')), - '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)), - '$author' => '', - '$owner' => '', - '$profile_page' => xmlify(z_root() . '/display/' . $target_item['mid']), - )); - - $x = [ 'xml' => $atom, 'channel' => $channel, 'observer_hash' => $observer_hash, 'params' => $params ]; - call_hooks('atom_feed_top',$x); + case 'atom': - $atom = $x['xml']; + $atom = replace_macros(get_markup_template('atom_feed.tpl'), array( + '$version' => xmlify(System::get_project_version()), + '$generator' => xmlify(System::get_platform_name()), + '$generator_uri' => 'https://hubzilla.org', + '$feed_id' => xmlify(App::$cmd), + '$feed_title' => xmlify(t('Article')), + '$feed_updated' => xmlify(datetime_convert('UTC', 'UTC', 'now', ATOM_TIME)), + '$author' => '', + '$owner' => '', + '$profile_page' => xmlify(z_root() . '/display/' . $target_item['mid']), + )); - // a much simpler interface - call_hooks('atom_feed', $atom); + $x = ['xml' => $atom, 'channel' => $channel, 'observer_hash' => $observer_hash, 'params' => $params]; + call_hooks('atom_feed_top', $x); + + $atom = $x['xml']; + + // a much simpler interface + call_hooks('atom_feed', $atom); - if($items) { - $type = 'html'; - foreach($items as $item) { - if($item['item_private']) - continue; - $atom .= atom_entry($item, $type, null, '', true, '', false); - } - } + if ($items) { + $type = 'html'; + foreach ($items as $item) { + if ($item['item_private']) + continue; + $atom .= atom_entry($item, $type, null, '', true, '', false); + } + } - call_hooks('atom_feed_end', $atom); + call_hooks('atom_feed_end', $atom); - $atom .= '' . "\r\n"; + $atom .= '' . "\r\n"; - header('Content-type: application/atom+xml'); - echo $atom; - killme(); - - } - - if($updateable) { - $x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ", - intval(local_channel()), - intval($r[0]['item_id']) - ); + header('Content-type: application/atom+xml'); + echo $atom; + killme(); + + } + + if ($updateable) { + $x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ", + intval(local_channel()), + intval($r[0]['item_id']) + ); - } + } - $o .= '
        '; + $o .= '
        '; - if((($this->updating && $this->loading) || $noscript_content) && (! $items)) { - - $r = q("SELECT id, item_deleted FROM item WHERE mid = '%s' LIMIT 1", - dbesc($item_hash) - ); + if ((($this->updating && $this->loading) || $noscript_content) && (!$items)) { - if($r) { - if(intval($r[0]['item_deleted'])) { - notice( t('Item has been removed.') . EOL ); - } - else { - notice( t('Permission denied.') . EOL ); - } - } - else { - notice( t('Item not found.') . EOL ); - } - - } + $r = q("SELECT id, item_deleted FROM item WHERE mid = '%s' LIMIT 1", + dbesc($item_hash) + ); - return $o; + if ($r) { + if (intval($r[0]['item_deleted'])) { + notice(t('Item has been removed.') . EOL); + } else { + notice(t('Permission denied.') . EOL); + } + } else { + notice(t('Item not found.') . EOL); + } - } + } + + return $o; + + } } diff --git a/Zotlabs/Module/Drafts.php b/Zotlabs/Module/Drafts.php index 0d7431452..35ca8802b 100644 --- a/Zotlabs/Module/Drafts.php +++ b/Zotlabs/Module/Drafts.php @@ -6,24 +6,27 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Drafts extends Controller { +class Drafts extends Controller +{ - function init() { - if (local_channel() && Apps::system_app_installed(local_channel(),'Drafts')) { - goaway(z_root() . '/stream/?draft=1'); + public function init() + { + if (local_channel() && Apps::system_app_installed(local_channel(), 'Drafts')) { + goaway(z_root() . '/stream/?draft=1'); } - } + } - function get() { + public function get() + { $desc = t('This app allows you to save posts you are writing and finish them later prior to sharing/publishing.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Drafts'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Drafts'))) { return $text; } - } + } } diff --git a/Zotlabs/Module/Dreport.php b/Zotlabs/Module/Dreport.php index 0498f14e7..7d1e3b27f 100644 --- a/Zotlabs/Module/Dreport.php +++ b/Zotlabs/Module/Dreport.php @@ -5,191 +5,191 @@ use App; use Zotlabs\Web\Controller; use Zotlabs\Daemon\Run; -class Dreport extends Controller { +class Dreport extends Controller +{ - function get() { - - if (! local_channel()) { - notice( t('Permission denied') . EOL); - return; - } - - $table = 'item'; - - $channel = App::get_channel(); + public function get() + { - if (argc() > 2) { - $cmd = argv(1); - $mid = argv(2); - } - elseif (argc() > 1) { - $cmd = EMPTY_STR; - $mid = argv(1); - } + if (!local_channel()) { + notice(t('Permission denied') . EOL); + return; + } - $message_id = unpack_link_id($mid); + $table = 'item'; - if (! $message_id) { - notice( t('Invalid message') . EOL); - return; - } - - if($cmd === 'push') { - $i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ", - dbesc($message_id), - intval($channel['channel_id']), - dbesc($channel['channel_hash']), - dbesc($channel['channel_hash']) - ); - if ($i) { - Run::Summon([ 'Notifier', 'edit_post', $i[0]['id'] ]); - } - sleep(3); - goaway(z_root() . '/dreport/' . urlencode($mid)); - } + $channel = App::get_channel(); - if ($cmd === 'log') { - $host = escape_tags($_REQUEST['host']); - $r = q("select * from dreport where dreport_xchan = '%s' and dreport_mid = '%s' and dreport_recip = '%s'", - dbesc($channel['channel_hash']), - dbesc($message_id), - dbesc($host) - ); - if ($r) { - $output = '

        ' . t('Delivery Log') . '

        '; - $output .= EOL . $r[0]['dreport_log']; - return $output; - } - else { - notice( t('Item not found') . EOL); - return; - } - } - - switch ($table) { - case 'item': - $i = q("select id from item where mid = '%s' and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ", - dbesc($message_id), - dbesc($channel['channel_hash']), - dbesc($channel['channel_hash']) - ); - break; - default: - break; - } - - if(! $i) { - notice( t('Permission denied') . EOL); - return; - } - - $r = q("select * from dreport where dreport_xchan = '%s' and dreport_mid = '%s'", - dbesc($channel['channel_hash']), - dbesc($message_id) - ); - - if (! $r) { - notice( t('no results') . EOL); - } - - for($x = 0; $x < count($r); $x++ ) { - - // This has two purposes: 1. make the delivery report strings translateable, and - // 2. assign an ordering to item delivery results so we can group them and provide - // a readable report with more interesting events listed toward the top and lesser - // interesting items towards the bottom - - switch($r[$x]['dreport_result']) { - case 'channel sync processed': - $r[$x]['gravity'] = 0; - $r[$x]['dreport_result'] = t('channel sync processed'); - break; - case 'queued': - $r[$x]['gravity'] = 2; - $r[$x]['dreport_result'] = '' . t('queued') . ''; - break; - case 'site dead': - $r[$x]['gravity'] = 3; - $r[$x]['dreport_result'] = t('site dead'); - break; - case 'site deferred': - $r[$x]['gravity'] = 3; - $r[$x]['dreport_result'] = t('site might be dead - deferred'); - break; - case 'posted': - $r[$x]['gravity'] = 3; - $r[$x]['dreport_result'] = t('posted'); - break; - case 'accepted for delivery': - $r[$x]['gravity'] = 4; - $r[$x]['dreport_result'] = t('accepted for delivery'); - break; - case 'updated': - $r[$x]['gravity'] = 5; - $r[$x]['dreport_result'] = t('updated'); - case 'update ignored': - $r[$x]['gravity'] = 6; - $r[$x]['dreport_result'] = t('update ignored'); - break; - case 'permission denied': - $r[$x]['dreport_result'] = t('permission denied'); - $r[$x]['gravity'] = 6; - break; - case 'recipient not found': - $r[$x]['dreport_result'] = t('recipient not found'); - break; - case 'mail recalled': - $r[$x]['dreport_result'] = t('mail recalled'); - break; - case 'duplicate mail received': - $r[$x]['dreport_result'] = t('duplicate mail received'); - break; - case 'mail delivered': - $r[$x]['dreport_result'] = t('mail delivered'); - break; - default: - if (strpos($r[$x]['dreport_result'],'delivery rejected') === 0) { - $r[$x]['dreport_result'] = t('delivery rejected') . ' ' . substr($r[$x]['dreport_result'],17); - } - $r[$x]['gravity'] = 1; - break; - } - } - - usort($r,'self::dreport_gravity_sort'); + if (argc() > 2) { + $cmd = argv(1); + $mid = argv(2); + } elseif (argc() > 1) { + $cmd = EMPTY_STR; + $mid = argv(1); + } - $entries = []; - foreach($r as $rr) { - $entries[] = [ - 'name' => escape_tags($rr['dreport_name'] ?: $rr['dreport_recip']), - 'result' => $rr['dreport_result'], - 'time' => escape_tags(datetime_convert('UTC',date_default_timezone_get(),$rr['dreport_time'])) - ]; - } + $message_id = unpack_link_id($mid); + + if (!$message_id) { + notice(t('Invalid message') . EOL); + return; + } + + if ($cmd === 'push') { + $i = q("select id from item where mid = '%s' and uid = %d and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ", + dbesc($message_id), + intval($channel['channel_id']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_hash']) + ); + if ($i) { + Run::Summon(['Notifier', 'edit_post', $i[0]['id']]); + } + sleep(3); + goaway(z_root() . '/dreport/' . urlencode($mid)); + } + + if ($cmd === 'log') { + $host = escape_tags($_REQUEST['host']); + $r = q("select * from dreport where dreport_xchan = '%s' and dreport_mid = '%s' and dreport_recip = '%s'", + dbesc($channel['channel_hash']), + dbesc($message_id), + dbesc($host) + ); + if ($r) { + $output = '

        ' . t('Delivery Log') . '

        '; + $output .= EOL . $r[0]['dreport_log']; + return $output; + } else { + notice(t('Item not found') . EOL); + return; + } + } + + switch ($table) { + case 'item': + $i = q("select id from item where mid = '%s' and ( author_xchan = '%s' or ( owner_xchan = '%s' and item_wall = 1 )) ", + dbesc($message_id), + dbesc($channel['channel_hash']), + dbesc($channel['channel_hash']) + ); + break; + default: + break; + } + + if (!$i) { + notice(t('Permission denied') . EOL); + return; + } + + $r = q("select * from dreport where dreport_xchan = '%s' and dreport_mid = '%s'", + dbesc($channel['channel_hash']), + dbesc($message_id) + ); + + if (!$r) { + notice(t('no results') . EOL); + } + + for ($x = 0; $x < count($r); $x++) { + + // This has two purposes: 1. make the delivery report strings translateable, and + // 2. assign an ordering to item delivery results so we can group them and provide + // a readable report with more interesting events listed toward the top and lesser + // interesting items towards the bottom + + switch ($r[$x]['dreport_result']) { + case 'channel sync processed': + $r[$x]['gravity'] = 0; + $r[$x]['dreport_result'] = t('channel sync processed'); + break; + case 'queued': + $r[$x]['gravity'] = 2; + $r[$x]['dreport_result'] = '' . t('queued') . ''; + break; + case 'site dead': + $r[$x]['gravity'] = 3; + $r[$x]['dreport_result'] = t('site dead'); + break; + case 'site deferred': + $r[$x]['gravity'] = 3; + $r[$x]['dreport_result'] = t('site might be dead - deferred'); + break; + case 'posted': + $r[$x]['gravity'] = 3; + $r[$x]['dreport_result'] = t('posted'); + break; + case 'accepted for delivery': + $r[$x]['gravity'] = 4; + $r[$x]['dreport_result'] = t('accepted for delivery'); + break; + case 'updated': + $r[$x]['gravity'] = 5; + $r[$x]['dreport_result'] = t('updated'); + case 'update ignored': + $r[$x]['gravity'] = 6; + $r[$x]['dreport_result'] = t('update ignored'); + break; + case 'permission denied': + $r[$x]['dreport_result'] = t('permission denied'); + $r[$x]['gravity'] = 6; + break; + case 'recipient not found': + $r[$x]['dreport_result'] = t('recipient not found'); + break; + case 'mail recalled': + $r[$x]['dreport_result'] = t('mail recalled'); + break; + case 'duplicate mail received': + $r[$x]['dreport_result'] = t('duplicate mail received'); + break; + case 'mail delivered': + $r[$x]['dreport_result'] = t('mail delivered'); + break; + default: + if (strpos($r[$x]['dreport_result'], 'delivery rejected') === 0) { + $r[$x]['dreport_result'] = t('delivery rejected') . ' ' . substr($r[$x]['dreport_result'], 17); + } + $r[$x]['gravity'] = 1; + break; + } + } + + usort($r, 'self::dreport_gravity_sort'); + + $entries = []; + foreach ($r as $rr) { + $entries[] = [ + 'name' => escape_tags($rr['dreport_name'] ?: $rr['dreport_recip']), + 'result' => $rr['dreport_result'], + 'time' => escape_tags(datetime_convert('UTC', date_default_timezone_get(), $rr['dreport_time'])) + ]; + } + + $output = replace_macros(get_markup_template('dreport.tpl'), array( + '$title' => sprintf(t('Delivery report for %1$s'), basename($message_id)) . '...', + '$table' => $table, + '$mid' => urlencode($mid), + '$options' => t('Options'), + '$push' => t('Redeliver'), + '$entries' => $entries + )); + + + return $output; + + + } + + private static function dreport_gravity_sort($a, $b) + { + if ($a['gravity'] == $b['gravity']) { + if ($a['dreport_name'] === $b['dreport_name']) + return strcmp($a['dreport_time'], $b['dreport_time']); + return strcmp($a['dreport_name'], $b['dreport_name']); + } + return (($a['gravity'] > $b['gravity']) ? 1 : (-1)); + } - $output = replace_macros(get_markup_template('dreport.tpl'), array( - '$title' => sprintf( t('Delivery report for %1$s'),basename($message_id)) . '...', - '$table' => $table, - '$mid' => urlencode($mid), - '$options' => t('Options'), - '$push' => t('Redeliver'), - '$entries' => $entries - )); - - - return $output; - - - - } - - private static function dreport_gravity_sort($a,$b) { - if($a['gravity'] == $b['gravity']) { - if($a['dreport_name'] === $b['dreport_name']) - return strcmp($a['dreport_time'],$b['dreport_time']); - return strcmp($a['dreport_name'],$b['dreport_name']); - } - return (($a['gravity'] > $b['gravity']) ? 1 : (-1)); - } - } diff --git a/Zotlabs/Module/Editblock.php b/Zotlabs/Module/Editblock.php index 9e46693f3..198bd30ab 100644 --- a/Zotlabs/Module/Editblock.php +++ b/Zotlabs/Module/Editblock.php @@ -10,145 +10,147 @@ require_once('include/channel.php'); require_once('include/acl_selectors.php'); require_once('include/conversation.php'); -class Editblock extends Controller { +class Editblock extends Controller +{ - function init() { + public function init() + { - if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - App::$is_sys = true; - } - } + if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + App::$is_sys = true; + } + } - if(argc() > 1) - $which = argv(1); - else - return; + if (argc() > 1) + $which = argv(1); + else + return; - Libprofile::load($which); + Libprofile::load($which); - } + } - function get() { + public function get() + { - if(! App::$profile) { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } + if (!App::$profile) { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } - $which = argv(1); + $which = argv(1); - $uid = local_channel(); - $owner = 0; - $channel = null; - $observer = App::get_observer(); + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = App::get_observer(); - $channel = App::get_channel(); + $channel = App::get_channel(); - if(App::$is_sys && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - $uid = $owner = intval($sys['channel_id']); - $channel = $sys; - $observer = $sys; - } - } + if (App::$is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } - if(! $owner) { - // Figure out who the page owner is. - $r = q("select channel_id from channel where channel_address = '%s'", - dbesc($which) - ); - if($r) { - $owner = intval($r[0]['channel_id']); - } - } + if (!$owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if ($r) { + $owner = intval($r[0]['channel_id']); + } + } - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - if(! perm_is_allowed($owner,$ob_hash,'write_pages')) { - notice( t('Permission denied.') . EOL); - return; - } + if (!perm_is_allowed($owner, $ob_hash, 'write_pages')) { + notice(t('Permission denied.') . EOL); + return; + } - $is_owner = (($uid && $uid == $owner) ? true : false); + $is_owner = (($uid && $uid == $owner) ? true : false); - $o = ''; + $o = ''; - // Figure out which post we're editing - $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); - if(! ($post_id && $owner)) { - notice( t('Item not found') . EOL); - return; - } + if (!($post_id && $owner)) { + notice(t('Item not found') . EOL); + return; + } - $itm = q("SELECT * FROM item WHERE id = %d and uid = %s LIMIT 1", - intval($post_id), - intval($owner) - ); - if($itm) { - $item_id = q("select * from iconfig where cat = 'system' and k = 'BUILDBLOCK' and iid = %d limit 1", - intval($itm[0]['id']) - ); - if($item_id) - $block_title = $item_id[0]['v']; - } - else { - notice( t('Item not found') . EOL); - return; - } + $itm = q("SELECT * FROM item WHERE id = %d and uid = %s LIMIT 1", + intval($post_id), + intval($owner) + ); + if ($itm) { + $item_id = q("select * from iconfig where cat = 'system' and k = 'BUILDBLOCK' and iid = %d limit 1", + intval($itm[0]['id']) + ); + if ($item_id) + $block_title = $item_id[0]['v']; + } else { + notice(t('Item not found') . EOL); + return; + } - $mimetype = $itm[0]['mimetype']; + $mimetype = $itm[0]['mimetype']; - $content = $itm[0]['body']; - if($itm[0]['mimetype'] === 'text/markdown') - $content = MarkdownSoap::unescape($itm[0]['body']); + $content = $itm[0]['body']; + if ($itm[0]['mimetype'] === 'text/markdown') + $content = MarkdownSoap::unescape($itm[0]['body']); - $rp = 'blocks/' . $channel['channel_address']; + $rp = 'blocks/' . $channel['channel_address']; - $x = array( - 'nickname' => $channel['channel_address'], - 'bbco_autocomplete'=> (($mimetype == 'text/bbcode') ? 'bbcode' : 'comanche-block'), - 'return_path' => $rp, - 'webpage' => ITEM_TYPE_BLOCK, - 'ptlabel' => t('Block Name'), - 'button' => t('Edit'), - 'writefiles' => (($mimetype == 'text/bbcode') ? perm_is_allowed($owner, get_observer_hash(), 'write_storage') : false), - 'weblink' => (($mimetype == 'text/bbcode') ? t('Insert web link') : false), - 'hide_voting' => true, - 'hide_future' => true, - 'hide_location' => true, - 'hide_expire' => true, - 'showacl' => false, - 'ptyp' => $itm[0]['type'], - 'mimeselect' => true, - 'mimetype' => $itm[0]['mimetype'], - 'body' => undo_post_tagging($content), - 'post_id' => $post_id, - 'visitor' => true, - 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), - 'placeholdertitle' => t('Title (optional)'), - 'pagetitle' => $block_title, - 'profile_uid' => (intval($channel['channel_id'])), - 'bbcode' => (($mimetype == 'text/bbcode') ? true : false) - ); + $x = array( + 'nickname' => $channel['channel_address'], + 'bbco_autocomplete' => (($mimetype == 'text/bbcode') ? 'bbcode' : 'comanche-block'), + 'return_path' => $rp, + 'webpage' => ITEM_TYPE_BLOCK, + 'ptlabel' => t('Block Name'), + 'button' => t('Edit'), + 'writefiles' => (($mimetype == 'text/bbcode') ? perm_is_allowed($owner, get_observer_hash(), 'write_storage') : false), + 'weblink' => (($mimetype == 'text/bbcode') ? t('Insert web link') : false), + 'hide_voting' => true, + 'hide_future' => true, + 'hide_location' => true, + 'hide_expire' => true, + 'showacl' => false, + 'ptyp' => $itm[0]['type'], + 'mimeselect' => true, + 'mimetype' => $itm[0]['mimetype'], + 'body' => undo_post_tagging($content), + 'post_id' => $post_id, + 'visitor' => true, + 'title' => htmlspecialchars($itm[0]['title'], ENT_COMPAT, 'UTF-8'), + 'placeholdertitle' => t('Title (optional)'), + 'pagetitle' => $block_title, + 'profile_uid' => (intval($channel['channel_id'])), + 'bbcode' => (($mimetype == 'text/bbcode') ? true : false) + ); - $editor = status_editor($x); + $editor = status_editor($x); - $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( - '$title' => t('Edit Block'), - '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), - '$id' => $itm[0]['id'], - '$cancel' => t('Cancel'), - '$editor' => $editor - )); + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Block'), + '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), + '$id' => $itm[0]['id'], + '$cancel' => t('Cancel'), + '$editor' => $editor + )); - return $o; + return $o; - } + } } diff --git a/Zotlabs/Module/Editlayout.php b/Zotlabs/Module/Editlayout.php index 8d46de944..7bcb3ab47 100644 --- a/Zotlabs/Module/Editlayout.php +++ b/Zotlabs/Module/Editlayout.php @@ -12,142 +12,144 @@ require_once('include/conversation.php'); class Editlayout extends Controller { - function init() { + public function init() + { - if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - App::$is_sys = true; - } - } + if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + App::$is_sys = true; + } + } - if(argc() > 1) - $which = argv(1); - else - return; + if (argc() > 1) + $which = argv(1); + else + return; - Libprofile::load($which); + Libprofile::load($which); - } + } - function get() { + public function get() + { - if(! App::$profile) { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } + if (!App::$profile) { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } - $which = argv(1); + $which = argv(1); - $uid = local_channel(); - $owner = 0; - $channel = null; - $observer = App::get_observer(); + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = App::get_observer(); - $channel = App::get_channel(); + $channel = App::get_channel(); - if(App::$is_sys && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - $uid = $owner = intval($sys['channel_id']); - $channel = $sys; - $observer = $sys; - } - } + if (App::$is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } - if(! $owner) { - // Figure out who the page owner is. - $r = q("select channel_id from channel where channel_address = '%s'", - dbesc($which) - ); - if($r) { - $owner = intval($r[0]['channel_id']); - } - } + if (!$owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if ($r) { + $owner = intval($r[0]['channel_id']); + } + } - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - if(! perm_is_allowed($owner,$ob_hash,'write_pages')) { - notice( t('Permission denied.') . EOL); - return; - } + if (!perm_is_allowed($owner, $ob_hash, 'write_pages')) { + notice(t('Permission denied.') . EOL); + return; + } - $is_owner = (($uid && $uid == $owner) ? true : false); + $is_owner = (($uid && $uid == $owner) ? true : false); - $o = ''; + $o = ''; - // Figure out which post we're editing - $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); - if(! $post_id) { - notice( t('Item not found') . EOL); - return; - } + if (!$post_id) { + notice(t('Item not found') . EOL); + return; + } - // Now we've got a post and an owner, let's find out if we're allowed to edit it + // Now we've got a post and an owner, let's find out if we're allowed to edit it - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - $perms = get_all_perms($owner,$ob_hash); + $perms = get_all_perms($owner, $ob_hash); - if(! $perms['write_pages']) { - notice( t('Permission denied.') . EOL); - return; - } + if (!$perms['write_pages']) { + notice(t('Permission denied.') . EOL); + return; + } - $itm = q("SELECT * FROM item WHERE id = %d and uid = %s LIMIT 1", - intval($post_id), - intval($owner) - ); + $itm = q("SELECT * FROM item WHERE id = %d and uid = %s LIMIT 1", + intval($post_id), + intval($owner) + ); - $item_id = q("select * from iconfig where cat = 'system' and k = 'PDL' and iid = %d limit 1", - intval($itm[0]['id']) - ); - if($item_id) - $layout_title = $item_id[0]['v']; + $item_id = q("select * from iconfig where cat = 'system' and k = 'PDL' and iid = %d limit 1", + intval($itm[0]['id']) + ); + if ($item_id) + $layout_title = $item_id[0]['v']; - $rp = 'layouts/' . $which; + $rp = 'layouts/' . $which; - $x = array( - 'webpage' => ITEM_TYPE_PDL, - 'nickname' => $channel['channel_address'], - 'editor_autocomplete'=> true, - 'bbco_autocomplete'=> 'comanche', - 'return_path' => $rp, - 'button' => t('Edit'), - 'hide_voting' => true, - 'hide_future' => true, - 'hide_expire' => true, - 'hide_location' => true, - 'hide_weblink' => true, - 'hide_attach' => true, - 'hide_preview' => true, - 'disable_comments' => true, - 'ptyp' => $itm[0]['obj_type'], - 'body' => undo_post_tagging($itm[0]['body']), - 'post_id' => $post_id, - 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), - 'pagetitle' => $layout_title, - 'ptlabel' => t('Layout Name'), - 'placeholdertitle' => t('Layout Description (Optional)'), - 'showacl' => false, - 'profile_uid' => intval($owner), - ); + $x = array( + 'webpage' => ITEM_TYPE_PDL, + 'nickname' => $channel['channel_address'], + 'editor_autocomplete' => true, + 'bbco_autocomplete' => 'comanche', + 'return_path' => $rp, + 'button' => t('Edit'), + 'hide_voting' => true, + 'hide_future' => true, + 'hide_expire' => true, + 'hide_location' => true, + 'hide_weblink' => true, + 'hide_attach' => true, + 'hide_preview' => true, + 'disable_comments' => true, + 'ptyp' => $itm[0]['obj_type'], + 'body' => undo_post_tagging($itm[0]['body']), + 'post_id' => $post_id, + 'title' => htmlspecialchars($itm[0]['title'], ENT_COMPAT, 'UTF-8'), + 'pagetitle' => $layout_title, + 'ptlabel' => t('Layout Name'), + 'placeholdertitle' => t('Layout Description (Optional)'), + 'showacl' => false, + 'profile_uid' => intval($owner), + ); - $editor = status_editor($x); + $editor = status_editor($x); - $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( - '$title' => t('Edit Layout'), - '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), - '$id' => $itm[0]['id'], - '$cancel' => t('Cancel'), - '$editor' => $editor - )); + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Layout'), + '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), + '$id' => $itm[0]['id'], + '$cancel' => t('Cancel'), + '$editor' => $editor + )); - return $o; + return $o; - } + } } diff --git a/Zotlabs/Module/Editpost.php b/Zotlabs/Module/Editpost.php index 6e9754689..801770ca4 100644 --- a/Zotlabs/Module/Editpost.php +++ b/Zotlabs/Module/Editpost.php @@ -10,139 +10,141 @@ require_once('include/acl_selectors.php'); require_once('include/taxonomy.php'); require_once('include/conversation.php'); -class Editpost extends Controller { +class Editpost extends Controller +{ - function get() { + public function get() + { - $output = EMPTY_STR; + $output = EMPTY_STR; - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - $post_id = ((argc() > 1) ? intval(argv(1)) : 0); + $post_id = ((argc() > 1) ? intval(argv(1)) : 0); - if (! $post_id) { - notice( t('Item not found') . EOL); - return; - } + if (!$post_id) { + notice(t('Item not found') . EOL); + return; + } - $item = q("SELECT * FROM item WHERE id = %d AND ( owner_xchan = '%s' OR author_xchan = '%s' ) LIMIT 1", - intval($post_id), - dbesc(get_observer_hash()), - dbesc(get_observer_hash()) - ); + $item = q("SELECT * FROM item WHERE id = %d AND ( owner_xchan = '%s' OR author_xchan = '%s' ) LIMIT 1", + intval($post_id), + dbesc(get_observer_hash()), + dbesc(get_observer_hash()) + ); - // don't allow web editing of potentially binary content (item_obscured = 1) + // don't allow web editing of potentially binary content (item_obscured = 1) - if ((! $item) || intval($item[0]['item_obscured'])) { - notice( t('Item is not editable') . EOL); - return; - } + if ((!$item) || intval($item[0]['item_obscured'])) { + notice(t('Item is not editable') . EOL); + return; + } - $item = array_shift($item); + $item = array_shift($item); - $owner_uid = intval($item['uid']); - $owner = channelx_by_n($owner_uid); + $owner_uid = intval($item['uid']); + $owner = channelx_by_n($owner_uid); - if ($item['resource_type'] === 'photo' && $item['resource_id'] && $owner) { - goaway(z_root() . '/photos/' . $owner['channel_address'] . '/image/' . $item['resource_id'] . '?expandform=1'); - } + if ($item['resource_type'] === 'photo' && $item['resource_id'] && $owner) { + goaway(z_root() . '/photos/' . $owner['channel_address'] . '/image/' . $item['resource_id'] . '?expandform=1'); + } - if ($item['resource_type'] === 'event' && $item['resource_id']) { - goaway(z_root() . '/events/' . $item['resource_id'] . '?expandform=1'); - } + if ($item['resource_type'] === 'event' && $item['resource_id']) { + goaway(z_root() . '/events/' . $item['resource_id'] . '?expandform=1'); + } - $channel = App::get_channel(); + $channel = App::get_channel(); - $category = ''; - $collections = []; - $catsenabled = ((Apps::system_app_installed($owner_uid,'Categories')) ? 'categories' : ''); + $category = ''; + $collections = []; + $catsenabled = ((Apps::system_app_installed($owner_uid, 'Categories')) ? 'categories' : ''); - // we have a single item, but fetch_post_tags expects an array. Convert it before and after. + // we have a single item, but fetch_post_tags expects an array. Convert it before and after. - $item = array_shift(fetch_post_tags([$item])); + $item = array_shift(fetch_post_tags([$item])); - if ($catsenabled) { - $cats = get_terms_oftype($item['term'], TERM_CATEGORY); + if ($catsenabled) { + $cats = get_terms_oftype($item['term'], TERM_CATEGORY); - if ($cats) { - foreach ($cats as $cat) { - if (strlen($category)) { - $category .= ', '; - } - $category .= $cat['term']; - } - } - } + if ($cats) { + foreach ($cats as $cat) { + if (strlen($category)) { + $category .= ', '; + } + $category .= $cat['term']; + } + } + } - $clcts = get_terms_oftype($item['term'], TERM_PCATEGORY); - if ($clcts) { - foreach ($clcts as $clct) { - $collections[] = $clct['term']; - } - } + $clcts = get_terms_oftype($item['term'], TERM_PCATEGORY); + if ($clcts) { + foreach ($clcts as $clct) { + $collections[] = $clct['term']; + } + } - if ($item['attach']) { - $j = json_decode($item['attach'],true); - if ($j) { - foreach ($j as $jj) { - $item['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n"; - } - } - } + if ($item['attach']) { + $j = json_decode($item['attach'], true); + if ($j) { + foreach ($j as $jj) { + $item['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n"; + } + } + } - if (intval($item['item_unpublished'])) { - // clear the old creation date if editing a saved draft. These will always show as just created. - unset($item['created']); - } + if (intval($item['item_unpublished'])) { + // clear the old creation date if editing a saved draft. These will always show as just created. + unset($item['created']); + } - if ($item['summary']) { - $item['body'] = '[summary]' . $item['summary'] . '[/summary]' . "\n\n" . $item['body']; - } + if ($item['summary']) { + $item['body'] = '[summary]' . $item['summary'] . '[/summary]' . "\n\n" . $item['body']; + } - $x = [ - 'nickname' => $channel['channel_address'], - 'item' => $item, - 'editor_autocomplete'=> true, - 'bbco_autocomplete'=> 'bbcode', - 'return_path' => $_SESSION['return_url'], - 'button' => t('Submit'), - 'hide_voting' => true, - 'hide_future' => true, - 'hide_location' => true, - 'is_draft' => ((intval($item['item_unpublished'])) ? true : false), - 'parent' => (($item['mid'] === $item['parent_mid']) ? 0 : $item['parent']), - 'mimetype' => $item['mimetype'], - 'ptyp' => $item['obj_type'], - 'body' => htmlspecialchars_decode(undo_post_tagging($item['body']),ENT_COMPAT), - 'post_id' => $post_id, - 'defloc' => $channel['channel_location'], - 'visitor' => true, - 'title' => htmlspecialchars_decode($item['title'],ENT_COMPAT), - 'category' => $category, - 'showacl' => ((intval($item['item_unpublished'])) ? true : false), - 'lockstate' => (($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) ? 'lock' : 'unlock'), - 'acl' => populate_acl($item, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), - 'bang' => EMPTY_STR, - 'permissions' => $item, - 'profile_uid' => $owner_uid, - 'catsenabled' => $catsenabled, - 'collections' => $collections, - 'jotnets' => true, - 'hide_expire' => true, - 'bbcode' => true - ]; + $x = [ + 'nickname' => $channel['channel_address'], + 'item' => $item, + 'editor_autocomplete' => true, + 'bbco_autocomplete' => 'bbcode', + 'return_path' => $_SESSION['return_url'], + 'button' => t('Submit'), + 'hide_voting' => true, + 'hide_future' => true, + 'hide_location' => true, + 'is_draft' => ((intval($item['item_unpublished'])) ? true : false), + 'parent' => (($item['mid'] === $item['parent_mid']) ? 0 : $item['parent']), + 'mimetype' => $item['mimetype'], + 'ptyp' => $item['obj_type'], + 'body' => htmlspecialchars_decode(undo_post_tagging($item['body']), ENT_COMPAT), + 'post_id' => $post_id, + 'defloc' => $channel['channel_location'], + 'visitor' => true, + 'title' => htmlspecialchars_decode($item['title'], ENT_COMPAT), + 'category' => $category, + 'showacl' => ((intval($item['item_unpublished'])) ? true : false), + 'lockstate' => (($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl($item, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), + 'bang' => EMPTY_STR, + 'permissions' => $item, + 'profile_uid' => $owner_uid, + 'catsenabled' => $catsenabled, + 'collections' => $collections, + 'jotnets' => true, + 'hide_expire' => true, + 'bbcode' => true + ]; - $editor = status_editor($x); + $editor = status_editor($x); - $output .= replace_macros(get_markup_template('edpost_head.tpl'), - [ '$title' => t('Edit post'), '$cancel' => t('Cancel'), '$editor' => $editor ] ); + $output .= replace_macros(get_markup_template('edpost_head.tpl'), + ['$title' => t('Edit post'), '$cancel' => t('Cancel'), '$editor' => $editor]); - return $output; + return $output; - } + } } diff --git a/Zotlabs/Module/Editwebpage.php b/Zotlabs/Module/Editwebpage.php index eb54ff386..9e7a86bab 100644 --- a/Zotlabs/Module/Editwebpage.php +++ b/Zotlabs/Module/Editwebpage.php @@ -12,172 +12,175 @@ require_once('include/acl_selectors.php'); require_once('include/conversation.php'); -class Editwebpage extends Controller { +class Editwebpage extends Controller +{ - function init() { + public function init() + { - if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - App::$is_sys = true; - } - } + if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + App::$is_sys = true; + } + } - if(argc() > 1) - $which = argv(1); - else - return; + if (argc() > 1) + $which = argv(1); + else + return; - Libprofile::load($which); + Libprofile::load($which); - } + } - function get() { + public function get() + { - if(! App::$profile) { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } + if (!App::$profile) { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } - $which = argv(1); + $which = argv(1); - $uid = local_channel(); - $owner = 0; - $channel = null; - $observer = App::get_observer(); + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = App::get_observer(); - $channel = App::get_channel(); + $channel = App::get_channel(); - if(App::$is_sys && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - $uid = $owner = intval($sys['channel_id']); - $channel = $sys; - $observer = $sys; - } - } + if (App::$is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } - if(! $owner) { - // Figure out who the page owner is. - $r = q("select channel_id from channel where channel_address = '%s'", - dbesc($which) - ); - if($r) { - $owner = intval($r[0]['channel_id']); - } - } + if (!$owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if ($r) { + $owner = intval($r[0]['channel_id']); + } + } - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - if(! perm_is_allowed($owner,$ob_hash,'write_pages')) { - notice( t('Permission denied.') . EOL); - return; - } + if (!perm_is_allowed($owner, $ob_hash, 'write_pages')) { + notice(t('Permission denied.') . EOL); + return; + } - $is_owner = (($uid && $uid == $owner) ? true : false); + $is_owner = (($uid && $uid == $owner) ? true : false); - $o = ''; + $o = ''; - // Figure out which post we're editing - $post_id = ((argc() > 2) ? intval(argv(2)) : 0); - - if(! $post_id) { - notice( t('Item not found') . EOL); - return; - } + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + if (!$post_id) { + notice(t('Item not found') . EOL); + return; + } - $perms = get_all_perms($owner,$ob_hash); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - if(! $perms['write_pages']) { - notice( t('Permission denied.') . EOL); - return; - } + $perms = get_all_perms($owner, $ob_hash); - // We've already figured out which item we want and whose copy we need, - // so we don't need anything fancy here + if (!$perms['write_pages']) { + notice(t('Permission denied.') . EOL); + return; + } - $sql_extra = item_permissions_sql($owner); + // We've already figured out which item we want and whose copy we need, + // so we don't need anything fancy here - $itm = q("SELECT * FROM item WHERE id = %d and uid = %s $sql_extra LIMIT 1", - intval($post_id), - intval($owner) - ); + $sql_extra = item_permissions_sql($owner); - // don't allow web editing of potentially binary content (item_obscured = 1) - // @FIXME how do we do it instead? + $itm = q("SELECT * FROM item WHERE id = %d and uid = %s $sql_extra LIMIT 1", + intval($post_id), + intval($owner) + ); - if((! $itm) || intval($itm[0]['item_obscured'])) { - notice( t('Permission denied.') . EOL); - return; - } + // don't allow web editing of potentially binary content (item_obscured = 1) + // @FIXME how do we do it instead? - $item_id = q("select * from iconfig where cat = 'system' and k = 'WEBPAGE' and iid = %d limit 1", - intval($itm[0]['id']) - ); - if($item_id) - $page_title = urldecode($item_id[0]['v']); + if ((!$itm) || intval($itm[0]['item_obscured'])) { + notice(t('Permission denied.') . EOL); + return; + } - $mimetype = $itm[0]['mimetype']; + $item_id = q("select * from iconfig where cat = 'system' and k = 'WEBPAGE' and iid = %d limit 1", + intval($itm[0]['id']) + ); + if ($item_id) + $page_title = urldecode($item_id[0]['v']); - if($mimetype === 'application/x-php') { - if((! $uid) || ($uid != $itm[0]['uid'])) { - notice( t('Permission denied.') . EOL); - return; - } - } - - $layout = $itm[0]['layout_mid']; + $mimetype = $itm[0]['mimetype']; - $content = $itm[0]['body']; - if($itm[0]['mimetype'] === 'text/markdown') - $content = MarkdownSoap::unescape($itm[0]['body']); - - $rp = 'webpages/' . $which; + if ($mimetype === 'application/x-php') { + if ((!$uid) || ($uid != $itm[0]['uid'])) { + notice(t('Permission denied.') . EOL); + return; + } + } - $x = array( - 'nickname' => $channel['channel_address'], - 'bbco_autocomplete'=> (($mimetype == 'text/bbcode') ? 'bbcode' : ''), - 'return_path' => $rp, - 'webpage' => ITEM_TYPE_WEBPAGE, - 'ptlabel' => t('Page link'), - 'pagetitle' => $page_title, - 'writefiles' => (($mimetype == 'text/bbcode') ? perm_is_allowed($owner, get_observer_hash(), 'write_storage') : false), - 'button' => t('Edit'), - 'weblink' => (($mimetype == 'text/bbcode') ? t('Insert web link') : false), - 'hide_location' => true, - 'hide_voting' => true, - 'ptyp' => $itm[0]['type'], - 'body' => undo_post_tagging($content), - 'post_id' => $post_id, - 'visitor' => ($is_owner) ? true : false, - 'acl' => populate_acl($itm[0],false, PermissionDescription::fromGlobalPermission('view_pages')), - 'permissions' => $itm[0], - 'showacl' => ($is_owner) ? true : false, - 'mimetype' => $mimetype, - 'mimeselect' => true, - 'layout' => $layout, - 'layoutselect' => true, - 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), - 'lockstate' => (((strlen($itm[0]['allow_cid'])) || (strlen($itm[0]['allow_gid'])) || (strlen($itm[0]['deny_cid'])) || (strlen($itm[0]['deny_gid']))) ? 'lock' : 'unlock'), - 'profile_uid' => (intval($owner)), - 'bbcode' => (($mimetype == 'text/bbcode') ? true : false) - ); + $layout = $itm[0]['layout_mid']; - $editor = status_editor($x); + $content = $itm[0]['body']; + if ($itm[0]['mimetype'] === 'text/markdown') + $content = MarkdownSoap::unescape($itm[0]['body']); - $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( - '$title' => t('Edit Webpage'), - '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), - '$editor' => $editor, - '$cancel' => t('Cancel'), - '$id' => $itm[0]['id'] - )); + $rp = 'webpages/' . $which; - return $o; + $x = array( + 'nickname' => $channel['channel_address'], + 'bbco_autocomplete' => (($mimetype == 'text/bbcode') ? 'bbcode' : ''), + 'return_path' => $rp, + 'webpage' => ITEM_TYPE_WEBPAGE, + 'ptlabel' => t('Page link'), + 'pagetitle' => $page_title, + 'writefiles' => (($mimetype == 'text/bbcode') ? perm_is_allowed($owner, get_observer_hash(), 'write_storage') : false), + 'button' => t('Edit'), + 'weblink' => (($mimetype == 'text/bbcode') ? t('Insert web link') : false), + 'hide_location' => true, + 'hide_voting' => true, + 'ptyp' => $itm[0]['type'], + 'body' => undo_post_tagging($content), + 'post_id' => $post_id, + 'visitor' => ($is_owner) ? true : false, + 'acl' => populate_acl($itm[0], false, PermissionDescription::fromGlobalPermission('view_pages')), + 'permissions' => $itm[0], + 'showacl' => ($is_owner) ? true : false, + 'mimetype' => $mimetype, + 'mimeselect' => true, + 'layout' => $layout, + 'layoutselect' => true, + 'title' => htmlspecialchars($itm[0]['title'], ENT_COMPAT, 'UTF-8'), + 'lockstate' => (((strlen($itm[0]['allow_cid'])) || (strlen($itm[0]['allow_gid'])) || (strlen($itm[0]['deny_cid'])) || (strlen($itm[0]['deny_gid']))) ? 'lock' : 'unlock'), + 'profile_uid' => (intval($owner)), + 'bbcode' => (($mimetype == 'text/bbcode') ? true : false) + ); - } + $editor = status_editor($x); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Webpage'), + '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), + '$editor' => $editor, + '$cancel' => t('Cancel'), + '$id' => $itm[0]['id'] + )); + + return $o; + + } } diff --git a/Zotlabs/Module/Email_resend.php b/Zotlabs/Module/Email_resend.php index b8e2c6a79..ce00a7cd5 100644 --- a/Zotlabs/Module/Email_resend.php +++ b/Zotlabs/Module/Email_resend.php @@ -5,44 +5,46 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Email_resend extends Controller { +class Email_resend extends Controller +{ - function post() { + public function post() + { - if($_POST['token']) { - if(! account_approve(trim($_POST['token']))) { - notice(t('Token verification failed.')); - } - } + if ($_POST['token']) { + if (!account_approve(trim($_POST['token']))) { + notice(t('Token verification failed.')); + } + } - } + } - function get() { + public function get() + { - if(argc() > 1) { - $result = false; - $email = hex2bin(argv(1)); + if (argc() > 1) { + $result = false; + $email = hex2bin(argv(1)); - if($email) { - $result = verify_email_address( [ 'resend' => true, 'email' => $email ] ); - } + if ($email) { + $result = verify_email_address(['resend' => true, 'email' => $email]); + } - if($result) { - notice(t('Email verification resent')); - } - else { - notice(t('Unable to resend email verification message.')); - } + if ($result) { + notice(t('Email verification resent')); + } else { + notice(t('Unable to resend email verification message.')); + } - goaway(z_root() . '/email_validation/' . bin2hex($email)); + goaway(z_root() . '/email_validation/' . bin2hex($email)); - } + } - // @todo - one can provide a form here to resend the mail - // after directing to here if a succesful login was attempted from an unverified address. + // @todo - one can provide a form here to resend the mail + // after directing to here if a succesful login was attempted from an unverified address. - } + } } diff --git a/Zotlabs/Module/Email_validation.php b/Zotlabs/Module/Email_validation.php index 1aaabe749..c6e686f4c 100644 --- a/Zotlabs/Module/Email_validation.php +++ b/Zotlabs/Module/Email_validation.php @@ -5,46 +5,49 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Email_validation extends Controller { +class Email_validation extends Controller +{ - function post() { + public function post() + { - $success = false; - if($_POST['token']) { - // This will redirect internally on success unless the channel is auto_created - if(account_approve(trim(basename($_POST['token'])))) { - $success = true; - if(get_config('system','auto_channel_create')) { - $next_page = get_config('system', 'workflow_channel_next', 'profiles'); - } - if($next_page) { - goaway(z_root() . '/' . $next_page); - } - } - } - if(! $success) { - notice( t('Token verification failed.') . EOL); - } - } + $success = false; + if ($_POST['token']) { + // This will redirect internally on success unless the channel is auto_created + if (account_approve(trim(basename($_POST['token'])))) { + $success = true; + if (get_config('system', 'auto_channel_create')) { + $next_page = get_config('system', 'workflow_channel_next', 'profiles'); + } + if ($next_page) { + goaway(z_root() . '/' . $next_page); + } + } + } + if (!$success) { + notice(t('Token verification failed.') . EOL); + } + } - function get() { + public function get() + { - if(argc() > 1) { - $email = hex2bin(argv(1)); - } + if (argc() > 1) { + $email = hex2bin(argv(1)); + } - $o = replace_macros(get_markup_template('email_validation.tpl'), [ - '$title' => t('Email Verification Required'), - '$desc' => sprintf( t('A verification token was sent to your email address [%s]. Enter that token here to complete the account verification step. Please allow a few minutes for delivery, and check your spam folder if you do not see the message.'),$email), - '$resend' => t('Resend Email'), - '$email' => bin2hex($email), - '$submit' => t('Submit'), - '$token' => [ 'token', t('Validation token'),'','' ], - ]); - - return $o; + $o = replace_macros(get_markup_template('email_validation.tpl'), [ + '$title' => t('Email Verification Required'), + '$desc' => sprintf(t('A verification token was sent to your email address [%s]. Enter that token here to complete the account verification step. Please allow a few minutes for delivery, and check your spam folder if you do not see the message.'), $email), + '$resend' => t('Resend Email'), + '$email' => bin2hex($email), + '$submit' => t('Submit'), + '$token' => ['token', t('Validation token'), '', ''], + ]); - } + return $o; + + } } \ No newline at end of file diff --git a/Zotlabs/Module/Embed.php b/Zotlabs/Module/Embed.php index d470719a0..1cd6e296b 100644 --- a/Zotlabs/Module/Embed.php +++ b/Zotlabs/Module/Embed.php @@ -9,14 +9,16 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Embed extends Controller { +class Embed extends Controller +{ - function init() { - $post_id = ((argc() > 1) ? intval(argv(1)) : 0); - - if ($post_id && local_channel()) { - echo '[share=' . $post_id . '][/share]'; - } - killme(); - } + public function init() + { + $post_id = ((argc() > 1) ? intval(argv(1)) : 0); + + if ($post_id && local_channel()) { + echo '[share=' . $post_id . '][/share]'; + } + killme(); + } } diff --git a/Zotlabs/Module/Embedphotos.php b/Zotlabs/Module/Embedphotos.php index cd4db4aa9..52e207470 100644 --- a/Zotlabs/Module/Embedphotos.php +++ b/Zotlabs/Module/Embedphotos.php @@ -8,240 +8,234 @@ use Zotlabs\Web\Controller; require_once('include/attach.php'); require_once('include/photos.php'); -class Embedphotos extends Controller { +class Embedphotos extends Controller +{ - /** - * - * This is the POST destination for the embedphotos button - * - */ - function post() { - - // The admin tools for setting a site logo and cover photo set the channel_id explicitly - // to the 'sys' channel and use stored resources for that channel. - // Legacy behaviour uses the local logged in channel. - - if (argc() > 2 && is_site_admin() && intval(argv(2))) { - $channel_id = argv(2); - } - else { - $channel_id = local_channel(); - } - if (argc() > 1 && argv(1) === 'album') { - // API: /embedphotos/album - $name = (x($_POST,'name') ? $_POST['name'] : null ); - if (! $name) { - json_return_and_die(array('errormsg' => 'Error retrieving album', 'status' => false)); - } - $album = $this->embedphotos_widget_album(array('channel_id' => $channel_id, 'album' => $name)); - json_return_and_die(array('status' => true, 'content' => $album)); - } - if (argc() > 1 && argv(1) === 'albumlist') { - // API: /embedphotos/albumlist - $album_list = $this->embedphotos_album_list($channel_id); - json_return_and_die(array('status' => true, 'albumlist' => $album_list)); - } - if (argc() > 1 && argv(1) === 'photolink') { - // API: /embedphotos/photolink - $href = (x($_POST,'href') ? $_POST['href'] : null ); - if (! $href) { - json_return_and_die(array('errormsg' => 'Error retrieving link ' . $href, 'status' => false)); - } - $resource_id = array_pop(explode("/", $href)); + /** + * + * This is the POST destination for the embedphotos button + * + */ + public function post() + { - $x = self::photolink($resource_id, $channel_id); - if ($x) { - json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id)); - } - json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false)); + // The admin tools for setting a site logo and cover photo set the channel_id explicitly + // to the 'sys' channel and use stored resources for that channel. + // Legacy behaviour uses the local logged in channel. - } - } + if (argc() > 2 && is_site_admin() && intval(argv(2))) { + $channel_id = argv(2); + } else { + $channel_id = local_channel(); + } + if (argc() > 1 && argv(1) === 'album') { + // API: /embedphotos/album + $name = (x($_POST, 'name') ? $_POST['name'] : null); + if (!$name) { + json_return_and_die(array('errormsg' => 'Error retrieving album', 'status' => false)); + } + $album = $this->embedphotos_widget_album(array('channel_id' => $channel_id, 'album' => $name)); + json_return_and_die(array('status' => true, 'content' => $album)); + } + if (argc() > 1 && argv(1) === 'albumlist') { + // API: /embedphotos/albumlist + $album_list = $this->embedphotos_album_list($channel_id); + json_return_and_die(array('status' => true, 'albumlist' => $album_list)); + } + if (argc() > 1 && argv(1) === 'photolink') { + // API: /embedphotos/photolink + $href = (x($_POST, 'href') ? $_POST['href'] : null); + if (!$href) { + json_return_and_die(array('errormsg' => 'Error retrieving link ' . $href, 'status' => false)); + } + $resource_id = array_pop(explode("/", $href)); + + $x = self::photolink($resource_id, $channel_id); + if ($x) { + json_return_and_die(array('status' => true, 'photolink' => $x, 'resource_id' => $resource_id)); + } + json_return_and_die(array('errormsg' => 'Error retrieving resource ' . $resource_id, 'status' => false)); + + } + } - protected static function photolink($resource, $channel_id = 0) { - if (intval($channel_id)) { - $channel = channelx_by_n($channel_id); - } - else { - $channel = App::get_channel(); - } - - $output = EMPTY_STR; - if ($channel) { - $resolution = ((feature_enabled($channel['channel_id'],'large_photos')) ? 1 : 2); - $r = q("select mimetype, height, width, title from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1", - dbesc($resource), - intval($resolution), - intval($channel['channel_id']) - ); - if (! $r) { - return $output; - } - - if ($r[0]['mimetype'] === 'image/jpeg') { - $ext = '.jpg'; - } - elseif ($r[0]['mimetype'] === 'image/png') { - $ext = '.png'; - } - elseif ($r[0]['mimetype'] === 'image/gif') { - $ext = '.gif'; - } - else { - $ext = EMPTY_STR; - } + protected static function photolink($resource, $channel_id = 0) + { + if (intval($channel_id)) { + $channel = channelx_by_n($channel_id); + } else { + $channel = App::get_channel(); + } - $alt = $r[0]['title']; - if (! $alt) { - $a = q("select filename from attach where hash = '%s' and uid = %d limit 1", - dbesc($resource), - intval($channel['channel_id']) - ); - if ($a) { - $alt = $a[0]['filename']; - } - else { - $alt = t('Image/photo'); - } - } - $alt = ' alt="' . $alt . '"'; + $output = EMPTY_STR; + if ($channel) { + $resolution = ((feature_enabled($channel['channel_id'], 'large_photos')) ? 1 : 2); + $r = q("select mimetype, height, width, title from photo where resource_id = '%s' and $resolution = %d and uid = %d limit 1", + dbesc($resource), + intval($resolution), + intval($channel['channel_id']) + ); + if (!$r) { + return $output; + } - $output = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $resource . ']' - . '[zmg width="' . $r[0]['width'] . '" height="' . $r[0]['height'] . '"' . $alt . ']' - . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . '[/zmg][/zrl]'; + if ($r[0]['mimetype'] === 'image/jpeg') { + $ext = '.jpg'; + } elseif ($r[0]['mimetype'] === 'image/png') { + $ext = '.png'; + } elseif ($r[0]['mimetype'] === 'image/gif') { + $ext = '.gif'; + } else { + $ext = EMPTY_STR; + } - return $output; - } - } + $alt = $r[0]['title']; + if (!$alt) { + $a = q("select filename from attach where hash = '%s' and uid = %d limit 1", + dbesc($resource), + intval($channel['channel_id']) + ); + if ($a) { + $alt = $a[0]['filename']; + } else { + $alt = t('Image/photo'); + } + } + $alt = ' alt="' . $alt . '"'; + + $output = '[zrl=' . z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $resource . ']' + . '[zmg width="' . $r[0]['width'] . '" height="' . $r[0]['height'] . '"' . $alt . ']' + . z_root() . '/photo/' . $resource . '-' . $resolution . $ext . '[/zmg][/zrl]'; + + return $output; + } + } + /** + * Copied from include/widgets.php::widget_album() with a modification to get the profile_uid from + * the input array as in widget_item() + * + * @param array $args + * @return string with HTML + */ + public function embedphotos_widget_album($args) + { + $channel_id = 0; + if (array_key_exists('channel_id', $args)) { + $channel_id = $args['channel_id']; + $channel = channelx_by_n($channel_id); + } - /** - * Copied from include/widgets.php::widget_album() with a modification to get the profile_uid from - * the input array as in widget_item() - * - * @param array $args - * @return string with HTML - */ + if (!$channel_id) { + return ''; + } - function embedphotos_widget_album($args) { + $owner_uid = $channel_id; + require_once('include/security.php'); + $sql_extra = permissions_sql($channel_id); - $channel_id = 0; - if (array_key_exists('channel_id', $args)) { - $channel_id = $args['channel_id']; - $channel = channelx_by_n($channel_id); - } - - if (! $channel_id) { - return ''; - } + if (!perm_is_allowed($channel_id, get_observer_hash(), 'view_storage')) + return ''; - $owner_uid = $channel_id; - require_once('include/security.php'); - $sql_extra = permissions_sql($channel_id); + if ($args['album']) { + $album = (($args['album'] === '/') ? '' : $args['album']); + } - if (! perm_is_allowed($channel_id,get_observer_hash(),'view_storage')) - return ''; + if ($args['title']) { + $title = $args['title']; + } - if ($args['album']) { - $album = (($args['album'] === '/') ? '' : $args['album']); - } - - if ($args['title']) { - $title = $args['title']; - } + /** + * This may return incorrect permissions if you have multiple directories of the same name. + * It is a limitation of the photo table using a name for a photo album instead of a folder hash + */ + if ($album) { + $x = q("select hash from attach where filename = '%s' and uid = %d limit 1", + dbesc($album), + intval($owner_uid) + ); + if ($x) { + $y = attach_can_view_folder($owner_uid, get_observer_hash(), $x[0]['hash']); + if (!$y) { + return ''; + } + } + } - /** - * This may return incorrect permissions if you have multiple directories of the same name. - * It is a limitation of the photo table using a name for a photo album instead of a folder hash - */ - if ($album) { - $x = q("select hash from attach where filename = '%s' and uid = %d limit 1", - dbesc($album), - intval($owner_uid) - ); - if ($x) { - $y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']); - if (! $y) { - return ''; - } - } - } + $order = 'DESC'; - $order = 'DESC'; - - $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN + $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN (SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale) ORDER BY created $order", - intval($owner_uid), - dbesc($album), - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE) - ); + intval($owner_uid), + dbesc($album), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) + ); - $photos = []; - if ($r) { - $twist = 'rotright'; - foreach ($r as $rr) { - if ($twist == 'rotright') { - $twist = 'rotleft'; - } - else { - $twist = 'rotright'; - } + $photos = []; + if ($r) { + $twist = 'rotright'; + foreach ($r as $rr) { + if ($twist == 'rotright') { + $twist = 'rotleft'; + } else { + $twist = 'rotright'; + } - $ext = $phototypes[$rr['mimetype']]; + $ext = $phototypes[$rr['mimetype']]; - $imgalt_e = $rr['filename']; - $desc_e = $rr['description']; + $imgalt_e = $rr['filename']; + $desc_e = $rr['description']; - $imagelink = (z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $rr['resource_id'] - . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '')); + $imagelink = (z_root() . '/photos/' . $channel['channel_address'] . '/image/' . $rr['resource_id'] + . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '')); - $photos[] = [ - 'id' => $rr['id'], - 'twist' => ' ' . $twist . rand(2,4), - 'link' => $imagelink, - 'title' => t('View Photo'), - 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext, - 'alt' => $imgalt_e, - 'desc' => $desc_e, - 'ext' => $ext, - 'hash' => $rr['resource_id'], - 'unknown' => t('Unknown') - ]; - } - } + $photos[] = [ + 'id' => $rr['id'], + 'twist' => ' ' . $twist . rand(2, 4), + 'link' => $imagelink, + 'title' => t('View Photo'), + 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' . $ext, + 'alt' => $imgalt_e, + 'desc' => $desc_e, + 'ext' => $ext, + 'hash' => $rr['resource_id'], + 'unknown' => t('Unknown') + ]; + } + } - $o .= replace_macros(get_markup_template('photo_album.tpl'), [ - '$photos' => $photos, - '$album' => (($title) ? $title : $album), - '$album_id' => rand(), - '$album_edit' => array(t('Edit Album'), $album_edit), - '$can_post' => false, - '$upload' => [ t('Upload'), z_root() . '/photos/' . $channel['channel_address'] . '/upload/' . bin2hex($album) ], - '$order' => false, - '$upload_form' => $upload_form, - '$no_fullscreen_btn' => true - ]); + $o .= replace_macros(get_markup_template('photo_album.tpl'), [ + '$photos' => $photos, + '$album' => (($title) ? $title : $album), + '$album_id' => rand(), + '$album_edit' => array(t('Edit Album'), $album_edit), + '$can_post' => false, + '$upload' => [t('Upload'), z_root() . '/photos/' . $channel['channel_address'] . '/upload/' . bin2hex($album)], + '$order' => false, + '$upload_form' => $upload_form, + '$no_fullscreen_btn' => true + ]); - return $o; - } + return $o; + } - function embedphotos_album_list($channel_id) { - $channel = channelx_by_n($channel_id); - $p = photos_albums_list($channel,App::get_observer()); - if ($p['success']) { - return $p['albums']; - } - else { - return null; - } - } + public function embedphotos_album_list($channel_id) + { + $channel = channelx_by_n($channel_id); + $p = photos_albums_list($channel, App::get_observer()); + if ($p['success']) { + return $p['albums']; + } else { + return null; + } + } } diff --git a/Zotlabs/Module/Event.php b/Zotlabs/Module/Event.php index 9b9769cdf..06ec8a4ce 100644 --- a/Zotlabs/Module/Event.php +++ b/Zotlabs/Module/Event.php @@ -7,51 +7,52 @@ use Zotlabs\Lib\Activity; use Zotlabs\Lib\LDSignatures; use Zotlabs\Web\HTTPSig; -class Event extends Controller { +class Event extends Controller +{ - function init() { + public function init() + { - if(ActivityStreams::is_as_request()) { - $item_id = argv(1); + if (ActivityStreams::is_as_request()) { + $item_id = argv(1); - if(! $item_id) - return; + if (!$item_id) + return; - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 "; - $sql_extra = item_permissions_sql(0); + $sql_extra = item_permissions_sql(0); - $r = q("select * from item where mid like '%s' $item_normal $sql_extra limit 1", - dbesc(z_root() . '/activity/' . $item_id . '%') - ); + $r = q("select * from item where mid like '%s' $item_normal $sql_extra limit 1", + dbesc(z_root() . '/activity/' . $item_id . '%') + ); - if(! $r) { - $r = q("select * from item where mid like '%s' $item_normal limit 1", - dbesc(z_root() . '/activity/' . $item_id . '%') - ); + if (!$r) { + $r = q("select * from item where mid like '%s' $item_normal limit 1", + dbesc(z_root() . '/activity/' . $item_id . '%') + ); - if($r) { - http_status_exit(403, 'Forbidden'); - } - http_status_exit(404, 'Not found'); - } + if ($r) { + http_status_exit(403, 'Forbidden'); + } + http_status_exit(404, 'Not found'); + } - xchan_query($r,true); - $items = fetch_post_tags($r,true); + xchan_query($r, true); + $items = fetch_post_tags($r, true); - $channel = channelx_by_n($items[0]['uid']); + $channel = channelx_by_n($items[0]['uid']); - if(! is_array($items[0]['obj'])) { - $obj = json_decode($items[0]['obj'],true); - } - else { - $obj = $items[0]['obj']; - } + if (!is_array($items[0]['obj'])) { + $obj = json_decode($items[0]['obj'], true); + } else { + $obj = $items[0]['obj']; + } - as_return_and_die($obj,$channel); - } + as_return_and_die($obj, $channel); + } - } + } } \ No newline at end of file diff --git a/Zotlabs/Module/Events.php b/Zotlabs/Module/Events.php index fd74046d5..849ca0e79 100644 --- a/Zotlabs/Module/Events.php +++ b/Zotlabs/Module/Events.php @@ -16,824 +16,817 @@ require_once('include/datetime.php'); require_once('include/event.php'); require_once('include/html2plain.php'); -class Events extends Controller { +class Events extends Controller +{ - function post() { - - logger('post: ' . print_r($_REQUEST,true), LOGGER_DATA); - - if(! local_channel()) - return; + public function post() + { - $channel = App::get_channel(); + logger('post: ' . print_r($_REQUEST, true), LOGGER_DATA); - if(($_FILES) && array_key_exists('userfile',$_FILES) && intval($_FILES['userfile']['size'])) { - $src = $_FILES['userfile']['tmp_name']; - if($src) { - $result = parse_ical_file($src,local_channel()); - if($result) - info( t('Calendar entries imported.') . EOL); - else - notice( t('No calendar entries found.') . EOL); - @unlink($src); - } - goaway(z_root() . '/events'); - } - - - $event_id = ((x($_POST,'event_id')) ? intval($_POST['event_id']) : 0); - $event_hash = ((x($_POST,'event_hash')) ? $_POST['event_hash'] : ''); - - $xchan = ((x($_POST,'xchan')) ? dbesc($_POST['xchan']) : ''); - $uid = local_channel(); - - $start_text = escape_tags($_REQUEST['start_text']); - $finish_text = escape_tags($_REQUEST['finish_text']); - - $adjust = intval($_POST['adjust']); - $nofinish = intval($_POST['nofinish']); - - $timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); + if (!local_channel()) + return; - $tz = (($timezone) ? $timezone : date_default_timezone_get()); + $channel = App::get_channel(); - $categories = escape_tags(trim($_POST['category'])); - - // only allow editing your own events. - - if(($xchan) && ($xchan !== get_observer_hash())) - return; - - if($start_text) { - $start = $start_text; - } - else { - $start = sprintf('%d-%d-%d %d:%d:0',$startyear,$startmonth,$startday,$starthour,$startminute); - } - - - if($finish_text) { - $finish = $finish_text; - } - else { - $finish = sprintf('%d-%d-%d %d:%d:0',$finishyear,$finishmonth,$finishday,$finishhour,$finishminute); - } + if (($_FILES) && array_key_exists('userfile', $_FILES) && intval($_FILES['userfile']['size'])) { + $src = $_FILES['userfile']['tmp_name']; + if ($src) { + $result = parse_ical_file($src, local_channel()); + if ($result) + info(t('Calendar entries imported.') . EOL); + else + notice(t('No calendar entries found.') . EOL); + @unlink($src); + } + goaway(z_root() . '/events'); + } - if($nofinish) { - $finish = NULL_DATE; - } - - if($adjust) { - $start = datetime_convert($tz,'UTC',$start); - if(! $nofinish) - $finish = datetime_convert($tz,'UTC',$finish); - } - else { - $start = datetime_convert('UTC','UTC',$start); - if(! $nofinish) - $finish = datetime_convert('UTC','UTC',$finish); - } - - // Don't allow the event to finish before it begins. - // It won't hurt anything, but somebody will file a bug report - // and we'll waste a bunch of time responding to it. Time that - // could've been spent doing something else. - - - $summary = escape_tags(trim($_POST['summary'])); - $desc = escape_tags(trim($_POST['desc'])); - $location = escape_tags(trim($_POST['location'])); - $type = escape_tags(trim($_POST['type'])); + $event_id = ((x($_POST, 'event_id')) ? intval($_POST['event_id']) : 0); + $event_hash = ((x($_POST, 'event_hash')) ? $_POST['event_hash'] : ''); - $repeat = ((array_key_exists('repeat',$_REQUEST) && intval($_REQUEST['repeat'])) ? 1 : 0); - $freq = ((array_key_exists('freq',$_REQUEST) && $_REQUEST['freq']) ? escape_tags(trim($_REQUEST['freq'])) : EMPTY_STR); - $interval = ((array_key_exists('interval',$_REQUEST) && intval($_REQUEST['interval'])) ? 1 : 0); - $count = ((array_key_exists('count',$_REQUEST) && intval($_REQUEST['count'])) ? intval($_REQUEST['count']) : 0); - $until = ((array_key_exists('until',$_REQUEST) && $_REQUEST['until']) ? datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['until']) : NULL_DATE); - $byday = []; + $xchan = ((x($_POST, 'xchan')) ? dbesc($_POST['xchan']) : ''); + $uid = local_channel(); - if((! $freq) || (! in_array($freq, [ 'DAILY','WEEKLY','MONTHLY','YEARLY' ]))) { - $repeat = 0; - } - if($count < 0) { - $count = 0; - } - if($count > MAX_EVENT_REPEAT_COUNT) { - $count = MAX_EVENT_REPEAT_COUNT; - } + $start_text = escape_tags($_REQUEST['start_text']); + $finish_text = escape_tags($_REQUEST['finish_text']); - require_once('include/text.php'); - linkify_tags($desc, local_channel()); - linkify_tags($location, local_channel()); - - //$action = ($event_hash == '') ? 'new' : "event/" . $event_hash; - - //@fixme: this url gives a wsod if there is a linebreak detected in one of the variables ($desc or $location) - //$onerror_url = z_root() . "/events/" . $action . "?summary=$summary&description=$desc&location=$location&start=$start_text&finish=$finish_text&adjust=$adjust&nofinish=$nofinish&type=$type"; - $onerror_url = z_root() . "/events"; - - if(strcmp($finish,$start) < 0 && !$nofinish) { - notice( t('Event can not end before it has started.') . EOL); - if(intval($_REQUEST['preview'])) { - echo( t('Unable to generate preview.')); - killme(); - } - goaway($onerror_url); - } - - if((! $summary) || (! $start)) { - notice( t('Event title and start time are required.') . EOL); - if(intval($_REQUEST['preview'])) { - echo( t('Unable to generate preview.')); - killme(); - } - goaway($onerror_url); - } - - // $share = ((intval($_POST['distr'])) ? intval($_POST['distr']) : 0); + $adjust = intval($_POST['adjust']); + $nofinish = intval($_POST['nofinish']); - $share = 1; + $timezone = ((x($_POST, 'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); - - $acl = new AccessControl(false); - - if($event_id) { - $x = q("select * from event where id = %d and uid = %d limit 1", - intval($event_id), - intval(local_channel()) - ); - if(! $x) { - notice( t('Event not found.') . EOL); - if(intval($_REQUEST['preview'])) { - echo( t('Unable to generate preview.')); - killme(); - } - return; - } - - $acl->set($x[0]); - - $created = $x[0]['created']; - $edited = datetime_convert(); - - if($x[0]['allow_cid'] === '<' . $channel['channel_hash'] . '>' - && $x[0]['allow_gid'] === '' && $x[0]['deny_cid'] === '' && $x[0]['deny_gid'] === '') { - $share = false; - } - else { - $share = true; - } - } - else { - $created = $edited = datetime_convert(); - if($share) { - $acl->set_from_array($_POST); - } - else { - $acl->set(array('allow_cid' => '<' . $channel['channel_hash'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '')); - } - } - - $post_tags = []; + $tz = (($timezone) ? $timezone : date_default_timezone_get()); - $ac = $acl->get(); - - if(strlen($categories)) { - $cats = explode(',',$categories); - foreach($cats as $cat) { - $post_tags[] = array( - 'uid' => $profile_uid, - 'ttype' => TERM_CATEGORY, - 'otype' => TERM_OBJ_POST, - 'term' => trim($cat), - 'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)) - ); - } - } - - $datarray = []; - $datarray['dtstart'] = $start; - $datarray['dtend'] = $finish; - $datarray['summary'] = $summary; - $datarray['description'] = $desc; - $datarray['location'] = $location; - $datarray['etype'] = $type; - $datarray['adjust'] = $adjust; - $datarray['nofinish'] = $nofinish; - $datarray['uid'] = local_channel(); - $datarray['account'] = get_account_id(); - $datarray['event_xchan'] = $channel['channel_hash']; - $datarray['allow_cid'] = $ac['allow_cid']; - $datarray['allow_gid'] = $ac['allow_gid']; - $datarray['deny_cid'] = $ac['deny_cid']; - $datarray['deny_gid'] = $ac['deny_gid']; - $datarray['private'] = (($acl->is_private()) ? 1 : 0); - $datarray['id'] = $event_id; - $datarray['created'] = $created; - $datarray['edited'] = $edited; - - if(intval($_REQUEST['preview'])) { - $html = format_event_html($datarray); - echo $html; - killme(); - } - - $event = event_store_event($datarray); - - if($post_tags) - $datarray['term'] = $post_tags; - - $item_id = event_store_item($datarray,$event); - - if($item_id) { - $r = q("select * from item where id = %d", - intval($item_id) - ); - if($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - $z = q("select * from event where event_hash = '%s' and uid = %d limit 1", - dbesc($r[0]['resource_id']), - intval($channel['channel_id']) - ); - if($z) { - Libsync::build_sync_packet($channel['channel_id'], [ 'event_item' => [ encode_item($sync_item[0],true)],'event' => $z ]); - } - } - } - - if($share) - Run::Summon( [ 'Notifier', 'event', $item_id ] ); - - } - - - - function get() { - - if(argc() > 2 && argv(1) == 'ical') { - $event_id = argv(2); - - require_once('include/security.php'); - $sql_extra = permissions_sql(local_channel()); - - $r = q("select * from event where event_hash = '%s' $sql_extra limit 1", - dbesc($event_id) - ); - if($r) { - header('Content-type: text/calendar'); - header('Content-Disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' ); - echo ical_wrapper($r); - killme(); - } - else { - notice( t('Event not found.') . EOL ); - return; - } - } - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - $channel = App::get_channel(); + $categories = escape_tags(trim($_POST['category'])); - nav_set_selected('Events'); - - if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) { - $r = q("update event set dismissed = 1 where id = %d and uid = %d", - intval(argv(2)), - intval(local_channel()) - ); - } - - if((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) { - $r = q("update event set dismissed = 0 where id = %d and uid = %d", - intval(argv(2)), - intval(local_channel()) - ); - } - - $first_day = intval(get_pconfig(local_channel(),'system','cal_first_day',0)); - - $htpl = get_markup_template('event_head.tpl'); - App::$page['htmlhead'] .= replace_macros($htpl,array( - '$baseurl' => z_root(), - '$module_url' => '/events', - '$modparams' => 1, - '$lang' => App::$language, - '$first_day' => $first_day - )); - - $o = ''; - - $mode = 'view'; - $y = 0; - $m = 0; - $ignored = ((x($_REQUEST,'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : ''); - - - // logger('args: ' . print_r(App::$argv,true)); - - - - if(argc() > 1) { - if(argc() > 2 && argv(1) === 'add') { - $mode = 'add'; - $item_id = intval(argv(2)); - } - if(argc() > 2 && argv(1) === 'drop') { - $mode = 'drop'; - $event_id = argv(2); - } - if(argc() > 2 && intval(argv(1)) && intval(argv(2))) { - $mode = 'view'; - $y = intval(argv(1)); - $m = intval(argv(2)); - } - if(argc() <= 2) { - $mode = 'view'; - $event_id = argv(1); - } - } - - if($mode === 'add') { - event_addtocal($item_id,local_channel()); - killme(); - } - - if($mode == 'view') { - - /* edit/create form */ - if($event_id) { - $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", - dbesc($event_id), - intval(local_channel()) - ); - if(count($r)) - $orig_event = $r[0]; - } - - $channel = App::get_channel(); - - // Passed parameters overrides anything found in the DB - if(!x($orig_event)) - $orig_event = []; - - // In case of an error the browser is redirected back here, with these parameters filled in with the previous values - /* - if(x($_REQUEST,'nofinish')) $orig_event['nofinish'] = $_REQUEST['nofinish']; - if(x($_REQUEST,'adjust')) $orig_event['adjust'] = $_REQUEST['adjust']; - if(x($_REQUEST,'summary')) $orig_event['summary'] = $_REQUEST['summary']; - if(x($_REQUEST,'description')) $orig_event['description'] = $_REQUEST['description']; - if(x($_REQUEST,'location')) $orig_event['location'] = $_REQUEST['location']; - if(x($_REQUEST,'start')) $orig_event['dtstart'] = $_REQUEST['start']; - if(x($_REQUEST,'finish')) $orig_event['dtend'] = $_REQUEST['finish']; - if(x($_REQUEST,'type')) $orig_event['etype'] = $_REQUEST['type']; - */ - - $n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : ''); - $a_checked = ((x($orig_event) && $orig_event['adjust']) ? ' checked="checked" ' : ''); - $t_orig = ((x($orig_event)) ? $orig_event['summary'] : ''); - $d_orig = ((x($orig_event)) ? $orig_event['description'] : ''); - $l_orig = ((x($orig_event)) ? $orig_event['location'] : ''); - $eid = ((x($orig_event)) ? $orig_event['id'] : 0); - $event_xchan = ((x($orig_event)) ? $orig_event['event_xchan'] : $channel['channel_hash']); - $mid = ((x($orig_event)) ? $orig_event['mid'] : ''); - - if(! x($orig_event)) { - $sh_checked = ''; - $a_checked = ' checked="checked" '; - } - else { - $sh_checked = ((($orig_event['allow_cid'] === '<' . $channel['channel_hash'] . '>' || (! $orig_event['allow_cid'])) && (! $orig_event['allow_gid']) && (! $orig_event['deny_cid']) && (! $orig_event['deny_gid'])) ? '' : ' checked="checked" ' ); - } + // only allow editing your own events. - if($orig_event['event_xchan']) - $sh_checked .= ' disabled="disabled" '; - - $sdt = ((x($orig_event)) ? $orig_event['dtstart'] : 'now'); - - $fdt = ((x($orig_event)) ? $orig_event['dtend'] : '+1 hour'); - - $tz = date_default_timezone_get(); - if(x($orig_event)) - $tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC'); - - $syear = datetime_convert('UTC', $tz, $sdt, 'Y'); - $smonth = datetime_convert('UTC', $tz, $sdt, 'm'); - $sday = datetime_convert('UTC', $tz, $sdt, 'd'); - $shour = datetime_convert('UTC', $tz, $sdt, 'H'); - $sminute = datetime_convert('UTC', $tz, $sdt, 'i'); - - $stext = datetime_convert('UTC',$tz,$sdt); - $stext = substr($stext,0,14) . "00:00"; - - $fyear = datetime_convert('UTC', $tz, $fdt, 'Y'); - $fmonth = datetime_convert('UTC', $tz, $fdt, 'm'); - $fday = datetime_convert('UTC', $tz, $fdt, 'd'); - $fhour = datetime_convert('UTC', $tz, $fdt, 'H'); - $fminute = datetime_convert('UTC', $tz, $fdt, 'i'); - - $ftext = datetime_convert('UTC',$tz,$fdt); - $ftext = substr($ftext,0,14) . "00:00"; - - $type = ((x($orig_event)) ? $orig_event['etype'] : 'event'); - - $f = get_config('system','event_input_format'); - if(! $f) - $f = 'ymd'; - - $catsenabled = Apps::system_app_installed(local_channel(),'Categories'); - - $category = ''; - - if($catsenabled && x($orig_event)){ - $itm = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d limit 1", - dbesc($orig_event['event_hash']), - intval(local_channel()) - ); - $itm = fetch_post_tags($itm); - if($itm) { - $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); - foreach ($cats as $cat) { - if(strlen($category)) - $category .= ', '; - $category .= $cat['term']; - } - } - } - - require_once('include/acl_selectors.php'); - - $acl = new AccessControl($channel); - $perm_defaults = $acl->get(); + if (($xchan) && ($xchan !== get_observer_hash())) + return; - $permissions = ((x($orig_event)) ? $orig_event : $perm_defaults); + if ($start_text) { + $start = $start_text; + } else { + $start = sprintf('%d-%d-%d %d:%d:0', $startyear, $startmonth, $startday, $starthour, $startminute); + } - $freq_options = [ - 'DAILY' => t('day(s)'), - 'WEEKLY' => t('week(s)'), - 'MONTHLY' => t('month(s)'), - 'YEARLY' => t('year(s)') - ]; - - $tpl = get_markup_template('event_form.tpl'); - - $form = replace_macros($tpl,array( - '$post' => z_root() . '/events', - '$eid' => $eid, - '$type' => $type, - '$xchan' => $event_xchan, - '$mid' => $mid, - '$event_hash' => $event_id, - '$summary' => array('summary', (($event_id) ? t('Edit event title') : t('Event title')), $t_orig, t('Required'), '*'), - '$catsenabled' => $catsenabled, - '$placeholdercategory' => t('Categories (comma-separated list)'), - '$c_text' => (($event_id) ? t('Edit Category') : t('Category')), - '$category' => $category, - '$required' => '*', - '$s_dsel' => datetimesel($f,new DateTime(), DateTime::createFromFormat('Y',$syear+5), DateTime::createFromFormat('Y-m-d H:i',"$syear-$smonth-$sday $shour:$sminute"), (($event_id) ? t('Edit start date and time') : t('Start date and time')), 'start_text',true,true,'','',true,$first_day), - '$n_text' => t('Finish date and time are not known or not relevant'), - '$n_checked' => $n_checked, - '$f_dsel' => datetimesel($f,new DateTime(), DateTime::createFromFormat('Y',$fyear+5), DateTime::createFromFormat('Y-m-d H:i',"$fyear-$fmonth-$fday $fhour:$fminute"), (($event_id) ? t('Edit finish date and time') : t('Finish date and time')),'finish_text',true,true,'start_text','',false,$first_day), - '$nofinish' => array('nofinish', t('Finish date and time are not known or not relevant'), $n_checked, '', array(t('No'),t('Yes')), 'onclick="enableDisableFinishDate();"'), - '$adjust' => array('adjust', t('Adjust for viewer timezone'), $a_checked, t('Important for events that happen in a particular place. Not practical for global holidays.'), array(t('No'),t('Yes'))), - '$a_text' => t('Adjust for viewer timezone'), - '$d_text' => (($event_id) ? t('Edit Description') : t('Description')), - '$d_orig' => $d_orig, - '$l_text' => (($event_id) ? t('Edit Location') : t('Location')), - '$l_orig' => $l_orig, - '$t_orig' => $t_orig, - '$preview' => t('Preview'), - '$perms_label' => t('Permission settings'), - // populating the acl dialog was a permission description from view_stream because Cal.php, which - // displays events, says "since we don't currently have an event permission - use the stream permission" - '$acl' => (($orig_event['event_xchan']) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $perm_defaults), false, PermissionDescription::fromGlobalPermission('view_stream'))), + if ($finish_text) { + $finish = $finish_text; + } else { + $finish = sprintf('%d-%d-%d %d:%d:0', $finishyear, $finishmonth, $finishday, $finishhour, $finishminute); + } - '$allow_cid' => acl2json($permissions['allow_cid']), - '$allow_gid' => acl2json($permissions['allow_gid']), - '$deny_cid' => acl2json($permissions['deny_cid']), - '$deny_gid' => acl2json($permissions['deny_gid']), - '$tz_choose' => feature_enabled(local_channel(),'event_tz_select'), - '$timezone' => array('timezone_select' , t('Timezone:'), date_default_timezone_get(), '', get_timezones()), + if ($nofinish) { + $finish = NULL_DATE; + } - '$lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'), - '$submit' => t('Submit'), - '$advanced' => t('Advanced Options'), + if ($adjust) { + $start = datetime_convert($tz, 'UTC', $start); + if (!$nofinish) + $finish = datetime_convert($tz, 'UTC', $finish); + } else { + $start = datetime_convert('UTC', 'UTC', $start); + if (!$nofinish) + $finish = datetime_convert('UTC', 'UTC', $finish); + } - '$repeat' => [ 'repeat' , t('Event repeat'), false, '', [ t('No'), t('Yes') ] ], - '$freq' => [ 'freq' , t('Repeat frequency') , '', '', $freq_options ], - '$interval' => [ 'interval', t('Repeat every'), 1 , '' ], - '$count' => [ 'count', t('Number of total repeats'), 10, '' ], - '$until' => '', - '$byday' => '', - - )); - /* end edit/create form */ - - $thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); - $thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m'); - if(! $y) - $y = intval($thisyear); - if(! $m) - $m = intval($thismonth); - - $export = false; - if(argc() === 4 && argv(3) === 'export') - $export = true; - - // Put some limits on dates. The PHP date functions don't seem to do so well before 1900. - // An upper limit was chosen to keep search engines from exploring links millions of years in the future. - - if($y < 1901) - $y = 1900; - if($y > 2099) - $y = 2100; - - $nextyear = $y; - $nextmonth = $m + 1; - if($nextmonth > 12) { - $nextmonth = 1; - $nextyear ++; - } - - $prevyear = $y; - if($m > 1) - $prevmonth = $m - 1; - else { - $prevmonth = 12; - $prevyear --; - } - - $dim = get_dim($y,$m); - $start = sprintf('%d-%d-%d %d:%d:%d',$y,$m,1,0,0,0); - $finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59); - - - if (argv(1) === 'json'){ - if (x($_GET,'start')) $start = $_GET['start']; - if (x($_GET,'end')) $finish = $_GET['end']; - } - - $start = datetime_convert('UTC','UTC',$start); - $finish = datetime_convert('UTC','UTC',$finish); - - $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); - $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); - - if (x($_GET,'id')){ - $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan + // Don't allow the event to finish before it begins. + // It won't hurt anything, but somebody will file a bug report + // and we'll waste a bunch of time responding to it. Time that + // could've been spent doing something else. + + + $summary = escape_tags(trim($_POST['summary'])); + $desc = escape_tags(trim($_POST['desc'])); + $location = escape_tags(trim($_POST['location'])); + $type = escape_tags(trim($_POST['type'])); + + $repeat = ((array_key_exists('repeat', $_REQUEST) && intval($_REQUEST['repeat'])) ? 1 : 0); + $freq = ((array_key_exists('freq', $_REQUEST) && $_REQUEST['freq']) ? escape_tags(trim($_REQUEST['freq'])) : EMPTY_STR); + $interval = ((array_key_exists('interval', $_REQUEST) && intval($_REQUEST['interval'])) ? 1 : 0); + $count = ((array_key_exists('count', $_REQUEST) && intval($_REQUEST['count'])) ? intval($_REQUEST['count']) : 0); + $until = ((array_key_exists('until', $_REQUEST) && $_REQUEST['until']) ? datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['until']) : NULL_DATE); + $byday = []; + + if ((!$freq) || (!in_array($freq, ['DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY']))) { + $repeat = 0; + } + if ($count < 0) { + $count = 0; + } + if ($count > MAX_EVENT_REPEAT_COUNT) { + $count = MAX_EVENT_REPEAT_COUNT; + } + + require_once('include/text.php'); + linkify_tags($desc, local_channel()); + linkify_tags($location, local_channel()); + + //$action = ($event_hash == '') ? 'new' : "event/" . $event_hash; + + //@fixme: this url gives a wsod if there is a linebreak detected in one of the variables ($desc or $location) + //$onerror_url = z_root() . "/events/" . $action . "?summary=$summary&description=$desc&location=$location&start=$start_text&finish=$finish_text&adjust=$adjust&nofinish=$nofinish&type=$type"; + $onerror_url = z_root() . "/events"; + + if (strcmp($finish, $start) < 0 && !$nofinish) { + notice(t('Event can not end before it has started.') . EOL); + if (intval($_REQUEST['preview'])) { + echo(t('Unable to generate preview.')); + killme(); + } + goaway($onerror_url); + } + + if ((!$summary) || (!$start)) { + notice(t('Event title and start time are required.') . EOL); + if (intval($_REQUEST['preview'])) { + echo(t('Unable to generate preview.')); + killme(); + } + goaway($onerror_url); + } + + // $share = ((intval($_POST['distr'])) ? intval($_POST['distr']) : 0); + + $share = 1; + + + $acl = new AccessControl(false); + + if ($event_id) { + $x = q("select * from event where id = %d and uid = %d limit 1", + intval($event_id), + intval(local_channel()) + ); + if (!$x) { + notice(t('Event not found.') . EOL); + if (intval($_REQUEST['preview'])) { + echo(t('Unable to generate preview.')); + killme(); + } + return; + } + + $acl->set($x[0]); + + $created = $x[0]['created']; + $edited = datetime_convert(); + + if ($x[0]['allow_cid'] === '<' . $channel['channel_hash'] . '>' + && $x[0]['allow_gid'] === '' && $x[0]['deny_cid'] === '' && $x[0]['deny_gid'] === '') { + $share = false; + } else { + $share = true; + } + } else { + $created = $edited = datetime_convert(); + if ($share) { + $acl->set_from_array($_POST); + } else { + $acl->set(array('allow_cid' => '<' . $channel['channel_hash'] . '>', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '')); + } + } + + $post_tags = []; + + $ac = $acl->get(); + + if (strlen($categories)) { + $cats = explode(',', $categories); + foreach ($cats as $cat) { + $post_tags[] = array( + 'uid' => $profile_uid, + 'ttype' => TERM_CATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => trim($cat), + 'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)) + ); + } + } + + $datarray = []; + $datarray['dtstart'] = $start; + $datarray['dtend'] = $finish; + $datarray['summary'] = $summary; + $datarray['description'] = $desc; + $datarray['location'] = $location; + $datarray['etype'] = $type; + $datarray['adjust'] = $adjust; + $datarray['nofinish'] = $nofinish; + $datarray['uid'] = local_channel(); + $datarray['account'] = get_account_id(); + $datarray['event_xchan'] = $channel['channel_hash']; + $datarray['allow_cid'] = $ac['allow_cid']; + $datarray['allow_gid'] = $ac['allow_gid']; + $datarray['deny_cid'] = $ac['deny_cid']; + $datarray['deny_gid'] = $ac['deny_gid']; + $datarray['private'] = (($acl->is_private()) ? 1 : 0); + $datarray['id'] = $event_id; + $datarray['created'] = $created; + $datarray['edited'] = $edited; + + if (intval($_REQUEST['preview'])) { + $html = format_event_html($datarray); + echo $html; + killme(); + } + + $event = event_store_event($datarray); + + if ($post_tags) + $datarray['term'] = $post_tags; + + $item_id = event_store_item($datarray, $event); + + if ($item_id) { + $r = q("select * from item where id = %d", + intval($item_id) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + $z = q("select * from event where event_hash = '%s' and uid = %d limit 1", + dbesc($r[0]['resource_id']), + intval($channel['channel_id']) + ); + if ($z) { + Libsync::build_sync_packet($channel['channel_id'], ['event_item' => [encode_item($sync_item[0], true)], 'event' => $z]); + } + } + } + + if ($share) + Run::Summon(['Notifier', 'event', $item_id]); + + } + + + public function get() + { + + if (argc() > 2 && argv(1) == 'ical') { + $event_id = argv(2); + + require_once('include/security.php'); + $sql_extra = permissions_sql(local_channel()); + + $r = q("select * from event where event_hash = '%s' $sql_extra limit 1", + dbesc($event_id) + ); + if ($r) { + header('Content-type: text/calendar'); + header('Content-Disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"'); + echo ical_wrapper($r); + killme(); + } else { + notice(t('Event not found.') . EOL); + return; + } + } + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + $channel = App::get_channel(); + + nav_set_selected('Events'); + + if ((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) { + $r = q("update event set dismissed = 1 where id = %d and uid = %d", + intval(argv(2)), + intval(local_channel()) + ); + } + + if ((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) { + $r = q("update event set dismissed = 0 where id = %d and uid = %d", + intval(argv(2)), + intval(local_channel()) + ); + } + + $first_day = intval(get_pconfig(local_channel(), 'system', 'cal_first_day', 0)); + + $htpl = get_markup_template('event_head.tpl'); + App::$page['htmlhead'] .= replace_macros($htpl, array( + '$baseurl' => z_root(), + '$module_url' => '/events', + '$modparams' => 1, + '$lang' => App::$language, + '$first_day' => $first_day + )); + + $o = ''; + + $mode = 'view'; + $y = 0; + $m = 0; + $ignored = ((x($_REQUEST, 'ignored')) ? " and dismissed = " . intval($_REQUEST['ignored']) . " " : ''); + + + // logger('args: ' . print_r(App::$argv,true)); + + + if (argc() > 1) { + if (argc() > 2 && argv(1) === 'add') { + $mode = 'add'; + $item_id = intval(argv(2)); + } + if (argc() > 2 && argv(1) === 'drop') { + $mode = 'drop'; + $event_id = argv(2); + } + if (argc() > 2 && intval(argv(1)) && intval(argv(2))) { + $mode = 'view'; + $y = intval(argv(1)); + $m = intval(argv(2)); + } + if (argc() <= 2) { + $mode = 'view'; + $event_id = argv(1); + } + } + + if ($mode === 'add') { + event_addtocal($item_id, local_channel()); + killme(); + } + + if ($mode == 'view') { + + /* edit/create form */ + if ($event_id) { + $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + dbesc($event_id), + intval(local_channel()) + ); + if (count($r)) + $orig_event = $r[0]; + } + + $channel = App::get_channel(); + + // Passed parameters overrides anything found in the DB + if (!x($orig_event)) + $orig_event = []; + + // In case of an error the browser is redirected back here, with these parameters filled in with the previous values + /* + if(x($_REQUEST,'nofinish')) $orig_event['nofinish'] = $_REQUEST['nofinish']; + if(x($_REQUEST,'adjust')) $orig_event['adjust'] = $_REQUEST['adjust']; + if(x($_REQUEST,'summary')) $orig_event['summary'] = $_REQUEST['summary']; + if(x($_REQUEST,'description')) $orig_event['description'] = $_REQUEST['description']; + if(x($_REQUEST,'location')) $orig_event['location'] = $_REQUEST['location']; + if(x($_REQUEST,'start')) $orig_event['dtstart'] = $_REQUEST['start']; + if(x($_REQUEST,'finish')) $orig_event['dtend'] = $_REQUEST['finish']; + if(x($_REQUEST,'type')) $orig_event['etype'] = $_REQUEST['type']; + */ + + $n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : ''); + $a_checked = ((x($orig_event) && $orig_event['adjust']) ? ' checked="checked" ' : ''); + $t_orig = ((x($orig_event)) ? $orig_event['summary'] : ''); + $d_orig = ((x($orig_event)) ? $orig_event['description'] : ''); + $l_orig = ((x($orig_event)) ? $orig_event['location'] : ''); + $eid = ((x($orig_event)) ? $orig_event['id'] : 0); + $event_xchan = ((x($orig_event)) ? $orig_event['event_xchan'] : $channel['channel_hash']); + $mid = ((x($orig_event)) ? $orig_event['mid'] : ''); + + if (!x($orig_event)) { + $sh_checked = ''; + $a_checked = ' checked="checked" '; + } else { + $sh_checked = ((($orig_event['allow_cid'] === '<' . $channel['channel_hash'] . '>' || (!$orig_event['allow_cid'])) && (!$orig_event['allow_gid']) && (!$orig_event['deny_cid']) && (!$orig_event['deny_gid'])) ? '' : ' checked="checked" '); + } + + if ($orig_event['event_xchan']) + $sh_checked .= ' disabled="disabled" '; + + $sdt = ((x($orig_event)) ? $orig_event['dtstart'] : 'now'); + + $fdt = ((x($orig_event)) ? $orig_event['dtend'] : '+1 hour'); + + $tz = date_default_timezone_get(); + if (x($orig_event)) + $tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC'); + + $syear = datetime_convert('UTC', $tz, $sdt, 'Y'); + $smonth = datetime_convert('UTC', $tz, $sdt, 'm'); + $sday = datetime_convert('UTC', $tz, $sdt, 'd'); + $shour = datetime_convert('UTC', $tz, $sdt, 'H'); + $sminute = datetime_convert('UTC', $tz, $sdt, 'i'); + + $stext = datetime_convert('UTC', $tz, $sdt); + $stext = substr($stext, 0, 14) . "00:00"; + + $fyear = datetime_convert('UTC', $tz, $fdt, 'Y'); + $fmonth = datetime_convert('UTC', $tz, $fdt, 'm'); + $fday = datetime_convert('UTC', $tz, $fdt, 'd'); + $fhour = datetime_convert('UTC', $tz, $fdt, 'H'); + $fminute = datetime_convert('UTC', $tz, $fdt, 'i'); + + $ftext = datetime_convert('UTC', $tz, $fdt); + $ftext = substr($ftext, 0, 14) . "00:00"; + + $type = ((x($orig_event)) ? $orig_event['etype'] : 'event'); + + $f = get_config('system', 'event_input_format'); + if (!$f) + $f = 'ymd'; + + $catsenabled = Apps::system_app_installed(local_channel(), 'Categories'); + + $category = ''; + + if ($catsenabled && x($orig_event)) { + $itm = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d limit 1", + dbesc($orig_event['event_hash']), + intval(local_channel()) + ); + $itm = fetch_post_tags($itm); + if ($itm) { + $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); + foreach ($cats as $cat) { + if (strlen($category)) + $category .= ', '; + $category .= $cat['term']; + } + } + } + + require_once('include/acl_selectors.php'); + + $acl = new AccessControl($channel); + $perm_defaults = $acl->get(); + + $permissions = ((x($orig_event)) ? $orig_event : $perm_defaults); + + $freq_options = [ + 'DAILY' => t('day(s)'), + 'WEEKLY' => t('week(s)'), + 'MONTHLY' => t('month(s)'), + 'YEARLY' => t('year(s)') + ]; + + + $tpl = get_markup_template('event_form.tpl'); + + $form = replace_macros($tpl, array( + '$post' => z_root() . '/events', + '$eid' => $eid, + '$type' => $type, + '$xchan' => $event_xchan, + '$mid' => $mid, + '$event_hash' => $event_id, + '$summary' => array('summary', (($event_id) ? t('Edit event title') : t('Event title')), $t_orig, t('Required'), '*'), + '$catsenabled' => $catsenabled, + '$placeholdercategory' => t('Categories (comma-separated list)'), + '$c_text' => (($event_id) ? t('Edit Category') : t('Category')), + '$category' => $category, + '$required' => '*', + '$s_dsel' => datetimesel($f, new DateTime(), DateTime::createFromFormat('Y', $syear + 5), DateTime::createFromFormat('Y-m-d H:i', "$syear-$smonth-$sday $shour:$sminute"), (($event_id) ? t('Edit start date and time') : t('Start date and time')), 'start_text', true, true, '', '', true, $first_day), + '$n_text' => t('Finish date and time are not known or not relevant'), + '$n_checked' => $n_checked, + '$f_dsel' => datetimesel($f, new DateTime(), DateTime::createFromFormat('Y', $fyear + 5), DateTime::createFromFormat('Y-m-d H:i', "$fyear-$fmonth-$fday $fhour:$fminute"), (($event_id) ? t('Edit finish date and time') : t('Finish date and time')), 'finish_text', true, true, 'start_text', '', false, $first_day), + '$nofinish' => array('nofinish', t('Finish date and time are not known or not relevant'), $n_checked, '', array(t('No'), t('Yes')), 'onclick="enableDisableFinishDate();"'), + '$adjust' => array('adjust', t('Adjust for viewer timezone'), $a_checked, t('Important for events that happen in a particular place. Not practical for global holidays.'), array(t('No'), t('Yes'))), + '$a_text' => t('Adjust for viewer timezone'), + '$d_text' => (($event_id) ? t('Edit Description') : t('Description')), + '$d_orig' => $d_orig, + '$l_text' => (($event_id) ? t('Edit Location') : t('Location')), + '$l_orig' => $l_orig, + '$t_orig' => $t_orig, + '$preview' => t('Preview'), + '$perms_label' => t('Permission settings'), + // populating the acl dialog was a permission description from view_stream because Cal.php, which + // displays events, says "since we don't currently have an event permission - use the stream permission" + '$acl' => (($orig_event['event_xchan']) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $perm_defaults), false, PermissionDescription::fromGlobalPermission('view_stream'))), + + '$allow_cid' => acl2json($permissions['allow_cid']), + '$allow_gid' => acl2json($permissions['allow_gid']), + '$deny_cid' => acl2json($permissions['deny_cid']), + '$deny_gid' => acl2json($permissions['deny_gid']), + '$tz_choose' => feature_enabled(local_channel(), 'event_tz_select'), + '$timezone' => array('timezone_select', t('Timezone:'), date_default_timezone_get(), '', get_timezones()), + + '$lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'), + + '$submit' => t('Submit'), + '$advanced' => t('Advanced Options'), + + '$repeat' => ['repeat', t('Event repeat'), false, '', [t('No'), t('Yes')]], + '$freq' => ['freq', t('Repeat frequency'), '', '', $freq_options], + '$interval' => ['interval', t('Repeat every'), 1, ''], + '$count' => ['count', t('Number of total repeats'), 10, ''], + '$until' => '', + '$byday' => '', + + )); + /* end edit/create form */ + + $thisyear = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y'); + $thismonth = datetime_convert('UTC', date_default_timezone_get(), 'now', 'm'); + if (!$y) + $y = intval($thisyear); + if (!$m) + $m = intval($thismonth); + + $export = false; + if (argc() === 4 && argv(3) === 'export') + $export = true; + + // Put some limits on dates. The PHP date functions don't seem to do so well before 1900. + // An upper limit was chosen to keep search engines from exploring links millions of years in the future. + + if ($y < 1901) + $y = 1900; + if ($y > 2099) + $y = 2100; + + $nextyear = $y; + $nextmonth = $m + 1; + if ($nextmonth > 12) { + $nextmonth = 1; + $nextyear++; + } + + $prevyear = $y; + if ($m > 1) + $prevmonth = $m - 1; + else { + $prevmonth = 12; + $prevyear--; + } + + $dim = get_dim($y, $m); + $start = sprintf('%d-%d-%d %d:%d:%d', $y, $m, 1, 0, 0, 0); + $finish = sprintf('%d-%d-%d %d:%d:%d', $y, $m, $dim, 23, 59, 59); + + + if (argv(1) === 'json') { + if (x($_GET, 'start')) $start = $_GET['start']; + if (x($_GET, 'end')) $finish = $_GET['end']; + } + + $start = datetime_convert('UTC', 'UTC', $start); + $finish = datetime_convert('UTC', 'UTC', $finish); + + $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); + $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); + + if (x($_GET, 'id')) { + $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d limit 1", - intval(local_channel()), - intval($_GET['id']) - ); - } elseif($export) { - $r = q("SELECT * from event where uid = %d + intval(local_channel()), + intval($_GET['id']) + ); + } elseif ($export) { + $r = q("SELECT * from event where uid = %d AND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' ) OR ( adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) ", - intval(local_channel()), - dbesc($start), - dbesc($finish), - dbesc($adjust_start), - dbesc($adjust_finish) - ); - } - else { - // fixed an issue with "nofinish" events not showing up in the calendar. - // There's still an issue if the finish date crosses the end of month. - // Noting this for now - it will need to be fixed here and in Friendica. - // Ultimately the finish date shouldn't be involved in the query. + intval(local_channel()), + dbesc($start), + dbesc($finish), + dbesc($adjust_start), + dbesc($adjust_finish) + ); + } else { + // fixed an issue with "nofinish" events not showing up in the calendar. + // There's still an issue if the finish date crosses the end of month. + // Noting this for now - it will need to be fixed here and in Friendica. + // Ultimately the finish date shouldn't be involved in the query. - $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan + $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan from event left join item on event_hash = resource_id where resource_type = 'event' and event.uid = %d and event.uid = item.uid $ignored AND (( adjust = 0 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' ) OR ( adjust = 1 AND ( dtend >= '%s' or nofinish = 1 ) AND dtstart <= '%s' )) ", - intval(local_channel()), - dbesc($start), - dbesc($finish), - dbesc($adjust_start), - dbesc($adjust_finish) - ); - } - - $links = []; - - if($r && ! $export) { - xchan_query($r); - $r = fetch_post_tags($r,true); - - $r = sort_by_date($r); - } - - if($r) { - foreach($r as $rr) { - $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j')); - if(! x($links,$j)) - $links[$j] = z_root() . '/' . App::$cmd . '#link-' . $j; - } - } - - $events=[]; - - $last_date = ''; - $fmt = t('l, F j'); - - if($r) { - - foreach($r as $rr) { - - $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'j') : datetime_convert('UTC','UTC',$rr['dtstart'],'j')); - $d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], $fmt) : datetime_convert('UTC','UTC',$rr['dtstart'],$fmt)); - $d = day_translate($d); - - $start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtstart'], 'c') : datetime_convert('UTC','UTC',$rr['dtstart'],'c')); - if ($rr['nofinish']){ - $end = null; - } else { - $end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['dtend'], 'c') : datetime_convert('UTC','UTC',$rr['dtend'],'c')); + intval(local_channel()), + dbesc($start), + dbesc($finish), + dbesc($adjust_start), + dbesc($adjust_finish) + ); + } - // give a fake end to birthdays so they get crammed into a - // single day on the calendar + $links = []; - if($rr['etype'] === 'birthday') - $end = null; - } - - - $is_first = ($d !== $last_date); - - $last_date = $d; - - $edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root().'/events/'.$rr['event_hash'].'?expandform=1',t('Edit event'),'','') : false); - - $drop = array(z_root().'/events/drop/'.$rr['event_hash'],t('Delete event'),'',''); - - $title = strip_tags(html_entity_decode(zidify_links(bbcode($rr['summary'])),ENT_QUOTES,'UTF-8')); - if(! $title) { - list($title, $_trash) = explode("$rr['id'], - 'hash' => $rr['event_hash'], - 'start'=> $start, - 'end' => $end, - 'drop' => $drop, - 'allDay' => false, - 'title' => $title, - - 'j' => $j, - 'd' => $d, - 'edit' => $edit, - 'is_first'=>$is_first, - 'item'=>$rr, - 'html'=>$html, - 'plink' => array($rr['plink'],t('Link to Source'),'',''), - ); - - - } - } - - if($export) { - header('Content-type: text/calendar'); - header('Content-Disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' ); - echo ical_wrapper($r); - killme(); - } - - if (App::$argv[1] === 'json'){ - echo json_encode($events); killme(); - } - - // links: array('href', 'text', 'extra css classes', 'title') - if (x($_GET,'id')){ - $tpl = get_markup_template("event.tpl"); - } - else { - $tpl = get_markup_template("events-js.tpl"); - } - - $o = replace_macros($tpl, array( - '$baseurl' => z_root(), - '$new_event' => array(z_root().'/events',(($event_id) ? t('Edit Event') : t('Create Event')),'',''), - '$previus' => array(z_root()."/events/$prevyear/$prevmonth",t('Previous'),'',''), - '$next' => array(z_root()."/events/$nextyear/$nextmonth",t('Next'),'',''), - '$export' => array(z_root()."/events/$y/$m/export",t('Export'),'',''), - '$calendar' => cal($y,$m,$links, ' eventcal'), - '$events' => $events, - '$view_label' => t('View'), - '$month' => t('Month'), - '$week' => t('Week'), - '$day' => t('Day'), - '$prev' => t('Previous'), - '$next' => t('Next'), - '$today' => t('Today'), - '$form' => $form, - '$expandform' => ((x($_GET,'expandform')) ? true : false), - )); - - if (x($_GET,'id')){ echo $o; killme(); } - - return $o; - } - - if($mode === 'drop' && $event_id) { - $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", - dbesc($event_id), - intval(local_channel()) - ); + if ($r && !$export) { + xchan_query($r); + $r = fetch_post_tags($r, true); - $sync_event = $r[0]; - - if($r) { - $r = q("delete from event where event_hash = '%s' and uid = %d", - dbesc($event_id), - intval(local_channel()) - ); - if ($r) { - $i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d", - dbesc($event_id), - intval(local_channel()) - ); + $r = sort_by_date($r); + } - if ($i) { + if ($r) { + foreach ($r as $rr) { + $j = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'j') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'j')); + if (!x($links, $j)) + $links[$j] = z_root() . '/' . App::$cmd . '#link-' . $j; + } + } - $can_delete = false; - $local_delete = true; + $events = []; - $ob_hash = get_observer_hash(); - if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { - $can_delete = true; - } + $last_date = ''; + $fmt = t('l, F j'); - // The site admin can delete any post/item on the site. - // If the item originated on this site+channel the deletion will propagate downstream. - // Otherwise just the local copy is removed. + if ($r) { - if(is_site_admin()) { - $local_delete = true; - if(intval($i[0]['item_origin'])) - $can_delete = true; - } + foreach ($r as $rr) { - if($can_delete || $local_delete) { - - // if this is a different page type or it's just a local delete - // but not by the item author or owner, do a simple deletion + $j = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'j') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'j')); + $d = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], $fmt) : datetime_convert('UTC', 'UTC', $rr['dtstart'], $fmt)); + $d = day_translate($d); - $complex = false; + $start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c')); + if ($rr['nofinish']) { + $end = null; + } else { + $end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c')); - if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) { - drop_item($i[0]['id']); - } - else { - // complex deletion that needs to propagate and be performed in phases - drop_item($i[0]['id'],true,DROPITEM_PHASE1); - $complex = true; - } + // give a fake end to birthdays so they get crammed into a + // single day on the calendar - $ii = q("select * from item where id = %d", - intval($i[0]['id']) - ); - if($ii) { - xchan_query($ii); - $sync_item = fetch_post_tags($ii); - Libsync::build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true)))); - } + if ($rr['etype'] === 'birthday') + $end = null; + } - if($complex) { - tag_deliver($i[0]['uid'],$i[0]['id']); - } - } - } - $r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d", - dbesc($event_id), - intval(local_channel()) - ); - $sync_event['event_deleted'] = 1; - Libsync::build_sync_packet(0,array('event' => array($sync_event))); - - info( t('Event removed') . EOL); - } - else { - notice( t('Failed to remove event' ) . EOL); - } - goaway(z_root() . '/events'); - } - } - - } - + $is_first = ($d !== $last_date); + + $last_date = $d; + + $edit = ((local_channel() && $rr['author_xchan'] == get_observer_hash()) ? array(z_root() . '/events/' . $rr['event_hash'] . '?expandform=1', t('Edit event'), '', '') : false); + + $drop = array(z_root() . '/events/drop/' . $rr['event_hash'], t('Delete event'), '', ''); + + $title = strip_tags(html_entity_decode(zidify_links(bbcode($rr['summary'])), ENT_QUOTES, 'UTF-8')); + if (!$title) { + list($title, $_trash) = explode(" $rr['id'], + 'hash' => $rr['event_hash'], + 'start' => $start, + 'end' => $end, + 'drop' => $drop, + 'allDay' => false, + 'title' => $title, + + 'j' => $j, + 'd' => $d, + 'edit' => $edit, + 'is_first' => $is_first, + 'item' => $rr, + 'html' => $html, + 'plink' => array($rr['plink'], t('Link to Source'), '', ''), + ); + + + } + } + + if ($export) { + header('Content-type: text/calendar'); + header('Content-Disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"'); + echo ical_wrapper($r); + killme(); + } + + if (App::$argv[1] === 'json') { + echo json_encode($events); + killme(); + } + + // links: array('href', 'text', 'extra css classes', 'title') + if (x($_GET, 'id')) { + $tpl = get_markup_template("event.tpl"); + } else { + $tpl = get_markup_template("events-js.tpl"); + } + + $o = replace_macros($tpl, array( + '$baseurl' => z_root(), + '$new_event' => array(z_root() . '/events', (($event_id) ? t('Edit Event') : t('Create Event')), '', ''), + '$previus' => array(z_root() . "/events/$prevyear/$prevmonth", t('Previous'), '', ''), + '$next' => array(z_root() . "/events/$nextyear/$nextmonth", t('Next'), '', ''), + '$export' => array(z_root() . "/events/$y/$m/export", t('Export'), '', ''), + '$calendar' => cal($y, $m, $links, ' eventcal'), + '$events' => $events, + '$view_label' => t('View'), + '$month' => t('Month'), + '$week' => t('Week'), + '$day' => t('Day'), + '$prev' => t('Previous'), + '$next' => t('Next'), + '$today' => t('Today'), + '$form' => $form, + '$expandform' => ((x($_GET, 'expandform')) ? true : false), + )); + + if (x($_GET, 'id')) { + echo $o; + killme(); + } + + return $o; + } + + if ($mode === 'drop' && $event_id) { + $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + dbesc($event_id), + intval(local_channel()) + ); + + $sync_event = $r[0]; + + if ($r) { + $r = q("delete from event where event_hash = '%s' and uid = %d", + dbesc($event_id), + intval(local_channel()) + ); + if ($r) { + $i = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d", + dbesc($event_id), + intval(local_channel()) + ); + + if ($i) { + + $can_delete = false; + $local_delete = true; + + $ob_hash = get_observer_hash(); + if ($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { + $can_delete = true; + } + + // The site admin can delete any post/item on the site. + // If the item originated on this site+channel the deletion will propagate downstream. + // Otherwise just the local copy is removed. + + if (is_site_admin()) { + $local_delete = true; + if (intval($i[0]['item_origin'])) + $can_delete = true; + } + + if ($can_delete || $local_delete) { + + // if this is a different page type or it's just a local delete + // but not by the item author or owner, do a simple deletion + + $complex = false; + + if (intval($i[0]['item_type']) || ($local_delete && (!$can_delete))) { + drop_item($i[0]['id']); + } else { + // complex deletion that needs to propagate and be performed in phases + drop_item($i[0]['id'], true, DROPITEM_PHASE1); + $complex = true; + } + + $ii = q("select * from item where id = %d", + intval($i[0]['id']) + ); + if ($ii) { + xchan_query($ii); + $sync_item = fetch_post_tags($ii); + Libsync::build_sync_packet($i[0]['uid'], array('item' => array(encode_item($sync_item[0], true)))); + } + + if ($complex) { + tag_deliver($i[0]['uid'], $i[0]['id']); + } + } + } + + $r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d", + dbesc($event_id), + intval(local_channel()) + ); + $sync_event['event_deleted'] = 1; + Libsync::build_sync_packet(0, array('event' => array($sync_event))); + + info(t('Event removed') . EOL); + } else { + notice(t('Failed to remove event') . EOL); + } + goaway(z_root() . '/events'); + } + } + + } + } diff --git a/Zotlabs/Module/Expire.php b/Zotlabs/Module/Expire.php index 81c932430..c5b2ab1f5 100644 --- a/Zotlabs/Module/Expire.php +++ b/Zotlabs/Module/Expire.php @@ -6,48 +6,50 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Expire extends Controller { +class Expire extends Controller +{ - function post() { + public function post() + { - if (! ( local_channel() && Apps::system_app_installed(local_channel(),'Expire Posts'))) { - return; - } + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Expire Posts'))) { + return; + } - if ($_POST['expire-submit']) { - $expire = intval($_POST['selfexpiredays']); - if ($expire < 0) { - $expire = 0; - } - set_pconfig(local_channel(),'system','selfexpiredays',$expire); - info( t('Expiration settings updated.') . EOL); - } - - Libsync::build_sync_packet(); - } + if ($_POST['expire-submit']) { + $expire = intval($_POST['selfexpiredays']); + if ($expire < 0) { + $expire = 0; + } + set_pconfig(local_channel(), 'system', 'selfexpiredays', $expire); + info(t('Expiration settings updated.') . EOL); + } + + Libsync::build_sync_packet(); + } - - function get() { + public function get() + { $desc = t('This app allows you to set an optional expiration date/time for your own posts, after which they will be deleted. This must be at least fifteen minutes into the future. You may also choose to automatically delete all your posts after a set number of days'); $text = ''; - if (! ( local_channel() && Apps::system_app_installed(local_channel(),'Expire Posts'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Expire Posts'))) { return $text; } - $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), [ - '$field' => array('selfexpiredays', t('Expire and delete all my posts after this many days'), intval(get_pconfig(local_channel(),'system','selfexpiredays',0)), t('Leave at 0 if you wish to manually control expiration of specific posts.')) - ]); + $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), [ + '$field' => array('selfexpiredays', t('Expire and delete all my posts after this many days'), intval(get_pconfig(local_channel(), 'system', 'selfexpiredays', 0)), t('Leave at 0 if you wish to manually control expiration of specific posts.')) + ]); - return replace_macros(get_markup_template('generic_app_settings.tpl'), [ - '$addon' => array('expire', t('Automatic Expiration Settings'), '', t('Submit')), - '$content' => $setting_fields - ]); + return replace_macros(get_markup_template('generic_app_settings.tpl'), [ + '$addon' => array('expire', t('Automatic Expiration Settings'), '', t('Submit')), + '$content' => $setting_fields + ]); - } + } } diff --git a/Zotlabs/Module/Fastping.php b/Zotlabs/Module/Fastping.php index 5eea05c56..d1938a1dc 100644 --- a/Zotlabs/Module/Fastping.php +++ b/Zotlabs/Module/Fastping.php @@ -15,59 +15,60 @@ require_once('include/bbcode.php'); * Called from the client at regular intervals to check for updates from the server * */ +class Fastping extends Controller +{ -class Fastping extends Controller { + /** + * @brief do several updates when pinged. + * + * This function does several tasks. Whenever called it checks for new messages, + * introductions, notifications, etc. and returns a json with the results. + * + * @result JSON + */ - /** - * @brief do several updates when pinged. - * - * This function does several tasks. Whenever called it checks for new messages, - * introductions, notifications, etc. and returns a json with the results. - * - * @result JSON - */ + public function init() + { - function init() { + $result['notice'] = []; + $result['info'] = []; - $result['notice'] = []; - $result['info'] = []; + $vnotify = (-1); - $vnotify = (-1); + $result['invalid'] = ((isset($_GET['uid']) && intval($_GET['uid'])) && (intval($_GET['uid']) != local_channel()) ? 1 : 0); - $result['invalid'] = ((isset($_GET['uid']) && intval($_GET['uid'])) && (intval($_GET['uid']) != local_channel()) ? 1 : 0); + if (local_channel()) { + $vnotify = get_pconfig(local_channel(), 'system', 'vnotify', (-1)); + } - if (local_channel()) { - $vnotify = get_pconfig(local_channel(),'system','vnotify',(-1)); - } + /** + * Send all system messages (alerts) to the browser. + * Some are marked as informational and some represent + * errors or serious notifications. These typically + * will popup on the current page (no matter what page it is) + */ - /** - * Send all system messages (alerts) to the browser. - * Some are marked as informational and some represent - * errors or serious notifications. These typically - * will popup on the current page (no matter what page it is) - */ + if (x($_SESSION, 'sysmsg')) { + foreach ($_SESSION['sysmsg'] as $m) { + $result['notice'][] = array('message' => $m); + } + unset($_SESSION['sysmsg']); + } + if (x($_SESSION, 'sysmsg_info')) { + foreach ($_SESSION['sysmsg_info'] as $m) { + $result['info'][] = array('message' => $m); + } + unset($_SESSION['sysmsg_info']); + } + if (!($vnotify & VNOTIFY_INFO)) { + $result['info'] = []; + } + if (!($vnotify & VNOTIFY_ALERT)) { + $result['notice'] = []; + } - if (x($_SESSION, 'sysmsg')) { - foreach ($_SESSION['sysmsg'] as $m) { - $result['notice'][] = array('message' => $m); - } - unset($_SESSION['sysmsg']); - } - if (x($_SESSION, 'sysmsg_info')) { - foreach ($_SESSION['sysmsg_info'] as $m) { - $result['info'][] = array('message' => $m); - } - unset($_SESSION['sysmsg_info']); - } - if (! ($vnotify & VNOTIFY_INFO)) { - $result['info'] = []; - } - if (! ($vnotify & VNOTIFY_ALERT)) { - $result['notice'] = []; - } + json_return_and_die($result); - json_return_and_die($result); - - } + } } diff --git a/Zotlabs/Module/Fbrowser.php b/Zotlabs/Module/Fbrowser.php index ed0a6227c..d5c15b293 100644 --- a/Zotlabs/Module/Fbrowser.php +++ b/Zotlabs/Module/Fbrowser.php @@ -12,125 +12,129 @@ use Zotlabs\Web\Controller; require_once('include/photo_factory.php'); -class Fbrowser extends Controller { +class Fbrowser extends Controller +{ - function get(){ - - if (!local_channel()) - killme(); - - if (App::$argc==1) - killme(); - - //echo "
        "; var_dump(\App::$argv); killme();	
        -		
        -		switch(App::$argv[1]){
        -			case "image":
        -				$path = array( array(z_root()."/fbrowser/image/", t("Photos")));
        -				$albums = false;
        -				$sql_extra = "";
        -				$sql_extra2 = " ORDER BY created DESC LIMIT 0, 10";
        -				
        -				if (App::$argc==2){
        -					$albums = q("SELECT distinct(album) AS album FROM photo WHERE uid = %d ",
        -						intval(local_channel())
        -					);
        -					// anon functions only from 5.3.0... meglio tardi che mai..
        -					$albums = array_map( "self::folder1" , $albums);
        -					
        -				}
        -				
        -				$album = "";
        -				if (App::$argc==3){
        -					$album = hex2bin(App::$argv[2]);
        -					$sql_extra = sprintf("AND album = '%s' ",dbesc($album));
        -					$sql_extra2 = "";
        -					$path[]=array(z_root() . "/fbrowser/image/" . App::$argv[2] . "/", $album);
        -				}
        -					
        -				$r = q("SELECT resource_id, id, filename, type, min(imgscale) AS hiq,max(imgscale) AS loq, description  
        +    public function get()
        +    {
        +
        +        if (!local_channel())
        +            killme();
        +
        +        if (App::$argc == 1)
        +            killme();
        +
        +        //echo "
        "; var_dump(\App::$argv); killme();
        +
        +        switch (App::$argv[1]) {
        +            case "image":
        +                $path = array(array(z_root() . "/fbrowser/image/", t("Photos")));
        +                $albums = false;
        +                $sql_extra = "";
        +                $sql_extra2 = " ORDER BY created DESC LIMIT 0, 10";
        +
        +                if (App::$argc == 2) {
        +                    $albums = q("SELECT distinct(album) AS album FROM photo WHERE uid = %d ",
        +                        intval(local_channel())
        +                    );
        +                    // anon functions only from 5.3.0... meglio tardi che mai..
        +                    $albums = array_map("self::folder1", $albums);
        +
        +                }
        +
        +                $album = "";
        +                if (App::$argc == 3) {
        +                    $album = hex2bin(App::$argv[2]);
        +                    $sql_extra = sprintf("AND album = '%s' ", dbesc($album));
        +                    $sql_extra2 = "";
        +                    $path[] = array(z_root() . "/fbrowser/image/" . App::$argv[2] . "/", $album);
        +                }
        +
        +                $r = q("SELECT resource_id, id, filename, type, min(imgscale) AS hiq,max(imgscale) AS loq, description  
         						FROM photo WHERE uid = %d $sql_extra
         						GROUP BY resource_id $sql_extra2",
        -					intval(local_channel())					
        -				);
        -				
        -				$files = array_map("self::files1", $r);
        -				
        -				$tpl = get_markup_template("filebrowser.tpl");
        -				echo replace_macros($tpl, array(
        -					'$type' => 'image',
        -					'$baseurl' => z_root(),
        -					'$path' => $path,
        -					'$folders' => $albums,
        -					'$files' =>$files,
        -					'$cancel' => t('Cancel'),
        -				));
        -					
        -					
        -				break;
        -			case "file":
        -				if (App::$argc==2){
        -					$files = q("SELECT id, filename, filetype FROM attach WHERE uid = %d ",
        -						intval(local_channel())
        -					);
        -					
        -					$files = array_map("self::files2", $files);
        -					//echo "
        "; var_dump($files); killme();
        -				
        -								
        -					$tpl = get_markup_template("filebrowser.tpl");
        -					echo replace_macros($tpl, array(
        -						'$type' => 'file',
        -						'$baseurl' => z_root(),
        -						'$path' => array( array(z_root()."/fbrowser/image/", t("Files")) ),
        -						'$folders' => false,
        -						'$files' =>$files,
        -						'$cancel' => t('Cancel'),
        -					));
        -					
        -				}
        -			
        -				break;
        -		}
        -		
        -	
        -		killme();
        -		
        -	}
        +                    intval(local_channel())
        +                );
         
        -	private static function folder1($el){
        -		return array(bin2hex($el['album']),$el['album']);
        -	}	
        +                $files = array_map("self::files1", $r);
        +
        +                $tpl = get_markup_template("filebrowser.tpl");
        +                echo replace_macros($tpl, array(
        +                    '$type' => 'image',
        +                    '$baseurl' => z_root(),
        +                    '$path' => $path,
        +                    '$folders' => $albums,
        +                    '$files' => $files,
        +                    '$cancel' => t('Cancel'),
        +                ));
         
         
        -	private static function files1($rr){ 
        +                break;
        +            case "file":
        +                if (App::$argc == 2) {
        +                    $files = q("SELECT id, filename, filetype FROM attach WHERE uid = %d ",
        +                        intval(local_channel())
        +                    );
         
        -		$ph = photo_factory('');
        -		$types = $ph->supportedTypes();
        -		$ext = $types[$rr['type']];
        -	
        -		$filename_e = $rr['filename'];
        -			
        -		return array( 
        -			z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['hiq'] . '.' .$ext, 
        -			$filename_e, 
        -			z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['loq'] . '.'. $ext
        -		);
        -	}
        +                    $files = array_map("self::files2", $files);
        +                    //echo "
        "; var_dump($files); killme();
        +
        +
        +                    $tpl = get_markup_template("filebrowser.tpl");
        +                    echo replace_macros($tpl, array(
        +                        '$type' => 'file',
        +                        '$baseurl' => z_root(),
        +                        '$path' => array(array(z_root() . "/fbrowser/image/", t("Files"))),
        +                        '$folders' => false,
        +                        '$files' => $files,
        +                        '$cancel' => t('Cancel'),
        +                    ));
        +
        +                }
        +
        +                break;
        +        }
        +
        +
        +        killme();
        +
        +    }
        +
        +    private static function folder1($el)
        +    {
        +        return array(bin2hex($el['album']), $el['album']);
        +    }
        +
        +
        +    private static function files1($rr)
        +    {
        +
        +        $ph = photo_factory('');
        +        $types = $ph->supportedTypes();
        +        $ext = $types[$rr['type']];
        +
        +        $filename_e = $rr['filename'];
        +
        +        return array(
        +            z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['hiq'] . '.' . $ext,
        +            $filename_e,
        +            z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['loq'] . '.' . $ext
        +        );
        +    }
        +
        +    private static function files2($rr)
        +    {
        +        list($m1, $m2) = explode("/", $rr['filetype']);
        +        $filetype = ((file_exists("images/icons/$m1.png")) ? $m1 : "zip");
        +
        +        if (App::get_template_engine() === 'internal') {
        +            $filename_e = template_escape($rr['filename']);
        +        } else {
        +            $filename_e = $rr['filename'];
        +        }
        +
        +        return array(z_root() . '/attach/' . $rr['id'], $filename_e, z_root() . '/images/icons/16/' . $filetype . '.png');
        +    }
         
        -	private static function files2($rr){
        -		list($m1,$m2) = explode("/",$rr['filetype']);
        -		$filetype = ( (file_exists("images/icons/$m1.png"))?$m1:"zip");
        -	
        -		if(App::get_template_engine() === 'internal') {
        -			$filename_e = template_escape($rr['filename']);
        -		}
        -		else {
        -			$filename_e = $rr['filename'];
        -		}
        -	
        -		return array( z_root() . '/attach/' . $rr['id'], $filename_e, z_root() . '/images/icons/16/' . $filetype . '.png'); 
        -	}
         
        -	
         }
        diff --git a/Zotlabs/Module/Fedi_id.php b/Zotlabs/Module/Fedi_id.php
        index d3ee3ff96..f69455b6d 100644
        --- a/Zotlabs/Module/Fedi_id.php
        +++ b/Zotlabs/Module/Fedi_id.php
        @@ -5,49 +5,52 @@ namespace Zotlabs\Module;
         use Zotlabs\Web\Controller;
         
         
        -class Fedi_id extends Controller {
        +class Fedi_id extends Controller
        +{
         
        -	function post() {
        -		$channel = channelx_by_n(argv(1));
        -		if (! $channel) {
        -			return;
        -		}
        -		if ($_REQUEST['address']) {
        -			$x = discover_by_webbie(trim($_REQUEST['address']));
        -			if ($x) {
        -				$ab = q("select * from abook where abook_xchan = '%s' and abook_channel = %d",
        -					dbesc($x),
        -					intval($channel['channel_id'])
        -				);
        -				if ($ab) {
        -					notice( t('You are already connected with this channel.') );
        -					goaway(channel_url($channel));
        -				}
        -				$r = q("select * from xchan where xchan_hash = '%s'",
        -					dbesc($x)
        -				);
        -				if ($r && $r[0]['xchan_follow']) {
        -					goaway(sprintf($r[0]['xchan_follow'],urlencode(channel_reddress($channel))));
        -				}				
        -			}
        +    public function post()
        +    {
        +        $channel = channelx_by_n(argv(1));
        +        if (!$channel) {
        +            return;
        +        }
        +        if ($_REQUEST['address']) {
        +            $x = discover_by_webbie(trim($_REQUEST['address']));
        +            if ($x) {
        +                $ab = q("select * from abook where abook_xchan = '%s' and abook_channel = %d",
        +                    dbesc($x),
        +                    intval($channel['channel_id'])
        +                );
        +                if ($ab) {
        +                    notice(t('You are already connected with this channel.'));
        +                    goaway(channel_url($channel));
        +                }
        +                $r = q("select * from xchan where xchan_hash = '%s'",
        +                    dbesc($x)
        +                );
        +                if ($r && $r[0]['xchan_follow']) {
        +                    goaway(sprintf($r[0]['xchan_follow'], urlencode(channel_reddress($channel))));
        +                }
        +            }
         
        -			notice( t('Unknown or unreachable identifier') );
        -			return;
        -		}
        -	}
        +            notice(t('Unknown or unreachable identifier'));
        +            return;
        +        }
        +    }
         
        -	function get() {
        +    public function get()
        +    {
         
        -		return replace_macros(get_markup_template('fedi_id.tpl'),
        -			[
        -				'$title'   => t('Home instance'),
        -				'$address' => [ 'address', t('Enter your channel address or fediverse ID (e.g. channel@example.com)'), '', t('If you do not have a fediverse ID, please use your browser \'back\' button to return to the previous page') ],
        -				'$action'  => 'fedi_id/' . argv(1),
        -				'$method'  => 'post',
        -				'$submit'  => t('Connect')
        -			]
        -		);	
        +        return replace_macros(get_markup_template('fedi_id.tpl'),
        +            [
        +                '$title' => t('Home instance'),
        +                '$address' => ['address', t('Enter your channel address or fediverse ID (e.g. channel@example.com)'), '', t('If you do not have a fediverse ID, please use your browser \'back\' button to return to the previous page')],
        +                '$action' => 'fedi_id/' . argv(1),
        +                '$method' => 'post',
        +                '$submit' => t('Connect')
        +            ]
        +        );
         
        -	}
        +    }
         
         }
        \ No newline at end of file
        diff --git a/Zotlabs/Module/Feed.php b/Zotlabs/Module/Feed.php
        index ace1109a8..8966ff598 100644
        --- a/Zotlabs/Module/Feed.php
        +++ b/Zotlabs/Module/Feed.php
        @@ -5,45 +5,47 @@ use Zotlabs\Web\Controller;
         
         require_once('include/feedutils.php');
         
        -class Feed extends Controller {
        +class Feed extends Controller
        +{
         
        -	function init() {
        -	
        -		$params = [];
        -	
        -		$params['begin']     = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin']       : NULL_DATE);
        -		$params['end']       = ((x($_REQUEST,'date_end'))   ? $_REQUEST['date_end']         : '');
        -		$params['type']      = ((stristr(argv(0),'json'))   ? 'json'                        : 'xml');
        -		$params['pages']     = ((x($_REQUEST,'pages'))      ? intval($_REQUEST['pages'])    : 0);
        -		$params['top']       = ((x($_REQUEST,'top'))        ? intval($_REQUEST['top'])      : 0);
        -		$params['start']     = ((x($_REQUEST,'start'))      ? intval($_REQUEST['start'])      : 0);
        -		$params['records']   = ((x($_REQUEST,'records'))    ? intval($_REQUEST['records'])    : 40);
        -		$params['direction'] = ((x($_REQUEST,'direction'))  ? dbesc($_REQUEST['direction'])   : 'desc');
        -		$params['cat']       = ((x($_REQUEST,'cat'))        ? escape_tags($_REQUEST['cat']) : '');
        -		$params['compat']    = ((x($_REQUEST,'compat'))     ? intval($_REQUEST['compat'])   : 0);	
        +    public function init()
        +    {
         
        -		if (! in_array($params['direction'],['asc','desc'])) {
        -			$params['direction'] = 'desc';
        -		}
        +        $params = [];
         
        -		if (argc() > 1) {
        +        $params['begin'] = ((x($_REQUEST, 'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE);
        +        $params['end'] = ((x($_REQUEST, 'date_end')) ? $_REQUEST['date_end'] : '');
        +        $params['type'] = ((stristr(argv(0), 'json')) ? 'json' : 'xml');
        +        $params['pages'] = ((x($_REQUEST, 'pages')) ? intval($_REQUEST['pages']) : 0);
        +        $params['top'] = ((x($_REQUEST, 'top')) ? intval($_REQUEST['top']) : 0);
        +        $params['start'] = ((x($_REQUEST, 'start')) ? intval($_REQUEST['start']) : 0);
        +        $params['records'] = ((x($_REQUEST, 'records')) ? intval($_REQUEST['records']) : 40);
        +        $params['direction'] = ((x($_REQUEST, 'direction')) ? dbesc($_REQUEST['direction']) : 'desc');
        +        $params['cat'] = ((x($_REQUEST, 'cat')) ? escape_tags($_REQUEST['cat']) : '');
        +        $params['compat'] = ((x($_REQUEST, 'compat')) ? intval($_REQUEST['compat']) : 0);
         
        -			if (observer_prohibited(true)) {
        -				killme();
        -			}
        +        if (!in_array($params['direction'], ['asc', 'desc'])) {
        +            $params['direction'] = 'desc';
        +        }
        +
        +        if (argc() > 1) {
        +
        +            if (observer_prohibited(true)) {
        +                killme();
        +            }
        +
        +            $channel = channelx_by_nick(argv(1));
        +            if (!$channel) {
        +                killme();
        +            }
        +
        +            logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
        +
        +            echo get_public_feed($channel, $params);
        +
        +            killme();
        +        }
        +
        +    }
         
        -			$channel = channelx_by_nick(argv(1));
        -			if (! $channel) {
        -				killme();
        -			}	
        -	 
        -			logger('public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
        -	
        -			echo get_public_feed($channel,$params);
        -	
        -			killme();
        -		}
        -	
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php
        index 5b24159d1..a9d92e648 100644
        --- a/Zotlabs/Module/File_upload.php
        +++ b/Zotlabs/Module/File_upload.php
        @@ -9,103 +9,101 @@ require_once('include/channel.php');
         require_once('include/photos.php');
         
         
        -class File_upload extends Controller {
        +class File_upload extends Controller
        +{
         
        -	function post() {
        +    public function post()
        +    {
         
        -		logger('file upload: ' . print_r($_REQUEST,true));
        -		logger('file upload: ' . print_r($_FILES,true));
        -	
        -		$channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null);
        -	
        -		if(! $channel) {
        -			logger('channel not found');
        -			killme();
        -		}
        -	
        -		$_REQUEST['source'] = 'file_upload';
        +        logger('file upload: ' . print_r($_REQUEST, true));
        +        logger('file upload: ' . print_r($_FILES, true));
         
        -		if($channel['channel_id'] != local_channel()) {
        -			$_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
        -			$_REQUEST['group_allow']   = expand_acl($channel['channel_allow_gid']);
        -			$_REQUEST['contact_deny']  = expand_acl($channel['channel_deny_cid']);
        -			$_REQUEST['group_deny']    = expand_acl($channel['channel_deny_gid']);
        -		}
        +        $channel = (($_REQUEST['channick']) ? channelx_by_nick($_REQUEST['channick']) : null);
         
        -		$_REQUEST['allow_cid'] = perms2str($_REQUEST['contact_allow']);
        -		$_REQUEST['allow_gid'] = perms2str($_REQUEST['group_allow']);
        -		$_REQUEST['deny_cid']  = perms2str($_REQUEST['contact_deny']);
        -		$_REQUEST['deny_gid']  = perms2str($_REQUEST['group_deny']);
        +        if (!$channel) {
        +            logger('channel not found');
        +            killme();
        +        }
         
        -		if($_REQUEST['filename']) {
        -			$r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
        -			if($r['success']) {
        -				$hash = $r['data']['hash'];
        +        $_REQUEST['source'] = 'file_upload';
         
        -				$sync = attach_export_data($channel,$hash);
        -				if($sync) {
        -					Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
        -				}
        -				goaway(z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']);
        +        if ($channel['channel_id'] != local_channel()) {
        +            $_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']);
        +            $_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']);
        +            $_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']);
        +            $_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']);
        +        }
         
        -			}
        -		}
        -		else {
        +        $_REQUEST['allow_cid'] = perms2str($_REQUEST['contact_allow']);
        +        $_REQUEST['allow_gid'] = perms2str($_REQUEST['group_allow']);
        +        $_REQUEST['deny_cid'] = perms2str($_REQUEST['contact_deny']);
        +        $_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']);
         
        -			$matches = [];
        -			$partial = false;
        +        if ($_REQUEST['filename']) {
        +            $r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
        +            if ($r['success']) {
        +                $hash = $r['data']['hash'];
        +
        +                $sync = attach_export_data($channel, $hash);
        +                if ($sync) {
        +                    Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync)));
        +                }
        +                goaway(z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']);
        +
        +            }
        +        } else {
        +
        +            $matches = [];
        +            $partial = false;
         
         
        +            if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) {
        +                $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches);
        +                if ($pm) {
        +                    logger('Content-Range: ' . print_r($matches, true));
        +                    $partial = true;
        +                }
        +            }
         
        -			if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) {
        -				$pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches);
        -				if($pm) {
        -					logger('Content-Range: ' . print_r($matches,true));
        -					$partial = true;
        -				}
        -			}
        +            if ($partial) {
        +                $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]);
         
        -			if($partial) {
        -				$x = save_chunk($channel,$matches[1],$matches[2],$matches[3]);
        +                if ($x['partial']) {
        +                    header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
        +                    json_return_and_die($x);
        +                } else {
        +                    header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0));
         
        -				if($x['partial']) {
        -					header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0));
        -					json_return_and_die($x);
        -				}
        -				else {
        -					header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0));
        +                    $_FILES['userfile'] = [
        +                        'name' => $x['name'],
        +                        'type' => $x['type'],
        +                        'tmp_name' => $x['tmp_name'],
        +                        'error' => $x['error'],
        +                        'size' => $x['size']
        +                    ];
        +                }
        +            } else {
        +                if (!array_key_exists('userfile', $_FILES)) {
        +                    $_FILES['userfile'] = [
        +                        'name' => $_FILES['files']['name'],
        +                        'type' => $_FILES['files']['type'],
        +                        'tmp_name' => $_FILES['files']['tmp_name'],
        +                        'error' => $_FILES['files']['error'],
        +                        'size' => $_FILES['files']['size']
        +                    ];
        +                }
        +            }
         
        -					$_FILES['userfile'] = [
        -						'name'     => $x['name'],
        -						'type'     => $x['type'],
        -						'tmp_name' => $x['tmp_name'],
        -						'error'    => $x['error'],
        -						'size'     => $x['size']
        -					];
        -				}
        -			}
        -			else {	
        -				if(! array_key_exists('userfile',$_FILES)) {
        -					$_FILES['userfile'] = [
        -						'name'     => $_FILES['files']['name'],
        -						'type'     => $_FILES['files']['type'],
        -						'tmp_name' => $_FILES['files']['tmp_name'],
        -						'error'    => $_FILES['files']['error'],
        -						'size'     => $_FILES['files']['size']
        -					];
        -				}
        -			}
        +            $r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
        +            if ($r['success']) {
        +                $sync = attach_export_data($channel, $r['data']['hash']);
        +                if ($sync)
        +                    Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync)));
         
        -			$r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
        -			if($r['success']) {
        -				$sync = attach_export_data($channel,$r['data']['hash']);
        -				if($sync)
        -					Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync)));
        +            }
        +        }
        +        goaway(z_root() . '/' . $_REQUEST['return_url']);
        +
        +    }
         
        -			}
        -		}
        -		goaway(z_root() . '/' . $_REQUEST['return_url']);
        -	
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Filer.php b/Zotlabs/Module/Filer.php
        index 7d69a3be8..7ab4a0fb2 100644
        --- a/Zotlabs/Module/Filer.php
        +++ b/Zotlabs/Module/Filer.php
        @@ -8,57 +8,58 @@ require_once('include/security.php');
         require_once('include/bbcode.php');
         
         
        -class Filer extends Controller {
        +class Filer extends Controller
        +{
        +
        +    public function get()
        +    {
        +
        +        if (!local_channel()) {
        +            killme();
        +        }
        +
        +        $term = unxmlify(trim($_GET['term']));
        +        $item_id = ((App::$argc > 1) ? intval(App::$argv[1]) : 0);
        +
        +        logger('filer: tag ' . $term . ' item ' . $item_id);
        +
        +        if ($item_id && strlen($term)) {
        +            // file item
        +            store_item_tag(local_channel(), $item_id, TERM_OBJ_POST, TERM_FILE, $term, '');
        +
        +            // protect the entire conversation from periodic expiration
        +
        +            $r = q("select parent from item where id = %d and uid = %d limit 1",
        +                intval($item_id),
        +                intval(local_channel())
        +            );
        +            if ($r) {
        +                $x = q("update item set item_retained = 1 where id = %d and uid = %d",
        +                    intval($r[0]['parent']),
        +                    intval(local_channel())
        +                );
        +            }
        +        } else {
        +            $filetags = [];
        +            $r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
        +                intval(local_channel()),
        +                intval(TERM_FILE)
        +            );
        +            if (count($r)) {
        +                foreach ($r as $rr)
        +                    $filetags[] = $rr['term'];
        +            }
        +            $tpl = get_markup_template("filer_dialog.tpl");
        +            $o = replace_macros($tpl, array(
        +                '$field' => array('term', t('Enter a folder name'), '', '', $filetags, 'placeholder="' . t('or select an existing folder (doubleclick)') . '"'),
        +                '$submit' => t('Save'),
        +                '$title' => t('Save to Folder'),
        +                '$cancel' => t('Cancel')
        +            ));
        +
        +            echo $o;
        +        }
        +        killme();
        +    }
         
        -	function get() {
        -	
        -		if(! local_channel()) {
        -			killme();
        -		}
        -	
        -		$term = unxmlify(trim($_GET['term']));
        -		$item_id = ((App::$argc > 1) ? intval(App::$argv[1]) : 0);
        -	
        -		logger('filer: tag ' . $term . ' item ' . $item_id);
        -	
        -		if($item_id && strlen($term)){
        -			// file item
        -			store_item_tag(local_channel(),$item_id,TERM_OBJ_POST,TERM_FILE,$term,'');
        -	
        -			// protect the entire conversation from periodic expiration
        -	
        -			$r = q("select parent from item where id = %d and uid = %d limit 1",
        -				intval($item_id),
        -				intval(local_channel())
        -			);
        -			if($r) {
        -				$x = q("update item set item_retained = 1 where id = %d and uid = %d",
        -					intval($r[0]['parent']),
        -					intval(local_channel())
        -				);
        -			}
        -		} 
        -		else {
        -			$filetags = [];
        -			$r = q("select distinct(term) from term where uid = %d and ttype = %d order by term asc",
        -				intval(local_channel()),
        -				intval(TERM_FILE)
        -			);
        -			if(count($r)) {
        -				foreach($r as $rr)
        -					$filetags[] = $rr['term'];
        -			}
        -			$tpl = get_markup_template("filer_dialog.tpl");
        -			$o = replace_macros($tpl, array(
        -				'$field' => array('term', t('Enter a folder name'), '', '', $filetags, 'placeholder="' . t('or select an existing folder (doubleclick)') . '"'),
        -				'$submit' => t('Save'),
        -				'$title' => t('Save to Folder'),
        -				'$cancel' => t('Cancel')
        -			));
        -			
        -			echo $o;
        -		}
        -		killme();
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Filerm.php b/Zotlabs/Module/Filerm.php
        index a3bff8119..1d76f199f 100644
        --- a/Zotlabs/Module/Filerm.php
        +++ b/Zotlabs/Module/Filerm.php
        @@ -5,38 +5,40 @@ namespace Zotlabs\Module;
         use App;
         use Zotlabs\Web\Controller;
         
        -class Filerm extends Controller {
        +class Filerm extends Controller
        +{
        +
        +    public function get()
        +    {
        +
        +        if (!local_channel()) {
        +            killme();
        +        }
        +
        +        $term = trim($_GET['term']);
        +        $cat = trim($_GET['cat']);
        +
        +        $category = (($cat) ? true : false);
        +        if ($category)
        +            $term = $cat;
        +
        +        $item_id = ((App::$argc > 1) ? intval(App::$argv[1]) : 0);
        +
        +        logger('filerm: tag ' . $term . ' item ' . $item_id);
        +
        +        if ($item_id && strlen($term)) {
        +            $r = q("delete from term where uid = %d and ttype = %d and oid = %d and term = '%s'",
        +                intval(local_channel()),
        +                intval(($category) ? TERM_CATEGORY : TERM_FILE),
        +                intval($item_id),
        +                dbesc($term)
        +            );
        +        }
        +
        +        if (x($_SESSION, 'return_url'))
        +            goaway(z_root() . '/' . $_SESSION['return_url']);
        +
        +        killme();
        +    }
         
        -	function get() {
        -	
        -		if(! local_channel()) {
        -			killme();
        -		}
        -	
        -		$term = trim($_GET['term']);
        -		$cat  = trim($_GET['cat']);
        -	
        -		$category = (($cat) ? true : false);
        -		if($category)
        -			$term = $cat;
        -	
        -		$item_id = ((App::$argc > 1) ? intval(App::$argv[1]) : 0);
        -	
        -		logger('filerm: tag ' . $term . ' item ' . $item_id);
        -	
        -		if($item_id && strlen($term)) {
        -			$r = q("delete from term where uid = %d and ttype = %d and oid = %d and term = '%s'",
        -				intval(local_channel()),
        -				intval(($category) ? TERM_CATEGORY : TERM_FILE),
        -				intval($item_id),
        -				dbesc($term)
        -			);
        -		}
        -	
        -		if(x($_SESSION,'return_url'))
        -			goaway(z_root() . '/' . $_SESSION['return_url']);
        -		
        -		killme();
        -	}
        -	
         }
        diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php
        index b2928bd7a..21efd1452 100644
        --- a/Zotlabs/Module/Filestorage.php
        +++ b/Zotlabs/Module/Filestorage.php
        @@ -13,241 +13,243 @@ use Zotlabs\Web\Controller;
         use Zotlabs\Lib\Libsync;
         use Zotlabs\Access\AccessControl;
         
        -class Filestorage extends Controller {
        +class Filestorage extends Controller
        +{
         
        -	function post() {
        +    public function post()
        +    {
         
        -		$channel_id = ((x($_POST, 'uid')) ? intval($_POST['uid']) : 0);
        +        $channel_id = ((x($_POST, 'uid')) ? intval($_POST['uid']) : 0);
         
        -		if ((! $channel_id) || (! local_channel()) || ($channel_id != local_channel())) {
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        +        if ((!$channel_id) || (!local_channel()) || ($channel_id != local_channel())) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
         
        -		$recurse = ((x($_POST, 'recurse')) ? intval($_POST['recurse']) : 0);
        -		$resource = ((x($_POST, 'filehash')) ? notags($_POST['filehash']) : '');
        -		$notify = ((x($_POST, 'notify_edit')) ? intval($_POST['notify_edit']) : 0);
        +        $recurse = ((x($_POST, 'recurse')) ? intval($_POST['recurse']) : 0);
        +        $resource = ((x($_POST, 'filehash')) ? notags($_POST['filehash']) : '');
        +        $notify = ((x($_POST, 'notify_edit')) ? intval($_POST['notify_edit']) : 0);
         
        -		$newname = ((x($_POST, 'newname')) ? notags(trim($_POST['newname'])) : '');
        -		$newdir  = ((x($_POST, 'newdir'))  ? notags($_POST['newdir'])  : false);
        +        $newname = ((x($_POST, 'newname')) ? notags(trim($_POST['newname'])) : '');
        +        $newdir = ((x($_POST, 'newdir')) ? notags($_POST['newdir']) : false);
         
        -		if (! $resource) {
        -			notice(t('Item not found.') . EOL);
        -			return;
        -		}
        +        if (!$resource) {
        +            notice(t('Item not found.') . EOL);
        +            return;
        +        }
         
        -		$channel = App::get_channel();
        +        $channel = App::get_channel();
         
        -		if ($newdir || $newname) {
        -			$changed = false;
        -			
        -			$m = q("select folder from attach where hash = '%s' and uid = %d limit 1",
        -				dbesc($resource),
        -				intval($channel_id)
        -			);
        -			
        -			if ($m) {
        -			
        -				// we should always have $newdir, but only call attach_move()
        -				// if it is being changed *or* a new filename is set, and
        -				// account for the fact $newdir can legally be an empty sring
        -				// to indicate the cloud root directory
        +        if ($newdir || $newname) {
        +            $changed = false;
         
        -				if ($newdir !== false && $newdir !== $m[0]['folder']) {
        -					$changed = true;
        -				}
        -				if ($newname) {
        -					$changed = true;
        -				}
        -				if ($changed) {
        -					attach_move($channel_id, $resource, $newdir, $newname);
        -				}
        -			}
        -		}
        +            $m = q("select folder from attach where hash = '%s' and uid = %d limit 1",
        +                dbesc($resource),
        +                intval($channel_id)
        +            );
         
        -		$acl = new AccessControl($channel);
        -		$acl->set_from_array($_POST);
        -		$x = $acl->get();
        +            if ($m) {
         
        -		$url = get_cloud_url($channel_id, $channel['channel_address'], $resource);
        +                // we should always have $newdir, but only call attach_move()
        +                // if it is being changed *or* a new filename is set, and
        +                // account for the fact $newdir can legally be an empty sring
        +                // to indicate the cloud root directory
         
        -		// get the object before permissions change so we can catch eventual former allowed members
        -		$object = get_file_activity_object($channel_id, $resource, $url);
        +                if ($newdir !== false && $newdir !== $m[0]['folder']) {
        +                    $changed = true;
        +                }
        +                if ($newname) {
        +                    $changed = true;
        +                }
        +                if ($changed) {
        +                    attach_move($channel_id, $resource, $newdir, $newname);
        +                }
        +            }
        +        }
         
        -		attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true);
        +        $acl = new AccessControl($channel);
        +        $acl->set_from_array($_POST);
        +        $x = $acl->get();
         
        -		$sync = attach_export_data($channel,$resource,false);
        -		if ($sync) {
        -			Libsync::build_sync_packet($channel_id,array('file' => array($sync)));
        -		}
        +        $url = get_cloud_url($channel_id, $channel['channel_address'], $resource);
        +
        +        // get the object before permissions change so we can catch eventual former allowed members
        +        $object = get_file_activity_object($channel_id, $resource, $url);
        +
        +        attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true);
        +
        +        $sync = attach_export_data($channel, $resource, false);
        +        if ($sync) {
        +            Libsync::build_sync_packet($channel_id, array('file' => array($sync)));
        +        }
         
         //		file_activity($channel_id, $object, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], 'post', $notify);
         
        -		goaway(dirname($url));
        -	}
        +        goaway(dirname($url));
        +    }
         
        -	function get() {
        +    public function get()
        +    {
         
        -		if (argc() > 1) {
        -			$channel = channelx_by_nick(argv(1));
        -		}
        -		if (! $channel) {
        -			notice( t('Channel unavailable.') . EOL);
        -			App::$error = 404;
        -			return;
        -		}			
        +        if (argc() > 1) {
        +            $channel = channelx_by_nick(argv(1));
        +        }
        +        if (!$channel) {
        +            notice(t('Channel unavailable.') . EOL);
        +            App::$error = 404;
        +            return;
        +        }
         
        -		$owner = intval($channel['channel_id']);
        -		$observer = App::get_observer();
        -		
        -		$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
        +        $owner = intval($channel['channel_id']);
        +        $observer = App::get_observer();
         
        -		$perms = get_all_perms($owner, $ob_hash);
        +        $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
         
        -		if (! ($perms['view_storage'] || is_site_admin())){
        -			notice( t('Permission denied.') . EOL);
        -			return;
        -		}
        +        $perms = get_all_perms($owner, $ob_hash);
        +
        +        if (!($perms['view_storage'] || is_site_admin())) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
         
         
        -		if (argc() > 3 && argv(3) === 'delete') {
        +        if (argc() > 3 && argv(3) === 'delete') {
         
        -			if (argc() > 4 && argv(4) === 'json') {
        -				$json_return = true;
        -			}
        +            if (argc() > 4 && argv(4) === 'json') {
        +                $json_return = true;
        +            }
         
        -			$admin_delete = false;
        +            $admin_delete = false;
         
        -			if (! $perms['write_storage']) {
        -				if (is_site_admin()) {
        -					$admin_delete = true;
        -				}
        -				else {
        -					notice( t('Permission denied.') . EOL);
        -					if ($json_return) {
        -						json_return_and_die([ 'success' => false ]);
        -					}
        -					return;
        -				}
        -			}
        +            if (!$perms['write_storage']) {
        +                if (is_site_admin()) {
        +                    $admin_delete = true;
        +                } else {
        +                    notice(t('Permission denied.') . EOL);
        +                    if ($json_return) {
        +                        json_return_and_die(['success' => false]);
        +                    }
        +                    return;
        +                }
        +            }
         
        -			$file = intval(argv(2));
        -			$r = q("SELECT hash, creator FROM attach WHERE id = %d AND uid = %d LIMIT 1",
        -				dbesc($file),
        -				intval($owner)
        -			);
        -			if (! $r) {
        -				notice( t('File not found.') . EOL);
        +            $file = intval(argv(2));
        +            $r = q("SELECT hash, creator FROM attach WHERE id = %d AND uid = %d LIMIT 1",
        +                dbesc($file),
        +                intval($owner)
        +            );
        +            if (!$r) {
        +                notice(t('File not found.') . EOL);
         
        -				if ($json_return) {
        -					json_return_and_die([ 'success' => false ]);
        -				}
        +                if ($json_return) {
        +                    json_return_and_die(['success' => false]);
        +                }
         
        -				goaway(z_root() . '/cloud/' . $which);
        -			}
        +                goaway(z_root() . '/cloud/' . $which);
        +            }
         
        -			$f = array_shift($r);
        +            $f = array_shift($r);
         
        -			if (intval(local_channel()) !== $owner) {
        -				if ($f['creator'] && $f['creator'] !== $ob_hash) {
        -					notice( t('Permission denied.') . EOL);
        +            if (intval(local_channel()) !== $owner) {
        +                if ($f['creator'] && $f['creator'] !== $ob_hash) {
        +                    notice(t('Permission denied.') . EOL);
         
        -					if ($json_return) {
        -						json_return_and_die([ 'success' => false ]);
        -					}
        -					goaway(z_root() . '/cloud/' . $which);
        -				}
        -			}
        +                    if ($json_return) {
        +                        json_return_and_die(['success' => false]);
        +                    }
        +                    goaway(z_root() . '/cloud/' . $which);
        +                }
        +            }
         
        -			$url = get_cloud_url($channel['channel_id'], $channel['channel_address'], $f['hash']);
        +            $url = get_cloud_url($channel['channel_id'], $channel['channel_address'], $f['hash']);
         
        -			attach_delete($owner, $f['hash']);
        +            attach_delete($owner, $f['hash']);
         
        -			if (! $admin_delete) {
        -				$sync = attach_export_data($channel, $f['hash'], true);
        -				if ($sync) {
        -					Libsync::build_sync_packet($channel['channel_id'], [ 'file' => [ $sync ] ]);
        -				}
        -			}
        +            if (!$admin_delete) {
        +                $sync = attach_export_data($channel, $f['hash'], true);
        +                if ($sync) {
        +                    Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
        +                }
        +            }
         
        -			if ($json_return) {
        -				json_return_and_die([ 'success' => true ]);
        -			}
        +            if ($json_return) {
        +                json_return_and_die(['success' => true]);
        +            }
         
        -			goaway(dirname($url));
        -		}
        +            goaway(dirname($url));
        +        }
         
         
        -		// Since we have ACL'd files in the wild, but don't have ACL here yet, we
        -		// need to return for anyone other than the owner, despite the perms check for now.
        +        // Since we have ACL'd files in the wild, but don't have ACL here yet, we
        +        // need to return for anyone other than the owner, despite the perms check for now.
         
        -		$is_owner = (((local_channel()) && ($owner  == local_channel())) ? true : false);
        -		if (! ($is_owner || is_site_admin())) {
        -			notice( t('Permission denied.') . EOL );
        -			return;
        -		}
        +        $is_owner = (((local_channel()) && ($owner == local_channel())) ? true : false);
        +        if (!($is_owner || is_site_admin())) {
        +            notice(t('Permission denied.') . EOL);
        +            return;
        +        }
         
         
        -		if (argc() > 3 && argv(3) === 'edit') {
        -			require_once('include/acl_selectors.php');
        -			if (! $perms['write_storage']) {
        -				notice( t('Permission denied.') . EOL);
        -				return;
        -			}
        -			
        -			$file = intval(argv(2));
        +        if (argc() > 3 && argv(3) === 'edit') {
        +            require_once('include/acl_selectors.php');
        +            if (!$perms['write_storage']) {
        +                notice(t('Permission denied.') . EOL);
        +                return;
        +            }
         
        -			$r = q("select id, uid, folder, filename, revision, flags, is_dir, os_storage, hash, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and uid = %d limit 1",
        -				intval($file),
        -				intval($owner)
        -			);
        +            $file = intval(argv(2));
         
        -			$f = array_shift($r);
        -			
        -			$channel = App::get_channel();
        +            $r = q("select id, uid, folder, filename, revision, flags, is_dir, os_storage, hash, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and uid = %d limit 1",
        +                intval($file),
        +                intval($owner)
        +            );
         
        -			$cloudpath = get_cloudpath($f);
        +            $f = array_shift($r);
         
        -			$aclselect_e = populate_acl($f, false, PermissionDescription::fromGlobalPermission('view_storage'));
        -			$is_a_dir = (intval($f['is_dir']) ? true : false);
        +            $channel = App::get_channel();
         
        -			$lockstate = (($f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid']) ? 'lock' : 'unlock');
        +            $cloudpath = get_cloudpath($f);
         
        -			// Encode path that is used for link so it's a valid URL
        -			// Keep slashes as slashes, otherwise mod_rewrite doesn't work correctly
        -			$encoded_path = str_replace('%2F', '/', rawurlencode($cloudpath));
        -			$folder_list = attach_folder_select_list($channel['channel_id']);
        +            $aclselect_e = populate_acl($f, false, PermissionDescription::fromGlobalPermission('view_storage'));
        +            $is_a_dir = (intval($f['is_dir']) ? true : false);
         
        -			$o = replace_macros(get_markup_template('attach_edit.tpl'), [
        -				'$header' => t('Edit file permissions'),
        -				'$file' => $f,
        -				'$cloudpath' => z_root() . '/' . $encoded_path,
        -				'$uid' => $channel['channel_id'],
        -				'$channelnick' => $channel['channel_address'],
        -				'$permissions' => t('Permissions'),
        -				'$aclselect' => $aclselect_e,
        -				'$allow_cid' => acl2json($f['allow_cid']),
        -				'$allow_gid' => acl2json($f['allow_gid']),
        -				'$deny_cid' => acl2json($f['deny_cid']),
        -				'$deny_gid' => acl2json($f['deny_gid']),
        -				'$lockstate' => $lockstate,
        -				'$newname' => [ 'newname', t('Change filename to') , '', t('Leave blank to keep the existing filename') ],
        -				'$newdir'  => [ 'newdir', t('Move to directory'), $f['folder'], '', $folder_list ],
        -				'$permset' => t('Set/edit permissions'),
        -				'$recurse' => [ 'recurse', t('Include all files and sub folders'), 0, '', [ t('No'), t('Yes') ] ],
        -				'$backlink' => t('Return to file list'),
        -				'$isadir' => $is_a_dir,
        -				'$cpdesc' => t('Copy/paste this code to attach file to a post'),
        -				'$cpldesc' => t('Copy/paste this URL to link file from a web page'),
        -				'$submit' => t('Submit'),
        -				'$attach_btn_title' => t('Share this file'),
        -				'$link_btn_title' => t('Show URL to this file'),
        -				'$notify' => [ 'notify_edit', t('Show in your contacts shared folder'), 0, '', [ t('No'), t('Yes') ] ],
        -			]);
        +            $lockstate = (($f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid']) ? 'lock' : 'unlock');
         
        -			echo $o;
        -			killme();
        -		}
        -		goaway(z_root() . '/cloud/' . $which);
        -	}
        +            // Encode path that is used for link so it's a valid URL
        +            // Keep slashes as slashes, otherwise mod_rewrite doesn't work correctly
        +            $encoded_path = str_replace('%2F', '/', rawurlencode($cloudpath));
        +            $folder_list = attach_folder_select_list($channel['channel_id']);
        +
        +            $o = replace_macros(get_markup_template('attach_edit.tpl'), [
        +                '$header' => t('Edit file permissions'),
        +                '$file' => $f,
        +                '$cloudpath' => z_root() . '/' . $encoded_path,
        +                '$uid' => $channel['channel_id'],
        +                '$channelnick' => $channel['channel_address'],
        +                '$permissions' => t('Permissions'),
        +                '$aclselect' => $aclselect_e,
        +                '$allow_cid' => acl2json($f['allow_cid']),
        +                '$allow_gid' => acl2json($f['allow_gid']),
        +                '$deny_cid' => acl2json($f['deny_cid']),
        +                '$deny_gid' => acl2json($f['deny_gid']),
        +                '$lockstate' => $lockstate,
        +                '$newname' => ['newname', t('Change filename to'), '', t('Leave blank to keep the existing filename')],
        +                '$newdir' => ['newdir', t('Move to directory'), $f['folder'], '', $folder_list],
        +                '$permset' => t('Set/edit permissions'),
        +                '$recurse' => ['recurse', t('Include all files and sub folders'), 0, '', [t('No'), t('Yes')]],
        +                '$backlink' => t('Return to file list'),
        +                '$isadir' => $is_a_dir,
        +                '$cpdesc' => t('Copy/paste this code to attach file to a post'),
        +                '$cpldesc' => t('Copy/paste this URL to link file from a web page'),
        +                '$submit' => t('Submit'),
        +                '$attach_btn_title' => t('Share this file'),
        +                '$link_btn_title' => t('Show URL to this file'),
        +                '$notify' => ['notify_edit', t('Show in your contacts shared folder'), 0, '', [t('No'), t('Yes')]],
        +            ]);
        +
        +            echo $o;
        +            killme();
        +        }
        +        goaway(z_root() . '/cloud/' . $which);
        +    }
         }
        diff --git a/Zotlabs/Module/Finger.php b/Zotlabs/Module/Finger.php
        index b16ce7d88..44665ea67 100644
        --- a/Zotlabs/Module/Finger.php
        +++ b/Zotlabs/Module/Finger.php
        @@ -12,25 +12,27 @@ namespace Zotlabs\Module;
         use Zotlabs\Web\Controller;
         use Zotlabs\Lib\Webfinger;
         
        -class Finger extends Controller {
        +class Finger extends Controller
        +{
         
        -	function get() {
        +    public function get()
        +    {
         
        -		$o = replace_macros(get_markup_template('finger.tpl'), [
        -			'$page_title' => t('Webfinger Diagnostic'),
        -			'$resource'   => [ 'resource', t('Lookup address or URL') , $_GET['resource'], EMPTY_STR ],
        -			'$submit'     => t('Submit')
        -		]);
        -		
        -		if($_GET['resource']) {
        +        $o = replace_macros(get_markup_template('finger.tpl'), [
        +            '$page_title' => t('Webfinger Diagnostic'),
        +            '$resource' => ['resource', t('Lookup address or URL'), $_GET['resource'], EMPTY_STR],
        +            '$submit' => t('Submit')
        +        ]);
         
        -			$resource = trim(escape_tags($_GET['resource']));
        +        if ($_GET['resource']) {
        +
        +            $resource = trim(escape_tags($_GET['resource']));
        +
        +            $result = Webfinger::exec($resource);
        +
        +            $o .= '
        ' . str_replace("\n", '
        ', print_array($result)) . '
        '; + } + return $o; + } - $result = Webfinger::exec($resource); - - $o .= '
        ' . str_replace("\n",'
        ',print_array($result)) . '
        '; - } - return $o; - } - } diff --git a/Zotlabs/Module/Follow.php b/Zotlabs/Module/Follow.php index c667eca82..65feca08c 100644 --- a/Zotlabs/Module/Follow.php +++ b/Zotlabs/Module/Follow.php @@ -12,162 +12,161 @@ use Zotlabs\Lib\LDSignatures; use Zotlabs\Lib\Connect; use Zotlabs\Daemon\Run; -class Follow extends Controller { +class Follow extends Controller +{ - function init() { - - - if (ActivityStreams::is_as_request() && argc() >= 2) { - $abook_id = intval(argv(1)); - if(! $abook_id) - return; - - $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d", - intval($abook_id) - ); - if (! $r) { - return; - } - - $chan = channelx_by_n($r[0]['abook_channel']); - - if (! $chan) { - http_status_exit(404, 'Not found'); - } - - $actor = Activity::encode_person($chan,true,true); - if (! $actor) { - http_status_exit(404, 'Not found'); - } - - // Pleroma requires a unique follow id for every follow and follow response - // instead of our method of re-using the abook_id. This causes issues if they unfollow - // and re-follow so md5 their follow id and slap it on the end so they don't simply discard our - // subsequent accept/reject actions. - - $orig_follow = get_abconfig($chan['channel_id'],$r[0]['xchan_hash'],'activitypub','their_follow_id'); - $orig_follow_type = get_abconfig($chan['channel_id'],$r[0]['xchan_hash'],'activitypub','their_follow_type'); - - as_return_and_die([ - 'id' => z_root() . '/follow/' . $r[0]['abook_id'] . (($orig_follow) ? '/' . md5($orig_follow) : EMPTY_STR), - 'type' => (($orig_follow_type) ? $orig_follow_type : 'Follow'), - 'actor' => $actor, - 'object' => $r[0]['xchan_url'] - ], $chan); - - } + public function init() + { + if (ActivityStreams::is_as_request() && argc() >= 2) { + $abook_id = intval(argv(1)); + if (!$abook_id) + return; - $uid = local_channel(); + $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d", + intval($abook_id) + ); + if (!$r) { + return; + } - if (! $uid) { - return; - } + $chan = channelx_by_n($r[0]['abook_channel']); - $url = notags(trim(punify($_REQUEST['url']))); - $return_url = $_SESSION['return_url']; - $confirm = intval($_REQUEST['confirm']); - $interactive = (($_REQUEST['interactive']) ? intval($_REQUEST['interactive']) : 1); - $channel = App::get_channel(); + if (!$chan) { + http_status_exit(404, 'Not found'); + } - if ((strpos($url,'http') === 0) || strpos($url,'bear:') === 0 || strpos($url,'x-zot:') === 0) { - $n = Activity::fetch($url); - if ($n && isset($n['type']) && ! ActivityStreams::is_an_actor($n['type'])) { - // set client flag to convert objects to implied activities - $a = new ActivityStreams($n,null,true); - if ($a->type === 'Announce' && is_array($a->obj) - && array_key_exists('object',$a->obj) && array_key_exists('actor',$a->obj)) { - // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) - // Reparse the encapsulated Activity and use that instead - logger('relayed activity',LOGGER_DEBUG); - $a = new ActivityStreams($a->obj,null,true); - } + $actor = Activity::encode_person($chan, true, true); + if (!$actor) { + http_status_exit(404, 'Not found'); + } - if ($a->is_valid()) { + // Pleroma requires a unique follow id for every follow and follow response + // instead of our method of re-using the abook_id. This causes issues if they unfollow + // and re-follow so md5 their follow id and slap it on the end so they don't simply discard our + // subsequent accept/reject actions. - if (is_array($a->actor) && array_key_exists('id',$a->actor)) { - Activity::actor_store($a->actor['id'],$a->actor); - } + $orig_follow = get_abconfig($chan['channel_id'], $r[0]['xchan_hash'], 'activitypub', 'their_follow_id'); + $orig_follow_type = get_abconfig($chan['channel_id'], $r[0]['xchan_hash'], 'activitypub', 'their_follow_type'); - // ActivityPub sourced items are cacheable - $item = Activity::decode_note($a,true); - - if ($item) { - Activity::store($channel,get_observer_hash(),$a,$item,true); - - $r = q("select * from item where mid = '%s' and uid = %d", - dbesc($item['mid']), - intval($uid) - ); - if ($r) { - if ($interactive) { - goaway(z_root() . '/display/' . gen_link_id($item['mid'])); - } - else { - $result['success'] = true; - json_return_and_die($result); - } - } - } - } - } - } + as_return_and_die([ + 'id' => z_root() . '/follow/' . $r[0]['abook_id'] . (($orig_follow) ? '/' . md5($orig_follow) : EMPTY_STR), + 'type' => (($orig_follow_type) ? $orig_follow_type : 'Follow'), + 'actor' => $actor, + 'object' => $r[0]['xchan_url'] + ], $chan); - - $result = Connect::connect($channel,$url); - - if ($result['success'] == false) { - - if ($result['message']) { - notice($result['message']); - } - if ($interactive) { - goaway($return_url); - } - else { - json_return_and_die($result); - } - } - - info( t('Connection added.') . EOL); - - $clone = []; - foreach ($result['abook'] as $k => $v) { - if (strpos($k,'abook_') === 0) { - $clone[$k] = $v; - } - } - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); - - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if ($abconfig) { - $clone['abconfig'] = $abconfig; - } - Libsync::build_sync_packet(0, [ 'abook' => [ $clone ] ], true); - - $can_view_stream = their_perms_contains($channel['channel_id'],$clone['abook_xchan'],'view_stream'); - - // If we can view their stream, pull in some posts - - if (($can_view_stream) || ($result['abook']['xchan_network'] === 'rss')) { - Run::Summon([ 'Onepoll', $result['abook']['abook_id'] ]); - } - - if ($interactive) { - goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1'); - } - else { - json_return_and_die([ 'success' => true ]); - } - - } - - function get() { - if (! local_channel()) { - return login(); - } - } + } + + + $uid = local_channel(); + + if (!$uid) { + return; + } + + $url = notags(trim(punify($_REQUEST['url']))); + $return_url = $_SESSION['return_url']; + $confirm = intval($_REQUEST['confirm']); + $interactive = (($_REQUEST['interactive']) ? intval($_REQUEST['interactive']) : 1); + $channel = App::get_channel(); + + if ((strpos($url, 'http') === 0) || strpos($url, 'bear:') === 0 || strpos($url, 'x-zot:') === 0) { + $n = Activity::fetch($url); + if ($n && isset($n['type']) && !ActivityStreams::is_an_actor($n['type'])) { + // set client flag to convert objects to implied activities + $a = new ActivityStreams($n, null, true); + if ($a->type === 'Announce' && is_array($a->obj) + && array_key_exists('object', $a->obj) && array_key_exists('actor', $a->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $a = new ActivityStreams($a->obj, null, true); + } + + if ($a->is_valid()) { + + if (is_array($a->actor) && array_key_exists('id', $a->actor)) { + Activity::actor_store($a->actor['id'], $a->actor); + } + + // ActivityPub sourced items are cacheable + $item = Activity::decode_note($a, true); + + if ($item) { + Activity::store($channel, get_observer_hash(), $a, $item, true); + + $r = q("select * from item where mid = '%s' and uid = %d", + dbesc($item['mid']), + intval($uid) + ); + if ($r) { + if ($interactive) { + goaway(z_root() . '/display/' . gen_link_id($item['mid'])); + } else { + $result['success'] = true; + json_return_and_die($result); + } + } + } + } + } + } + + + $result = Connect::connect($channel, $url); + + if ($result['success'] == false) { + + if ($result['message']) { + notice($result['message']); + } + if ($interactive) { + goaway($return_url); + } else { + json_return_and_die($result); + } + } + + info(t('Connection added.') . EOL); + + $clone = []; + foreach ($result['abook'] as $k => $v) { + if (strpos($k, 'abook_') === 0) { + $clone[$k] = $v; + } + } + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + + $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + if ($abconfig) { + $clone['abconfig'] = $abconfig; + } + Libsync::build_sync_packet(0, ['abook' => [$clone]], true); + + $can_view_stream = their_perms_contains($channel['channel_id'], $clone['abook_xchan'], 'view_stream'); + + // If we can view their stream, pull in some posts + + if (($can_view_stream) || ($result['abook']['xchan_network'] === 'rss')) { + Run::Summon(['Onepoll', $result['abook']['abook_id']]); + } + + if ($interactive) { + goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1'); + } else { + json_return_and_die(['success' => true]); + } + + } + + public function get() + { + if (!local_channel()) { + return login(); + } + } } diff --git a/Zotlabs/Module/Followers.php b/Zotlabs/Module/Followers.php index e24d73558..378ef4de8 100644 --- a/Zotlabs/Module/Followers.php +++ b/Zotlabs/Module/Followers.php @@ -10,69 +10,70 @@ use Zotlabs\Web\HTTPSig; use Zotlabs\Web\Controller; use Zotlabs\Lib\Libprofile; -class Followers extends Controller { +class Followers extends Controller +{ - function init() { + public function init() + { - if (observer_prohibited(true)) { - http_status_exit(403, 'Forbidden'); - } + if (observer_prohibited(true)) { + http_status_exit(403, 'Forbidden'); + } - if (argc() < 2) { - http_status_exit(404, 'Not found'); - } + if (argc() < 2) { + http_status_exit(404, 'Not found'); + } - $channel = channelx_by_nick(argv(1)); - if (! $channel) { - http_status_exit(404, 'Not found'); - } + $channel = channelx_by_nick(argv(1)); + if (!$channel) { + http_status_exit(404, 'Not found'); + } // if (intval($channel['channel_system'])) { // http_status_exit(403,'Permission denied'); // } - Libprofile::load(argv(1)); + Libprofile::load(argv(1)); - $observer_hash = get_observer_hash(); + $observer_hash = get_observer_hash(); - if (((! (is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) { - http_status_exit(403, 'Forbidden'); - } + if (((!(is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) { + http_status_exit(403, 'Forbidden'); + } - if (! perm_is_allowed($channel['channel_id'],$observer_hash,'view_contacts')) { - http_status_exit(403, 'Forbidden'); - } + if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_contacts')) { + http_status_exit(403, 'Forbidden'); + } - $t = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 ", - intval($channel['channel_id']), - intval($channel['channel_id']), - dbesc($channel['channel_hash']) - ); - if ($t) { - App::set_pager_total($t[0]['total']); - App::set_pager_itemspage(100); - } + $t = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 ", + intval($channel['channel_id']), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); + if ($t) { + App::set_pager_total($t[0]['total']); + App::set_pager_itemspage(100); + } - if(App::$pager['unset'] && intval($t[0]['total']) > 100) { - $ret = Activity::paged_collection_init($t[0]['total'],App::$query_string); - } - else { - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + if (App::$pager['unset'] && intval($t[0]['total']) > 100) { + $ret = Activity::paged_collection_init($t[0]['total'], App::$query_string); + } else { + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", - intval($channel['channel_id']), - intval($channel['channel_id']), - dbesc($channel['channel_hash']) - ); + $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", + intval($channel['channel_id']), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); - $ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']); - } + $ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']); + } - if (ActivityStreams::is_as_request()) { - as_return_and_die($ret,$channel); - } + if (ActivityStreams::is_as_request()) { + as_return_and_die($ret, $channel); + } - } + } } diff --git a/Zotlabs/Module/Following.php b/Zotlabs/Module/Following.php index 1ecd3ceb9..1de7a269e 100644 --- a/Zotlabs/Module/Following.php +++ b/Zotlabs/Module/Following.php @@ -9,68 +9,69 @@ use Zotlabs\Web\HTTPSig; use Zotlabs\Web\Controller; use Zotlabs\Lib\Libprofile; -class Following extends Controller { +class Following extends Controller +{ - function init() { + public function init() + { - if (observer_prohibited(true)) { - http_status_exit(403, 'Forbidden'); - } + if (observer_prohibited(true)) { + http_status_exit(403, 'Forbidden'); + } - if (argc() < 2) { - http_status_exit(404, 'Not found'); - } + if (argc() < 2) { + http_status_exit(404, 'Not found'); + } - $channel = channelx_by_nick(argv(1)); - if (! $channel) { - http_status_exit(404, 'Not found'); - } + $channel = channelx_by_nick(argv(1)); + if (!$channel) { + http_status_exit(404, 'Not found'); + } // if (intval($channel['channel_system'])) { // http_status_exit(403,'Permission denied'); // } - Libprofile::load(argv(1)); + Libprofile::load(argv(1)); - $observer_hash = get_observer_hash(); + $observer_hash = get_observer_hash(); - if (((! (is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) { - http_status_exit(403, 'Forbidden'); - } + if (((!(is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) { + http_status_exit(403, 'Forbidden'); + } - if (! perm_is_allowed($channel['channel_id'],$observer_hash,'view_contacts')) { - http_status_exit(403, 'Forbidden'); - } + if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_contacts')) { + http_status_exit(403, 'Forbidden'); + } - $t = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", - intval($channel['channel_id']), - intval($channel['channel_id']), - dbesc($channel['channel_hash']) - ); + $t = q("select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", + intval($channel['channel_id']), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); - if ($t) { - App::set_pager_total($t[0]['total']); - App::set_pager_itemspage(100); - } + if ($t) { + App::set_pager_total($t[0]['total']); + App::set_pager_itemspage(100); + } - if(App::$pager['unset'] && $t[0]['total'] > 100) { - $ret = Activity::paged_collection_init($t[0]['total'],App::$query_string); - } - else { - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + if (App::$pager['unset'] && $t[0]['total'] > 100) { + $ret = Activity::paged_collection_init($t[0]['total'], App::$query_string); + } else { + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", - intval($channel['channel_id']), - intval($channel['channel_id']), - dbesc($channel['channel_hash']) - ); + $r = q("select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", + intval($channel['channel_id']), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); - $ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']); - } - - if (ActivityStreams::is_as_request()) { - as_return_and_die($ret,$channel); - } - } + $ret = Activity::encode_follow_collection($r, App::$query_string, 'OrderedCollection', $t[0]['total']); + } + + if (ActivityStreams::is_as_request()) { + as_return_and_die($ret, $channel); + } + } } diff --git a/Zotlabs/Module/Future.php b/Zotlabs/Module/Future.php index 215e5434d..c9f80e6c8 100644 --- a/Zotlabs/Module/Future.php +++ b/Zotlabs/Module/Future.php @@ -6,16 +6,18 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Future extends Controller { +class Future extends Controller +{ - function get() { + public function get() + { $desc = t('This app allows you to set an optional publish date/time for posts, which may be in the future. This must be at least ten minutes into the future to initiate delayed publishing. The posts will be published automatically after that time has passed. Once installed, a new button will appear in the post editor to set the date/time.'); $text = ''; - return $text; + return $text; - } + } } diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php index e1541bff7..a2be961c0 100644 --- a/Zotlabs/Module/Getfile.php +++ b/Zotlabs/Module/Getfile.php @@ -27,119 +27,118 @@ use Zotlabs\Web\HTTPSig; require_once('include/attach.php'); +class Getfile extends Controller +{ -class Getfile extends Controller { + public function post() + { - function post() { + $header_verified = false; - $header_verified = false; + logger('getfile_args: ' . print_r($_POST, true)); - logger('getfile_args: ' . print_r($_POST,true)); + $hash = $_POST['hash']; + $resource = $_POST['resource']; + $revision = intval($_POST['revision']); + $resolution = ((isset($_POST['resolution'])) ? intval($_POST['resolution']) : (-1)); - $hash = $_POST['hash']; - $resource = $_POST['resource']; - $revision = intval($_POST['revision']); - $resolution = ((isset($_POST['resolution'])) ? intval($_POST['resolution']) : (-1)); + if (argc() > 1) { + $verify_hash = argv(1); + if ($verify_hash !== $resource) { + logger('resource mismatch'); + killme(); + } + } - if(argc() > 1) { - $verify_hash = argv(1); - if($verify_hash !== $resource) { - logger('resource mismatch'); - killme(); - } - } + if (!$hash) { + logger('no sender hash'); + killme(); + } - if(! $hash) { - logger('no sender hash'); - killme(); - } + foreach (['REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION'] as $head) { + if (array_key_exists($head, $_SERVER) && substr(trim($_SERVER[$head]), 0, 9) === 'Signature') { + if ($head !== 'HTTP_AUTHORIZATION') { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; + continue; + } - foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) { - if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') { - if($head !== 'HTTP_AUTHORIZATION') { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head]; - continue; - } + $verified = HTTPSig::verify(''); + if ($verified && $verified['header_signed'] && $verified['header_valid']) { + $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_addr = '%s' limit 1", + dbesc($verified['signer']), + dbesc(str_replace('acct:', '', $verified['signer'])) + ); + if ($r && $r[0]['hubloc_hash'] === $hash) { + $header_verified = true; + } + } + } + } - $verified = HTTPSig::verify(''); - if($verified && $verified['header_signed'] && $verified['header_valid']) { - $r = q("select hubloc_hash from hubloc where hubloc_id_url = '%s' or hubloc_addr = '%s' limit 1", - dbesc($verified['signer']), - dbesc(str_replace('acct:','',$verified['signer'])) - ); - if($r && $r[0]['hubloc_hash'] === $hash) { - $header_verified = true; - } - } - } - } + if (!$header_verified) { + http_status_exit(403, 'Permission denied'); + } - if(! $header_verified) { - http_status_exit(403,'Permission denied'); - } + $channel = channelx_by_hash($hash); - $channel = channelx_by_hash($hash); + if (!$channel) { + logger('error: missing info'); + killme(); + } - if(! $channel) { - logger('error: missing info'); - killme(); - } - - if($resolution > 0) { - $r = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = %d limit 1", - dbesc($resource), - intval($channel['channel_id']), - intval($resolution) - ); - if($r) { - header('Content-type: ' . $r[0]['mimetype']); + if ($resolution > 0) { + $r = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = %d limit 1", + dbesc($resource), + intval($channel['channel_id']), + intval($resolution) + ); + if ($r) { + header('Content-type: ' . $r[0]['mimetype']); - if(intval($r[0]['os_storage'])) { - $fname = dbunescbin($r[0]['content']); - if(strpos($fname,'store') !== false) - $istream = fopen($fname,'rb'); - else - $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname,'rb'); - $ostream = fopen('php://output','wb'); - if($istream && $ostream) { - pipe_streams($istream,$ostream); - fclose($istream); - fclose($ostream); - } - } - else { - echo dbunescbin($r[0]['content']); - } - } - killme(); - } + if (intval($r[0]['os_storage'])) { + $fname = dbunescbin($r[0]['content']); + if (strpos($fname, 'store') !== false) + $istream = fopen($fname, 'rb'); + else + $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname, 'rb'); + $ostream = fopen('php://output', 'wb'); + if ($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } + } else { + echo dbunescbin($r[0]['content']); + } + } + killme(); + } - $r = attach_by_hash($resource,$channel['channel_hash'],$revision); - - if(! $r['success']) { - logger('attach_by_hash failed: ' . $r['message']); - notice( $r['message'] . EOL); - return; - } - - header('Content-type: ' . $r['data']['filetype']); - header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"'); - if(intval($r['data']['os_storage'])) { - $fname = dbunescbin($r['data']['content']); - if(strpos($fname,'store') !== false) - $istream = fopen($fname,'rb'); - else - $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname,'rb'); - $ostream = fopen('php://output','wb'); - if($istream && $ostream) { - pipe_streams($istream,$ostream); - fclose($istream); - fclose($ostream); - } - } - else { - echo dbunescbin($r['data']['content']); - } - killme(); - } + $r = attach_by_hash($resource, $channel['channel_hash'], $revision); + + if (!$r['success']) { + logger('attach_by_hash failed: ' . $r['message']); + notice($r['message'] . EOL); + return; + } + + header('Content-type: ' . $r['data']['filetype']); + header('Content-Disposition: attachment; filename="' . $r['data']['filename'] . '"'); + if (intval($r['data']['os_storage'])) { + $fname = dbunescbin($r['data']['content']); + if (strpos($fname, 'store') !== false) + $istream = fopen($fname, 'rb'); + else + $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname, 'rb'); + $ostream = fopen('php://output', 'wb'); + if ($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } + } else { + echo dbunescbin($r['data']['content']); + } + killme(); + } } diff --git a/Zotlabs/Module/Hashtags.php b/Zotlabs/Module/Hashtags.php index f31e86ab7..ccf7d76ec 100644 --- a/Zotlabs/Module/Hashtags.php +++ b/Zotlabs/Module/Hashtags.php @@ -9,25 +9,27 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Hashtags extends Controller { +class Hashtags extends Controller +{ - function init() { - $result = []; + public function init() + { + $result = []; - $t = escape_tags($_REQUEST['t']); - if(! $t) - json_return_and_die($result); + $t = escape_tags($_REQUEST['t']); + if (!$t) + json_return_and_die($result); - $r = q("select distinct(term) from term where term like '%s' and ttype = %d order by term", - dbesc($t . '%'), - intval(TERM_HASHTAG) - ); - if($r) { - foreach($r as $rv) { - $result[] = [ 'text' => $rv['term'] ]; - } - } + $r = q("select distinct(term) from term where term like '%s' and ttype = %d order by term", + dbesc($t . '%'), + intval(TERM_HASHTAG) + ); + if ($r) { + foreach ($r as $rv) { + $result[] = ['text' => $rv['term']]; + } + } - json_return_and_die($result); - } + json_return_and_die($result); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Hcard.php b/Zotlabs/Module/Hcard.php index dff05cbf4..fab97a6a3 100644 --- a/Zotlabs/Module/Hcard.php +++ b/Zotlabs/Module/Hcard.php @@ -5,72 +5,74 @@ use App; use Zotlabs\Web\Controller; use Zotlabs\Lib\Libprofile; -class Hcard extends Controller { +class Hcard extends Controller +{ - function init() { - - if(argc() > 1) - $which = argv(1); - else { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } - - logger('hcard_request: ' . $which, LOGGER_DEBUG); + public function init() + { - $profile = ''; - $channel = App::get_channel(); - - if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { - $which = $channel['channel_address']; - $profile = argv(1); - $r = q("select profile_guid from profile where id = %d and uid = %d limit 1", - intval($profile), - intval(local_channel()) - ); - if(! $r) - $profile = ''; - $profile = $r[0]['profile_guid']; - } - - head_add_link( [ - 'rel' => 'alternate', - 'type' => 'application/atom+xml', - 'title' => t('Posts and comments'), - 'href' => z_root() . '/feed/' . $which - ]); + if (argc() > 1) + $which = argv(1); + else { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } - head_add_link( [ - 'rel' => 'alternate', - 'type' => 'application/atom+xml', - 'title' => t('Only posts'), - 'href' => z_root() . '/feed/' . $which . '?f=&top=1' - ]); + logger('hcard_request: ' . $which, LOGGER_DEBUG); + + $profile = ''; + $channel = App::get_channel(); + + if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + $r = q("select profile_guid from profile where id = %d and uid = %d limit 1", + intval($profile), + intval(local_channel()) + ); + if (!$r) + $profile = ''; + $profile = $r[0]['profile_guid']; + } + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/atom+xml', + 'title' => t('Posts and comments'), + 'href' => z_root() . '/feed/' . $which + ]); + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/atom+xml', + 'title' => t('Only posts'), + 'href' => z_root() . '/feed/' . $which . '?f=&top=1' + ]); + + + if (!$profile) { + $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", + dbesc(argv(1)) + ); + if ($x) { + App::$profile = $x[0]; + } + } + + Libprofile::load($which, $profile); + + + } + + + public function get() + { + + $x = new \Zotlabs\Widget\Profile(); + return $x->widget([]); + + } - - if(! $profile) { - $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", - dbesc(argv(1)) - ); - if($x) { - App::$profile = $x[0]; - } - } - - Libprofile::load($which,$profile); - - - } - - - function get() { - $x = new \Zotlabs\Widget\Profile(); - return $x->widget([]); - - } - - - } diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php index 27c0c928f..d761b4c36 100644 --- a/Zotlabs/Module/Help.php +++ b/Zotlabs/Module/Help.php @@ -10,133 +10,133 @@ require_once('include/help.php'); /** * You can create local site resources in doc/site */ -class Help extends Controller { +class Help extends Controller +{ - function get() { - nav_set_selected('Help'); + public function get() + { + nav_set_selected('Help'); - if($_REQUEST['search']) { - $o .= '
        '; - $o .= '
        '; - $o .= '

        ' . t('Documentation Search') . ' - ' . htmlspecialchars($_REQUEST['search']) . '

        '; - $o .= '
        '; - $o .= '
        '; + if ($_REQUEST['search']) { + $o .= '
        '; + $o .= '
        '; + $o .= '

        ' . t('Documentation Search') . ' - ' . htmlspecialchars($_REQUEST['search']) . '

        '; + $o .= '
        '; + $o .= '
        '; - $r = search_doc_files($_REQUEST['search']); - if($r) { - $o .= '
          '; - foreach($r as $rr) { - $dirname = dirname($rr['v']); - $fname = basename($rr['v']); - $fname = substr($fname, 0, strrpos($fname, '.')); - $path = trim(substr($dirname, 4), '/'); + $r = search_doc_files($_REQUEST['search']); + if ($r) { + $o .= '
            '; + foreach ($r as $rr) { + $dirname = dirname($rr['v']); + $fname = basename($rr['v']); + $fname = substr($fname, 0, strrpos($fname, '.')); + $path = trim(substr($dirname, 4), '/'); - $o .= '
          • ' . ucwords(str_replace('_',' ',notags($fname))) . '
            ' - . '' . 'help/' . (($path) ? $path . '/' : '') . $fname . '
            ' - . '...' . str_replace('$Projectname', System::get_platform_name(), $rr['text']) . '...

          • '; - } - $o .= '
          '; - $o .= '
        '; - $o .= '
        '; - } + $o .= '
      • ' . ucwords(str_replace('_', ' ', notags($fname))) . '
        ' + . '' . 'help/' . (($path) ? $path . '/' : '') . $fname . '
        ' + . '...' . str_replace('$Projectname', System::get_platform_name(), $rr['text']) . '...

      • '; + } + $o .= '
      '; + $o .= ''; + $o .= ''; + } - return $o; - } - - - if(argc() > 2 && argv(argc()-2) === 'assets') { - $path = ''; - for($x = 1; $x < argc(); $x ++) { - if(strlen($path)) - $path .= '/'; - $path .= argv($x); - } - $realpath = 'doc/' . $path; - //Set the content-type header as appropriate - $imageInfo = getimagesize($realpath); - switch ($imageInfo[2]) { - case IMAGETYPE_JPEG: - header("Content-Type: image/jpeg"); - break; - case IMAGETYPE_GIF: - header("Content-Type: image/gif"); - break; - case IMAGETYPE_PNG: - header("Content-Type: image/png"); - break; - default: - break; - } - header("Content-Length: " . filesize($realpath)); + return $o; + } - // dump the picture and stop the script - readfile($realpath); - killme(); - } - if (argc() === 1) { - $files = self::listdir('doc'); - - if ($files) { - foreach ($files as $file) { - if ((! strpos($file,'/site/')) && file_exists(str_replace('doc/','doc/site/',$file))) { - continue; - } - if (strpos($file,'README')) { - continue; - } - if (preg_match('/\/(..|..\-..)\//',$file,$matches)) { - $language = $matches[1]; - } - else { - $language = t('Unknown language'); - } - if ($language === substr(App::$language,0,2)) { - $language = ''; - } + if (argc() > 2 && argv(argc() - 2) === 'assets') { + $path = ''; + for ($x = 1; $x < argc(); $x++) { + if (strlen($path)) + $path .= '/'; + $path .= argv($x); + } + $realpath = 'doc/' . $path; + //Set the content-type header as appropriate + $imageInfo = getimagesize($realpath); + switch ($imageInfo[2]) { + case IMAGETYPE_JPEG: + header("Content-Type: image/jpeg"); + break; + case IMAGETYPE_GIF: + header("Content-Type: image/gif"); + break; + case IMAGETYPE_PNG: + header("Content-Type: image/png"); + break; + default: + break; + } + header("Content-Length: " . filesize($realpath)); - $link = str_replace( [ 'doc/', '.mc' ], [ 'help/', '' ], $file); - if (strpos($link,'/global/') !== false || strpos($link,'/media/') !== false) { - continue; - } - $content .= '' . (($language) ? " [$language]" : '') . EOL; - } - } - } - else { - $content = get_help_content(); - } - + // dump the picture and stop the script + readfile($realpath); + killme(); + } - return replace_macros(get_markup_template('help.tpl'), array( - '$title' => t('$Projectname Documentation'), - '$tocHeading' => t('Contents'), - '$content' => $content, - '$heading' => $heading, - '$language' => $language - )); - } + if (argc() === 1) { + $files = self::listdir('doc'); - static function listdir($path) { - $results = []; - $handle = opendir($path); - if (! $handle) { - return $results; - } - while (false !== ($file = readdir($handle))) { - if ($file === '.' || $file === '..') { - continue; - } - if (is_dir($path . '/' . $file)) { - $results = array_merge($results, self::listdir($path . '/' . $file)); - } - else { - $results[] = $path . '/' . $file; - } - } - closedir($handle); - return $results; - } + if ($files) { + foreach ($files as $file) { + if ((!strpos($file, '/site/')) && file_exists(str_replace('doc/', 'doc/site/', $file))) { + continue; + } + if (strpos($file, 'README')) { + continue; + } + if (preg_match('/\/(..|..\-..)\//', $file, $matches)) { + $language = $matches[1]; + } else { + $language = t('Unknown language'); + } + if ($language === substr(App::$language, 0, 2)) { + $language = ''; + } + + $link = str_replace(['doc/', '.mc'], ['help/', ''], $file); + if (strpos($link, '/global/') !== false || strpos($link, '/media/') !== false) { + continue; + } + $content .= '' . (($language) ? " [$language]" : '') . EOL; + } + } + } else { + $content = get_help_content(); + } + + + return replace_macros(get_markup_template('help.tpl'), array( + '$title' => t('$Projectname Documentation'), + '$tocHeading' => t('Contents'), + '$content' => $content, + '$heading' => $heading, + '$language' => $language + )); + } + + public static function listdir($path) + { + $results = []; + $handle = opendir($path); + if (!$handle) { + return $results; + } + while (false !== ($file = readdir($handle))) { + if ($file === '.' || $file === '..') { + continue; + } + if (is_dir($path . '/' . $file)) { + $results = array_merge($results, self::listdir($path . '/' . $file)); + } else { + $results[] = $path . '/' . $file; + } + } + closedir($handle); + return $results; + } } diff --git a/Zotlabs/Module/Home.php b/Zotlabs/Module/Home.php index 91ee71d45..51c25cd89 100644 --- a/Zotlabs/Module/Home.php +++ b/Zotlabs/Module/Home.php @@ -12,158 +12,159 @@ use Zotlabs\Web\Controller; require_once('include/conversation.php'); -class Home extends Controller { +class Home extends Controller +{ - function init() { + public function init() + { + $ret = []; - $ret = []; - - call_hooks('home_init',$ret); + call_hooks('home_init', $ret); - if (ActivityStreams::is_as_request()) { - $x = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], Activity::encode_site() ); + if (ActivityStreams::is_as_request()) { + $x = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], Activity::encode_site()); - $headers = []; - $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"' ; - $x['signature'] = LDSignatures::sign($x,[ 'channel_address' => z_root(), 'channel_prvkey' => get_config('system','prvkey') ]); - $ret = json_encode($x, JSON_UNESCAPED_SLASHES); - logger('data: ' . jindent($ret), LOGGER_DATA); - $headers['Date'] = datetime_convert('UTC','UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'); - $headers['Digest'] = HTTPSig::generate_digest_header($ret); - $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; + $headers = []; + $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; + $x['signature'] = LDSignatures::sign($x, ['channel_address' => z_root(), 'channel_prvkey' => get_config('system', 'prvkey')]); + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + logger('data: ' . jindent($ret), LOGGER_DATA); + $headers['Date'] = datetime_convert('UTC', 'UTC', 'now', 'D, d M Y H:i:s \\G\\M\\T'); + $headers['Digest'] = HTTPSig::generate_digest_header($ret); + $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; - $h = HTTPSig::create_sig($headers,get_config('system','prvkey'),z_root()); - HTTPSig::set_headers($h); + $h = HTTPSig::create_sig($headers, get_config('system', 'prvkey'), z_root()); + HTTPSig::set_headers($h); - echo $ret; - killme(); - } + echo $ret; + killme(); + } - if (Libzot::is_zot_request()) { + if (Libzot::is_zot_request()) { - $channel = get_sys_channel(); - $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); + $channel = get_sys_channel(); + $sigdata = HTTPSig::verify(file_get_contents('php://input'), EMPTY_STR, 'zot6'); - if($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { - $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer'] ])); - $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", - dbesc($sigdata['signer']) - ); + if ($sigdata && $sigdata['signer'] && $sigdata['header_valid']) { + $data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash'], 'target_url' => $sigdata['signer']])); + $s = q("select site_crypto, hubloc_sitekey from site left join hubloc on hubloc_url = site_url where hubloc_id_url = '%s' and hubloc_network = 'zot6' limit 1", + dbesc($sigdata['signer']) + ); - if($s && $s[0]['hubloc_sitekey'] && $s[0]['site_crypto']) { - $data = json_encode(Crypto::encapsulate($data,$s[0]['hubloc_sitekey'],Libzot::best_algorithm($s[0]['site_crypto']))); - } - } - else { - $data = json_encode(Libzot::zotinfo([ 'guid_hash' => $channel['channel_hash'] ])); - } + if ($s && $s[0]['hubloc_sitekey'] && $s[0]['site_crypto']) { + $data = json_encode(Crypto::encapsulate($data, $s[0]['hubloc_sitekey'], Libzot::best_algorithm($s[0]['site_crypto']))); + } + } else { + $data = json_encode(Libzot::zotinfo(['guid_hash' => $channel['channel_hash']])); + } - $headers = [ - 'Content-Type' => 'application/x-zot+json', - 'Digest' => HTTPSig::generate_digest_header($data), - '(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'] - ]; - $h = HTTPSig::create_sig($headers,get_config('system','prvkey'),z_root()); - HTTPSig::set_headers($h); - echo $data; - killme(); - } + $headers = [ + 'Content-Type' => 'application/x-zot+json', + 'Digest' => HTTPSig::generate_digest_header($data), + '(request-target)' => strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI'] + ]; + $h = HTTPSig::create_sig($headers, get_config('system', 'prvkey'), z_root()); + HTTPSig::set_headers($h); + echo $data; + killme(); + } - $splash = ((argc() > 1 && argv(1) === 'splash') ? true : false); - - $channel = App::get_channel(); - if (local_channel() && $channel && $channel['xchan_url'] && ! $splash) { - $dest = $channel['channel_startpage']; - if (! $dest) { - $dest = get_pconfig(local_channel(),'system','startpage'); - } - if (! $dest) { - $dest = get_config('system','startpage'); - } - if (! $dest) { - $dest = z_root() . '/stream'; - } - goaway($dest); - } + $splash = ((argc() > 1 && argv(1) === 'splash') ? true : false); - if (remote_channel() && (! $splash) && $_SESSION['atoken']) { - $r = q("select * from atoken where atoken_id = %d", - intval($_SESSION['atoken']) - ); - if ($r) { - $x = channelx_by_n($r[0]['atoken_uid']); - if ($x) { - goaway(z_root() . '/channel/' . $x['channel_address']); - } - } - } + $channel = App::get_channel(); + if (local_channel() && $channel && $channel['xchan_url'] && !$splash) { + $dest = $channel['channel_startpage']; + if (!$dest) { + $dest = get_pconfig(local_channel(), 'system', 'startpage'); + } + if (!$dest) { + $dest = get_config('system', 'startpage'); + } + if (!$dest) { + $dest = z_root() . '/stream'; + } + goaway($dest); + } - - if (get_account_id() && ! $splash) { - goaway(z_root() . '/new_channel'); - } - - } - - - function get() { - - $o = EMPTY_STR; - - if (x($_SESSION,'theme')) { - unset($_SESSION['theme']); - } - if (x($_SESSION,'mobile_theme')) { - unset($_SESSION['mobile_theme']); - } - - $splash = ((argc() > 1 && argv(1) === 'splash') ? true : false); - - call_hooks('home_content',$o); - if ($o) { - return $o; - } - - $frontpage = get_config('system','frontpage'); - if ($frontpage) { - if (strpos($frontpage,'include:') !== false) { - $file = trim(str_replace('include:' , '', $frontpage)); - if (file_exists($file)) { - App::$page['template'] = 'full'; - App::$page['title'] = t('$Projectname'); - $o .= file_get_contents($file); - return $o; - } - } - if (strpos($frontpage,'http') !== 0) { - $frontpage = z_root() . '/' . $frontpage; - } - if (intval(get_config('system','mirror_frontpage'))) { - $o = '' . t('$Projectname') . ''; - echo $o; - killme(); - } - goaway($frontpage); - } - - - $sitename = get_config('system','sitename'); - if ($sitename) { - $o .= '

      ' . sprintf( t('Welcome to %s') ,$sitename) . '

      '; - } - - $loginbox = get_config('system','login_on_homepage'); - if (intval($loginbox) || $loginbox === false) { - $o .= login(true); - } - - return $o; - } + if (remote_channel() && (!$splash) && $_SESSION['atoken']) { + $r = q("select * from atoken where atoken_id = %d", + intval($_SESSION['atoken']) + ); + if ($r) { + $x = channelx_by_n($r[0]['atoken_uid']); + if ($x) { + goaway(z_root() . '/channel/' . $x['channel_address']); + } + } + } + + + if (get_account_id() && !$splash) { + goaway(z_root() . '/new_channel'); + } + + } + + + public function get() + { + + $o = EMPTY_STR; + + if (x($_SESSION, 'theme')) { + unset($_SESSION['theme']); + } + if (x($_SESSION, 'mobile_theme')) { + unset($_SESSION['mobile_theme']); + } + + $splash = ((argc() > 1 && argv(1) === 'splash') ? true : false); + + call_hooks('home_content', $o); + if ($o) { + return $o; + } + + $frontpage = get_config('system', 'frontpage'); + if ($frontpage) { + if (strpos($frontpage, 'include:') !== false) { + $file = trim(str_replace('include:', '', $frontpage)); + if (file_exists($file)) { + App::$page['template'] = 'full'; + App::$page['title'] = t('$Projectname'); + $o .= file_get_contents($file); + return $o; + } + } + if (strpos($frontpage, 'http') !== 0) { + $frontpage = z_root() . '/' . $frontpage; + } + if (intval(get_config('system', 'mirror_frontpage'))) { + $o = '' . t('$Projectname') . ''; + echo $o; + killme(); + } + goaway($frontpage); + } + + + $sitename = get_config('system', 'sitename'); + if ($sitename) { + $o .= '

      ' . sprintf(t('Welcome to %s'), $sitename) . '

      '; + } + + $loginbox = get_config('system', 'login_on_homepage'); + if (intval($loginbox) || $loginbox === false) { + $o .= login(true); + } + + return $o; + } } diff --git a/Zotlabs/Module/Hostxrd.php b/Zotlabs/Module/Hostxrd.php index 727751ad9..ea6740d47 100644 --- a/Zotlabs/Module/Hostxrd.php +++ b/Zotlabs/Module/Hostxrd.php @@ -5,24 +5,26 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Hostxrd extends Controller { +class Hostxrd extends Controller +{ + + public function init() + { + session_write_close(); + header('Access-Control-Allow-Origin: *'); + header("Content-type: application/xrd+xml"); + logger('hostxrd', LOGGER_DEBUG); + + $tpl = get_markup_template('xrd_host.tpl'); + $x = replace_macros(get_markup_template('xrd_host.tpl'), array( + '$zhost' => App::get_hostname(), + '$zroot' => z_root() + )); + $arr = array('xrd' => $x); + call_hooks('hostxrd', $arr); + + echo $arr['xrd']; + killme(); + } - function init() { - session_write_close(); - header('Access-Control-Allow-Origin: *'); - header("Content-type: application/xrd+xml"); - logger('hostxrd',LOGGER_DEBUG); - - $tpl = get_markup_template('xrd_host.tpl'); - $x = replace_macros(get_markup_template('xrd_host.tpl'), array( - '$zhost' => App::get_hostname(), - '$zroot' => z_root() - )); - $arr = array('xrd' => $x); - call_hooks('hostxrd',$arr); - - echo $arr['xrd']; - killme(); - } - } diff --git a/Zotlabs/Module/Hq.php b/Zotlabs/Module/Hq.php index 70a3dbcc9..d9f9a8480 100644 --- a/Zotlabs/Module/Hq.php +++ b/Zotlabs/Module/Hq.php @@ -11,296 +11,296 @@ require_once('include/conversation.php'); require_once('include/acl_selectors.php'); -class Hq extends Controller { +class Hq extends Controller +{ - // State passed in from the Update module. - - public $profile_uid = 0; - public $loading = 0; - public $updating = 0; + // State passed in from the Update module. + + public $profile_uid = 0; + public $loading = 0; + public $updating = 0; - function init() { - if(! local_channel()) - return; + public function init() + { + if (!local_channel()) + return; - App::$profile_uid = local_channel(); - } + App::$profile_uid = local_channel(); + } - function post() { + public function post() + { - if(!local_channel()) - return; + if (!local_channel()) + return; - if($_REQUEST['notify_id']) { - q("update notify set seen = 1 where id = %d and uid = %d", - intval($_REQUEST['notify_id']), - intval(local_channel()) - ); - } + if ($_REQUEST['notify_id']) { + q("update notify set seen = 1 where id = %d and uid = %d", + intval($_REQUEST['notify_id']), + intval(local_channel()) + ); + } - killme(); + killme(); - } + } - function get() { + public function get() + { - if(!local_channel()) - return; + if (!local_channel()) + return; - if($this->loading) - $_SESSION['loadtime_hq'] = datetime_convert(); - - if(argc() > 1 && argv(1) !== 'load') { - $item_hash = argv(1); - } - - if($_REQUEST['mid']) - $item_hash = $_REQUEST['mid']; + if ($this->loading) + $_SESSION['loadtime_hq'] = datetime_convert(); - $item_normal = item_normal(); - $item_normal_update = item_normal_update(); + if (argc() > 1 && argv(1) !== 'load') { + $item_hash = argv(1); + } - if(! $item_hash) { - $r = q("SELECT mid FROM item + if ($_REQUEST['mid']) + $item_hash = $_REQUEST['mid']; + + $item_normal = item_normal(); + $item_normal_update = item_normal_update(); + + if (!$item_hash) { + $r = q("SELECT mid FROM item WHERE uid = %d $item_normal AND mid = parent_mid ORDER BY created DESC LIMIT 1", - intval(local_channel()) - ); + intval(local_channel()) + ); - if($r[0]['mid']) { - $item_hash = gen_link_id($r[0]['mid']); - } - } + if ($r[0]['mid']) { + $item_hash = gen_link_id($r[0]['mid']); + } + } - if($item_hash) { + if ($item_hash) { - $item_hash = unpack_link_id($item_hash); + $item_hash = unpack_link_id($item_hash); - $target_item = null; + $target_item = null; - $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1", - dbesc($item_hash . '%') - ); - - if($r) { - $target_item = $r[0]; - } + $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1", + dbesc($item_hash . '%') + ); - //if the item is to be moderated redirect to /moderate - if($target_item['item_blocked'] == ITEM_MODERATED) { - goaway(z_root() . '/moderate/' . $target_item['id']); - } - - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); + if ($r) { + $target_item = $r[0]; + } - $simple_update = (($this->updating) ? " AND item_unseen = 1 " : ''); - - if($this->updating && $_SESSION['loadtime_hq']) - $simple_update = " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime_hq']) . "' "; - - if($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + //if the item is to be moderated redirect to /moderate + if ($target_item['item_blocked'] == ITEM_MODERATED) { + goaway(z_root() . '/moderate/' . $target_item['id']); + } - $sys = get_sys_channel(); - $sql_extra = item_permissions_sql($sys['channel_id']); + $static = ((array_key_exists('static', $_REQUEST)) ? intval($_REQUEST['static']) : 0); - $sys_item = false; + $simple_update = (($this->updating) ? " AND item_unseen = 1 " : ''); - } - - if(! $this->updating) { - $channel = App::get_channel(); + if ($this->updating && $_SESSION['loadtime_hq']) + $simple_update = " AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime_hq']) . "' "; - $channel_acl = [ - 'allow_cid' => $channel['channel_allow_cid'], - 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ]; + if ($static && $simple_update) + $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; - $x = [ - 'is_owner' => true, - 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), - 'default_location' => $channel['channel_location'], - 'nickname' => $channel['channel_address'], - 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => populate_acl($channel_acl,true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), - 'permissions' => $channel_acl, - 'bang' => '', - 'visitor' => true, - 'profile_uid' => local_channel(), - 'return_path' => 'hq', - 'expanded' => true, - 'editor_autocomplete' => true, - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true, - 'jotnets' => true, - 'reset' => t('Reset form') - ]; + $sys = get_sys_channel(); + $sql_extra = item_permissions_sql($sys['channel_id']); - $o = replace_macros(get_markup_template("hq.tpl"), - [ - '$no_messages' => (($target_item) ? false : true), - '$no_messages_label' => [ t('Welcome to $Projectname!'), t('You have got no unseen posts...') ], - '$editor' => status_editor($x) - ] - ); + $sys_item = false; - } + } - if(! $this->updating && ! $this->loading) { + if (!$this->updating) { + $channel = App::get_channel(); - nav_set_selected('HQ'); + $channel_acl = [ + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ]; - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); + $x = [ + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), + 'permissions' => $channel_acl, + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_channel(), + 'return_path' => 'hq', + 'expanded' => true, + 'editor_autocomplete' => true, + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true, + 'jotnets' => true, + 'reset' => t('Reset form') + ]; - if($target_item) { - // if the target item is not a post (eg a like) we want to address its thread parent - $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']); + $o = replace_macros(get_markup_template("hq.tpl"), + [ + '$no_messages' => (($target_item) ? false : true), + '$no_messages_label' => [t('Welcome to $Projectname!'), t('You have got no unseen posts...')], + '$editor' => status_editor($x) + ] + ); - // if we got a decoded hash we must encode it again before handing to javascript - $mid = gen_link_id($mid); - } - else { - $mid = ''; - } + } - $o .= '
      ' . "\r\n"; - $o .= "\r\n"; - - App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),[ - '$baseurl' => z_root(), - '$pgtype' => 'hq', - '$uid' => local_channel(), - '$gid' => '0', - '$cid' => '0', - '$cmin' => '0', - '$cmax' => '99', - '$star' => '0', - '$liked' => '0', - '$conv' => '0', - '$spam' => '0', - '$fh' => '0', - '$dm' => '0', - '$nouveau' => '0', - '$wall' => '0', - '$draft' => '0', - '$static' => $static, - '$page' => 1, - '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), - '$search' => '', - '$xchan' => '', - '$order' => '', - '$file' => '', - '$cats' => '', - '$tags' => '', - '$dend' => '', - '$dbegin' => '', - '$verb' => '', - '$net' => '', - '$mid' => (($mid) ? urlencode($mid) : '') - ]); - } + if (!$this->updating && !$this->loading) { - $updateable = false; + nav_set_selected('HQ'); - if($this->loading && $target_item) { - $r = null; + $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); - $r = q("SELECT item.id AS item_id FROM item + if ($target_item) { + // if the target item is not a post (eg a like) we want to address its thread parent + $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']); + + // if we got a decoded hash we must encode it again before handing to javascript + $mid = gen_link_id($mid); + } else { + $mid = ''; + } + + $o .= '
      ' . "\r\n"; + $o .= "\r\n"; + + App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), [ + '$baseurl' => z_root(), + '$pgtype' => 'hq', + '$uid' => local_channel(), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '0', + '$cmax' => '99', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '0', + '$dm' => '0', + '$nouveau' => '0', + '$wall' => '0', + '$draft' => '0', + '$static' => $static, + '$page' => 1, + '$list' => ((x($_REQUEST, 'list')) ? intval($_REQUEST['list']) : 0), + '$search' => '', + '$xchan' => '', + '$order' => '', + '$file' => '', + '$cats' => '', + '$tags' => '', + '$dend' => '', + '$dbegin' => '', + '$verb' => '', + '$net' => '', + '$mid' => (($mid) ? urlencode($mid) : '') + ]); + } + + $updateable = false; + + if ($this->loading && $target_item) { + $r = null; + + $r = q("SELECT item.id AS item_id FROM item WHERE uid = %d AND mid = '%s' $item_normal LIMIT 1", - intval(local_channel()), - dbesc($target_item['parent_mid']) - ); + intval(local_channel()), + dbesc($target_item['parent_mid']) + ); - if($r) { - $updateable = true; - } + if ($r) { + $updateable = true; + } - if(!$r) { - $sys_item = true; + if (!$r) { + $sys_item = true; - $r = q("SELECT item.id AS item_id FROM item + $r = q("SELECT item.id AS item_id FROM item LEFT JOIN abook ON item.author_xchan = abook.abook_xchan WHERE mid = '%s' AND item.uid = %d $item_normal AND (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra LIMIT 1", - dbesc($target_item['parent_mid']), - intval($sys['channel_id']) - ); - } - } - elseif($this->updating && $target_item) { - $r = null; + dbesc($target_item['parent_mid']), + intval($sys['channel_id']) + ); + } + } elseif ($this->updating && $target_item) { + $r = null; - $r = q("SELECT item.parent AS item_id FROM item + $r = q("SELECT item.parent AS item_id FROM item WHERE uid = %d AND parent_mid = '%s' $item_normal_update $simple_update LIMIT 1", - intval(local_channel()), - dbesc($target_item['parent_mid']) - ); + intval(local_channel()), + dbesc($target_item['parent_mid']) + ); - if($r) { - $updateable = true; - } + if ($r) { + $updateable = true; + } - if(!$r) { - $sys_item = true; + if (!$r) { + $sys_item = true; - $r = q("SELECT item.parent AS item_id FROM item + $r = q("SELECT item.parent AS item_id FROM item LEFT JOIN abook ON item.author_xchan = abook.abook_xchan WHERE mid = '%s' AND item.uid = %d $item_normal_update $simple_update AND (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra LIMIT 1", - dbesc($target_item['parent_mid']), - intval($sys['channel_id']) - ); - } + dbesc($target_item['parent_mid']), + intval($sys['channel_id']) + ); + } - $_SESSION['loadtime_hq'] = datetime_convert(); - } - else { - $r = []; - } - - if($r) { - $items = q("SELECT item.*, item.id AS item_id + $_SESSION['loadtime_hq'] = datetime_convert(); + } else { + $r = []; + } + + if ($r) { + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE parent = '%s' $item_normal ", - dbesc($r[0]['item_id']) - ); - - xchan_query($items,true,(($sys_item) ? local_channel() : 0)); - $items = fetch_post_tags($items,true); - $items = conv_sort($items,'created'); - } - else { - $items = []; - } + dbesc($r[0]['item_id']) + ); - $o .= conversation($items, 'hq', $this->updating, 'client'); + xchan_query($items, true, (($sys_item) ? local_channel() : 0)); + $items = fetch_post_tags($items, true); + $items = conv_sort($items, 'created'); + } else { + $items = []; + } - if($updateable) { - $x = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d AND parent = %d ", - intval(local_channel()), - intval($r[0]['item_id']) - ); - } + $o .= conversation($items, 'hq', $this->updating, 'client'); - $o .= '
      '; + if ($updateable) { + $x = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d AND parent = %d ", + intval(local_channel()), + intval($r[0]['item_id']) + ); + } - return $o; + $o .= '
      '; - } + return $o; + + } } diff --git a/Zotlabs/Module/Id.php b/Zotlabs/Module/Id.php index ecb10dbeb..283327ce0 100644 --- a/Zotlabs/Module/Id.php +++ b/Zotlabs/Module/Id.php @@ -27,93 +27,94 @@ require_once('include/bbcode.php'); require_once('include/security.php'); -class Id extends Controller { +class Id extends Controller +{ - function init() { + public function init() + { - if (Libzot::is_zot_request()) { + if (Libzot::is_zot_request()) { - $conversation = false; + $conversation = false; - $request_portable_id = argv(1); - if(argc() > 2) { - $item_id = argv(2); - } + $request_portable_id = argv(1); + if (argc() > 2) { + $item_id = argv(2); + } - $portable_id = EMPTY_STR; + $portable_id = EMPTY_STR; - $sigdata = HTTPSig::verify(EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - } + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + } - $chan = channelx_by_hash($request_portable_id); + $chan = channelx_by_hash($request_portable_id); - if ($chan) { - $channel_id = $chan['channel_id']; - if (! $item_id) { - $handler = new Channel(); - App::$argc = 2; - App::$argv[0] = 'channel'; - App::$argv[1] = $chan['channel_address']; - $handler->init(); - } - } - else { - http_status_exit(404, 'Not found'); - } + if ($chan) { + $channel_id = $chan['channel_id']; + if (!$item_id) { + $handler = new Channel(); + App::$argc = 2; + App::$argv[0] = 'channel'; + App::$argv[1] = $chan['channel_address']; + $handler->init(); + } + } else { + http_status_exit(404, 'Not found'); + } - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 "; + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 "; - $sql_extra = item_permissions_sql(0); + $sql_extra = item_permissions_sql(0); - $r = q("select * from item where uuid = '%s' $item_normal $sql_extra and uid = %d limit 1", - dbesc($item_id), - intval($channel_id) - ); - if(! $r) { + $r = q("select * from item where uuid = '%s' $item_normal $sql_extra and uid = %d limit 1", + dbesc($item_id), + intval($channel_id) + ); + if (!$r) { - $r = q("select * from item where uuid = '%s' $item_normal and uid = %d limit 1", - dbesc($item_id), - intval($channel_id) - ); - if($r) { - http_status_exit(403, 'Forbidden'); - } - http_status_exit(404, 'Not found'); - } + $r = q("select * from item where uuid = '%s' $item_normal and uid = %d limit 1", + dbesc($item_id), + intval($channel_id) + ); + if ($r) { + http_status_exit(403, 'Forbidden'); + } + http_status_exit(404, 'Not found'); + } - if(! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) - http_status_exit(403, 'Forbidden'); + if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) + http_status_exit(403, 'Forbidden'); - xchan_query($r,true); - $items = fetch_post_tags($r,true); + xchan_query($r, true); + $items = fetch_post_tags($r, true); - $i = Activity::encode_item($items[0],( get_config('system','activitypub', ACTIVITYPUB_ENABLED) ? true : false )); + $i = Activity::encode_item($items[0], (get_config('system', 'activitypub', ACTIVITYPUB_ENABLED) ? true : false)); - if(! $i) - http_status_exit(404, 'Not found'); + if (!$i) + http_status_exit(404, 'Not found'); - $x = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], $i); + $x = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], $i); - $headers = []; - $headers['Content-Type'] = 'application/x-zot+json' ; - $ret = json_encode($x, JSON_UNESCAPED_SLASHES); - $headers['Digest'] = HTTPSig::generate_digest_header($ret); - $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; - $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan)); - HTTPSig::set_headers($h); - echo $ret; - killme(); + $headers = []; + $headers['Content-Type'] = 'application/x-zot+json'; + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + $headers['Digest'] = HTTPSig::generate_digest_header($ret); + $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; + $h = HTTPSig::create_sig($headers, $chan['channel_prvkey'], channel_url($chan)); + HTTPSig::set_headers($h); + echo $ret; + killme(); - } + } - } + } } diff --git a/Zotlabs/Module/Impel.php b/Zotlabs/Module/Impel.php index 12319e2b3..0a2c248d0 100644 --- a/Zotlabs/Module/Impel.php +++ b/Zotlabs/Module/Impel.php @@ -11,192 +11,190 @@ use Zotlabs\Web\Controller; require_once('include/menu.php'); -class Impel extends Controller { +class Impel extends Controller +{ - function init() { - - $ret = array('success' => false); - - if(! local_channel()) - json_return_and_die($ret); - - logger('impel: ' . print_r($_REQUEST,true), LOGGER_DATA); - - $elm = $_REQUEST['element']; - $x = base64url_decode($elm); - if(! $x) - json_return_and_die($ret); - - $j = json_decode($x,true); - if(! $j) - json_return_and_die($ret); - - // logger('element: ' . print_r($j,true)); + public function init() + { - $channel = App::get_channel(); - - $arr = []; - $is_menu = false; - - // a portable menu has its links rewritten with the local baseurl - $portable_menu = false; - - switch($j['type']) { - case 'webpage': - $arr['item_type'] = ITEM_TYPE_WEBPAGE; - $namespace = 'WEBPAGE'; - $installed_type = t('webpage'); - break; - case 'block': - $arr['item_type'] = ITEM_TYPE_BLOCK; - $namespace = 'BUILDBLOCK'; - $installed_type = t('block'); - break; - case 'layout': - $arr['item_type'] = ITEM_TYPE_PDL; - $namespace = 'PDL'; - $installed_type = t('layout'); - break; - case 'portable-menu': - $portable_menu = true; - // fall through - case 'menu': - $is_menu = true; - $installed_type = t('menu'); - break; - default: - logger('mod_impel: unrecognised element type' . print_r($j,true)); - break; - } - - if($is_menu) { - $m = []; - $m['menu_channel_id'] = local_channel(); - $m['menu_name'] = $j['pagetitle']; - $m['menu_desc'] = $j['desc']; - if($j['created']) - $m['menu_created'] = datetime_convert($j['created']); - if($j['edited']) - $m['menu_edited'] = datetime_convert($j['edited']); - - $m['menu_flags'] = 0; - if($j['flags']) { - if(in_array('bookmark',$j['flags'])) - $m['menu_flags'] |= MENU_BOOKMARK; - if(in_array('system',$j['flags'])) - $m['menu_flags'] |= MENU_SYSTEM; - - } - - $menu_id = menu_create($m); - - if($menu_id) { - if(is_array($j['items'])) { - foreach($j['items'] as $it) { - $mitem = []; - - $mitem['mitem_link'] = str_replace('[channelurl]',z_root() . '/channel/' . $channel['channel_address'],$it['link']); - $mitem['mitem_link'] = str_replace('[pageurl]',z_root() . '/page/' . $channel['channel_address'],$it['link']); - $mitem['mitem_link'] = str_replace('[cloudurl]',z_root() . '/cloud/' . $channel['channel_address'],$it['link']); - $mitem['mitem_link'] = str_replace('[baseurl]',z_root(),$it['link']); + $ret = array('success' => false); - $mitem['mitem_desc'] = escape_tags($it['desc']); - $mitem['mitem_order'] = intval($it['order']); - if(is_array($it['flags'])) { - $mitem['mitem_flags'] = 0; - if(in_array('zid',$it['flags'])) - $mitem['mitem_flags'] |= MENU_ITEM_ZID; - if(in_array('new-window',$it['flags'])) - $mitem['mitem_flags'] |= MENU_ITEM_NEWWIN; - if(in_array('chatroom',$it['flags'])) - $mitem['mitem_flags'] |= MENU_ITEM_CHATROOM; - } - menu_add_item($menu_id,local_channel(),$mitem); - } - if($j['edited']) { - $x = q("update menu set menu_edited = '%s' where menu_id = %d and menu_channel_id = %d", - dbesc(datetime_convert('UTC','UTC',$j['edited'])), - intval($menu_id), - intval(local_channel()) - ); - } - } - $ret['success'] = true; - } - $x = $ret; - } - else { - $arr['uid'] = local_channel(); - $arr['aid'] = $channel['channel_account_id']; - $arr['title'] = $j['title']; - $arr['body'] = $j['body']; - $arr['term'] = $j['term']; - $arr['layout_mid'] = $j['layout_mid']; - $arr['created'] = datetime_convert('UTC','UTC', $j['created']); - $arr['edited'] = datetime_convert('UTC','UTC',$j['edited']); - $arr['owner_xchan'] = get_observer_hash(); - $arr['author_xchan'] = (($j['author_xchan']) ? $j['author_xchan'] : get_observer_hash()); - $arr['mimetype'] = (($j['mimetype']) ? $j['mimetype'] : 'text/bbcode'); - - if(! $j['mid']) { - $j['uuid'] = new_uuid(); - $j['mid'] = z_root() . '/item/' . $j['uuid']; - } - - $arr['uuid'] = $j['uuid']; - $arr['mid'] = $arr['parent_mid'] = $j['mid']; - - - if($j['pagetitle']) { - $pagetitle = strtolower(URLify::transliterate($j['pagetitle'])); - } - - // Verify ability to use html or php!!! - - $execflag = ((intval($channel['channel_id']) == intval(local_channel()) && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false); + if (!local_channel()) + json_return_and_die($ret); - $i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1", - dbesc($arr['mid']), - intval(local_channel()) - ); + logger('impel: ' . print_r($_REQUEST, true), LOGGER_DATA); - IConfig::Set($arr,'system',$namespace,(($pagetitle) ? $pagetitle : substr($arr['mid'],0,16)),true); - - if($i) { - $arr['id'] = $i[0]['id']; - // don't update if it has the same timestamp as the original - if($arr['edited'] > $i[0]['edited']) - $x = item_store_update($arr,$execflag); - } - else { - if(($i) && (intval($i[0]['item_deleted']))) { - // was partially deleted already, finish it off - q("delete from item where mid = '%s' and uid = %d", - dbesc($arr['mid']), - intval(local_channel()) - ); - } - else - $x = item_store($arr,$execflag); - } - - if($x && $x['success']) { - $item_id = $x['item_id']; - } - } - - if($x['success']) { - $ret['success'] = true; - info( sprintf( t('%s element installed'), $installed_type)); - } - else { - notice( sprintf( t('%s element installation failed'), $installed_type)); - } - - //??? should perhaps return ret? + $elm = $_REQUEST['element']; + $x = base64url_decode($elm); + if (!$x) + json_return_and_die($ret); + + $j = json_decode($x, true); + if (!$j) + json_return_and_die($ret); + + // logger('element: ' . print_r($j,true)); + + $channel = App::get_channel(); + + $arr = []; + $is_menu = false; + + // a portable menu has its links rewritten with the local baseurl + $portable_menu = false; + + switch ($j['type']) { + case 'webpage': + $arr['item_type'] = ITEM_TYPE_WEBPAGE; + $namespace = 'WEBPAGE'; + $installed_type = t('webpage'); + break; + case 'block': + $arr['item_type'] = ITEM_TYPE_BLOCK; + $namespace = 'BUILDBLOCK'; + $installed_type = t('block'); + break; + case 'layout': + $arr['item_type'] = ITEM_TYPE_PDL; + $namespace = 'PDL'; + $installed_type = t('layout'); + break; + case 'portable-menu': + $portable_menu = true; + // fall through + case 'menu': + $is_menu = true; + $installed_type = t('menu'); + break; + default: + logger('mod_impel: unrecognised element type' . print_r($j, true)); + break; + } + + if ($is_menu) { + $m = []; + $m['menu_channel_id'] = local_channel(); + $m['menu_name'] = $j['pagetitle']; + $m['menu_desc'] = $j['desc']; + if ($j['created']) + $m['menu_created'] = datetime_convert($j['created']); + if ($j['edited']) + $m['menu_edited'] = datetime_convert($j['edited']); + + $m['menu_flags'] = 0; + if ($j['flags']) { + if (in_array('bookmark', $j['flags'])) + $m['menu_flags'] |= MENU_BOOKMARK; + if (in_array('system', $j['flags'])) + $m['menu_flags'] |= MENU_SYSTEM; + + } + + $menu_id = menu_create($m); + + if ($menu_id) { + if (is_array($j['items'])) { + foreach ($j['items'] as $it) { + $mitem = []; + + $mitem['mitem_link'] = str_replace('[channelurl]', z_root() . '/channel/' . $channel['channel_address'], $it['link']); + $mitem['mitem_link'] = str_replace('[pageurl]', z_root() . '/page/' . $channel['channel_address'], $it['link']); + $mitem['mitem_link'] = str_replace('[cloudurl]', z_root() . '/cloud/' . $channel['channel_address'], $it['link']); + $mitem['mitem_link'] = str_replace('[baseurl]', z_root(), $it['link']); + + $mitem['mitem_desc'] = escape_tags($it['desc']); + $mitem['mitem_order'] = intval($it['order']); + if (is_array($it['flags'])) { + $mitem['mitem_flags'] = 0; + if (in_array('zid', $it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_ZID; + if (in_array('new-window', $it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_NEWWIN; + if (in_array('chatroom', $it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_CHATROOM; + } + menu_add_item($menu_id, local_channel(), $mitem); + } + if ($j['edited']) { + $x = q("update menu set menu_edited = '%s' where menu_id = %d and menu_channel_id = %d", + dbesc(datetime_convert('UTC', 'UTC', $j['edited'])), + intval($menu_id), + intval(local_channel()) + ); + } + } + $ret['success'] = true; + } + $x = $ret; + } else { + $arr['uid'] = local_channel(); + $arr['aid'] = $channel['channel_account_id']; + $arr['title'] = $j['title']; + $arr['body'] = $j['body']; + $arr['term'] = $j['term']; + $arr['layout_mid'] = $j['layout_mid']; + $arr['created'] = datetime_convert('UTC', 'UTC', $j['created']); + $arr['edited'] = datetime_convert('UTC', 'UTC', $j['edited']); + $arr['owner_xchan'] = get_observer_hash(); + $arr['author_xchan'] = (($j['author_xchan']) ? $j['author_xchan'] : get_observer_hash()); + $arr['mimetype'] = (($j['mimetype']) ? $j['mimetype'] : 'text/bbcode'); + + if (!$j['mid']) { + $j['uuid'] = new_uuid(); + $j['mid'] = z_root() . '/item/' . $j['uuid']; + } + + $arr['uuid'] = $j['uuid']; + $arr['mid'] = $arr['parent_mid'] = $j['mid']; + + + if ($j['pagetitle']) { + $pagetitle = strtolower(URLify::transliterate($j['pagetitle'])); + } + + // Verify ability to use html or php!!! + + $execflag = ((intval($channel['channel_id']) == intval(local_channel()) && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false); + + $i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['mid']), + intval(local_channel()) + ); + + IConfig::Set($arr, 'system', $namespace, (($pagetitle) ? $pagetitle : substr($arr['mid'], 0, 16)), true); + + if ($i) { + $arr['id'] = $i[0]['id']; + // don't update if it has the same timestamp as the original + if ($arr['edited'] > $i[0]['edited']) + $x = item_store_update($arr, $execflag); + } else { + if (($i) && (intval($i[0]['item_deleted']))) { + // was partially deleted already, finish it off + q("delete from item where mid = '%s' and uid = %d", + dbesc($arr['mid']), + intval(local_channel()) + ); + } else + $x = item_store($arr, $execflag); + } + + if ($x && $x['success']) { + $item_id = $x['item_id']; + } + } + + if ($x['success']) { + $ret['success'] = true; + info(sprintf(t('%s element installed'), $installed_type)); + } else { + notice(sprintf(t('%s element installation failed'), $installed_type)); + } + + //??? should perhaps return ret? + + json_return_and_die(true); + + } - json_return_and_die(true); - - } - } diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php index a61bb23a6..9040c0f96 100644 --- a/Zotlabs/Module/Import.php +++ b/Zotlabs/Module/Import.php @@ -23,517 +23,509 @@ require_once('include/photo_factory.php'); * Import a channel, either by direct file upload or via * connection to another server. */ - -class Import extends Controller { +class Import extends Controller +{ - /** - * @brief Import channel into account. - * - * @param int $account_id - */ - function import_account($account_id) { + /** + * @brief Import channel into account. + * + * @param int $account_id + */ + public function import_account($account_id) + { - if (! $account_id) { - logger('No account ID supplied'); - return; - } + if (!$account_id) { + logger('No account ID supplied'); + return; + } - $max_friends = account_service_class_fetch($account_id,'total_channels'); - $max_feeds = account_service_class_fetch($account_id,'total_feeds'); - $data = null; - $seize = ((x($_REQUEST,'make_primary')) ? intval($_REQUEST['make_primary']) : 0); - $import_posts = ((x($_REQUEST,'import_posts')) ? intval($_REQUEST['import_posts']) : 0); - $moving = false; // intval($_REQUEST['moving']); - $src = $_FILES['filename']['tmp_name']; - $filename = basename($_FILES['filename']['name']); - $filesize = intval($_FILES['filename']['size']); - $filetype = $_FILES['filename']['type']; - $newname = trim(strtolower($_REQUEST['newname'])); + $max_friends = account_service_class_fetch($account_id, 'total_channels'); + $max_feeds = account_service_class_fetch($account_id, 'total_feeds'); + $data = null; + $seize = ((x($_REQUEST, 'make_primary')) ? intval($_REQUEST['make_primary']) : 0); + $import_posts = ((x($_REQUEST, 'import_posts')) ? intval($_REQUEST['import_posts']) : 0); + $moving = false; // intval($_REQUEST['moving']); + $src = $_FILES['filename']['tmp_name']; + $filename = basename($_FILES['filename']['name']); + $filesize = intval($_FILES['filename']['size']); + $filetype = $_FILES['filename']['type']; + $newname = trim(strtolower($_REQUEST['newname'])); - // import channel from file - if ($src) { + // import channel from file + if ($src) { - // This is OS specific and could also fail if your tmpdir isn't very - // large mostly used for Diaspora which exports gzipped files. + // This is OS specific and could also fail if your tmpdir isn't very + // large mostly used for Diaspora which exports gzipped files. - if (strpos($filename,'.gz')){ - @rename($src,$src . '.gz'); - @system('gunzip ' . escapeshellarg($src . '.gz')); - } + if (strpos($filename, '.gz')) { + @rename($src, $src . '.gz'); + @system('gunzip ' . escapeshellarg($src . '.gz')); + } - if ($filesize) { - $data = @file_get_contents($src); - } - unlink($src); - } + if ($filesize) { + $data = @file_get_contents($src); + } + unlink($src); + } - // import channel from another server - if (! $src) { - $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); - if (! $old_address) { - logger('Nothing to import.'); - notice( t('Nothing to import.') . EOL); - return; - } - elseif (strpos($old_address, 'ï¼ ')) { - // if you copy the identity address from your profile page, make it work for convenience - WARNING: this is a utf-8 variant and NOT an ASCII ampersand. Please do not edit. - $old_address = str_replace('ï¼ ', '@', $old_address); - } + // import channel from another server + if (!$src) { + $old_address = ((x($_REQUEST, 'old_address')) ? $_REQUEST['old_address'] : ''); + if (!$old_address) { + logger('Nothing to import.'); + notice(t('Nothing to import.') . EOL); + return; + } elseif (strpos($old_address, 'ï¼ ')) { + // if you copy the identity address from your profile page, make it work for convenience - WARNING: this is a utf-8 variant and NOT an ASCII ampersand. Please do not edit. + $old_address = str_replace('ï¼ ', '@', $old_address); + } - $email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : ''); - $password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : ''); + $email = ((x($_REQUEST, 'email')) ? $_REQUEST['email'] : ''); + $password = ((x($_REQUEST, 'password')) ? $_REQUEST['password'] : ''); - $channelname = substr($old_address,0,strpos($old_address,'@')); - $servername = substr($old_address,strpos($old_address,'@')+1); + $channelname = substr($old_address, 0, strpos($old_address, '@')); + $servername = substr($old_address, strpos($old_address, '@') + 1); - $api_path = probe_api_path($servername); - if (! $api_path) { - notice( t('Unable to download data from old server') . EOL); - return; - } + $api_path = probe_api_path($servername); + if (!$api_path) { + notice(t('Unable to download data from old server') . EOL); + return; + } - $api_path .= 'channel/export/basic?f=&zap_compat=1&channel=' . $channelname; - if ($import_posts) { - $api_path .= '&posts=1'; - } - $binary = false; - $redirects = 0; - $opts = [ 'http_auth' => $email . ':' . $password ]; - $ret = z_fetch_url($api_path, $binary, $redirects, $opts); - if ($ret['success']) { - $data = $ret['body']; - } - else { - notice( t('Unable to download data from old server') . EOL); - return; - } - } + $api_path .= 'channel/export/basic?f=&zap_compat=1&channel=' . $channelname; + if ($import_posts) { + $api_path .= '&posts=1'; + } + $binary = false; + $redirects = 0; + $opts = ['http_auth' => $email . ':' . $password]; + $ret = z_fetch_url($api_path, $binary, $redirects, $opts); + if ($ret['success']) { + $data = $ret['body']; + } else { + notice(t('Unable to download data from old server') . EOL); + return; + } + } - if (! $data) { - logger('Empty import file.'); - notice( t('Imported file is empty.') . EOL); - return; - } + if (!$data) { + logger('Empty import file.'); + notice(t('Imported file is empty.') . EOL); + return; + } - $data = json_decode($data,true); + $data = json_decode($data, true); - //logger('import: data: ' . print_r($data,true)); - //print_r($data); + //logger('import: data: ' . print_r($data,true)); + //print_r($data); - // handle Friendica export - - if (array_path_exists('user/parent-uid',$data)) { + // handle Friendica export - $settings = [ 'account_id' => $account_id, 'sieze' => 1, 'newname' => $newname ]; - $f = new Friendica($data, $settings); - - return; - } + if (array_path_exists('user/parent-uid', $data)) { - if (! array_key_exists('compatibility',$data)) { - call_hooks('import_foreign_channel_data',$data); - if ($data['handled']) { - return; - } - } + $settings = ['account_id' => $account_id, 'sieze' => 1, 'newname' => $newname]; + $f = new Friendica($data, $settings); - $codebase = 'zap'; + return; + } - if ((! array_path_exists('compatibility/codebase',$data)) || $data['compatibility']['codebase'] !== $codebase) { - notice('Data export format is not compatible with this software'); - return; - } + if (!array_key_exists('compatibility', $data)) { + call_hooks('import_foreign_channel_data', $data); + if ($data['handled']) { + return; + } + } - if ($moving) { - $seize = 1; - } + $codebase = 'zap'; - // import channel + if ((!array_path_exists('compatibility/codebase', $data)) || $data['compatibility']['codebase'] !== $codebase) { + notice('Data export format is not compatible with this software'); + return; + } - $relocate = ((array_key_exists('relocate',$data)) ? $data['relocate'] : null); + if ($moving) { + $seize = 1; + } - if (array_key_exists('channel',$data)) { + // import channel - $max_identities = account_service_class_fetch($account_id,'total_identities'); + $relocate = ((array_key_exists('relocate', $data)) ? $data['relocate'] : null); - if ($max_identities !== false) { - $r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 ", - intval($account_id) - ); - if ($r && count($r) > $max_identities) { - notice( sprintf( t('Your service plan only allows %d channels.'), $max_identities) . EOL); - return; - } - } + if (array_key_exists('channel', $data)) { + + $max_identities = account_service_class_fetch($account_id, 'total_identities'); + + if ($max_identities !== false) { + $r = q("select channel_id from channel where channel_account_id = %d and channel_removed = 0 ", + intval($account_id) + ); + if ($r && count($r) > $max_identities) { + notice(sprintf(t('Your service plan only allows %d channels.'), $max_identities) . EOL); + return; + } + } if ($newname) { - $x = false; + $x = false; - if (get_config('system','unicode_usernames')) { - $x = punify(mb_strtolower($newname)); - } + if (get_config('system', 'unicode_usernames')) { + $x = punify(mb_strtolower($newname)); + } - if ((! $x) || strlen($x) > 64) { - $x = strtolower(URLify::transliterate($newname)); - } - else { - $x = $newname; - } - $newname = $x; - } + if ((!$x) || strlen($x) > 64) { + $x = strtolower(URLify::transliterate($newname)); + } else { + $x = $newname; + } + $newname = $x; + } - $channel = import_channel($data['channel'], $account_id, $seize, $newname); - } - else { - $moving = false; - $channel = App::get_channel(); - } + $channel = import_channel($data['channel'], $account_id, $seize, $newname); + } else { + $moving = false; + $channel = App::get_channel(); + } - if (! $channel) { - logger('Channel not found. ' . print_r($channel,true)); - notice( t('No channel. Import failed.') . EOL); - return; - } + if (!$channel) { + logger('Channel not found. ' . print_r($channel, true)); + notice(t('No channel. Import failed.') . EOL); + return; + } - if (is_array($data['config'])) { - import_config($channel,$data['config']); - } + if (is_array($data['config'])) { + import_config($channel, $data['config']); + } - logger('import step 2'); + logger('import step 2'); - if (array_key_exists('channel',$data)) { - if ($data['photo']) { - import_channel_photo(base64url_decode($data['photo']['data']),$data['photo']['type'],$account_id,$channel['channel_id']); - } + if (array_key_exists('channel', $data)) { + if ($data['photo']) { + import_channel_photo(base64url_decode($data['photo']['data']), $data['photo']['type'], $account_id, $channel['channel_id']); + } - if (is_array($data['profile'])) { - import_profiles($channel,$data['profile']); - } - } + if (is_array($data['profile'])) { + import_profiles($channel, $data['profile']); + } + } - logger('import step 3'); + logger('import step 3'); - // import xchans and contact photos - // This *must* be done before importing hublocs - - if (array_key_exists('channel',$data) && $seize) { + // import xchans and contact photos + // This *must* be done before importing hublocs - // replace any existing xchan we may have on this site if we're seizing control + if (array_key_exists('channel', $data) && $seize) { - $r = q("delete from xchan where xchan_hash = '%s'", - dbesc($channel['channel_hash']) - ); + // replace any existing xchan we may have on this site if we're seizing control - $r = xchan_store_lowlevel( - [ - 'xchan_hash' => $channel['channel_hash'], - 'xchan_guid' => $channel['channel_guid'], - 'xchan_guid_sig' => $channel['channel_guid_sig'], - 'xchan_pubkey' => $channel['channel_pubkey'], - 'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'], - 'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'], - 'xchan_photo_s' => z_root() . "/photo/profile/s/" . $channel['channel_id'], - 'xchan_addr' => channel_reddress($channel), - 'xchan_url' => z_root() . '/channel/' . $channel['channel_address'], - 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'], - 'xchan_follow' => z_root() . '/follow?f=&url=%s', - 'xchan_name' => $channel['channel_name'], - 'xchan_network' => 'zot6', - 'xchan_updated' => datetime_convert(), - 'xchan_photo_date' => datetime_convert(), - 'xchan_name_date' => datetime_convert() - ] - ); - } + $r = q("delete from xchan where xchan_hash = '%s'", + dbesc($channel['channel_hash']) + ); - logger('import step 4'); + $r = xchan_store_lowlevel( + [ + 'xchan_hash' => $channel['channel_hash'], + 'xchan_guid' => $channel['channel_guid'], + 'xchan_guid_sig' => $channel['channel_guid_sig'], + 'xchan_pubkey' => $channel['channel_pubkey'], + 'xchan_photo_l' => z_root() . "/photo/profile/l/" . $channel['channel_id'], + 'xchan_photo_m' => z_root() . "/photo/profile/m/" . $channel['channel_id'], + 'xchan_photo_s' => z_root() . "/photo/profile/s/" . $channel['channel_id'], + 'xchan_addr' => channel_reddress($channel), + 'xchan_url' => z_root() . '/channel/' . $channel['channel_address'], + 'xchan_connurl' => z_root() . '/poco/' . $channel['channel_address'], + 'xchan_follow' => z_root() . '/follow?f=&url=%s', + 'xchan_name' => $channel['channel_name'], + 'xchan_network' => 'zot6', + 'xchan_updated' => datetime_convert(), + 'xchan_photo_date' => datetime_convert(), + 'xchan_name_date' => datetime_convert() + ] + ); + } - // import xchans - $xchans = $data['xchan']; - if ($xchans) { - foreach ($xchans as $xchan) { + logger('import step 4'); - // Provide backward compatibility for zot11 based projects - - if ($xchan['xchan_network'] === 'nomad' && version_compare(ZOT_REVISION, '10.0') <= 0) { - $xchan['xchan_network'] = 'zot6'; - } + // import xchans + $xchans = $data['xchan']; + if ($xchans) { + foreach ($xchans as $xchan) { - $hash = Libzot::make_xchan_hash($xchan['xchan_guid'],$xchan['xchan_pubkey']); + // Provide backward compatibility for zot11 based projects - if (in_array($xchan['xchan_network'],['nomad','zot6']) && $hash !== $xchan['xchan_hash']) { - logger('forged xchan: ' . print_r($xchan,true)); - continue; - } + if ($xchan['xchan_network'] === 'nomad' && version_compare(ZOT_REVISION, '10.0') <= 0) { + $xchan['xchan_network'] = 'zot6'; + } - $r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1", - dbesc($xchan['xchan_hash']) - ); - if ($r) { - continue; - } - xchan_store_lowlevel($xchan); + $hash = Libzot::make_xchan_hash($xchan['xchan_guid'], $xchan['xchan_pubkey']); + + if (in_array($xchan['xchan_network'], ['nomad', 'zot6']) && $hash !== $xchan['xchan_hash']) { + logger('forged xchan: ' . print_r($xchan, true)); + continue; + } + + $r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1", + dbesc($xchan['xchan_hash']) + ); + if ($r) { + continue; + } + xchan_store_lowlevel($xchan); - if ($xchan['xchan_hash'] === $channel['channel_hash']) { - $r = q("update xchan set xchan_updated = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']), - dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']), - dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), - dbesc($xchan['xchan_hash']) - ); - } - else { - $photos = import_remote_xchan_photo($xchan['xchan_photo_l'],$xchan['xchan_hash']); - if ($photos) { - if ($photos[4]) { - $photodate = NULL_DATE; - } - else { - $photodate = $xchan['xchan_photo_date']; - } + if ($xchan['xchan_hash'] === $channel['channel_hash']) { + $r = q("update xchan set xchan_updated = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), + dbesc($xchan['xchan_hash']) + ); + } else { + $photos = import_remote_xchan_photo($xchan['xchan_photo_l'], $xchan['xchan_hash']); + if ($photos) { + if ($photos[4]) { + $photodate = NULL_DATE; + } else { + $photodate = $xchan['xchan_photo_date']; + } - $r = q("update xchan set xchan_updated = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc($photos[0]), - dbesc($photos[1]), - dbesc($photos[2]), - dbesc($photos[3]), - dbesc($photodate), - dbesc($xchan['xchan_hash']) - ); - } - } - } + $r = q("update xchan set xchan_updated = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($photodate), + dbesc($xchan['xchan_hash']) + ); + } + } + } - logger('import step 5'); - } + logger('import step 5'); + } - logger('import step 6'); + logger('import step 6'); - if (is_array($data['hubloc'])) { - import_hublocs($channel,$data['hubloc'],$seize,$moving); - } + if (is_array($data['hubloc'])) { + import_hublocs($channel, $data['hubloc'], $seize, $moving); + } - logger('import step 7'); + logger('import step 7'); - // create new hubloc for the new channel at this site + // create new hubloc for the new channel at this site - if (array_key_exists('channel',$data)) { - $r = hubloc_store_lowlevel( - [ - 'hubloc_guid' => $channel['channel_guid'], - 'hubloc_guid_sig' => $channel['channel_guid_sig'], - 'hubloc_id_url' => channel_url($channel), - 'hubloc_hash' => $channel['channel_hash'], - 'hubloc_addr' => channel_reddress($channel), - 'hubloc_network' => 'zot6', - 'hubloc_primary' => (($seize) ? 1 : 0), - 'hubloc_url' => z_root(), - 'hubloc_url_sig' => Libzot::sign(z_root(),$channel['channel_prvkey']), - 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(),get_config('system','pubkey')), - 'hubloc_host' => App::get_hostname(), - 'hubloc_callback' => z_root() . '/zot', - 'hubloc_sitekey' => get_config('system','pubkey'), - 'hubloc_updated' => datetime_convert() - ] - ); + if (array_key_exists('channel', $data)) { + $r = hubloc_store_lowlevel( + [ + 'hubloc_guid' => $channel['channel_guid'], + 'hubloc_guid_sig' => $channel['channel_guid_sig'], + 'hubloc_id_url' => channel_url($channel), + 'hubloc_hash' => $channel['channel_hash'], + 'hubloc_addr' => channel_reddress($channel), + 'hubloc_network' => 'zot6', + 'hubloc_primary' => (($seize) ? 1 : 0), + 'hubloc_url' => z_root(), + 'hubloc_url_sig' => Libzot::sign(z_root(), $channel['channel_prvkey']), + 'hubloc_site_id' => Libzot::make_xchan_hash(z_root(), get_config('system', 'pubkey')), + 'hubloc_host' => App::get_hostname(), + 'hubloc_callback' => z_root() . '/zot', + 'hubloc_sitekey' => get_config('system', 'pubkey'), + 'hubloc_updated' => datetime_convert() + ] + ); - // reset the original primary hubloc if it is being seized + // reset the original primary hubloc if it is being seized - if ($seize) { - $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' and hubloc_url != '%s' ", - dbesc($channel['channel_hash']), - dbesc(z_root()) - ); - } - } + if ($seize) { + $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' and hubloc_url != '%s' ", + dbesc($channel['channel_hash']), + dbesc(z_root()) + ); + } + } - $friends = 0; - $feeds = 0; + $friends = 0; + $feeds = 0; - // import contacts - $abooks = $data['abook']; - if ($abooks) { - foreach ($abooks as $abook) { + // import contacts + $abooks = $data['abook']; + if ($abooks) { + foreach ($abooks as $abook) { - $abook_copy = $abook; + $abook_copy = $abook; - $abconfig = null; - if (array_key_exists('abconfig',$abook) && is_array($abook['abconfig']) && count($abook['abconfig'])) { - $abconfig = $abook['abconfig']; - } + $abconfig = null; + if (array_key_exists('abconfig', $abook) && is_array($abook['abconfig']) && count($abook['abconfig'])) { + $abconfig = $abook['abconfig']; + } - unset($abook['abook_id']); - unset($abook['abook_rating']); - unset($abook['abook_rating_text']); - unset($abook['abconfig']); - unset($abook['abook_their_perms']); - unset($abook['abook_my_perms']); - unset($abook['abook_not_here']); + unset($abook['abook_id']); + unset($abook['abook_rating']); + unset($abook['abook_rating_text']); + unset($abook['abconfig']); + unset($abook['abook_their_perms']); + unset($abook['abook_my_perms']); + unset($abook['abook_not_here']); - $abook['abook_account'] = $account_id; - $abook['abook_channel'] = $channel['channel_id']; + $abook['abook_account'] = $account_id; + $abook['abook_channel'] = $channel['channel_id']; - $reconnect = false; + $reconnect = false; - if (array_key_exists('abook_instance',$abook) && $abook['abook_instance'] && strpos($abook['abook_instance'],z_root()) === false) { - $abook['abook_not_here'] = 1; - if (! ($abook['abook_pending'] || $abook['abook_blocked'])) { - $reconnect = true; - } - } + if (array_key_exists('abook_instance', $abook) && $abook['abook_instance'] && strpos($abook['abook_instance'], z_root()) === false) { + $abook['abook_not_here'] = 1; + if (!($abook['abook_pending'] || $abook['abook_blocked'])) { + $reconnect = true; + } + } - if ($abook['abook_self']) { - $ctype = 0; - $role = get_pconfig($channel['channel_id'],'system','permissions_role'); - if (strpos($role,'collection' !== false)) { - $ctype = 2; - } - elseif (strpos($role,'group') !== false) { - $ctype = 1; - } - if ($ctype) { - q("update xchan set xchan_type = %d where xchan_hash = '%s' ", - intval($ctype), - dbesc($abook['abook_xchan']) - ); - } - } - else { - if ($max_friends !== false && $friends > $max_friends) { - continue; - } - if ($max_feeds !== false && intval($abook['abook_feed']) && ($feeds > $max_feeds)) { - continue; - } - } + if ($abook['abook_self']) { + $ctype = 0; + $role = get_pconfig($channel['channel_id'], 'system', 'permissions_role'); + if (strpos($role, 'collection' !== false)) { + $ctype = 2; + } elseif (strpos($role, 'group') !== false) { + $ctype = 1; + } + if ($ctype) { + q("update xchan set xchan_type = %d where xchan_hash = '%s' ", + intval($ctype), + dbesc($abook['abook_xchan']) + ); + } + } else { + if ($max_friends !== false && $friends > $max_friends) { + continue; + } + if ($max_feeds !== false && intval($abook['abook_feed']) && ($feeds > $max_feeds)) { + continue; + } + } - $r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($abook['abook_xchan']), - intval($channel['channel_id']) - ); - if($r) { - $columns = db_columns('abook'); + $r = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($abook['abook_xchan']), + intval($channel['channel_id']) + ); + if ($r) { + $columns = db_columns('abook'); - foreach ($abook as $k => $v) { - if (! in_array($k,$columns)) { - continue; - } - $r = q("UPDATE abook SET " . TQUOT . "%s" . TQUOT . " = '%s' WHERE abook_xchan = '%s' AND abook_channel = %d", - dbesc($k), - dbesc($v), - dbesc($abook['abook_xchan']), - intval($channel['channel_id']) - ); - } - } - else { - abook_store_lowlevel($abook); + foreach ($abook as $k => $v) { + if (!in_array($k, $columns)) { + continue; + } + $r = q("UPDATE abook SET " . TQUOT . "%s" . TQUOT . " = '%s' WHERE abook_xchan = '%s' AND abook_channel = %d", + dbesc($k), + dbesc($v), + dbesc($abook['abook_xchan']), + intval($channel['channel_id']) + ); + } + } else { + abook_store_lowlevel($abook); - $friends ++; - if (intval($abook['abook_feed'])) { - $feeds ++; - } - } + $friends++; + if (intval($abook['abook_feed'])) { + $feeds++; + } + } - if ($abconfig) { - foreach ($abconfig as $abc) { - set_abconfig($channel['channel_id'],$abc['xchan'],$abc['cat'],$abc['k'],$abc['v']); - } - } - if ($reconnect) { - Connect::connect($channel,$abook['abook_xchan']); - } - } + if ($abconfig) { + foreach ($abconfig as $abc) { + set_abconfig($channel['channel_id'], $abc['xchan'], $abc['cat'], $abc['k'], $abc['v']); + } + } + if ($reconnect) { + Connect::connect($channel, $abook['abook_xchan']); + } + } - logger('import step 8'); - } + logger('import step 8'); + } - // import groups - $groups = $data['group']; - if ($groups) { - $saved = []; - foreach ($groups as $group) { - $saved[$group['hash']] = [ 'old' => $group['id'] ]; - if (array_key_exists('name', $group)) { - $group['gname'] = $group['name']; - unset($group['name']); - } - unset($group['id']); - $group['uid'] = $channel['channel_id']; + // import groups + $groups = $data['group']; + if ($groups) { + $saved = []; + foreach ($groups as $group) { + $saved[$group['hash']] = ['old' => $group['id']]; + if (array_key_exists('name', $group)) { + $group['gname'] = $group['name']; + unset($group['name']); + } + unset($group['id']); + $group['uid'] = $channel['channel_id']; - create_table_from_array('pgrp', $group); - } - $r = q("select * from pgrp where uid = %d", - intval($channel['channel_id']) - ); - if ($r) { - foreach ($r as $rr) { - $saved[$rr['hash']]['new'] = $rr['id']; - } - } - } + create_table_from_array('pgrp', $group); + } + $r = q("select * from pgrp where uid = %d", + intval($channel['channel_id']) + ); + if ($r) { + foreach ($r as $rr) { + $saved[$rr['hash']]['new'] = $rr['id']; + } + } + } - // import group members - $group_members = $data['group_member']; - if ($group_members) { - foreach ($group_members as $group_member) { - unset($group_member['id']); - $group_member['uid'] = $channel['channel_id']; - foreach ($saved as $x) { - if ($x['old'] == $group_member['gid']) { - $group_member['gid'] = $x['new']; - } - } - create_table_from_array('pgrp_member', $group_member); - } - } + // import group members + $group_members = $data['group_member']; + if ($group_members) { + foreach ($group_members as $group_member) { + unset($group_member['id']); + $group_member['uid'] = $channel['channel_id']; + foreach ($saved as $x) { + if ($x['old'] == $group_member['gid']) { + $group_member['gid'] = $x['new']; + } + } + create_table_from_array('pgrp_member', $group_member); + } + } - logger('import step 9'); + logger('import step 9'); - if (is_array($data['atoken'])) { - import_atoken($channel,$data['atoken']); - } - if (is_array($data['xign'])) { - import_xign($channel,$data['xign']); - } - if (is_array($data['block'])) { - import_block($channel,$data['block']); - } - if (is_array($data['obj'])) { - import_objs($channel,$data['obj']); - } - if (is_array($data['likes'])) { - import_likes($channel,$data['likes']); - } - if (is_array($data['app'])) { - import_apps($channel,$data['app']); - } - if (is_array($data['sysapp'])) { - import_sysapps($channel,$data['sysapp']); - } - if (is_array($data['chatroom'])) { - import_chatrooms($channel,$data['chatroom']); - } + if (is_array($data['atoken'])) { + import_atoken($channel, $data['atoken']); + } + if (is_array($data['xign'])) { + import_xign($channel, $data['xign']); + } + if (is_array($data['block'])) { + import_block($channel, $data['block']); + } + if (is_array($data['obj'])) { + import_objs($channel, $data['obj']); + } + if (is_array($data['likes'])) { + import_likes($channel, $data['likes']); + } + if (is_array($data['app'])) { + import_apps($channel, $data['app']); + } + if (is_array($data['sysapp'])) { + import_sysapps($channel, $data['sysapp']); + } + if (is_array($data['chatroom'])) { + import_chatrooms($channel, $data['chatroom']); + } // if (is_array($data['conv'])) { // import_conv($channel,$data['conv']); // } // if (is_array($data['mail'])) { // import_mail($channel,$data['mail']); // } - if (is_array($data['event'])) { - import_events($channel,$data['event']); - } - if (is_array($data['event_item'])) { - import_items($channel,$data['event_item'],false,$relocate); - } + if (is_array($data['event'])) { + import_events($channel, $data['event']); + } + if (is_array($data['event_item'])) { + import_items($channel, $data['event_item'], false, $relocate); + } // if (is_array($data['menu'])) { // import_menus($channel,$data['menu']); // } @@ -543,171 +535,173 @@ class Import extends Controller { // if (is_array($data['webpages'])) { // import_items($channel,$data['webpages'],false,$relocate); // } - $addon = array('channel' => $channel,'data' => $data); - call_hooks('import_channel',$addon); + $addon = array('channel' => $channel, 'data' => $data); + call_hooks('import_channel', $addon); - $saved_notification_flags = notifications_off($channel['channel_id']); - if ($import_posts && array_key_exists('item',$data) && $data['item']) { - import_items($channel,$data['item'],false,$relocate); - } + $saved_notification_flags = notifications_off($channel['channel_id']); + if ($import_posts && array_key_exists('item', $data) && $data['item']) { + import_items($channel, $data['item'], false, $relocate); + } - if ($api_path && $import_posts) { // we are importing from a server and not a file + if ($api_path && $import_posts) { // we are importing from a server and not a file - $m = parse_url($api_path); + $m = parse_url($api_path); - $hz_server = $m['scheme'] . '://' . $m['host']; + $hz_server = $m['scheme'] . '://' . $m['host']; - $since = datetime_convert(date_default_timezone_get(),date_default_timezone_get(),'0001-01-01 00:00'); - $until = datetime_convert(date_default_timezone_get(),date_default_timezone_get(),'now + 1 day'); + $since = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), '0001-01-01 00:00'); + $until = datetime_convert(date_default_timezone_get(), date_default_timezone_get(), 'now + 1 day'); - $poll_interval = get_config('system','poll_interval',3); - $page = 0; + $poll_interval = get_config('system', 'poll_interval', 3); + $page = 0; - while (1) { - $headers = [ - 'X-API-Token' => random_string(), - 'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , - 'Host' => $m['host'], - '(request-target)' => 'get /api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page , - ]; + while (1) { + $headers = [ + 'X-API-Token' => random_string(), + 'X-API-Request' => $hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, + 'Host' => $m['host'], + '(request-target)' => 'get /api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, + ]; - $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); + $headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), true, 'sha512'); - $x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page,false,$redirects,[ 'headers' => $headers ]); + $x = z_fetch_url($hz_server . '/api/z/1.0/item/export_page?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until) . '&page=' . $page, false, $redirects, ['headers' => $headers]); - // logger('z_fetch: ' . print_r($x,true)); + // logger('z_fetch: ' . print_r($x,true)); - if (! $x['success']) { - logger('no API response'); - break; - } + if (!$x['success']) { + logger('no API response'); + break; + } - $j = json_decode($x['body'],true); + $j = json_decode($x['body'], true); - if (! $j) { - break; - } + if (!$j) { + break; + } - if (! ($j['item'] || count($j['item']))) { - break; - } + if (!($j['item'] || count($j['item']))) { + break; + } - Run::Summon([ 'Content_importer', sprintf('%d',$page), $since, $until, $channel['channel_address'], urlencode($hz_server) ]); - sleep($poll_interval); + Run::Summon(['Content_importer', sprintf('%d', $page), $since, $until, $channel['channel_address'], urlencode($hz_server)]); + sleep($poll_interval); - $page ++; - continue; - } + $page++; + continue; + } - $headers = [ - 'X-API-Token' => random_string(), - 'X-API-Request' => $hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), - 'Host' => $m['host'], - '(request-target)' => 'get /api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), - ]; + $headers = [ + 'X-API-Token' => random_string(), + 'X-API-Request' => $hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), + 'Host' => $m['host'], + '(request-target)' => 'get /api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), + ]; - $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); + $headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), true, 'sha512'); - $x = z_fetch_url($hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until),false,$redirects,[ 'headers' => $headers ]); + $x = z_fetch_url($hz_server . '/api/z/1.0/files?f=&zap_compat=1&since=' . urlencode($since) . '&until=' . urlencode($until), false, $redirects, ['headers' => $headers]); - if (! $x['success']) { - logger('no API response'); - return; - } + if (!$x['success']) { + logger('no API response'); + return; + } - $j = json_decode($x['body'],true); + $j = json_decode($x['body'], true); - if (! $j) { - return; - } + if (!$j) { + return; + } - if (! $j['success']) { - return; - } + if (!$j['success']) { + return; + } - $poll_interval = get_config('system','poll_interval',3); + $poll_interval = get_config('system', 'poll_interval', 3); - if(count($j['results'])) { - $todo = count($j['results']); - logger('total to process: ' . $todo,LOGGER_DEBUG); + if (count($j['results'])) { + $todo = count($j['results']); + logger('total to process: ' . $todo, LOGGER_DEBUG); - foreach($j['results'] as $jj) { - Run::Summon([ 'File_importer',$jj['hash'], $channel['channel_address'], urlencode($hz_server) ]); - sleep($poll_interval); - } - } + foreach ($j['results'] as $jj) { + Run::Summon(['File_importer', $jj['hash'], $channel['channel_address'], urlencode($hz_server)]); + sleep($poll_interval); + } + } - notice(t('Files and Posts imported.') . EOL); + notice(t('Files and Posts imported.') . EOL); - } + } - notifications_on($channel['channel_id'],$saved_notification_flags); + notifications_on($channel['channel_id'], $saved_notification_flags); - // send out refresh requests - // notify old server that it may no longer be primary. + // send out refresh requests + // notify old server that it may no longer be primary. - Run::Summon( [ 'Notifier','refresh_all',$channel['channel_id'] ] ); + Run::Summon(['Notifier', 'refresh_all', $channel['channel_id']]); - // This will indirectly perform a refresh_all *and* update the directory + // This will indirectly perform a refresh_all *and* update the directory - Run::Summon( [ 'Directory', $channel['channel_id'] ] ); + Run::Summon(['Directory', $channel['channel_id']]); - notice( t('Import completed.') . EOL); + notice(t('Import completed.') . EOL); - change_channel($channel['channel_id']); + change_channel($channel['channel_id']); - goaway(z_root() . '/stream' ); - } + goaway(z_root() . '/stream'); + } - /** - * @brief Handle POST action on channel import page. - */ + /** + * @brief Handle POST action on channel import page. + */ - function post() { - $account_id = get_account_id(); - if (! $account_id) { - return; - } + public function post() + { + $account_id = get_account_id(); + if (!$account_id) { + return; + } - check_form_security_token_redirectOnErr('/import', 'channel_import'); - $this->import_account($account_id); - } + check_form_security_token_redirectOnErr('/import', 'channel_import'); + $this->import_account($account_id); + } - /** - * @brief Generate channel import page. - * - * @return string with parsed HTML. - */ + /** + * @brief Generate channel import page. + * + * @return string with parsed HTML. + */ - function get() { + public function get() + { - if (! get_account_id()) { - notice( t('You must be logged in to use this feature.') . EOL); - return EMPTY_STR; - } + if (!get_account_id()) { + notice(t('You must be logged in to use this feature.') . EOL); + return EMPTY_STR; + } - return replace_macros(get_markup_template('channel_import.tpl'), [ - '$title' => t('Import Channel'), - '$desc' => t('Use this form to import an existing channel from a different server. You may retrieve the channel identity from the old server via the network or provide an export file.'), - '$label_filename' => t('File to Upload'), - '$choice' => t('Or provide the old server details'), - '$old_address' => [ 'old_address', t('Your old identity address (xyz@example.com)'), '', ''], - '$email' => [ 'email', t('Your old login email address'), '', '' ], - '$password' => [ 'password', t('Your old login password'), '', '' ], - '$import_posts' => [ 'import_posts', t('Import a few months of posts if possible (limited by available memory)'), false, '', [ t('No'), t('Yes') ]], + return replace_macros(get_markup_template('channel_import.tpl'), [ + '$title' => t('Import Channel'), + '$desc' => t('Use this form to import an existing channel from a different server. You may retrieve the channel identity from the old server via the network or provide an export file.'), + '$label_filename' => t('File to Upload'), + '$choice' => t('Or provide the old server details'), + '$old_address' => ['old_address', t('Your old identity address (xyz@example.com)'), '', ''], + '$email' => ['email', t('Your old login email address'), '', ''], + '$password' => ['password', t('Your old login password'), '', ''], + '$import_posts' => ['import_posts', t('Import a few months of posts if possible (limited by available memory)'), false, '', [t('No'), t('Yes')]], - '$common' => t('For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media.'), + '$common' => t('For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media.'), - '$make_primary' => [ 'make_primary', t('Make this hub my primary location'), false, '', [ t('No'), t('Yes') ] ], - '$moving' => [ 'moving', t('Move this channel (disable all previous locations)'), false, '', [ t('No'), t('Yes') ] ], - '$newname' => [ 'newname', t('Use this channel nickname instead of the one provided'), '', t('Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site.')], + '$make_primary' => ['make_primary', t('Make this hub my primary location'), false, '', [t('No'), t('Yes')]], + '$moving' => ['moving', t('Move this channel (disable all previous locations)'), false, '', [t('No'), t('Yes')]], + '$newname' => ['newname', t('Use this channel nickname instead of the one provided'), '', t('Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site.')], - '$pleasewait' => t('This process may take several minutes to complete and considerably longer if importing a large amount of posts and files. Please submit the form only once and leave this page open until finished.'), + '$pleasewait' => t('This process may take several minutes to complete and considerably longer if importing a large amount of posts and files. Please submit the form only once and leave this page open until finished.'), - '$form_security_token' => get_form_security_token('channel_import'), - '$submit' => t('Submit') - ]); - } + '$form_security_token' => get_form_security_token('channel_import'), + '$submit' => t('Submit') + ]); + } } diff --git a/Zotlabs/Module/Import_items.php b/Zotlabs/Module/Import_items.php index 57baf993f..87be5cb8f 100644 --- a/Zotlabs/Module/Import_items.php +++ b/Zotlabs/Module/Import_items.php @@ -11,83 +11,85 @@ require_once('include/import.php'); * * Import existing posts and content from an export file. */ -class Import_items extends Controller { +class Import_items extends Controller +{ - function post() { + public function post() + { - if(! local_channel()) - return; + if (!local_channel()) + return; - check_form_security_token_redirectOnErr('/import_items', 'import_items'); + check_form_security_token_redirectOnErr('/import_items', 'import_items'); - $data = null; + $data = null; - $src = $_FILES['filename']['tmp_name']; - $filename = basename($_FILES['filename']['name']); - $filesize = intval($_FILES['filename']['size']); - $filetype = $_FILES['filename']['type']; + $src = $_FILES['filename']['tmp_name']; + $filename = basename($_FILES['filename']['name']); + $filesize = intval($_FILES['filename']['size']); + $filetype = $_FILES['filename']['type']; - if($src) { - // This is OS specific and could also fail if your tmpdir isn't very large - // mostly used for Diaspora which exports gzipped files. + if ($src) { + // This is OS specific and could also fail if your tmpdir isn't very large + // mostly used for Diaspora which exports gzipped files. - if(strpos($filename,'.gz')){ - @rename($src,$src . '.gz'); - @system('gunzip ' . escapeshellarg($src . '.gz')); - } + if (strpos($filename, '.gz')) { + @rename($src, $src . '.gz'); + @system('gunzip ' . escapeshellarg($src . '.gz')); + } - if($filesize) { - $data = @file_get_contents($src); - } - unlink($src); - } + if ($filesize) { + $data = @file_get_contents($src); + } + unlink($src); + } - if(! $src) { + if (!$src) { - $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); + $old_address = ((x($_REQUEST, 'old_address')) ? $_REQUEST['old_address'] : ''); - if(! $old_address) { - logger('Nothing to import.'); - notice( t('Nothing to import.') . EOL); - return; - } + if (!$old_address) { + logger('Nothing to import.'); + notice(t('Nothing to import.') . EOL); + return; + } - $email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : ''); - $password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : ''); + $email = ((x($_REQUEST, 'email')) ? $_REQUEST['email'] : ''); + $password = ((x($_REQUEST, 'password')) ? $_REQUEST['password'] : ''); - $year = ((x($_REQUEST,'year')) ? $_REQUEST['year'] : ''); + $year = ((x($_REQUEST, 'year')) ? $_REQUEST['year'] : ''); - $channelname = substr($old_address,0,strpos($old_address,'@')); - $servername = substr($old_address,strpos($old_address,'@')+1); + $channelname = substr($old_address, 0, strpos($old_address, '@')); + $servername = substr($old_address, strpos($old_address, '@') + 1); - $scheme = 'https://'; - $api_path = '/api/red/channel/export/items?f=&zap_compat=1&channel=' . $channelname . '&year=' . intval($year); - $binary = false; - $redirects = 0; - $opts = array('http_auth' => $email . ':' . $password); - $url = $scheme . $servername . $api_path; - $ret = z_fetch_url($url, $binary, $redirects, $opts); - if(! $ret['success']) - $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts); - if($ret['success']) - $data = $ret['body']; - else - notice( t('Unable to download data from old server') . EOL); - } + $scheme = 'https://'; + $api_path = '/api/red/channel/export/items?f=&zap_compat=1&channel=' . $channelname . '&year=' . intval($year); + $binary = false; + $redirects = 0; + $opts = array('http_auth' => $email . ':' . $password); + $url = $scheme . $servername . $api_path; + $ret = z_fetch_url($url, $binary, $redirects, $opts); + if (!$ret['success']) + $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts); + if ($ret['success']) + $data = $ret['body']; + else + notice(t('Unable to download data from old server') . EOL); + } - if(! $data) { - logger('Empty file.'); - notice( t('Imported file is empty.') . EOL); - return; - } + if (!$data) { + logger('Empty file.'); + notice(t('Imported file is empty.') . EOL); + return; + } - $data = json_decode($data, true); + $data = json_decode($data, true); - //logger('import: data: ' . print_r($data,true)); - //print_r($data); + //logger('import: data: ' . print_r($data,true)); + //print_r($data); - if(! is_array($data)) - return; + if (!is_array($data)) + return; // if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) { // $v1 = substr($data['compatibility']['database'],-4); @@ -98,44 +100,45 @@ class Import_items extends Controller { // } // } - $codebase = 'zap'; + $codebase = 'zap'; - if ((! array_path_exists('compatibility/codebase',$data)) || $data['compatibility']['codebase'] !== $codebase) { - notice(t('Data export format is not compatible with this software')); - return; - } + if ((!array_path_exists('compatibility/codebase', $data)) || $data['compatibility']['codebase'] !== $codebase) { + notice(t('Data export format is not compatible with this software')); + return; + } - $channel = App::get_channel(); + $channel = App::get_channel(); - if(array_key_exists('item',$data) && $data['item']) { - import_items($channel,$data['item'],false,((array_key_exists('relocate',$data)) ? $data['relocate'] : null)); - } + if (array_key_exists('item', $data) && $data['item']) { + import_items($channel, $data['item'], false, ((array_key_exists('relocate', $data)) ? $data['relocate'] : null)); + } - info( t('Import completed') . EOL); - } + info(t('Import completed') . EOL); + } - /** - * @brief Generate item import page. - * - * @return string with parsed HTML. - */ - function get() { + /** + * @brief Generate item import page. + * + * @return string with parsed HTML. + */ + public function get() + { - if(! local_channel()) { - notice( t('Permission denied') . EOL); - return login(); - } + if (!local_channel()) { + notice(t('Permission denied') . EOL); + return login(); + } - $o = replace_macros(get_markup_template('item_import.tpl'), array( - '$title' => t('Import Items'), - '$desc' => t('Use this form to import existing posts and content from an export file.'), - '$label_filename' => t('File to Upload'), - '$form_security_token' => get_form_security_token('import_items'), - '$submit' => t('Submit') - )); + $o = replace_macros(get_markup_template('item_import.tpl'), array( + '$title' => t('Import Items'), + '$desc' => t('Use this form to import existing posts and content from an export file.'), + '$label_filename' => t('File to Upload'), + '$form_security_token' => get_form_security_token('import_items'), + '$submit' => t('Submit') + )); - return $o; - } + return $o; + } } diff --git a/Zotlabs/Module/Inbox.php b/Zotlabs/Module/Inbox.php index 89f08412e..953443ae0 100644 --- a/Zotlabs/Module/Inbox.php +++ b/Zotlabs/Module/Inbox.php @@ -12,398 +12,397 @@ use Zotlabs\Web\Controller; use Zotlabs\Lib\Config; use Zotlabs\Lib\PConfig; -class Inbox extends Controller { +class Inbox extends Controller +{ - function post() { + public function post() + { - // This SHOULD be handled by the webserver, but in the RFC it is only indicated as - // a SHOULD and not a MUST, so some webservers fail to reject appropriately. + // This SHOULD be handled by the webserver, but in the RFC it is only indicated as + // a SHOULD and not a MUST, so some webservers fail to reject appropriately. - if ((array_key_exists('HTTP_ACCEPT',$_SERVER)) && ($_SERVER['HTTP_ACCEPT']) - && (strpos($_SERVER['HTTP_ACCEPT'],'*') === false) && (! ActivityStreams::is_as_request())) { - logger('unhandled accept header: ' . $_SERVER['HTTP_ACCEPT'],LOGGER_DEBUG); - http_status_exit(406,'not acceptable'); - } + if ((array_key_exists('HTTP_ACCEPT', $_SERVER)) && ($_SERVER['HTTP_ACCEPT']) + && (strpos($_SERVER['HTTP_ACCEPT'], '*') === false) && (!ActivityStreams::is_as_request())) { + logger('unhandled accept header: ' . $_SERVER['HTTP_ACCEPT'], LOGGER_DEBUG); + http_status_exit(406, 'not acceptable'); + } - if (! Config::Get('system','activitypub',ACTIVITYPUB_ENABLED)) { - logger('ActivityPub INBOX request - protocol is disabled'); - http_status_exit(404,'Not found'); - } + if (!Config::Get('system', 'activitypub', ACTIVITYPUB_ENABLED)) { + logger('ActivityPub INBOX request - protocol is disabled'); + http_status_exit(404, 'Not found'); + } - $sys_disabled = ((intval(Config::Get('system','public_stream_mode')) !== PUBLIC_STREAM_FULL) ? true : false); + $sys_disabled = ((intval(Config::Get('system', 'public_stream_mode')) !== PUBLIC_STREAM_FULL) ? true : false); - logger('inbox_args: ' . print_r(App::$argv,true)); - - $is_public = false; + logger('inbox_args: ' . print_r(App::$argv, true)); - if (argc() == 1 || argv(1) === '[public]') { - $is_public = true; - } - else { - $c = channelx_by_nick(argv(1)); - if (! $c) { - http_status_exit(410,'Gone'); - } - $channels = [ $c ]; - } + $is_public = false; - $data = file_get_contents('php://input'); - if (! $data) { - return; - } + if (argc() == 1 || argv(1) === '[public]') { + $is_public = true; + } else { + $c = channelx_by_nick(argv(1)); + if (!$c) { + http_status_exit(410, 'Gone'); + } + $channels = [$c]; + } - logger('inbox_activity: ' . jindent($data), LOGGER_DATA); + $data = file_get_contents('php://input'); + if (!$data) { + return; + } - $hsig = HTTPSig::verify($data); + logger('inbox_activity: ' . jindent($data), LOGGER_DATA); - // By convention, fediverse server-to-server communications require a valid HTTP Signature - // which includes a signed digest header. - - // This check may need to move elsewhere or be modified in order to fully implement ActivityPub C2S. - - if (! ($hsig['header_signed'] && $hsig['header_valid'] && $hsig['content_signed'] && $hsig['content_valid'])) { - http_status_exit(403,'Permission denied'); - } + $hsig = HTTPSig::verify($data); - $AS = new ActivityStreams($data); - if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) - && array_key_exists('object',$AS->obj) && array_key_exists('actor',$AS->obj)) { - // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) - // Reparse the encapsulated Activity and use that instead - logger('relayed activity',LOGGER_DEBUG); - $AS = new ActivityStreams($AS->obj); - } + // By convention, fediverse server-to-server communications require a valid HTTP Signature + // which includes a signed digest header. - // logger('debug: ' . $AS->debug()); + // This check may need to move elsewhere or be modified in order to fully implement ActivityPub C2S. - if (! $AS->is_valid()) { - if ($AS->deleted) { - // process mastodon user deletion activities, but only if we can validate the signature - if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) { - logger('removing deleted actor'); - remove_all_xchan_resources($hsig['portable_id']); - } - else { - logger('ignoring deleted actor', LOGGER_DEBUG, LOG_INFO); - } - } - return; - } - + if (!($hsig['header_signed'] && $hsig['header_valid'] && $hsig['content_signed'] && $hsig['content_valid'])) { + http_status_exit(403, 'Permission denied'); + } - if (is_array($AS->actor) && array_key_exists('id',$AS->actor)) { - Activity::actor_store($AS->actor['id'],$AS->actor); - } + $AS = new ActivityStreams($data); + if ($AS->is_valid() && $AS->type === 'Announce' && is_array($AS->obj) + && array_key_exists('object', $AS->obj) && array_key_exists('actor', $AS->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $AS = new ActivityStreams($AS->obj); + } - if (is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { - Activity::actor_store($AS->obj['id'],$AS->obj); - } + // logger('debug: ' . $AS->debug()); - if (is_array($AS->obj) && is_array($AS->obj['actor']) && array_key_exists('id',$AS->obj['actor']) && $AS->obj['actor']['id'] !== $AS->actor['id']) { - Activity::actor_store($AS->obj['actor']['id'],$AS->obj['actor']); - if (! check_channelallowed($AS->obj['actor']['id'])) { - http_status_exit(403,'Permission denied'); - } - } - - // Validate that the channel that sent us this activity has authority to do so. - // Require a valid HTTPSignature with a signed Digest header. - - // Only permit relayed activities if the activity is signed with LDSigs - // AND the signature is valid AND the signer is the actor. - - if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) { - - // if the sender has the ability to send messages over zot/nomad, ignore messages sent via activitypub - // as observer aware features and client side markup will be unavailable - - $test = Activity::get_actor_hublocs($hsig['portable_id'],'all,not_deleted'); - if ($test) { - foreach ($test as $t) { - if ($t['hubloc_network'] === 'zot6') { - http_status_exit(409,'Conflict'); - } - } - } - - // fetch the portable_id for the actor, which may or may not be the sender - - $v = Activity::get_actor_hublocs($AS->actor['id'],'activitypub,not_deleted'); - - if ($v && $v[0]['hubloc_hash'] !== $hsig['portable_id']) { - // The sender is not actually the activity actor, so verify the LD signature. - // litepub activities (with no LD signature) will always have a matching actor and sender - - if ($AS->signer && is_array($AS->signer) && $AS->signer['id'] !== $AS->actor['id']) { - // the activity wasn't signed by the activity actor - return; - } - if (! $AS->sigok) { - // The activity signature isn't valid. - return; - } - - } - - if ($v) { - // The sender has been validated and stored - $observer_hash = $hsig['portable_id']; - } - - } - - if (! $observer_hash) { - return; - } - - // verify that this site has permitted communication with the sender. - - $m = parse_url($observer_hash); - - if ($m && $m['scheme'] && $m['host']) { - if (! check_siteallowed($m['scheme'] . '://' . $m['host'])) { - http_status_exit(403,'Permission denied'); - } - // this site obviously isn't dead because they are trying to communicate with us. - $test = q("update site set site_dead = 0 where site_dead = 1 and site_url = '%s' ", - dbesc($m['scheme'] . '://' . $m['host']) - ); - } - if (! check_channelallowed($observer_hash)) { - http_status_exit(403,'Permission denied'); - } - - // update the hubloc_connected timestamp, ignore failures - - $test = q("update hubloc set hubloc_connected = '%s' where hubloc_hash = '%s' and hubloc_network = 'activitypub'", - dbesc(datetime_convert()), - dbesc($observer_hash) - ); + if (!$AS->is_valid()) { + if ($AS->deleted) { + // process mastodon user deletion activities, but only if we can validate the signature + if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) { + logger('removing deleted actor'); + remove_all_xchan_resources($hsig['portable_id']); + } else { + logger('ignoring deleted actor', LOGGER_DEBUG, LOG_INFO); + } + } + return; + } - // Now figure out who the recipients are + if (is_array($AS->actor) && array_key_exists('id', $AS->actor)) { + Activity::actor_store($AS->actor['id'], $AS->actor); + } - if ($is_public) { + if (is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { + Activity::actor_store($AS->obj['id'], $AS->obj); + } - if (in_array($AS->type, [ 'Follow', 'Join' ]) && is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { - $channels = q("SELECT * from channel where channel_address = '%s' and channel_removed = 0 ", - dbesc(basename($AS->obj['id'])) - ); - } - else { - // deliver to anybody following $AS->actor + if (is_array($AS->obj) && is_array($AS->obj['actor']) && array_key_exists('id', $AS->obj['actor']) && $AS->obj['actor']['id'] !== $AS->actor['id']) { + Activity::actor_store($AS->obj['actor']['id'], $AS->obj['actor']); + if (!check_channelallowed($AS->obj['actor']['id'])) { + http_status_exit(403, 'Permission denied'); + } + } - $channels = q("SELECT * from channel where channel_id in ( SELECT abook_channel from abook left join xchan on abook_xchan = xchan_hash WHERE xchan_network = 'activitypub' and xchan_hash = '%s' ) and channel_removed = 0 ", - dbesc($observer_hash) - ); - if (! $channels) { - $channels = []; - } + // Validate that the channel that sent us this activity has authority to do so. + // Require a valid HTTPSignature with a signed Digest header. - $parent = $AS->parent_id; - if ($parent) { - // this is a comment - deliver to everybody who owns the parent - $owners = q("SELECT * from channel where channel_id in ( SELECT uid from item where mid = '%s' ) ", - dbesc($parent) - ); - if ($owners) { - $channels = array_merge($channels,$owners); - } - } - } + // Only permit relayed activities if the activity is signed with LDSigs + // AND the signature is valid AND the signer is the actor. - if ($channels === false) { - $channels = []; - } + if ($hsig['header_valid'] && $hsig['content_valid'] && $hsig['portable_id']) { - if (in_array(ACTIVITY_PUBLIC_INBOX,$AS->recips) || in_array('Public',$AS->recips) || in_array('as:Public',$AS->recips)) { + // if the sender has the ability to send messages over zot/nomad, ignore messages sent via activitypub + // as observer aware features and client side markup will be unavailable - // look for channels with send_stream = PERMS_PUBLIC (accept posts from anybody on the internet) + $test = Activity::get_actor_hublocs($hsig['portable_id'], 'all,not_deleted'); + if ($test) { + foreach ($test as $t) { + if ($t['hubloc_network'] === 'zot6') { + http_status_exit(409, 'Conflict'); + } + } + } - $r = q("select * from channel where channel_id in (select uid from pconfig where cat = 'perm_limits' and k = 'send_stream' and v = '1' ) and channel_removed = 0 "); - if ($r) { - $channels = array_merge($channels,$r); - } + // fetch the portable_id for the actor, which may or may not be the sender - // look for channels that are following hashtags. These will be checked in tgroup_check() - - $r = q("select * from channel where channel_id in (select uid from pconfig where cat = 'system' and k = 'followed_tags' and v != '' ) and channel_removed = 0 "); - if ($r) { - $channels = array_merge($channels,$r); - } + $v = Activity::get_actor_hublocs($AS->actor['id'], 'activitypub,not_deleted'); + + if ($v && $v[0]['hubloc_hash'] !== $hsig['portable_id']) { + // The sender is not actually the activity actor, so verify the LD signature. + // litepub activities (with no LD signature) will always have a matching actor and sender + + if ($AS->signer && is_array($AS->signer) && $AS->signer['id'] !== $AS->actor['id']) { + // the activity wasn't signed by the activity actor + return; + } + if (!$AS->sigok) { + // The activity signature isn't valid. + return; + } + + } + + if ($v) { + // The sender has been validated and stored + $observer_hash = $hsig['portable_id']; + } + + } + + if (!$observer_hash) { + return; + } + + // verify that this site has permitted communication with the sender. + + $m = parse_url($observer_hash); + + if ($m && $m['scheme'] && $m['host']) { + if (!check_siteallowed($m['scheme'] . '://' . $m['host'])) { + http_status_exit(403, 'Permission denied'); + } + // this site obviously isn't dead because they are trying to communicate with us. + $test = q("update site set site_dead = 0 where site_dead = 1 and site_url = '%s' ", + dbesc($m['scheme'] . '://' . $m['host']) + ); + } + if (!check_channelallowed($observer_hash)) { + http_status_exit(403, 'Permission denied'); + } + + // update the hubloc_connected timestamp, ignore failures + + $test = q("update hubloc set hubloc_connected = '%s' where hubloc_hash = '%s' and hubloc_network = 'activitypub'", + dbesc(datetime_convert()), + dbesc($observer_hash) + ); - if (! $sys_disabled) { - $channels[] = get_sys_channel(); - } + // Now figure out who the recipients are - } + if ($is_public) { - } + if (in_array($AS->type, ['Follow', 'Join']) && is_array($AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { + $channels = q("SELECT * from channel where channel_address = '%s' and channel_removed = 0 ", + dbesc(basename($AS->obj['id'])) + ); + } else { + // deliver to anybody following $AS->actor - // $channels represents all "potential" recipients. If they are not in this array, they will not receive the activity. - // If they are in this array, we will decide whether or not to deliver on a case-by-case basis. - - if (! $channels) { - logger('no deliveries on this site'); - return; - } + $channels = q("SELECT * from channel where channel_id in ( SELECT abook_channel from abook left join xchan on abook_xchan = xchan_hash WHERE xchan_network = 'activitypub' and xchan_hash = '%s' ) and channel_removed = 0 ", + dbesc($observer_hash) + ); + if (!$channels) { + $channels = []; + } - // Bto and Bcc will only be present in a C2S transaction and should not be stored. - - $saved_recips = []; - foreach ( [ 'to', 'cc', 'audience' ] as $x ) { - if (array_key_exists($x,$AS->data)) { - $saved_recips[$x] = $AS->data[$x]; - } - } - $AS->set_recips($saved_recips); + $parent = $AS->parent_id; + if ($parent) { + // this is a comment - deliver to everybody who owns the parent + $owners = q("SELECT * from channel where channel_id in ( SELECT uid from item where mid = '%s' ) ", + dbesc($parent) + ); + if ($owners) { + $channels = array_merge($channels, $owners); + } + } + } + + if ($channels === false) { + $channels = []; + } + + if (in_array(ACTIVITY_PUBLIC_INBOX, $AS->recips) || in_array('Public', $AS->recips) || in_array('as:Public', $AS->recips)) { + + // look for channels with send_stream = PERMS_PUBLIC (accept posts from anybody on the internet) + + $r = q("select * from channel where channel_id in (select uid from pconfig where cat = 'perm_limits' and k = 'send_stream' and v = '1' ) and channel_removed = 0 "); + if ($r) { + $channels = array_merge($channels, $r); + } + + // look for channels that are following hashtags. These will be checked in tgroup_check() + + $r = q("select * from channel where channel_id in (select uid from pconfig where cat = 'system' and k = 'followed_tags' and v != '' ) and channel_removed = 0 "); + if ($r) { + $channels = array_merge($channels, $r); + } - foreach ($channels as $channel) { + if (!$sys_disabled) { + $channels[] = get_sys_channel(); + } - // Even though activitypub may be enabled for the site, check if the channel has specifically disabled it - if (! PConfig::Get($channel['channel_id'],'system','activitypub',Config::Get('system','activitypub',ACTIVITYPUB_ENABLED))) { - continue; - } - - logger('inbox_channel: ' . $channel['channel_address'],LOGGER_DEBUG); + } - switch ($AS->type) { - case 'Follow': - if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { - // do follow activity - Activity::follow($channel,$AS); - } - break; - case 'Invite': - if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { - // do follow activity - Activity::follow($channel,$AS); - } - break; - case 'Join': - if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { - // do follow activity - Activity::follow($channel,$AS); - } - break; - case 'Accept': - // Activitypub for wordpress sends lowercase 'follow' on accept. - // https://github.com/pfefferle/wordpress-activitypub/issues/97 - // Mobilizon sends Accept/"Member" (not in vocabulary) in response to Join/Group - if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && in_array($AS->obj['type'], ['Follow','follow', 'Member'])) { - // do follow activity - Activity::follow($channel,$AS); - } - break; + } - case 'Reject': + // $channels represents all "potential" recipients. If they are not in this array, they will not receive the activity. + // If they are in this array, we will decide whether or not to deliver on a case-by-case basis. - default: - break; + if (!$channels) { + logger('no deliveries on this site'); + return; + } - } + // Bto and Bcc will only be present in a C2S transaction and should not be stored. - // These activities require permissions + $saved_recips = []; + foreach (['to', 'cc', 'audience'] as $x) { + if (array_key_exists($x, $AS->data)) { + $saved_recips[$x] = $AS->data[$x]; + } + } + $AS->set_recips($saved_recips); - $item = null; - switch ($AS->type) { - case 'Update': - if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { - Activity::actor_store($AS->obj['id'],$AS->obj, true /* force cache refresh */); - break; - } - case 'Accept': - if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && (ActivityStreams::is_an_actor($AS->obj['type']) || $AS->obj['type'] === 'Member')) { - break; - } - case 'Create': - case 'Like': - case 'Dislike': - case 'Announce': - case 'Reject': - case 'TentativeAccept': - case 'TentativeReject': - case 'Add': - case 'Arrive': - case 'Block': - case 'Flag': - case 'Ignore': - case 'Invite': - case 'Listen': - case 'Move': - case 'Offer': - case 'Question': - case 'Read': - case 'Travel': - case 'View': - case 'emojiReaction': - case 'EmojiReaction': - case 'EmojiReact': - // These require a resolvable object structure - if (is_array($AS->obj)) { - // The boolean flag enables html cache of the item - $item = Activity::decode_note($AS,true); - } - else { - logger('unresolved object: ' . print_r($AS->obj,true)); - } - break; - case 'Undo': - if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Follow') { - // do unfollow activity - Activity::unfollow($channel,$AS); - break; - } - case 'Leave': - if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { - // do unfollow activity - Activity::unfollow($channel,$AS); - break; - } - case 'Tombstone': - case 'Delete': - Activity::drop($channel,$observer_hash,$AS); - break; + foreach ($channels as $channel) { - case 'Move': - if($observer_hash && $observer_hash === $AS->actor - && is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStream::is_an_actor($AS->obj['type']) - && is_array($AS->tgt) && array_key_exists('type', $AS->tgt) && ActivityStream::is_an_actor($AS->tgt['type'])) { - ActivityPub::move($AS->obj,$AS->tgt); - } - break; - case 'Add': - case 'Remove': + // Even though activitypub may be enabled for the site, check if the channel has specifically disabled it + if (!PConfig::Get($channel['channel_id'], 'system', 'activitypub', Config::Get('system', 'activitypub', ACTIVITYPUB_ENABLED))) { + continue; + } - // for writeable collections as target, it's best to provide an array and include both the type and the id in the target element. - // If it's just a string id, we'll try to fetch the collection when we receive it and that's wasteful since we don't actually need - // the contents. - if (is_array($AS->obj) && isset($AS->tgt)) { - // The boolean flag enables html cache of the item - $item = Activity::decode_note($AS,true); - break; - } - default: - break; + logger('inbox_channel: ' . $channel['channel_address'], LOGGER_DEBUG); - } + switch ($AS->type) { + case 'Follow': + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { + // do follow activity + Activity::follow($channel, $AS); + } + break; + case 'Invite': + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { + // do follow activity + Activity::follow($channel, $AS); + } + break; + case 'Join': + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { + // do follow activity + Activity::follow($channel, $AS); + } + break; + case 'Accept': + // Activitypub for wordpress sends lowercase 'follow' on accept. + // https://github.com/pfefferle/wordpress-activitypub/issues/97 + // Mobilizon sends Accept/"Member" (not in vocabulary) in response to Join/Group + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && in_array($AS->obj['type'], ['Follow', 'follow', 'Member'])) { + // do follow activity + Activity::follow($channel, $AS); + } + break; - if ($item) { - logger('parsed_item: ' . print_r($item,true),LOGGER_DATA); - Activity::store($channel,$observer_hash,$AS,$item); - } + case 'Reject': - } + default: + break; - http_status_exit(200,'OK'); - } + } - function get() { + // These activities require permissions - } + $item = null; + + switch ($AS->type) { + case 'Update': + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { + Activity::actor_store($AS->obj['id'], $AS->obj, true /* force cache refresh */); + break; + } + case 'Accept': + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && (ActivityStreams::is_an_actor($AS->obj['type']) || $AS->obj['type'] === 'Member')) { + break; + } + case 'Create': + case 'Like': + case 'Dislike': + case 'Announce': + case 'Reject': + case 'TentativeAccept': + case 'TentativeReject': + case 'Add': + case 'Arrive': + case 'Block': + case 'Flag': + case 'Ignore': + case 'Invite': + case 'Listen': + case 'Move': + case 'Offer': + case 'Question': + case 'Read': + case 'Travel': + case 'View': + case 'emojiReaction': + case 'EmojiReaction': + case 'EmojiReact': + // These require a resolvable object structure + if (is_array($AS->obj)) { + // The boolean flag enables html cache of the item + $item = Activity::decode_note($AS, true); + } else { + logger('unresolved object: ' . print_r($AS->obj, true)); + } + break; + case 'Undo': + if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Follow') { + // do unfollow activity + Activity::unfollow($channel, $AS); + break; + } + case 'Leave': + if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { + // do unfollow activity + Activity::unfollow($channel, $AS); + break; + } + case 'Tombstone': + case 'Delete': + Activity::drop($channel, $observer_hash, $AS); + break; + + case 'Move': + if ($observer_hash && $observer_hash === $AS->actor + && is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStream::is_an_actor($AS->obj['type']) + && is_array($AS->tgt) && array_key_exists('type', $AS->tgt) && ActivityStream::is_an_actor($AS->tgt['type'])) { + ActivityPub::move($AS->obj, $AS->tgt); + } + break; + case 'Add': + case 'Remove': + + // for writeable collections as target, it's best to provide an array and include both the type and the id in the target element. + // If it's just a string id, we'll try to fetch the collection when we receive it and that's wasteful since we don't actually need + // the contents. + if (is_array($AS->obj) && isset($AS->tgt)) { + // The boolean flag enables html cache of the item + $item = Activity::decode_note($AS, true); + break; + } + default: + break; + + } + + if ($item) { + logger('parsed_item: ' . print_r($item, true), LOGGER_DATA); + Activity::store($channel, $observer_hash, $AS, $item); + } + + } + + http_status_exit(200, 'OK'); + } + + public function get() + { + + } } diff --git a/Zotlabs/Module/Inspect.php b/Zotlabs/Module/Inspect.php index e8081496e..6ccb5066b 100644 --- a/Zotlabs/Module/Inspect.php +++ b/Zotlabs/Module/Inspect.php @@ -6,88 +6,88 @@ use App; use Zotlabs\Web\Controller; use Zotlabs\Lib\Activity; -class Inspect extends Controller { +class Inspect extends Controller +{ - function get() { - - $output = EMPTY_STR; + public function get() + { - if (! is_site_admin()) { - notice( t('Permission denied.') . EOL); - return $output; - } - - $sys = get_sys_channel(); + $output = EMPTY_STR; - if (argc() > 2) { - $item_type = argv(1); - $item_id = argv(2); - } - elseif (argc() > 1) { - $item_type = 'item'; - $item_id = argv(1); - } - - if (! $item_id) { - App::$error = 404; - notice( t('Item not found.') . EOL); - } - - if ($item_type === 'item') { - $r = q("select * from item where uuid = '%s' or id = %d ", - dbesc($item_id), - intval($item_id) - ); - - if ($r) { - xchan_query($r); - $items = fetch_post_tags($r,true); - } + if (!is_site_admin()) { + notice(t('Permission denied.') . EOL); + return $output; + } - if(! $items) { - return $output; - } + $sys = get_sys_channel(); - foreach ($items as $item) { - if ($item['obj']) { - $item['obj'] = json_decode($item['obj'],true); - } - if ($item['target']) { - $item['target'] = json_decode($item['target'],true); - } - if ($item['attach']) { - $item['attach'] = json_decode($item['attach'],true); - } + if (argc() > 2) { + $item_type = argv(1); + $item_id = argv(2); + } elseif (argc() > 1) { + $item_type = 'item'; + $item_id = argv(1); + } - $output .= '
      ' . print_array($item) . '
      ' . EOL . EOL; + if (!$item_id) { + App::$error = 404; + notice(t('Item not found.') . EOL); + } - $output .= '
      ' . escape_tags(json_encode(Activity::encode_activity($item,true), JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) . '
      ' . EOL . EOL; + if ($item_type === 'item') { + $r = q("select * from item where uuid = '%s' or id = %d ", + dbesc($item_id), + intval($item_id) + ); - $output .= '
      ' . escape_tags(json_encode(json_decode(get_iconfig($item['id'],'activitypub','rawmsg'),true), JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) . '
      ' . EOL . EOL; - - } + if ($r) { + xchan_query($r); + $items = fetch_post_tags($r, true); + } - } + if (!$items) { + return $output; + } - if ($item_type === 'xchan') { - $items = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_hash = '%s' or hubloc_addr = '%s' ", - dbesc($item_id), - dbesc($item_id) - ); - - if(! $items) { - return $output; - } + foreach ($items as $item) { + if ($item['obj']) { + $item['obj'] = json_decode($item['obj'], true); + } + if ($item['target']) { + $item['target'] = json_decode($item['target'], true); + } + if ($item['attach']) { + $item['attach'] = json_decode($item['attach'], true); + } - foreach ($items as $item) { - $output .= '
      ' . print_array($item) . '
      ' . EOL . EOL; - } - } + $output .= '
      ' . print_array($item) . '
      ' . EOL . EOL; + + $output .= '
      ' . escape_tags(json_encode(Activity::encode_activity($item, true), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . '
      ' . EOL . EOL; + + $output .= '
      ' . escape_tags(json_encode(json_decode(get_iconfig($item['id'], 'activitypub', 'rawmsg'), true), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . '
      ' . EOL . EOL; + + } + + } + + if ($item_type === 'xchan') { + $items = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_hash = '%s' or hubloc_addr = '%s' ", + dbesc($item_id), + dbesc($item_id) + ); + + if (!$items) { + return $output; + } + + foreach ($items as $item) { + $output .= '
      ' . print_array($item) . '
      ' . EOL . EOL; + } + } + return $output; + } + - return $output; - } - - } diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php index a9a988681..4a1b0b193 100644 --- a/Zotlabs/Module/Invite.php +++ b/Zotlabs/Module/Invite.php @@ -11,161 +11,159 @@ use Zotlabs\Web\Controller; * send email invitations to join social network * */ +class Invite extends Controller +{ + + public function post() + { + + if (!local_channel()) { + return; + } + + if (!Apps::system_app_installed(local_channel(), 'Invite')) { + return; + } + + check_form_security_token_redirectOnErr('/', 'send_invite'); + + $max_invites = intval(get_config('system', 'max_invites'), 20); + + $current_invites = intval(get_pconfig(local_channel(), 'system', 'sent_invites')); + if ($current_invites > $max_invites) { + notice(t('Total invitation limit exceeded.') . EOL); + return; + } -class Invite extends Controller { + $recips = ((x($_POST, 'recipients')) ? explode("\n", $_POST['recipients']) : []); + $message = ((x($_POST, 'message')) ? notags(trim($_POST['message'])) : ''); - function post() { - - if (! local_channel()) { - return; - } + $total = 0; - if(! Apps::system_app_installed(local_channel(), 'Invite')) { - return; - } - - check_form_security_token_redirectOnErr('/', 'send_invite'); - - $max_invites = intval(get_config('system','max_invites'), 20); - - $current_invites = intval(get_pconfig(local_channel(),'system','sent_invites')); - if($current_invites > $max_invites) { - notice( t('Total invitation limit exceeded.') . EOL); - return; - } + if (get_config('system', 'invitation_only')) { + $invonly = true; + $x = get_pconfig(local_channel(), 'system', 'invites_remaining'); + if ((!$x) && (!is_site_admin())) + return; + } + + foreach ($recips as $recip) { + + $recip = trim($recip); + if (!$recip) + continue; + + if (!validate_email($recip)) { + notice(sprintf(t('%s : Not a valid email address.'), $recip) . EOL); + continue; + } else + $nmessage = $message; + + $account = App::get_account(); + + $res = z_mail( + [ + 'toEmail' => $recip, + 'fromName' => ' ', + 'fromEmail' => $account['account_email'], + 'messageSubject' => t('Please join us on $Projectname'), + 'textVersion' => $nmessage, + ] + ); + + if ($res) { + $total++; + $current_invites++; + set_pconfig(local_channel(), 'system', 'sent_invites', $current_invites); + if ($current_invites > $max_invites) { + notice(t('Invitation limit exceeded. Please contact your site administrator.') . EOL); + return; + } + } else { + notice(sprintf(t('%s : Message delivery failed.'), $recip) . EOL); + } + + } + notice(sprintf(tt("%d message sent.", "%d messages sent.", $total), $total) . EOL); + return; + } - $recips = ((x($_POST,'recipients')) ? explode("\n",$_POST['recipients']) : []); - $message = ((x($_POST,'message')) ? notags(trim($_POST['message'])) : ''); - - $total = 0; - - if (get_config('system','invitation_only')) { - $invonly = true; - $x = get_pconfig(local_channel(),'system','invites_remaining'); - if ((! $x) && (! is_site_admin())) - return; - } - - foreach ($recips as $recip) { - - $recip = trim($recip); - if(! $recip) - continue; - - if(! validate_email($recip)) { - notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL); - continue; - } - - else - $nmessage = $message; - - $account = App::get_account(); - - $res = z_mail( - [ - 'toEmail' => $recip, - 'fromName' => ' ', - 'fromEmail' => $account['account_email'], - 'messageSubject' => t('Please join us on $Projectname'), - 'textVersion' => $nmessage, - ] - ); - - if($res) { - $total ++; - $current_invites ++; - set_pconfig(local_channel(),'system','sent_invites',$current_invites); - if($current_invites > $max_invites) { - notice( t('Invitation limit exceeded. Please contact your site administrator.') . EOL); - return; - } - } - else { - notice( sprintf( t('%s : Message delivery failed.'), $recip) . EOL); - } - - } - notice( sprintf( tt("%d message sent.", "%d messages sent.", $total) , $total) . EOL); - return; - } - - - function get() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + public function get() + { - if(! Apps::system_app_installed(local_channel(), 'Invite')) { - //Do not display any associated widgets at this point - App::$pdl = ''; + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - $o = 'Invite App (Not Installed):
      '; - $o .= t('Send email invitations to join this network'); - return $o; - } + if (!Apps::system_app_installed(local_channel(), 'Invite')) { + //Do not display any associated widgets at this point + App::$pdl = ''; + + $o = 'Invite App (Not Installed):
      '; + $o .= t('Send email invitations to join this network'); + return $o; + } + + nav_set_selected('Invite'); + + $tpl = get_markup_template('invite.tpl'); + $invonly = false; + + if (get_config('system', 'invitation_only')) { + $invonly = true; + $x = get_pconfig(local_channel(), 'system', 'invites_remaining'); + if ((!$x) && (!is_site_admin())) { + notice(t('You have no more invitations available') . EOL); + return ''; + } + } + + if ($invonly && ($x || is_site_admin())) { + $invite_code = autoname(8) . rand(1000, 9999); + $nmessage = str_replace('$invite_code', $invite_code, $message); + + $r = q("INSERT INTO register (hash,created,uid,password,lang) VALUES ('%s', '%s',0,'','') ", + dbesc($invite_code), + dbesc(datetime_convert()) + ); + + if (!is_site_admin()) { + $x--; + if ($x >= 0) + set_pconfig(local_channel(), 'system', 'invites_remaining', $x); + else + return; + } + } + + $ob = App::get_observer(); + if (!$ob) + return $o; + + $channel = App::get_channel(); + + $o = replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("send_invite"), + '$invite' => t('Send invitations'), + '$addr_text' => t('Enter email addresses, one per line:'), + '$msg_text' => t('Your message:'), + '$default_message' => t('Please join my community on $Projectname.') . "\r\n" . "\r\n" + . $linktxt + . (($invonly) ? "\r\n" . "\r\n" . t('You will need to supply this invitation code:') . " " . $invite_code . "\r\n" . "\r\n" : '') + . t('1. Register at any $Projectname location (they are all inter-connected)') + . "\r\n" . "\r\n" . z_root() . '/register' + . "\r\n" . "\r\n" . t('2. Enter my $Projectname network address into the site searchbar.') + . "\r\n" . "\r\n" . $ob['xchan_addr'] . ' (' . t('or visit') . " " . z_root() . '/channel/' . $channel['channel_address'] . ')' + . "\r\n" . "\r\n" + . t('3. Click [Connect]') + . "\r\n" . "\r\n", + '$submit' => t('Submit') + )); + + return $o; + } - nav_set_selected('Invite'); - - $tpl = get_markup_template('invite.tpl'); - $invonly = false; - - if(get_config('system','invitation_only')) { - $invonly = true; - $x = get_pconfig(local_channel(),'system','invites_remaining'); - if((! $x) && (! is_site_admin())) { - notice( t('You have no more invitations available') . EOL); - return ''; - } - } - - if($invonly && ($x || is_site_admin())) { - $invite_code = autoname(8) . rand(1000,9999); - $nmessage = str_replace('$invite_code',$invite_code,$message); - - $r = q("INSERT INTO register (hash,created,uid,password,lang) VALUES ('%s', '%s',0,'','') ", - dbesc($invite_code), - dbesc(datetime_convert()) - ); - - if(! is_site_admin()) { - $x --; - if($x >= 0) - set_pconfig(local_channel(),'system','invites_remaining',$x); - else - return; - } - } - - $ob = App::get_observer(); - if(! $ob) - return $o; - - $channel = App::get_channel(); - - $o = replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("send_invite"), - '$invite' => t('Send invitations'), - '$addr_text' => t('Enter email addresses, one per line:'), - '$msg_text' => t('Your message:'), - '$default_message' => t('Please join my community on $Projectname.') . "\r\n" . "\r\n" - . $linktxt - . (($invonly) ? "\r\n" . "\r\n" . t('You will need to supply this invitation code:') . " " . $invite_code . "\r\n" . "\r\n" : '') - . t('1. Register at any $Projectname location (they are all inter-connected)') - . "\r\n" . "\r\n" . z_root() . '/register' - . "\r\n" . "\r\n" . t('2. Enter my $Projectname network address into the site searchbar.') - . "\r\n" . "\r\n" . $ob['xchan_addr'] . ' (' . t('or visit') . " " . z_root() . '/channel/' . $channel['channel_address'] . ')' - . "\r\n" . "\r\n" - . t('3. Click [Connect]') - . "\r\n" . "\r\n" , - '$submit' => t('Submit') - )); - - return $o; - } - } diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php index 93895991d..eeea9fde5 100644 --- a/Zotlabs/Module/Item.php +++ b/Zotlabs/Module/Item.php @@ -46,1905 +46,1878 @@ require_once('include/security.php'); use Zotlabs\Lib as Zlib; -class Item extends Controller { - - public $return_404 = false; - - function init() { - - - if (ActivityStreams::is_as_request()) { - $item_uuid = argv(1); - if (! $item_uuid) { - http_status_exit(404, 'Not found'); - } - $portable_id = EMPTY_STR; - - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 "; - - $i = null; - - // do we have the item (at all)? - // add preferential bias to item owners (item_wall = 1) - - $r = q("select * from item where (mid = '%s' or uuid = '%s') $item_normal order by item_wall desc limit 1", - dbesc(z_root() . '/item/' . $item_uuid), - dbesc($item_uuid) - ); - - if (! $r) { - http_status_exit(404,'Not found'); - } - - // process an authenticated fetch - - - $sigdata = HTTPSig::verify(EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { - http_status_exit(403, 'Permission denied'); - } - if (! check_siteallowed($sigdata['signer'])) { - http_status_exit(403, 'Permission denied'); - } - observer_auth($portable_id); - - $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1 ", - dbesc($r[0]['parent_mid']), - dbesc($portable_id) - ); - } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); - } - - // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access - // with a bias towards those items owned by channels on this site (item_wall = 1) - - $sql_extra = item_permissions_sql(0); - - if (! $i) { - $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", - dbesc($r[0]['parent_mid']) - ); - } - - $bear = Activity::token_from_request(); - if ($bear) { - logger('bear: ' . $bear, LOGGER_DEBUG); - if (! $i) { - $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'", - dbesc($bear) - ); - if ($t) { - $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1", - dbesc($item_uuid), - intval($t[0]['iid']) - ); - } - } - } - - if (! $i) { - http_status_exit(403,'Forbidden'); - } - - // If we get to this point we have determined we can access the original in $r (fetched much further above), so use it. - - xchan_query($r,true); - $items = fetch_post_tags($r,false); - - $chan = channelx_by_n($items[0]['uid']); - - if (! $chan) { - http_status_exit(404, 'Not found'); - } - - if (! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) { - http_status_exit(403, 'Forbidden'); - } - - $i = Activity::encode_item($items[0],true); - - if (! $i) { - http_status_exit(404, 'Not found'); - } - - - if ($portable_id && (! intval($items[0]['item_private']))) { - $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", - intval($items[0]['uid']), - dbesc($portable_id) - ); - if (! $c) { - ThreadListener::store(z_root() . '/item/' . $item_uuid,$portable_id); - } - } - - as_return_and_die($i,$chan); - } - - if (Libzot::is_zot_request()) { - - $item_uuid = argv(1); - - if (! $item_uuid) { - http_status_exit(404, 'Not found'); - } - - $portable_id = EMPTY_STR; - - $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) "; - - $i = null; - - // do we have the item (at all)? - - $r = q("select * from item where (mid = '%s' or uuid = '%s') $item_normal limit 1", - dbesc(z_root() . '/item/' . $item_uuid), - dbesc($item_uuid) - ); - - if (! $r) { - http_status_exit(404,'Not found'); - } - - // process an authenticated fetch - - $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { - http_status_exit(403, 'Permission denied'); - } - if (! check_siteallowed($sigdata['signer'])) { - http_status_exit(403, 'Permission denied'); - } - observer_auth($portable_id); - - $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1", - dbesc($r[0]['parent_mid']), - dbesc($portable_id) - ); - } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); - } - - // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access - // with a bias towards those items owned by channels on this site (item_wall = 1) - - $sql_extra = item_permissions_sql(0); - - if (! $i) { - $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", - dbesc($r[0]['parent_mid']) - ); - } - - $bear = Activity::token_from_request(); - if ($bear) { - logger('bear: ' . $bear, LOGGER_DEBUG); - if (! $i) { - $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'", - dbesc($bear) - ); - if ($t) { - $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1", - dbesc($item_uuid), - intval($t[0]['iid']) - ); - } - } - } - - if (! $i) { - http_status_exit(403,'Forbidden'); - } - - $parents_str = ids_to_querystr($i,'item_id'); - - $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal order by item.id asc", - dbesc($parents_str) - ); - - if (! $items) { - http_status_exit(404, 'Not found'); - } - - xchan_query($items,true); - $items = fetch_post_tags($items,true); - - if (! $items) { - http_status_exit(404, 'Not found'); - } - $chan = channelx_by_n($items[0]['uid']); - - if (! $chan) { - http_status_exit(404, 'Not found'); - } - - if (! perm_is_allowed($chan['channel_id'],get_observer_hash(),'view_stream')) { - http_status_exit(403, 'Forbidden'); - } - - $i = Activity::encode_item_collection($items,'conversation/' . $item_uuid,'OrderedCollection',true, count($items)); - if ($portable_id && (! intval($items[0]['item_private']))) { - ThreadListener::store(z_root() . '/item/' . $item_uuid,$portable_id); - } - - if (! $i) { - http_status_exit(404, 'Not found'); - } - $x = array_merge(['@context' => [ - ACTIVITYSTREAMS_JSONLD_REV, - 'https://w3id.org/security/v1', - Activity::ap_schema() - ]], $i); - - $headers = []; - $headers['Content-Type'] = 'application/x-zot+json' ; - $x['signature'] = LDSignatures::sign($x,$chan); - $ret = json_encode($x, JSON_UNESCAPED_SLASHES); - $headers['Digest'] = HTTPSig::generate_digest_header($ret); - $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; - $h = HTTPSig::create_sig($headers,$chan['channel_prvkey'],channel_url($chan)); - HTTPSig::set_headers($h); - echo $ret; - killme(); - - } - - // if it isn't a drop command and isn't a post method and wasn't handled already, - // the default action is a browser request for a persistent uri and this should return - // the text/html page of the item. - - if (argc() > 1 && argv(1) !== 'drop') { - $x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' or uuid = '%s'", - dbesc(z_root() . '/item/' . argv(1)), - dbesc(z_root() . '/activity/' . argv(1)), - dbesc(argv(1)) - ); - if ($x) { - foreach ($x as $xv) { - if (intval($xv['item_wall'])) { - $c = channelx_by_n($xv['uid']); - if ($c) { - goaway($c['xchan_url'] . '?mid=' . gen_link_id($xv['mid'])); - } - } - } - goaway($x[0]['llink']); - } - - // save this state and catch it in the get() function - $this->return_404 = true; - } - } - - function post() { - - if ((! local_channel()) && (! remote_channel()) && (! isset($_REQUEST['anonname']))) { - return; - } - - // drop an array of items. - - if (isset($_REQUEST['dropitems'])) { - $arr_drop = explode(',',$_REQUEST['dropitems']); - drop_items($arr_drop); - $json = array('success' => 1); - echo json_encode($json); - killme(); - } - - - $uid = local_channel(); - $channel = null; - $observer = null; - $token = EMPTY_STR; - $datarray = []; - $item_starred = false; - $item_uplink = false; - $item_notshown = false; - $item_nsfw = false; - $item_relay = false; - $item_mentionsme = false; - $item_verified = false; - $item_retained = false; - $item_rss = false; - $item_deleted = false; - $item_hidden = false; - $item_delayed = false; - $item_pending_remove = false; - $item_blocked = false; - - $post_tags = false; - $pub_copy = false; - - - - - /** - * Is this a reply to something? - */ - - $parent = ((isset($_REQUEST['parent'])) ? intval($_REQUEST['parent']) : 0); - $parent_mid = ((isset($_REQUEST['parent_mid'])) ? trim($_REQUEST['parent_mid']) : ''); - - $hidden_mentions = ((isset($_REQUEST['hidden_mentions'])) ? trim($_REQUEST['hidden_mentions']) : ''); - - - /** - * Who is viewing this page and posting this thing - */ - - $remote_xchan = ((isset($_REQUEST['remote_xchan'])) ? trim($_REQUEST['remote_xchan']) : false); - $remote_observer = xchan_match( ['xchan_hash' => $remote_xchan ] ); - - if (! $remote_observer) { - $remote_xchan = $remote_observer = false; - } - - // This is the local channel representing who the posted item will belong to. - - $profile_uid = ((isset($_REQUEST['profile_uid'])) ? intval($_REQUEST['profile_uid']) : 0); - - // *If* you are logged in as the site admin you are allowed to create top-level items for the sys channel. - // This would typically be a webpage or webpage element. - // Comments and replies are excluded because further below we also check for sys channel ownership and - // will make a copy of the parent that you can interact with in your own stream - - $sys = get_sys_channel(); - if ($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin() && ! $parent) { - $uid = intval($sys['channel_id']); - $channel = $sys; - $observer = $sys; - } - - call_hooks('post_local_start', $_REQUEST); - - // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); - - $api_source = ((isset($_REQUEST['api_source']) && $_REQUEST['api_source']) ? true : false); - - $nocomment = 0; - if (isset($_REQUEST['comments_enabled'])) { - $nocomment = 1 - intval($_REQUEST['comments_enabled']); - } - - // this is in days, convert to absolute time - $channel_comments_closed = get_pconfig($profile_uid,'system','close_comments'); - if (intval($channel_comments_closed)) { - $channel_comments_closed = datetime_convert(date_Default_timezone_get(),'UTC', 'now + ' . intval($channel_comments_closed) . ' days'); - } - else { - $channel_comments_closed = NULL_DATE; - } - - $comments_closed = ((isset($_REQUEST['comments_closed']) && $_REQUEST['comments_closed']) ? datetime_convert(date_default_timezone_get(),'UTC',$_REQUEST['comments_closed']) : $channel_comments_closed); - - $is_poll = ((trim($_REQUEST['poll_answers'][0]) != '' && trim($_REQUEST['poll_answers'][1]) != '') ? true : false); - - // 'origin' (if non-zero) indicates that this network is where the message originated, - // for the purpose of relaying comments to other conversation members. - // If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset. - // If the API is used from another network with its own distribution - // and deliveries, you may wish to set origin to 0 or false and allow the other - // network to relay comments. - - // If you are unsure, it is prudent (and important) to leave it unset. - - $origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1); - - // To represent message-ids on other networks - this will create an iconfig record - - $namespace = (($api_source && array_key_exists('namespace',$_REQUEST)) ? strip_tags($_REQUEST['namespace']) : ''); - $remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : ''); - - $owner_hash = null; - - $message_id = ((x($_REQUEST,'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); - $created = ((x($_REQUEST,'created')) ? datetime_convert(date_default_timezone_get(),'UTC',$_REQUEST['created']) : datetime_convert()); - - // Because somebody will probably try this and create a mess - - if ($created <= NULL_DATE) { - $created = datetime_convert(); - } - - $post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0); - - $app = ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''); - $return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : ''); - $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0); - $categories = ((x($_REQUEST,'category')) ? escape_tags($_REQUEST['category']) : ''); - $webpage = ((x($_REQUEST,'webpage')) ? intval($_REQUEST['webpage']) : 0); - $item_obscured = ((x($_REQUEST,'obscured')) ? intval($_REQUEST['obscured']) : 0); - $pagetitle = ((x($_REQUEST,'pagetitle')) ? escape_tags(urlencode($_REQUEST['pagetitle'])) : ''); - $layout_mid = ((x($_REQUEST,'layout_mid')) ? escape_tags($_REQUEST['layout_mid']): ''); - $plink = ((x($_REQUEST,'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); - $obj_type = ((x($_REQUEST,'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE); - - - $item_unpublished = ((isset($_REQUEST['draft'])) ? intval($_REQUEST['draft']) : 0); - - // allow API to bulk load a bunch of imported items without sending out a bunch of posts. - $nopush = ((x($_REQUEST,'nopush')) ? intval($_REQUEST['nopush']) : 0); - - /* - * Check service class limits - */ - if ($uid && !(x($_REQUEST,'parent')) && !(x($_REQUEST,'post_id'))) { - $ret = $this->item_check_service_class($uid,(($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false)); - if (!$ret['success']) { - notice( t($ret['message']) . EOL) ; - if($api_source) - return ( [ 'success' => false, 'message' => 'service class exception' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); - killme(); - } - } - - if ($pagetitle) { - $pagetitle = strtolower(URLify::transliterate($pagetitle)); - } - - $item_flags = $item_restrict = 0; - $expires = NULL_DATE; - - $route = ''; - $parent_item = null; - $parent_contact = null; - $thr_parent = ''; - $parid = 0; - $r = false; - - - // If this is a comment, find the parent and preset some stuff - - if ($parent || $parent_mid) { - - if (! x($_REQUEST,'type')) { - $_REQUEST['type'] = 'net-comment'; - } - if ($obj_type == ACTIVITY_OBJ_NOTE) { - $obj_type = ACTIVITY_OBJ_COMMENT; - } - - // fetch the parent item - - if ($parent) { - $r = q("SELECT * FROM item WHERE id = %d LIMIT 1", - intval($parent) - ); - } - elseif ($parent_mid && $uid) { - // This is coming from an API source, and we are logged in - $r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", - dbesc($parent_mid), - intval($uid) - ); - } - - // if this isn't the real parent of the conversation, find it - if ($r) { - $parid = $r[0]['parent']; - $parent_mid = $r[0]['mid']; - if ($r[0]['id'] != $r[0]['parent']) { - $r = q("SELECT * FROM item WHERE id = parent AND parent = %d LIMIT 1", - intval($parid) - ); - } - - // if interacting with a pubstream item (owned by the sys channel), - // create a copy of the parent in your stream - - // $r may have changed. Check it again before trying to use it. - - if ($r && local_channel() && (! is_sys_channel(local_channel()))) { - $old_id = $r[0]['id']; - $r = [ copy_of_pubitem(App::get_channel(), $r[0]['mid']) ]; - if ($r[0]['id'] !== $old_id) { - // keep track that a copy was made to display a special status notice that is unique to this condition - $pub_copy = true; - } - } - } - - if (! $r) { - notice( t('Unable to locate original post.') . EOL); - if ($api_source) { - return ( [ 'success' => false, 'message' => 'invalid post id' ] ); - } - if (x($_REQUEST,'return')) { - goaway(z_root() . "/" . $return_path ); - } - killme(); - } - - xchan_query($r,true); - - $parent_item = $r[0]; - $parent = $r[0]['id']; - - // multi-level threading - preserve the info but re-parent to our single level threading - - $thr_parent = $parent_mid; - - $route = $parent_item['route']; - - } - - if ($parent_item && isset($parent_item['replyto']) && $parent_item['replyto']) { - $replyto = unserialise($parent_item['replyto']); - } - - $moderated = false; - - if (! $observer) { - $observer = App::get_observer(); - if (! $observer) { - // perhaps we're allowing moderated comments from anonymous viewers - $observer = anon_identity_init($_REQUEST); - if ($observer) { - $moderated = true; - $remote_xchan = $remote_observer = $observer; - } - } - } - - if (! $observer) { - notice( t('Permission denied.') . EOL) ; - if ($api_source) { - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - } - if (x($_REQUEST,'return')) { - goaway(z_root() . "/" . $return_path ); - } - killme(); - } - - if ($parent) { - logger('mod_item: item_post parent=' . $parent); - $can_comment = false; - - $can_comment = can_comment_on_post($observer['xchan_hash'],$parent_item); - if (! $can_comment) { - if ((array_key_exists('owner',$parent_item)) && intval($parent_item['owner']['abook_self']) == 1 ) { - $can_comment = perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_comments'); - } - } - - if (! $can_comment) { - notice( t('Permission denied.') . EOL) ; - if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); - killme(); - } - } - else { - // fixme - $webpage could also be a wiki page or article and require a different permission to be checked. - if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],($webpage) ? 'write_pages' : 'post_wall')) { - notice( t('Permission denied.') . EOL) ; - if($api_source) - return ( [ 'success' => false, 'message' => 'permission denied' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); - killme(); - } - } - - // check if this author is being moderated through the 'moderated' (negative) permission - // when posting wall-to-wall - if ($moderated === false && intval($uid) !== intval($profile_uid)) { - $moderated = perm_is_allowed($profile_uid,$observer['xchan_hash'],'moderated'); - } - - // If this is a comment, check the moderated permission of the parent; who may be on another site - $remote_moderated = (($parent) ? their_perms_contains($profile_uid,$parent_item['owner_xchan'],'moderated') : false); - if ($remote_moderated) { - notice( t('Comment may be moderated.') . EOL); - } - - // is this an edited post? - - $orig_post = null; - - if ($namespace && $remote_id) { - // It wasn't an internally generated post - see if we've got an item matching this remote service id - $i = q("select iid from iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1", - dbesc($namespace), - dbesc($remote_id) - ); - if($i) - $post_id = $i[0]['iid']; - } - - $iconfig = null; - - if($post_id) { - $i = q("SELECT * FROM item WHERE uid = %d AND id = %d LIMIT 1", - intval($profile_uid), - intval($post_id) - ); - if(! count($i)) - killme(); - $orig_post = $i[0]; - $iconfig = q("select * from iconfig where iid = %d", - intval($post_id) - ); - } - - - if(! $channel) { - if($uid && $uid == $profile_uid) { - $channel = App::get_channel(); - } - else { - // posting as yourself but not necessarily to a channel you control - $r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1", - intval($profile_uid) - ); - if($r) - $channel = $r[0]; - } - } - - - if(! $channel) { - logger("mod_item: no channel."); - if($api_source) - return ( [ 'success' => false, 'message' => 'no channel' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); - killme(); - } - - $owner_xchan = null; - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($channel['channel_hash']) - ); - if($r && count($r)) { - $owner_xchan = $r[0]; - } - else { - logger("mod_item: no owner."); - if($api_source) - return ( [ 'success' => false, 'message' => 'no owner' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); - killme(); - } - - $walltowall = false; - $walltowall_comment = false; - - if($remote_xchan && ! $moderated) - $observer = $remote_observer; - - if($observer) { - logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG); - - // wall-to-wall detection. - // For top-level posts, if the author and owner are different it's a wall-to-wall - // For comments, We need to additionally look at the parent and see if it's a wall post that originated locally. - - if($observer['xchan_name'] != $owner_xchan['xchan_name']) { - if(($parent_item) && ($parent_item['item_wall'] && $parent_item['item_origin'])) { - $walltowall_comment = true; - $walltowall = true; - } - if(! $parent) { - $walltowall = true; - } - } - } - - if (! isset($replyto)) { - if (strpos($owner_xchan['xchan_hash'],'http') === 0) { - $replyto = $owner_xchan['xchan_hash']; - } - else { - $replyto = $owner_xchan['xchan_url']; - } - } - - - $acl = new AccessControl($channel); - - $view_policy = PermissionLimits::Get($channel['channel_id'],'view_stream'); - $comment_policy = ((isset($_REQUEST['comments_from']) && intval($_REQUEST['comments_from'])) ? intval($_REQUEST['comments_from']) : PermissionLimits::Get($channel['channel_id'],'post_comments')); - - $public_policy = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy,true)); - if($webpage) - $public_policy = ''; - if($public_policy) - $private = 1; - - if($orig_post) { - - $private = 0; - // webpages and unpublished drafts are allowed to change ACLs after the fact. Normal conversation items aren't. - if($webpage || intval($orig_post['item_unpublished'])) { - $acl->set_from_array($_REQUEST); - } - else { - $acl->set($orig_post); - $public_policy = $orig_post['public_policy']; - $private = $orig_post['item_private']; - } - - if($public_policy || $acl->is_private()) { - $private = (($private) ? $private : 1); - } - - $location = $orig_post['location']; - $coord = $orig_post['coord']; - $verb = $orig_post['verb']; - $app = $orig_post['app']; - $title = escape_tags(trim($_REQUEST['title'])); - $summary = trim($_REQUEST['summary']); - $body = trim($_REQUEST['body']); - - $item_flags = $orig_post['item_flags']; - $item_origin = $orig_post['item_origin']; - $item_unseen = $orig_post['item_unseen']; - $item_starred = $orig_post['item_starred']; - $item_uplink = $orig_post['item_uplink']; - $item_wall = $orig_post['item_wall']; - $item_thread_top = $orig_post['item_thread_top']; - $item_notshown = $orig_post['item_notshown']; - $item_nsfw = $orig_post['item_nsfw']; - $item_relay = $orig_post['item_relay']; - $item_mentionsme = $orig_post['item_mentionsme']; - $item_nocomment = $orig_post['item_nocomment']; - $item_obscured = $orig_post['item_obscured']; - $item_verified = $orig_post['item_verified']; - $item_retained = $orig_post['item_retained']; - $item_rss = $orig_post['item_rss']; - $item_deleted = $orig_post['item_deleted']; - $item_type = $orig_post['item_type']; - $item_hidden = $orig_post['item_hidden']; - $item_delayed = $orig_post['item_delayed']; - $item_pending_remove = $orig_post['item_pending_remove']; - $item_blocked = $orig_post['item_blocked']; - - - - $postopts = $orig_post['postopts']; - $created = ((intval($orig_post['item_unpublished'])) ? $created : $orig_post['created']); - $expires = ((intval($orig_post['item_unpublished'])) ? NULL_DATE : $orig_post['expires']); - $mid = $orig_post['mid']; - $parent_mid = $orig_post['parent_mid']; - $plink = $orig_post['plink']; - - } - else { - if(! $walltowall) { - if((array_key_exists('contact_allow',$_REQUEST)) - || (array_key_exists('group_allow',$_REQUEST)) - || (array_key_exists('contact_deny',$_REQUEST)) - || (array_key_exists('group_deny',$_REQUEST))) { - $acl->set_from_array($_REQUEST); - } - elseif(! $api_source) { - - // if no ACL has been defined and we aren't using the API, the form - // didn't send us any parameters. This means there's no ACL or it has - // been reset to the default audience. - // If $api_source is set and there are no ACL parameters, we default - // to the channel permissions which were set in the ACL contructor. - - $acl->set(array('allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '')); - } - } - - - $location = ((isset($_REQUEST['location'])) ? notags(trim($_REQUEST['location'])) : EMPTY_STR); - $coord = ((isset($_REQUEST['coord'])) ? notags(trim($_REQUEST['coord'])) : EMPTY_STR); - $verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : EMPTY_STR); - $title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : EMPTY_STR); - $summary = ((isset($_REQUEST['summary'])) ? trim($_REQUEST['summary']) : EMPTY_STR); - $body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : EMPTY_STR); - $body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : EMPTY_STR); - $postopts = ''; - - $allow_empty = ((array_key_exists('allow_empty',$_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); - - $private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy))); - - // If this is a comment, set the permissions from the parent. - - if($parent_item) { - $private = 0; - $acl->set($parent_item); - $private = ((intval($parent_item['item_private']) ? $parent_item['item_private'] : $acl->is_private())); - $public_policy = $parent_item['public_policy']; - $owner_hash = $parent_item['owner_xchan']; - $webpage = $parent_item['item_type']; - $comment_policy = $parent_item['comment_policy']; - $item_nocomment = $parent_item['item_nocomment']; - $comments_closed = $parent_item['comments_closed']; - } - - if((! $allow_empty) && (! strlen($body))) { - if($preview) - killme(); - info( t('Empty post discarded.') . EOL ); - if($api_source) - return ( [ 'success' => false, 'message' => 'no content' ] ); - if(x($_REQUEST,'return')) - goaway(z_root() . "/" . $return_path ); - killme(); - } - } - - - - if(Apps::system_app_installed($profile_uid,'Expire Posts')) { - if(x($_REQUEST,'expire')) { - $expires = datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expire']); - if($expires <= datetime_convert()) - $expires = NULL_DATE; - } - } - - - $mimetype = notags(trim($_REQUEST['mimetype'])); - if(! $mimetype) - $mimetype = 'text/bbcode'; - - - $execflag = ((intval($uid) == intval($profile_uid) - && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false); - - if($preview) { - $summary = z_input_filter($summary,$mimetype,$execflag); - $body = z_input_filter($body,$mimetype,$execflag); - } - - - $arr = [ 'profile_uid' => $profile_uid, 'summary' => $summary, 'content' => $body, 'mimetype' => $mimetype ]; - call_hooks('post_content',$arr); - $summary = $arr['summary']; - $body = $arr['content']; - $mimetype = $arr['mimetype']; - - - $gacl = $acl->get(); - $str_contact_allow = $gacl['allow_cid']; - $str_group_allow = $gacl['allow_gid']; - $str_contact_deny = $gacl['deny_cid']; - $str_group_deny = $gacl['deny_gid']; - - - // if the acl contains a single contact and it's a group, add a mention. This is for compatibility - // with other groups implementations which require a mention to trigger group delivery. - - if (($str_contact_allow) && (! $str_group_allow) && (! $str_contact_deny) && (! $str_group_deny)) { - $cida = expand_acl($str_contact_allow); - if (count($cida) === 1) { - $netgroups = get_forum_channels($profile_uid,1); - if ($netgroups) { - foreach($netgroups as $ng) { - if ($ng['xchan_hash'] == $cida[0]) { - if (! is_array($post_tags)) { - $post_tags = []; - } - $post_tags[] = array( - 'uid' => $profile_uid, - 'ttype' => TERM_MENTION, - 'otype' => TERM_OBJ_POST, - 'term' => $ng['xchan_name'], - 'url' => $ng['xchan_url'] - ); - - $colls = get_xconfig($ng['xchan_hash'],'activitypub','collections'); - if ($colls && is_array($colls) && isset($colls['wall'])) { - $datarray['target'] = [ - 'id' => $colls['wall'], - 'type' => 'Collection', - 'attributedTo' => (($ng['xchan_network'] === 'zot6') ? $ng['xchan_url'] : $ng['xchan_hash']) - ]; - $datarray['tgt_type'] = 'Collection'; - } - } - } - } - } - } - - $groupww = false; - - // if this is a wall-to-wall post to a group, turn it into a direct message - - $role = get_pconfig($profile_uid,'system','permissions_role'); - - $rolesettings = PermissionRoles::role_perms($role); - - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; - - $is_group = (($channel_type === 'group') ? true : false); - - if (($is_group) && ($walltowall) && (! $walltowall_comment)) { - $groupww = true; - $str_contact_allow = $owner_xchan['xchan_hash']; - $str_group_allow = ''; - } - - - if($mimetype === 'text/bbcode') { - - // BBCODE alert: the following functions assume bbcode input - // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) - // we may need virtual or template classes to implement the possible alternatives - - if(strpos($body,'[/summary]') !== false) { - $match = ''; - $cnt = preg_match("/\[summary\](.*?)\[\/summary\]/ism",$body,$match); - if($cnt) { - $summary .= $match[1]; - } - $body_content = preg_replace("/^(.*?)\[summary\](.*?)\[\/summary\]/ism", '',$body); - $body = trim($body_content); - } - - $summary = cleanup_bbcode($summary); - $body = cleanup_bbcode($body); - - // Look for tags and linkify them - $summary_tags = linkify_tags($summary, ($uid) ? $uid : $profile_uid); - $body_tags = linkify_tags($body, ($uid) ? $uid : $profile_uid); - $comment_tags = linkify_tags($hidden_mentions, ($uid) ? $uid : $profile_uid); - - foreach ( [ $summary_tags, $body_tags, $comment_tags ] as $results ) { - - if ($results) { - - // Set permissions based on tag replacements - set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private); - - if (! isset($post_tags)) { - $post_tags = []; - } - foreach ($results as $result) { - $success = $result['success']; - if ($success['replaced']) { - - // suppress duplicate mentions/tags - $already_tagged = false; - foreach ($post_tags as $pt) { - if ($pt['term'] === $success['term'] && $pt['url'] === $success['url'] && intval($pt['ttype']) === intval($success['termtype'])) { - $already_tagged = true; - break; - } - } - if ($already_tagged) { - continue; - } - - $post_tags[] = array( - 'uid' => $profile_uid, - 'ttype' => $success['termtype'], - 'otype' => TERM_OBJ_POST, - 'term' => $success['term'], - 'url' => $success['url'] - ); - - // support #collection syntax to post to a collection - // this is accomplished by adding a pcategory tag for each collection target - // this is checked inside tag_deliver() to create a second delivery chain - - if ($success['termtype'] === TERM_HASHTAG) { - $r = q("select xchan_url from channel left join xchan on xchan_hash = channel_hash where channel_address = '%s' and channel_parent = '%s' and channel_removed = 0", - dbesc($success['term']), - dbesc(get_observer_hash()) - ); - if ($r) { - $post_tags[] = [ - 'uid' => $profile_uid, - 'ttype' => TERM_PCATEGORY, - 'otype' => TERM_OBJ_POST, - 'term' => $success['term'] . '@' . App::get_hostname(), - 'url' => $r[0]['xchan_url'] - ]; - } - } - } - } - } - } - - - /** - * process collections selected manually - */ - - if (array_key_exists('collections',$_REQUEST) && is_array($_REQUEST['collections']) && count($_REQUEST['collections'])) { - foreach ($_REQUEST['collections'] as $clct) { - $r = q("select xchan_url, xchan_hash from xchan left join hubloc on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", - dbesc($clct) - ); - if ($r) { - if (! isset($post_tags)) { - $post_tags = []; - } - $post_tags[] = [ - 'uid' => $profile_uid, - 'ttype' => TERM_PCATEGORY, - 'otype' => TERM_OBJ_POST, - 'term' => $clct, - 'url' => $r[0]['xchan_url'] - ]; - } - } - } - - if(($str_contact_allow) && (! $str_group_allow)) { - // direct message - private between individual channels but not groups - $private = 2; - } - - if ($private) { - - // for edited posts, re-use any existing OCAP token (if found). - // Otherwise generate a new one. - - if ($iconfig) { - foreach ($iconfig as $cfg) { - if ($cfg['cat'] === 'ocap' && $cfg['k'] === 'relay') { - $token = $cfg['v']; - } - } - } - if (! $token) { - $token = new_token(); - } - } - - - /** - * - * When a photo was uploaded into the message using the (profile wall) ajax - * uploader, The permissions are initially set to disallow anybody but the - * owner from seeing it. This is because the permissions may not yet have been - * set for the post. If it's private, the photo permissions should be set - * appropriately. But we didn't know the final permissions on the post until - * now. So now we'll look for links of uploaded photos and attachments that are in the - * post and set them to the same permissions as the post itself. - * - * If the post was end-to-end encrypted we can't find images and attachments in the body, - * use our media_str input instead which only contains these elements - but only do this - * when encrypted content exists because the photo/attachment may have been removed from - * the post and we should keep it private. If it's encrypted we have no way of knowing - * so we'll set the permissions regardless and realise that the media may not be - * referenced in the post. - * - */ - - if(! $preview) { - fix_attached_permissions($profile_uid,((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny, $token); - } - - - $attachments = ''; - $match = false; - - if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { - $attachments = []; - $i = 0; - foreach($match[2] as $mtch) { - $attach_link = ''; - $hash = substr($mtch,0,strpos($mtch,',')); - $rev = intval(substr($mtch,strpos($mtch,','))); - $r = attach_by_hash_nodata($hash, $observer['xchan_hash'], $rev); - if($r['success']) { - $attachments[] = array( - 'href' => z_root() . '/attach/' . $r['data']['hash'], - 'length' => $r['data']['filesize'], - 'type' => $r['data']['filetype'], - 'title' => urlencode($r['data']['filename']), - 'revision' => $r['data']['revision'] - ); - } - $body = str_replace($match[1][$i],$attach_link,$body); - $i++; - } - } - - - if(preg_match_all('/(\[share=(.*?)\](.*?)\[\/share\])/',$body,$match)) { - // process share by id - - $i = 0; - foreach($match[2] as $mtch) { - $reshare = new \Zotlabs\Lib\Share($mtch); - $body = str_replace($match[1][$i],$reshare->bbcode(),$body); - $i++; - } - } - - } - - // BBCODE end alert - - if(strlen($categories)) { - if (! isset($post_tags)) { - $post_tags = []; - } - - $cats = explode(',',$categories); - foreach($cats as $cat) { - - if($webpage == ITEM_TYPE_CARD) { - $catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); - } - elseif($webpage == ITEM_TYPE_ARTICLE) { - $catlink = z_root() . '/articles/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); - } - else { - $catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)); - } - - $post_tags[] = array( - 'uid' => $profile_uid, - 'ttype' => TERM_CATEGORY, - 'otype' => TERM_OBJ_POST, - 'term' => trim($cat), - 'url' => $catlink - ); - } - } - - if($orig_post) { - // preserve original tags - $t = q("select * from term where oid = %d and otype = %d and uid = %d and ttype in ( %d, %d, %d )", - intval($orig_post['id']), - intval(TERM_OBJ_POST), - intval($profile_uid), - intval(TERM_UNKNOWN), - intval(TERM_FILE), - intval(TERM_COMMUNITYTAG) - ); - if($t) { - if (! isset($post_tags)) { - $post_tags = []; - } - - foreach($t as $t1) { - $post_tags[] = array( - 'uid' => $profile_uid, - 'ttype' => $t1['ttype'], - 'otype' => TERM_OBJ_POST, - 'term' => $t1['term'], - 'url' => $t1['url'], - ); - } - } - } - - - $item_unseen = ((local_channel() != $profile_uid) ? 1 : 0); - $item_wall = ((isset($_REQUEST['type']) && ($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment')) ? 1 : 0); - $item_origin = (($origin) ? 1 : 0); - $item_nocomment = ((isset($item_nocomment)) ? $item_nocomment : $nocomment); - - - // determine if this is a wall post - - if($parent) { - $item_wall = $parent_item['item_wall']; - } - else { - if(! $webpage) { - $item_wall = 1; - } - } - - - if($moderated) - $item_blocked = ITEM_MODERATED; - - - if(! strlen($verb)) - $verb = ACTIVITY_POST ; - - $notify_type = (($parent) ? 'comment-new' : 'wall-new' ); - - if (! (isset($mid) && $mid)) { - if($message_id) { - $mid = $message_id; - } - else { - $uuid = new_uuid(); - $mid = z_root() . '/item/' . $uuid; - } - } - - - if($is_poll) { - $poll = [ - 'question' => $body, - 'answers' => $_REQUEST['poll_answers'], - 'multiple_answers' => $_REQUEST['poll_multiple_answers'], - 'expire_value' => $_REQUEST['poll_expire_value'], - 'expire_unit' => $_REQUEST['poll_expire_unit'] - ]; - $obj = $this->extract_poll_data($poll, [ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); - } - else { - $obj = $this->extract_bb_poll_data($body,[ 'item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny ]); - } - - - if ($obj) { - $obj['url'] = $obj['id'] = $mid; - $obj['attributedTo'] = channel_url($channel); - $datarray['obj'] = $obj; - $obj_type = 'Question'; - if ($obj['endTime']) { - $d = datetime_convert('UTC','UTC', $obj['endTime']); - if ($d > NULL_DATE) { - $comments_closed = $d; - } - } - } - - if(! $parent_mid) { - $parent_mid = $mid; - } - - if($parent_item) - $parent_mid = $parent_item['mid']; - - - - // Fallback so that we alway have a thr_parent - - if(!$thr_parent) - $thr_parent = $mid; - - - $item_thread_top = ((! $parent) ? 1 : 0); - - - // fix permalinks for cards, etc. - - if($webpage == ITEM_TYPE_CARD) { - $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid); - } - if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_CARD)) { - $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.iid = %d limit 1", - intval($parent_item['id']) - ); - if($r) { - $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . $r[0]['v']; - } - } - - if($webpage == ITEM_TYPE_ARTICLE) { - $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid); - } - if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_ARTICLE)) { - $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.iid = %d limit 1", - intval($parent_item['id']) - ); - if($r) { - $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . $r[0]['v']; - } - } - - if ((! (isset($plink) && $plink)) && $item_thread_top) { - $plink = z_root() . '/item/' . $uuid; - } - - if (array_path_exists('obj/id',$datarray)) { - $datarray['obj']['id'] = $mid; - } - - $datarray['aid'] = $channel['channel_account_id']; - $datarray['uid'] = $profile_uid; - $datarray['uuid'] = $uuid; - $datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']); - $datarray['author_xchan'] = $observer['xchan_hash']; - $datarray['created'] = $created; - $datarray['edited'] = (($orig_post && (! intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); - $datarray['expires'] = $expires; - $datarray['commented'] = (($orig_post && (! intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); - $datarray['received'] = (($orig_post && (! intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); - $datarray['changed'] = (($orig_post && (! intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); - $datarray['comments_closed'] = $comments_closed; - $datarray['mid'] = $mid; - $datarray['parent_mid'] = $parent_mid; - $datarray['mimetype'] = $mimetype; - $datarray['title'] = $title; - $datarray['summary'] = $summary; - $datarray['body'] = $body; - $datarray['app'] = $app; - $datarray['location'] = $location; - $datarray['coord'] = $coord; - $datarray['verb'] = $verb; - $datarray['obj_type'] = $obj_type; - $datarray['allow_cid'] = $str_contact_allow; - $datarray['allow_gid'] = $str_group_allow; - $datarray['deny_cid'] = $str_contact_deny; - $datarray['deny_gid'] = $str_group_deny; - $datarray['attach'] = $attachments; - $datarray['thr_parent'] = $thr_parent; - $datarray['postopts'] = $postopts; - $datarray['item_unseen'] = intval($item_unseen); - $datarray['item_wall'] = intval($item_wall); - $datarray['item_origin'] = intval($item_origin); - $datarray['item_type'] = $webpage; - $datarray['item_private'] = intval($private); - $datarray['item_thread_top'] = intval($item_thread_top); - $datarray['item_unseen'] = intval($item_unseen); - $datarray['item_starred'] = intval($item_starred); - $datarray['item_uplink'] = intval($item_uplink); - $datarray['item_consensus'] = 0; - $datarray['item_notshown'] = intval($item_notshown); - $datarray['item_nsfw'] = intval($item_nsfw); - $datarray['item_relay'] = intval($item_relay); - $datarray['item_mentionsme'] = intval($item_mentionsme); - $datarray['item_nocomment'] = intval($item_nocomment); - $datarray['item_obscured'] = intval($item_obscured); - $datarray['item_verified'] = intval($item_verified); - $datarray['item_retained'] = intval($item_retained); - $datarray['item_rss'] = intval($item_rss); - $datarray['item_deleted'] = intval($item_deleted); - $datarray['item_hidden'] = intval($item_hidden); - $datarray['item_unpublished'] = intval($item_unpublished); - $datarray['item_delayed'] = intval($item_delayed); - $datarray['item_pending_remove'] = intval($item_pending_remove); - $datarray['item_blocked'] = intval($item_blocked); - $datarray['layout_mid'] = $layout_mid; - $datarray['public_policy'] = $public_policy; - $datarray['comment_policy'] = ((is_numeric($comment_policy)) ? map_scope($comment_policy) : $comment_policy); // only map scope if it is numeric, otherwise use what we have - $datarray['term'] = $post_tags; - $datarray['plink'] = $plink; - $datarray['route'] = $route; - $datarray['replyto'] = $replyto; - - // A specific ACL over-rides public_policy completely - - if(! empty_acl($datarray)) - $datarray['public_policy'] = ''; - - if ($iconfig) { - $datarray['iconfig'] = $iconfig; - } - if ($private) { - IConfig::set($datarray,'ocap','relay',$token); - } - - if(! array_key_exists('obj',$datarray)) { - $copy = $datarray; - $copy['author'] = $observer; - $datarray['obj'] = Activity::encode_item($copy,((get_config('system','activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); - $recips = []; - $i = $datarray['obj']; - if ($i['to']) { - $recips['to'] = $i['to']; - } - if ($i['cc']) { - $recips['cc'] = $i['cc']; - } - IConfig::Set($datarray,'activitypub','recips',$recips); - } - - Activity::rewrite_mentions($datarray); - - // preview mode - prepare the body for display and send it via json - - if($preview) { - require_once('include/conversation.php'); - - $datarray['owner'] = $owner_xchan; - $datarray['author'] = $observer; - $datarray['attach'] = json_encode($datarray['attach']); - $o = conversation(array($datarray),'search',false,'preview'); - // logger('preview: ' . $o, LOGGER_DEBUG); - echo json_encode(array('preview' => $o)); - killme(); - } - - // Let 'post_local' event listeners know if this is an edit. - // We will unset it immediately afterward. - - if ($orig_post) { - $datarray['edit'] = true; - } - - // suppress duplicates, *unless* you're editing an existing post. This could get picked up - // as a duplicate if you're editing it very soon after posting it initially and you edited - // some attribute besides the content, such as title or categories. - - if(PConfig::Get($profile_uid,'system','suppress_duplicates',true) && (! $orig_post)) { - - $z = q("select created from item where uid = %d and created > %s - INTERVAL %s and body = '%s' limit 1", - intval($profile_uid), - db_utcnow(), - db_quoteinterval('2 MINUTE'), - dbesc($body) - ); - - if($z) { - $datarray['cancel'] = 1; - notice( t('Duplicate post suppressed.') . EOL); - logger('Duplicate post. Cancelled.'); - } - } - - call_hooks('post_local',$datarray); - - // This is no longer needed - unset($datarray['edit']); - - if (x($datarray,'cancel')) { - logger('mod_item: post cancelled by plugin or duplicate suppressed.'); - if ($return_path) { - goaway(z_root() . "/" . $return_path); - } - if ($api_source) { - return ( [ 'success' => false, 'message' => 'operation cancelled' ] ); - } - $json = array('cancel' => 1); - $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; - json_return_and_die($json); - } - - - if(mb_strlen($datarray['title']) > 191) - $datarray['title'] = mb_substr($datarray['title'],0,191); - - if($webpage) { - IConfig::Set($datarray,'system', webpage_to_namespace($webpage), - (($pagetitle) ? $pagetitle : basename($datarray['mid'])), true); - } - elseif($namespace) { - IConfig::Set($datarray,'system', $namespace, - (($remote_id) ? $remote_id : basename($datarray['mid'])), true); - } - - if (intval($datarray['item_unpublished'])) { - $draft_msg = t('Draft saved. Use Drafts app to continue editing.'); - } - - if($orig_post) { - $datarray['id'] = $post_id; - - $x = item_store_update($datarray,$execflag); - if(! $parent) { - $r = q("select * from item where id = %d", - intval($post_id) - ); - if($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true)))); - } - } - if (! $nopush) { - Run::Summon( [ 'Notifier', 'edit_post', $post_id ] ); - } - - if ($api_source) { - return($x); - } - - - if (intval($datarray['item_unpublished'])) { - info($draft_msg); - } - - - if((x($_REQUEST,'return')) && strlen($return_path)) { - logger('return: ' . $return_path); - goaway(z_root() . "/" . $return_path ); - } - killme(); - } - else - $post_id = 0; - - $post = item_store($datarray,$execflag); - - if ($pub_copy) { - info( t('Your comment has been posted.') . EOL); - } - - $post_id = $post['item_id']; - $datarray = $post['item']; - - - - if($post_id) { - logger('mod_item: saved item ' . $post_id); - - if($parent) { - - // prevent conversations which you are involved from being expired - - if(local_channel()) - retain_item($parent); - - // only send comment notification if this is a wall-to-wall comment and not a DM, - // otherwise it will happen during delivery - - if(($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall'])) && intval($datarray['item_private']) != 2) { - Enotify::submit(array( - 'type' => NOTIFY_COMMENT, - 'from_xchan' => $datarray['author_xchan'], - 'to_xchan' => $datarray['owner_xchan'], - 'item' => $datarray, - 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), - 'verb' => ACTIVITY_POST, - 'otype' => 'item', - 'parent' => $parent, - 'parent_mid' => $parent_item['mid'] - )); - - } - } - else { - $parent = $post_id; - - if(($datarray['owner_xchan'] != $datarray['author_xchan']) && ($datarray['item_type'] == ITEM_TYPE_POST)) { - Enotify::submit(array( - 'type' => NOTIFY_WALL, - 'from_xchan' => $datarray['author_xchan'], - 'to_xchan' => $datarray['owner_xchan'], - 'item' => $datarray, - 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), - 'verb' => ACTIVITY_POST, - 'otype' => 'item' - )); - } - - if($uid && $uid == $profile_uid && (is_item_normal($datarray))) { - q("update channel set channel_lastpost = '%s' where channel_id = %d", - dbesc(datetime_convert()), - intval($uid) - ); - } - } - - // photo comments turn the corresponding item visible to the profile wall - // This way we don't see every picture in your new photo album posted to your wall at once. - // They will show up as people comment on them. - - if(intval($parent_item['item_hidden'])) { - $r = q("UPDATE item SET item_hidden = 0 WHERE id = %d", - intval($parent_item['id']) - ); - } - } - else { - logger('mod_item: unable to retrieve post that was just stored.'); - notice( t('System error. Post not saved.') . EOL); - if($return_path) - goaway(z_root() . "/" . $return_path ); - if($api_source) - return ( [ 'success' => false, 'message' => 'system error' ] ); - killme(); - } - - if(($parent) && ($parent != $post_id)) { - // Store the comment signature information in case we need to relay to Diaspora - //$ditem = $datarray; - //$ditem['author'] = $observer; - //store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0)); - } - else { - $r = q("select * from item where id = %d", - intval($post_id) - ); - if($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($profile_uid,array('item' => array(encode_item($sync_item[0],true)))); - } - } - - $datarray['id'] = $post_id; - $datarray['llink'] = z_root() . '/display/' . gen_link_id($datarray['mid']); - - call_hooks('post_local_end', $datarray); - - if ($groupww) { - $nopush = false; - } - - if(! $nopush) { - Run::Summon( [ 'Notifier', $notify_type, $post_id ] ); - } - logger('post_complete'); - - if($moderated) { - info(t('Your post/comment is awaiting approval.') . EOL); - } - - // figure out how to return, depending on from whence we came - - if($api_source) - return $post; - - if (intval($datarray['item_unpublished'])) { - info($draft_msg); - } - - if($return_path) { - goaway(z_root() . "/" . $return_path); - } - - $json = array('success' => 1); - if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload'])) - $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; - - logger('post_json: ' . print_r($json,true), LOGGER_DEBUG); - - echo json_encode($json); - killme(); - // NOTREACHED - } - - - function get() { - - - if ($this->return_404) { - notice( t('Not found') ); - return; - } - - if((! local_channel()) && (! remote_channel())) - return; - - // allow pinned items to be dropped. 'pin-' was prepended to the id of these - // items so that they would have a unique html id even if the pinned item - // was also displayed in a normal conversation on the same web page. - - $drop_id = str_replace('pin-','',argv(2)); - - if((argc() == 3) && (argv(1) === 'drop') && intval($drop_id)) { - - $i = q("select * from item where id = %d limit 1", - intval($drop_id) - ); - - if($i) { - $can_delete = false; - $local_delete = false; - $regular_delete = false; - - if(local_channel() && local_channel() == $i[0]['uid']) { - $local_delete = true; - } - - $ob_hash = get_observer_hash(); - if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { - $can_delete = true; - $regular_delete = true; - } - - // The site admin can delete any post/item on the site. - // If the item originated on this site+channel the deletion will propagate downstream. - // Otherwise just the local copy is removed. - - if(is_site_admin()) { - $local_delete = true; - if(intval($i[0]['item_origin'])) - $can_delete = true; - } - - - if(! ($can_delete || $local_delete)) { - notice( t('Permission denied.') . EOL); - return; - } - - if ($i[0]['resource_type'] === 'event') { - // delete and sync the event separately - $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", - dbesc($i[0]['resource_id']), - intval($i[0]['uid']) - ); - if ($r && $regular_delete) { - $sync_event = $r[0]; - q("delete from event WHERE event_hash = '%s' AND uid = %d LIMIT 1", - dbesc($i[0]['resource_id']), - intval($i[0]['uid']) - ); - $sync_event['event_deleted'] = 1; - Libsync::build_sync_packet($i[0]['uid'],array('event' => array($sync_event))); - } - } - - if ($i[0]['resource_type'] === 'photo') { - attach_delete($i[0]['uid'], $i[0]['resource_id'], true ); - $ch = channelx_by_n($i[0]['uid']); - if ($ch && $regular_delete) { - $sync = attach_export_data($ch,$i[0]['resource_id'], true); - if ($sync) { - Libsync::build_sync_packet($i[0]['uid'],array('file' => array($sync))); - } - } - } - - - // if this is a different page type or it's just a local delete - // but not by the item author or owner, do a simple deletion - - $complex = false; - - if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) { - drop_item($i[0]['id']); - } - else { - // complex deletion that needs to propagate and be performed in phases - drop_item($i[0]['id'],true,DROPITEM_PHASE1); - $complex = true; - } - - $r = q("select * from item where id = %d", - intval($i[0]['id']) - ); - if($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true)))); - } - - if($complex) { - tag_deliver($i[0]['uid'],$i[0]['id']); - } - } - } - } - - - - function item_check_service_class($channel_id,$iswebpage) { - $ret = array('success' => false, 'message' => ''); - - if ($iswebpage) { - $r = q("select count(i.id) as total from item i +class Item extends Controller +{ + + public $return_404 = false; + + public function init() + { + + + if (ActivityStreams::is_as_request()) { + $item_uuid = argv(1); + if (!$item_uuid) { + http_status_exit(404, 'Not found'); + } + $portable_id = EMPTY_STR; + + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 "; + + $i = null; + + // do we have the item (at all)? + // add preferential bias to item owners (item_wall = 1) + + $r = q("select * from item where (mid = '%s' or uuid = '%s') $item_normal order by item_wall desc limit 1", + dbesc(z_root() . '/item/' . $item_uuid), + dbesc($item_uuid) + ); + + if (!$r) { + http_status_exit(404, 'Not found'); + } + + // process an authenticated fetch + + + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (!check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (!check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + + $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1 ", + dbesc($r[0]['parent_mid']), + dbesc($portable_id) + ); + } elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); + } + + // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access + // with a bias towards those items owned by channels on this site (item_wall = 1) + + $sql_extra = item_permissions_sql(0); + + if (!$i) { + $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", + dbesc($r[0]['parent_mid']) + ); + } + + $bear = Activity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + if (!$i) { + $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'", + dbesc($bear) + ); + if ($t) { + $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1", + dbesc($item_uuid), + intval($t[0]['iid']) + ); + } + } + } + + if (!$i) { + http_status_exit(403, 'Forbidden'); + } + + // If we get to this point we have determined we can access the original in $r (fetched much further above), so use it. + + xchan_query($r, true); + $items = fetch_post_tags($r, false); + + $chan = channelx_by_n($items[0]['uid']); + + if (!$chan) { + http_status_exit(404, 'Not found'); + } + + if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) { + http_status_exit(403, 'Forbidden'); + } + + $i = Activity::encode_item($items[0], true); + + if (!$i) { + http_status_exit(404, 'Not found'); + } + + + if ($portable_id && (!intval($items[0]['item_private']))) { + $c = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", + intval($items[0]['uid']), + dbesc($portable_id) + ); + if (!$c) { + ThreadListener::store(z_root() . '/item/' . $item_uuid, $portable_id); + } + } + + as_return_and_die($i, $chan); + } + + if (Libzot::is_zot_request()) { + + $item_uuid = argv(1); + + if (!$item_uuid) { + http_status_exit(404, 'Not found'); + } + + $portable_id = EMPTY_STR; + + $item_normal = " and item.item_hidden = 0 and item.item_type = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_blocked = 0 and not verb in ( 'Follow', 'Ignore' ) "; + + $i = null; + + // do we have the item (at all)? + + $r = q("select * from item where (mid = '%s' or uuid = '%s') $item_normal limit 1", + dbesc(z_root() . '/item/' . $item_uuid), + dbesc($item_uuid) + ); + + if (!$r) { + http_status_exit(404, 'Not found'); + } + + // process an authenticated fetch + + $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (!check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (!check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + + $i = q("select id as item_id from item where mid = '%s' $item_normal and owner_xchan = '%s' limit 1", + dbesc($r[0]['parent_mid']), + dbesc($portable_id) + ); + } elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); + } + + // if we don't have a parent id belonging to the signer see if we can obtain one as a visitor that we have permission to access + // with a bias towards those items owned by channels on this site (item_wall = 1) + + $sql_extra = item_permissions_sql(0); + + if (!$i) { + $i = q("select id as item_id from item where mid = '%s' $item_normal $sql_extra order by item_wall desc limit 1", + dbesc($r[0]['parent_mid']) + ); + } + + $bear = Activity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + if (!$i) { + $t = q("select * from iconfig where cat = 'ocap' and k = 'relay' and v = '%s'", + dbesc($bear) + ); + if ($t) { + $i = q("select id as item_id from item where uuid = '%s' and id = %d $item_normal limit 1", + dbesc($item_uuid), + intval($t[0]['iid']) + ); + } + } + } + + if (!$i) { + http_status_exit(403, 'Forbidden'); + } + + $parents_str = ids_to_querystr($i, 'item_id'); + + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE item.parent IN ( %s ) $item_normal order by item.id asc", + dbesc($parents_str) + ); + + if (!$items) { + http_status_exit(404, 'Not found'); + } + + xchan_query($items, true); + $items = fetch_post_tags($items, true); + + if (!$items) { + http_status_exit(404, 'Not found'); + } + $chan = channelx_by_n($items[0]['uid']); + + if (!$chan) { + http_status_exit(404, 'Not found'); + } + + if (!perm_is_allowed($chan['channel_id'], get_observer_hash(), 'view_stream')) { + http_status_exit(403, 'Forbidden'); + } + + $i = Activity::encode_item_collection($items, 'conversation/' . $item_uuid, 'OrderedCollection', true, count($items)); + if ($portable_id && (!intval($items[0]['item_private']))) { + ThreadListener::store(z_root() . '/item/' . $item_uuid, $portable_id); + } + + if (!$i) { + http_status_exit(404, 'Not found'); + } + $x = array_merge(['@context' => [ + ACTIVITYSTREAMS_JSONLD_REV, + 'https://w3id.org/security/v1', + Activity::ap_schema() + ]], $i); + + $headers = []; + $headers['Content-Type'] = 'application/x-zot+json'; + $x['signature'] = LDSignatures::sign($x, $chan); + $ret = json_encode($x, JSON_UNESCAPED_SLASHES); + $headers['Digest'] = HTTPSig::generate_digest_header($ret); + $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; + $h = HTTPSig::create_sig($headers, $chan['channel_prvkey'], channel_url($chan)); + HTTPSig::set_headers($h); + echo $ret; + killme(); + + } + + // if it isn't a drop command and isn't a post method and wasn't handled already, + // the default action is a browser request for a persistent uri and this should return + // the text/html page of the item. + + if (argc() > 1 && argv(1) !== 'drop') { + $x = q("select uid, item_wall, llink, mid from item where mid = '%s' or mid = '%s' or uuid = '%s'", + dbesc(z_root() . '/item/' . argv(1)), + dbesc(z_root() . '/activity/' . argv(1)), + dbesc(argv(1)) + ); + if ($x) { + foreach ($x as $xv) { + if (intval($xv['item_wall'])) { + $c = channelx_by_n($xv['uid']); + if ($c) { + goaway($c['xchan_url'] . '?mid=' . gen_link_id($xv['mid'])); + } + } + } + goaway($x[0]['llink']); + } + + // save this state and catch it in the get() function + $this->return_404 = true; + } + } + + public function post() + { + + if ((!local_channel()) && (!remote_channel()) && (!isset($_REQUEST['anonname']))) { + return; + } + + // drop an array of items. + + if (isset($_REQUEST['dropitems'])) { + $arr_drop = explode(',', $_REQUEST['dropitems']); + drop_items($arr_drop); + $json = array('success' => 1); + echo json_encode($json); + killme(); + } + + + $uid = local_channel(); + $channel = null; + $observer = null; + $token = EMPTY_STR; + $datarray = []; + $item_starred = false; + $item_uplink = false; + $item_notshown = false; + $item_nsfw = false; + $item_relay = false; + $item_mentionsme = false; + $item_verified = false; + $item_retained = false; + $item_rss = false; + $item_deleted = false; + $item_hidden = false; + $item_delayed = false; + $item_pending_remove = false; + $item_blocked = false; + + $post_tags = false; + $pub_copy = false; + + + /** + * Is this a reply to something? + */ + + $parent = ((isset($_REQUEST['parent'])) ? intval($_REQUEST['parent']) : 0); + $parent_mid = ((isset($_REQUEST['parent_mid'])) ? trim($_REQUEST['parent_mid']) : ''); + + $hidden_mentions = ((isset($_REQUEST['hidden_mentions'])) ? trim($_REQUEST['hidden_mentions']) : ''); + + + /** + * Who is viewing this page and posting this thing + */ + + $remote_xchan = ((isset($_REQUEST['remote_xchan'])) ? trim($_REQUEST['remote_xchan']) : false); + $remote_observer = xchan_match(['xchan_hash' => $remote_xchan]); + + if (!$remote_observer) { + $remote_xchan = $remote_observer = false; + } + + // This is the local channel representing who the posted item will belong to. + + $profile_uid = ((isset($_REQUEST['profile_uid'])) ? intval($_REQUEST['profile_uid']) : 0); + + // *If* you are logged in as the site admin you are allowed to create top-level items for the sys channel. + // This would typically be a webpage or webpage element. + // Comments and replies are excluded because further below we also check for sys channel ownership and + // will make a copy of the parent that you can interact with in your own stream + + $sys = get_sys_channel(); + if ($sys && $profile_uid && ($sys['channel_id'] == $profile_uid) && is_site_admin() && !$parent) { + $uid = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + + call_hooks('post_local_start', $_REQUEST); + + // logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); + + $api_source = ((isset($_REQUEST['api_source']) && $_REQUEST['api_source']) ? true : false); + + $nocomment = 0; + if (isset($_REQUEST['comments_enabled'])) { + $nocomment = 1 - intval($_REQUEST['comments_enabled']); + } + + // this is in days, convert to absolute time + $channel_comments_closed = get_pconfig($profile_uid, 'system', 'close_comments'); + if (intval($channel_comments_closed)) { + $channel_comments_closed = datetime_convert(date_Default_timezone_get(), 'UTC', 'now + ' . intval($channel_comments_closed) . ' days'); + } else { + $channel_comments_closed = NULL_DATE; + } + + $comments_closed = ((isset($_REQUEST['comments_closed']) && $_REQUEST['comments_closed']) ? datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['comments_closed']) : $channel_comments_closed); + + $is_poll = ((trim($_REQUEST['poll_answers'][0]) != '' && trim($_REQUEST['poll_answers'][1]) != '') ? true : false); + + // 'origin' (if non-zero) indicates that this network is where the message originated, + // for the purpose of relaying comments to other conversation members. + // If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset. + // If the API is used from another network with its own distribution + // and deliveries, you may wish to set origin to 0 or false and allow the other + // network to relay comments. + + // If you are unsure, it is prudent (and important) to leave it unset. + + $origin = (($api_source && array_key_exists('origin', $_REQUEST)) ? intval($_REQUEST['origin']) : 1); + + // To represent message-ids on other networks - this will create an iconfig record + + $namespace = (($api_source && array_key_exists('namespace', $_REQUEST)) ? strip_tags($_REQUEST['namespace']) : ''); + $remote_id = (($api_source && array_key_exists('remote_id', $_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : ''); + + $owner_hash = null; + + $message_id = ((x($_REQUEST, 'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); + $created = ((x($_REQUEST, 'created')) ? datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['created']) : datetime_convert()); + + // Because somebody will probably try this and create a mess + + if ($created <= NULL_DATE) { + $created = datetime_convert(); + } + + $post_id = ((x($_REQUEST, 'post_id')) ? intval($_REQUEST['post_id']) : 0); + + $app = ((x($_REQUEST, 'source')) ? strip_tags($_REQUEST['source']) : ''); + $return_path = ((x($_REQUEST, 'return')) ? $_REQUEST['return'] : ''); + $preview = ((x($_REQUEST, 'preview')) ? intval($_REQUEST['preview']) : 0); + $categories = ((x($_REQUEST, 'category')) ? escape_tags($_REQUEST['category']) : ''); + $webpage = ((x($_REQUEST, 'webpage')) ? intval($_REQUEST['webpage']) : 0); + $item_obscured = ((x($_REQUEST, 'obscured')) ? intval($_REQUEST['obscured']) : 0); + $pagetitle = ((x($_REQUEST, 'pagetitle')) ? escape_tags(urlencode($_REQUEST['pagetitle'])) : ''); + $layout_mid = ((x($_REQUEST, 'layout_mid')) ? escape_tags($_REQUEST['layout_mid']) : ''); + $plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); + $obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE); + + + $item_unpublished = ((isset($_REQUEST['draft'])) ? intval($_REQUEST['draft']) : 0); + + // allow API to bulk load a bunch of imported items without sending out a bunch of posts. + $nopush = ((x($_REQUEST, 'nopush')) ? intval($_REQUEST['nopush']) : 0); + + /* + * Check service class limits + */ + if ($uid && !(x($_REQUEST, 'parent')) && !(x($_REQUEST, 'post_id'))) { + $ret = $this->item_check_service_class($uid, (($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false)); + if (!$ret['success']) { + notice(t($ret['message']) . EOL); + if ($api_source) + return (['success' => false, 'message' => 'service class exception']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); + killme(); + } + } + + if ($pagetitle) { + $pagetitle = strtolower(URLify::transliterate($pagetitle)); + } + + $item_flags = $item_restrict = 0; + $expires = NULL_DATE; + + $route = ''; + $parent_item = null; + $parent_contact = null; + $thr_parent = ''; + $parid = 0; + $r = false; + + + // If this is a comment, find the parent and preset some stuff + + if ($parent || $parent_mid) { + + if (!x($_REQUEST, 'type')) { + $_REQUEST['type'] = 'net-comment'; + } + if ($obj_type == ACTIVITY_OBJ_NOTE) { + $obj_type = ACTIVITY_OBJ_COMMENT; + } + + // fetch the parent item + + if ($parent) { + $r = q("SELECT * FROM item WHERE id = %d LIMIT 1", + intval($parent) + ); + } elseif ($parent_mid && $uid) { + // This is coming from an API source, and we are logged in + $r = q("SELECT * FROM item WHERE mid = '%s' AND uid = %d LIMIT 1", + dbesc($parent_mid), + intval($uid) + ); + } + + // if this isn't the real parent of the conversation, find it + if ($r) { + $parid = $r[0]['parent']; + $parent_mid = $r[0]['mid']; + if ($r[0]['id'] != $r[0]['parent']) { + $r = q("SELECT * FROM item WHERE id = parent AND parent = %d LIMIT 1", + intval($parid) + ); + } + + // if interacting with a pubstream item (owned by the sys channel), + // create a copy of the parent in your stream + + // $r may have changed. Check it again before trying to use it. + + if ($r && local_channel() && (!is_sys_channel(local_channel()))) { + $old_id = $r[0]['id']; + $r = [copy_of_pubitem(App::get_channel(), $r[0]['mid'])]; + if ($r[0]['id'] !== $old_id) { + // keep track that a copy was made to display a special status notice that is unique to this condition + $pub_copy = true; + } + } + } + + if (!$r) { + notice(t('Unable to locate original post.') . EOL); + if ($api_source) { + return (['success' => false, 'message' => 'invalid post id']); + } + if (x($_REQUEST, 'return')) { + goaway(z_root() . "/" . $return_path); + } + killme(); + } + + xchan_query($r, true); + + $parent_item = $r[0]; + $parent = $r[0]['id']; + + // multi-level threading - preserve the info but re-parent to our single level threading + + $thr_parent = $parent_mid; + + $route = $parent_item['route']; + + } + + if ($parent_item && isset($parent_item['replyto']) && $parent_item['replyto']) { + $replyto = unserialise($parent_item['replyto']); + } + + $moderated = false; + + if (!$observer) { + $observer = App::get_observer(); + if (!$observer) { + // perhaps we're allowing moderated comments from anonymous viewers + $observer = anon_identity_init($_REQUEST); + if ($observer) { + $moderated = true; + $remote_xchan = $remote_observer = $observer; + } + } + } + + if (!$observer) { + notice(t('Permission denied.') . EOL); + if ($api_source) { + return (['success' => false, 'message' => 'permission denied']); + } + if (x($_REQUEST, 'return')) { + goaway(z_root() . "/" . $return_path); + } + killme(); + } + + if ($parent) { + logger('mod_item: item_post parent=' . $parent); + $can_comment = false; + + $can_comment = can_comment_on_post($observer['xchan_hash'], $parent_item); + if (!$can_comment) { + if ((array_key_exists('owner', $parent_item)) && intval($parent_item['owner']['abook_self']) == 1) { + $can_comment = perm_is_allowed($profile_uid, $observer['xchan_hash'], 'post_comments'); + } + } + + if (!$can_comment) { + notice(t('Permission denied.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'permission denied']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); + killme(); + } + } else { + // fixme - $webpage could also be a wiki page or article and require a different permission to be checked. + if (!perm_is_allowed($profile_uid, $observer['xchan_hash'], ($webpage) ? 'write_pages' : 'post_wall')) { + notice(t('Permission denied.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'permission denied']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); + killme(); + } + } + + // check if this author is being moderated through the 'moderated' (negative) permission + // when posting wall-to-wall + if ($moderated === false && intval($uid) !== intval($profile_uid)) { + $moderated = perm_is_allowed($profile_uid, $observer['xchan_hash'], 'moderated'); + } + + // If this is a comment, check the moderated permission of the parent; who may be on another site + $remote_moderated = (($parent) ? their_perms_contains($profile_uid, $parent_item['owner_xchan'], 'moderated') : false); + if ($remote_moderated) { + notice(t('Comment may be moderated.') . EOL); + } + + // is this an edited post? + + $orig_post = null; + + if ($namespace && $remote_id) { + // It wasn't an internally generated post - see if we've got an item matching this remote service id + $i = q("select iid from iconfig where cat = 'system' and k = '%s' and v = '%s' limit 1", + dbesc($namespace), + dbesc($remote_id) + ); + if ($i) + $post_id = $i[0]['iid']; + } + + $iconfig = null; + + if ($post_id) { + $i = q("SELECT * FROM item WHERE uid = %d AND id = %d LIMIT 1", + intval($profile_uid), + intval($post_id) + ); + if (!count($i)) + killme(); + $orig_post = $i[0]; + $iconfig = q("select * from iconfig where iid = %d", + intval($post_id) + ); + } + + + if (!$channel) { + if ($uid && $uid == $profile_uid) { + $channel = App::get_channel(); + } else { + // posting as yourself but not necessarily to a channel you control + $r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1", + intval($profile_uid) + ); + if ($r) + $channel = $r[0]; + } + } + + + if (!$channel) { + logger("mod_item: no channel."); + if ($api_source) + return (['success' => false, 'message' => 'no channel']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); + killme(); + } + + $owner_xchan = null; + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($channel['channel_hash']) + ); + if ($r && count($r)) { + $owner_xchan = $r[0]; + } else { + logger("mod_item: no owner."); + if ($api_source) + return (['success' => false, 'message' => 'no owner']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); + killme(); + } + + $walltowall = false; + $walltowall_comment = false; + + if ($remote_xchan && !$moderated) + $observer = $remote_observer; + + if ($observer) { + logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG); + + // wall-to-wall detection. + // For top-level posts, if the author and owner are different it's a wall-to-wall + // For comments, We need to additionally look at the parent and see if it's a wall post that originated locally. + + if ($observer['xchan_name'] != $owner_xchan['xchan_name']) { + if (($parent_item) && ($parent_item['item_wall'] && $parent_item['item_origin'])) { + $walltowall_comment = true; + $walltowall = true; + } + if (!$parent) { + $walltowall = true; + } + } + } + + if (!isset($replyto)) { + if (strpos($owner_xchan['xchan_hash'], 'http') === 0) { + $replyto = $owner_xchan['xchan_hash']; + } else { + $replyto = $owner_xchan['xchan_url']; + } + } + + + $acl = new AccessControl($channel); + + $view_policy = PermissionLimits::Get($channel['channel_id'], 'view_stream'); + $comment_policy = ((isset($_REQUEST['comments_from']) && intval($_REQUEST['comments_from'])) ? intval($_REQUEST['comments_from']) : PermissionLimits::Get($channel['channel_id'], 'post_comments')); + + $public_policy = ((x($_REQUEST, 'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($view_policy, true)); + if ($webpage) + $public_policy = ''; + if ($public_policy) + $private = 1; + + if ($orig_post) { + + $private = 0; + // webpages and unpublished drafts are allowed to change ACLs after the fact. Normal conversation items aren't. + if ($webpage || intval($orig_post['item_unpublished'])) { + $acl->set_from_array($_REQUEST); + } else { + $acl->set($orig_post); + $public_policy = $orig_post['public_policy']; + $private = $orig_post['item_private']; + } + + if ($public_policy || $acl->is_private()) { + $private = (($private) ? $private : 1); + } + + $location = $orig_post['location']; + $coord = $orig_post['coord']; + $verb = $orig_post['verb']; + $app = $orig_post['app']; + $title = escape_tags(trim($_REQUEST['title'])); + $summary = trim($_REQUEST['summary']); + $body = trim($_REQUEST['body']); + + $item_flags = $orig_post['item_flags']; + $item_origin = $orig_post['item_origin']; + $item_unseen = $orig_post['item_unseen']; + $item_starred = $orig_post['item_starred']; + $item_uplink = $orig_post['item_uplink']; + $item_wall = $orig_post['item_wall']; + $item_thread_top = $orig_post['item_thread_top']; + $item_notshown = $orig_post['item_notshown']; + $item_nsfw = $orig_post['item_nsfw']; + $item_relay = $orig_post['item_relay']; + $item_mentionsme = $orig_post['item_mentionsme']; + $item_nocomment = $orig_post['item_nocomment']; + $item_obscured = $orig_post['item_obscured']; + $item_verified = $orig_post['item_verified']; + $item_retained = $orig_post['item_retained']; + $item_rss = $orig_post['item_rss']; + $item_deleted = $orig_post['item_deleted']; + $item_type = $orig_post['item_type']; + $item_hidden = $orig_post['item_hidden']; + $item_delayed = $orig_post['item_delayed']; + $item_pending_remove = $orig_post['item_pending_remove']; + $item_blocked = $orig_post['item_blocked']; + + + $postopts = $orig_post['postopts']; + $created = ((intval($orig_post['item_unpublished'])) ? $created : $orig_post['created']); + $expires = ((intval($orig_post['item_unpublished'])) ? NULL_DATE : $orig_post['expires']); + $mid = $orig_post['mid']; + $parent_mid = $orig_post['parent_mid']; + $plink = $orig_post['plink']; + + } else { + if (!$walltowall) { + if ((array_key_exists('contact_allow', $_REQUEST)) + || (array_key_exists('group_allow', $_REQUEST)) + || (array_key_exists('contact_deny', $_REQUEST)) + || (array_key_exists('group_deny', $_REQUEST))) { + $acl->set_from_array($_REQUEST); + } elseif (!$api_source) { + + // if no ACL has been defined and we aren't using the API, the form + // didn't send us any parameters. This means there's no ACL or it has + // been reset to the default audience. + // If $api_source is set and there are no ACL parameters, we default + // to the channel permissions which were set in the ACL contructor. + + $acl->set(array('allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '')); + } + } + + + $location = ((isset($_REQUEST['location'])) ? notags(trim($_REQUEST['location'])) : EMPTY_STR); + $coord = ((isset($_REQUEST['coord'])) ? notags(trim($_REQUEST['coord'])) : EMPTY_STR); + $verb = ((isset($_REQUEST['verb'])) ? notags(trim($_REQUEST['verb'])) : EMPTY_STR); + $title = ((isset($_REQUEST['title'])) ? escape_tags(trim($_REQUEST['title'])) : EMPTY_STR); + $summary = ((isset($_REQUEST['summary'])) ? trim($_REQUEST['summary']) : EMPTY_STR); + $body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : EMPTY_STR); + $body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : EMPTY_STR); + $postopts = ''; + + $allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); + + $private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy))); + + // If this is a comment, set the permissions from the parent. + + if ($parent_item) { + $private = 0; + $acl->set($parent_item); + $private = ((intval($parent_item['item_private']) ? $parent_item['item_private'] : $acl->is_private())); + $public_policy = $parent_item['public_policy']; + $owner_hash = $parent_item['owner_xchan']; + $webpage = $parent_item['item_type']; + $comment_policy = $parent_item['comment_policy']; + $item_nocomment = $parent_item['item_nocomment']; + $comments_closed = $parent_item['comments_closed']; + } + + if ((!$allow_empty) && (!strlen($body))) { + if ($preview) + killme(); + info(t('Empty post discarded.') . EOL); + if ($api_source) + return (['success' => false, 'message' => 'no content']); + if (x($_REQUEST, 'return')) + goaway(z_root() . "/" . $return_path); + killme(); + } + } + + + if (Apps::system_app_installed($profile_uid, 'Expire Posts')) { + if (x($_REQUEST, 'expire')) { + $expires = datetime_convert(date_default_timezone_get(), 'UTC', $_REQUEST['expire']); + if ($expires <= datetime_convert()) + $expires = NULL_DATE; + } + } + + + $mimetype = notags(trim($_REQUEST['mimetype'])); + if (!$mimetype) + $mimetype = 'text/bbcode'; + + + $execflag = ((intval($uid) == intval($profile_uid) + && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false); + + if ($preview) { + $summary = z_input_filter($summary, $mimetype, $execflag); + $body = z_input_filter($body, $mimetype, $execflag); + } + + + $arr = ['profile_uid' => $profile_uid, 'summary' => $summary, 'content' => $body, 'mimetype' => $mimetype]; + call_hooks('post_content', $arr); + $summary = $arr['summary']; + $body = $arr['content']; + $mimetype = $arr['mimetype']; + + + $gacl = $acl->get(); + $str_contact_allow = $gacl['allow_cid']; + $str_group_allow = $gacl['allow_gid']; + $str_contact_deny = $gacl['deny_cid']; + $str_group_deny = $gacl['deny_gid']; + + + // if the acl contains a single contact and it's a group, add a mention. This is for compatibility + // with other groups implementations which require a mention to trigger group delivery. + + if (($str_contact_allow) && (!$str_group_allow) && (!$str_contact_deny) && (!$str_group_deny)) { + $cida = expand_acl($str_contact_allow); + if (count($cida) === 1) { + $netgroups = get_forum_channels($profile_uid, 1); + if ($netgroups) { + foreach ($netgroups as $ng) { + if ($ng['xchan_hash'] == $cida[0]) { + if (!is_array($post_tags)) { + $post_tags = []; + } + $post_tags[] = array( + 'uid' => $profile_uid, + 'ttype' => TERM_MENTION, + 'otype' => TERM_OBJ_POST, + 'term' => $ng['xchan_name'], + 'url' => $ng['xchan_url'] + ); + + $colls = get_xconfig($ng['xchan_hash'], 'activitypub', 'collections'); + if ($colls && is_array($colls) && isset($colls['wall'])) { + $datarray['target'] = [ + 'id' => $colls['wall'], + 'type' => 'Collection', + 'attributedTo' => (($ng['xchan_network'] === 'zot6') ? $ng['xchan_url'] : $ng['xchan_hash']) + ]; + $datarray['tgt_type'] = 'Collection'; + } + } + } + } + } + } + + $groupww = false; + + // if this is a wall-to-wall post to a group, turn it into a direct message + + $role = get_pconfig($profile_uid, 'system', 'permissions_role'); + + $rolesettings = PermissionRoles::role_perms($role); + + $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; + + $is_group = (($channel_type === 'group') ? true : false); + + if (($is_group) && ($walltowall) && (!$walltowall_comment)) { + $groupww = true; + $str_contact_allow = $owner_xchan['xchan_hash']; + $str_group_allow = ''; + } + + + if ($mimetype === 'text/bbcode') { + + // BBCODE alert: the following functions assume bbcode input + // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) + // we may need virtual or template classes to implement the possible alternatives + + if (strpos($body, '[/summary]') !== false) { + $match = ''; + $cnt = preg_match("/\[summary\](.*?)\[\/summary\]/ism", $body, $match); + if ($cnt) { + $summary .= $match[1]; + } + $body_content = preg_replace("/^(.*?)\[summary\](.*?)\[\/summary\]/ism", '', $body); + $body = trim($body_content); + } + + $summary = cleanup_bbcode($summary); + $body = cleanup_bbcode($body); + + // Look for tags and linkify them + $summary_tags = linkify_tags($summary, ($uid) ? $uid : $profile_uid); + $body_tags = linkify_tags($body, ($uid) ? $uid : $profile_uid); + $comment_tags = linkify_tags($hidden_mentions, ($uid) ? $uid : $profile_uid); + + foreach ([$summary_tags, $body_tags, $comment_tags] as $results) { + + if ($results) { + + // Set permissions based on tag replacements + set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private); + + if (!isset($post_tags)) { + $post_tags = []; + } + foreach ($results as $result) { + $success = $result['success']; + if ($success['replaced']) { + + // suppress duplicate mentions/tags + $already_tagged = false; + foreach ($post_tags as $pt) { + if ($pt['term'] === $success['term'] && $pt['url'] === $success['url'] && intval($pt['ttype']) === intval($success['termtype'])) { + $already_tagged = true; + break; + } + } + if ($already_tagged) { + continue; + } + + $post_tags[] = array( + 'uid' => $profile_uid, + 'ttype' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + + // support #collection syntax to post to a collection + // this is accomplished by adding a pcategory tag for each collection target + // this is checked inside tag_deliver() to create a second delivery chain + + if ($success['termtype'] === TERM_HASHTAG) { + $r = q("select xchan_url from channel left join xchan on xchan_hash = channel_hash where channel_address = '%s' and channel_parent = '%s' and channel_removed = 0", + dbesc($success['term']), + dbesc(get_observer_hash()) + ); + if ($r) { + $post_tags[] = [ + 'uid' => $profile_uid, + 'ttype' => TERM_PCATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'] . '@' . App::get_hostname(), + 'url' => $r[0]['xchan_url'] + ]; + } + } + } + } + } + } + + + /** + * process collections selected manually + */ + + if (array_key_exists('collections', $_REQUEST) && is_array($_REQUEST['collections']) && count($_REQUEST['collections'])) { + foreach ($_REQUEST['collections'] as $clct) { + $r = q("select xchan_url, xchan_hash from xchan left join hubloc on hubloc_hash = xchan_hash where hubloc_addr = '%s' limit 1", + dbesc($clct) + ); + if ($r) { + if (!isset($post_tags)) { + $post_tags = []; + } + $post_tags[] = [ + 'uid' => $profile_uid, + 'ttype' => TERM_PCATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => $clct, + 'url' => $r[0]['xchan_url'] + ]; + } + } + } + + if (($str_contact_allow) && (!$str_group_allow)) { + // direct message - private between individual channels but not groups + $private = 2; + } + + if ($private) { + + // for edited posts, re-use any existing OCAP token (if found). + // Otherwise generate a new one. + + if ($iconfig) { + foreach ($iconfig as $cfg) { + if ($cfg['cat'] === 'ocap' && $cfg['k'] === 'relay') { + $token = $cfg['v']; + } + } + } + if (!$token) { + $token = new_token(); + } + } + + + /** + * + * When a photo was uploaded into the message using the (profile wall) ajax + * uploader, The permissions are initially set to disallow anybody but the + * owner from seeing it. This is because the permissions may not yet have been + * set for the post. If it's private, the photo permissions should be set + * appropriately. But we didn't know the final permissions on the post until + * now. So now we'll look for links of uploaded photos and attachments that are in the + * post and set them to the same permissions as the post itself. + * + * If the post was end-to-end encrypted we can't find images and attachments in the body, + * use our media_str input instead which only contains these elements - but only do this + * when encrypted content exists because the photo/attachment may have been removed from + * the post and we should keep it private. If it's encrypted we have no way of knowing + * so we'll set the permissions regardless and realise that the media may not be + * referenced in the post. + * + */ + + if (!$preview) { + fix_attached_permissions($profile_uid, ((strpos($body, '[/crypt]')) ? $_POST['media_str'] : $body), $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny, $token); + } + + + $attachments = ''; + $match = false; + + if (preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/', $body, $match)) { + $attachments = []; + $i = 0; + foreach ($match[2] as $mtch) { + $attach_link = ''; + $hash = substr($mtch, 0, strpos($mtch, ',')); + $rev = intval(substr($mtch, strpos($mtch, ','))); + $r = attach_by_hash_nodata($hash, $observer['xchan_hash'], $rev); + if ($r['success']) { + $attachments[] = array( + 'href' => z_root() . '/attach/' . $r['data']['hash'], + 'length' => $r['data']['filesize'], + 'type' => $r['data']['filetype'], + 'title' => urlencode($r['data']['filename']), + 'revision' => $r['data']['revision'] + ); + } + $body = str_replace($match[1][$i], $attach_link, $body); + $i++; + } + } + + + if (preg_match_all('/(\[share=(.*?)\](.*?)\[\/share\])/', $body, $match)) { + // process share by id + + $i = 0; + foreach ($match[2] as $mtch) { + $reshare = new \Zotlabs\Lib\Share($mtch); + $body = str_replace($match[1][$i], $reshare->bbcode(), $body); + $i++; + } + } + + } + + // BBCODE end alert + + if (strlen($categories)) { + if (!isset($post_tags)) { + $post_tags = []; + } + + $cats = explode(',', $categories); + foreach ($cats as $cat) { + + if ($webpage == ITEM_TYPE_CARD) { + $catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); + } elseif ($webpage == ITEM_TYPE_ARTICLE) { + $catlink = z_root() . '/articles/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat)); + } else { + $catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)); + } + + $post_tags[] = array( + 'uid' => $profile_uid, + 'ttype' => TERM_CATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => trim($cat), + 'url' => $catlink + ); + } + } + + if ($orig_post) { + // preserve original tags + $t = q("select * from term where oid = %d and otype = %d and uid = %d and ttype in ( %d, %d, %d )", + intval($orig_post['id']), + intval(TERM_OBJ_POST), + intval($profile_uid), + intval(TERM_UNKNOWN), + intval(TERM_FILE), + intval(TERM_COMMUNITYTAG) + ); + if ($t) { + if (!isset($post_tags)) { + $post_tags = []; + } + + foreach ($t as $t1) { + $post_tags[] = array( + 'uid' => $profile_uid, + 'ttype' => $t1['ttype'], + 'otype' => TERM_OBJ_POST, + 'term' => $t1['term'], + 'url' => $t1['url'], + ); + } + } + } + + + $item_unseen = ((local_channel() != $profile_uid) ? 1 : 0); + $item_wall = ((isset($_REQUEST['type']) && ($_REQUEST['type'] === 'wall' || $_REQUEST['type'] === 'wall-comment')) ? 1 : 0); + $item_origin = (($origin) ? 1 : 0); + $item_nocomment = ((isset($item_nocomment)) ? $item_nocomment : $nocomment); + + + // determine if this is a wall post + + if ($parent) { + $item_wall = $parent_item['item_wall']; + } else { + if (!$webpage) { + $item_wall = 1; + } + } + + + if ($moderated) + $item_blocked = ITEM_MODERATED; + + + if (!strlen($verb)) + $verb = ACTIVITY_POST; + + $notify_type = (($parent) ? 'comment-new' : 'wall-new'); + + if (!(isset($mid) && $mid)) { + if ($message_id) { + $mid = $message_id; + } else { + $uuid = new_uuid(); + $mid = z_root() . '/item/' . $uuid; + } + } + + + if ($is_poll) { + $poll = [ + 'question' => $body, + 'answers' => $_REQUEST['poll_answers'], + 'multiple_answers' => $_REQUEST['poll_multiple_answers'], + 'expire_value' => $_REQUEST['poll_expire_value'], + 'expire_unit' => $_REQUEST['poll_expire_unit'] + ]; + $obj = $this->extract_poll_data($poll, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]); + } else { + $obj = $this->extract_bb_poll_data($body, ['item_private' => $private, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_contact_deny]); + } + + + if ($obj) { + $obj['url'] = $obj['id'] = $mid; + $obj['attributedTo'] = channel_url($channel); + $datarray['obj'] = $obj; + $obj_type = 'Question'; + if ($obj['endTime']) { + $d = datetime_convert('UTC', 'UTC', $obj['endTime']); + if ($d > NULL_DATE) { + $comments_closed = $d; + } + } + } + + if (!$parent_mid) { + $parent_mid = $mid; + } + + if ($parent_item) + $parent_mid = $parent_item['mid']; + + + // Fallback so that we alway have a thr_parent + + if (!$thr_parent) + $thr_parent = $mid; + + + $item_thread_top = ((!$parent) ? 1 : 0); + + + // fix permalinks for cards, etc. + + if ($webpage == ITEM_TYPE_CARD) { + $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid); + } + if (($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_CARD)) { + $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.iid = %d limit 1", + intval($parent_item['id']) + ); + if ($r) { + $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . $r[0]['v']; + } + } + + if ($webpage == ITEM_TYPE_ARTICLE) { + $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : $uuid); + } + if (($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_ARTICLE)) { + $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.iid = %d limit 1", + intval($parent_item['id']) + ); + if ($r) { + $plink = z_root() . '/articles/' . $channel['channel_address'] . '/' . $r[0]['v']; + } + } + + if ((!(isset($plink) && $plink)) && $item_thread_top) { + $plink = z_root() . '/item/' . $uuid; + } + + if (array_path_exists('obj/id', $datarray)) { + $datarray['obj']['id'] = $mid; + } + + $datarray['aid'] = $channel['channel_account_id']; + $datarray['uid'] = $profile_uid; + $datarray['uuid'] = $uuid; + $datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']); + $datarray['author_xchan'] = $observer['xchan_hash']; + $datarray['created'] = $created; + $datarray['edited'] = (($orig_post && (!intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); + $datarray['expires'] = $expires; + $datarray['commented'] = (($orig_post && (!intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); + $datarray['received'] = (($orig_post && (!intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); + $datarray['changed'] = (($orig_post && (!intval($orig_post['item_unpublished']))) ? datetime_convert() : $created); + $datarray['comments_closed'] = $comments_closed; + $datarray['mid'] = $mid; + $datarray['parent_mid'] = $parent_mid; + $datarray['mimetype'] = $mimetype; + $datarray['title'] = $title; + $datarray['summary'] = $summary; + $datarray['body'] = $body; + $datarray['app'] = $app; + $datarray['location'] = $location; + $datarray['coord'] = $coord; + $datarray['verb'] = $verb; + $datarray['obj_type'] = $obj_type; + $datarray['allow_cid'] = $str_contact_allow; + $datarray['allow_gid'] = $str_group_allow; + $datarray['deny_cid'] = $str_contact_deny; + $datarray['deny_gid'] = $str_group_deny; + $datarray['attach'] = $attachments; + $datarray['thr_parent'] = $thr_parent; + $datarray['postopts'] = $postopts; + $datarray['item_unseen'] = intval($item_unseen); + $datarray['item_wall'] = intval($item_wall); + $datarray['item_origin'] = intval($item_origin); + $datarray['item_type'] = $webpage; + $datarray['item_private'] = intval($private); + $datarray['item_thread_top'] = intval($item_thread_top); + $datarray['item_unseen'] = intval($item_unseen); + $datarray['item_starred'] = intval($item_starred); + $datarray['item_uplink'] = intval($item_uplink); + $datarray['item_consensus'] = 0; + $datarray['item_notshown'] = intval($item_notshown); + $datarray['item_nsfw'] = intval($item_nsfw); + $datarray['item_relay'] = intval($item_relay); + $datarray['item_mentionsme'] = intval($item_mentionsme); + $datarray['item_nocomment'] = intval($item_nocomment); + $datarray['item_obscured'] = intval($item_obscured); + $datarray['item_verified'] = intval($item_verified); + $datarray['item_retained'] = intval($item_retained); + $datarray['item_rss'] = intval($item_rss); + $datarray['item_deleted'] = intval($item_deleted); + $datarray['item_hidden'] = intval($item_hidden); + $datarray['item_unpublished'] = intval($item_unpublished); + $datarray['item_delayed'] = intval($item_delayed); + $datarray['item_pending_remove'] = intval($item_pending_remove); + $datarray['item_blocked'] = intval($item_blocked); + $datarray['layout_mid'] = $layout_mid; + $datarray['public_policy'] = $public_policy; + $datarray['comment_policy'] = ((is_numeric($comment_policy)) ? map_scope($comment_policy) : $comment_policy); // only map scope if it is numeric, otherwise use what we have + $datarray['term'] = $post_tags; + $datarray['plink'] = $plink; + $datarray['route'] = $route; + $datarray['replyto'] = $replyto; + + // A specific ACL over-rides public_policy completely + + if (!empty_acl($datarray)) + $datarray['public_policy'] = ''; + + if ($iconfig) { + $datarray['iconfig'] = $iconfig; + } + if ($private) { + IConfig::set($datarray, 'ocap', 'relay', $token); + } + + if (!array_key_exists('obj', $datarray)) { + $copy = $datarray; + $copy['author'] = $observer; + $datarray['obj'] = Activity::encode_item($copy, ((get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); + $recips = []; + $i = $datarray['obj']; + if ($i['to']) { + $recips['to'] = $i['to']; + } + if ($i['cc']) { + $recips['cc'] = $i['cc']; + } + IConfig::Set($datarray, 'activitypub', 'recips', $recips); + } + + Activity::rewrite_mentions($datarray); + + // preview mode - prepare the body for display and send it via json + + if ($preview) { + require_once('include/conversation.php'); + + $datarray['owner'] = $owner_xchan; + $datarray['author'] = $observer; + $datarray['attach'] = json_encode($datarray['attach']); + $o = conversation(array($datarray), 'search', false, 'preview'); + // logger('preview: ' . $o, LOGGER_DEBUG); + echo json_encode(array('preview' => $o)); + killme(); + } + + // Let 'post_local' event listeners know if this is an edit. + // We will unset it immediately afterward. + + if ($orig_post) { + $datarray['edit'] = true; + } + + // suppress duplicates, *unless* you're editing an existing post. This could get picked up + // as a duplicate if you're editing it very soon after posting it initially and you edited + // some attribute besides the content, such as title or categories. + + if (PConfig::Get($profile_uid, 'system', 'suppress_duplicates', true) && (!$orig_post)) { + + $z = q("select created from item where uid = %d and created > %s - INTERVAL %s and body = '%s' limit 1", + intval($profile_uid), + db_utcnow(), + db_quoteinterval('2 MINUTE'), + dbesc($body) + ); + + if ($z) { + $datarray['cancel'] = 1; + notice(t('Duplicate post suppressed.') . EOL); + logger('Duplicate post. Cancelled.'); + } + } + + call_hooks('post_local', $datarray); + + // This is no longer needed + unset($datarray['edit']); + + if (x($datarray, 'cancel')) { + logger('mod_item: post cancelled by plugin or duplicate suppressed.'); + if ($return_path) { + goaway(z_root() . "/" . $return_path); + } + if ($api_source) { + return (['success' => false, 'message' => 'operation cancelled']); + } + $json = array('cancel' => 1); + $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; + json_return_and_die($json); + } + + + if (mb_strlen($datarray['title']) > 191) + $datarray['title'] = mb_substr($datarray['title'], 0, 191); + + if ($webpage) { + IConfig::Set($datarray, 'system', webpage_to_namespace($webpage), + (($pagetitle) ? $pagetitle : basename($datarray['mid'])), true); + } elseif ($namespace) { + IConfig::Set($datarray, 'system', $namespace, + (($remote_id) ? $remote_id : basename($datarray['mid'])), true); + } + + if (intval($datarray['item_unpublished'])) { + $draft_msg = t('Draft saved. Use Drafts app to continue editing.'); + } + + if ($orig_post) { + $datarray['id'] = $post_id; + + $x = item_store_update($datarray, $execflag); + if (!$parent) { + $r = q("select * from item where id = %d", + intval($post_id) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet($profile_uid, array('item' => array(encode_item($sync_item[0], true)))); + } + } + if (!$nopush) { + Run::Summon(['Notifier', 'edit_post', $post_id]); + } + + if ($api_source) { + return ($x); + } + + + if (intval($datarray['item_unpublished'])) { + info($draft_msg); + } + + + if ((x($_REQUEST, 'return')) && strlen($return_path)) { + logger('return: ' . $return_path); + goaway(z_root() . "/" . $return_path); + } + killme(); + } else + $post_id = 0; + + $post = item_store($datarray, $execflag); + + if ($pub_copy) { + info(t('Your comment has been posted.') . EOL); + } + + $post_id = $post['item_id']; + $datarray = $post['item']; + + + if ($post_id) { + logger('mod_item: saved item ' . $post_id); + + if ($parent) { + + // prevent conversations which you are involved from being expired + + if (local_channel()) + retain_item($parent); + + // only send comment notification if this is a wall-to-wall comment and not a DM, + // otherwise it will happen during delivery + + if (($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall'])) && intval($datarray['item_private']) != 2) { + Enotify::submit(array( + 'type' => NOTIFY_COMMENT, + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], + 'item' => $datarray, + 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), + 'verb' => ACTIVITY_POST, + 'otype' => 'item', + 'parent' => $parent, + 'parent_mid' => $parent_item['mid'] + )); + + } + } else { + $parent = $post_id; + + if (($datarray['owner_xchan'] != $datarray['author_xchan']) && ($datarray['item_type'] == ITEM_TYPE_POST)) { + Enotify::submit(array( + 'type' => NOTIFY_WALL, + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], + 'item' => $datarray, + 'link' => z_root() . '/display/' . gen_link_id($datarray['mid']), + 'verb' => ACTIVITY_POST, + 'otype' => 'item' + )); + } + + if ($uid && $uid == $profile_uid && (is_item_normal($datarray))) { + q("update channel set channel_lastpost = '%s' where channel_id = %d", + dbesc(datetime_convert()), + intval($uid) + ); + } + } + + // photo comments turn the corresponding item visible to the profile wall + // This way we don't see every picture in your new photo album posted to your wall at once. + // They will show up as people comment on them. + + if (intval($parent_item['item_hidden'])) { + $r = q("UPDATE item SET item_hidden = 0 WHERE id = %d", + intval($parent_item['id']) + ); + } + } else { + logger('mod_item: unable to retrieve post that was just stored.'); + notice(t('System error. Post not saved.') . EOL); + if ($return_path) + goaway(z_root() . "/" . $return_path); + if ($api_source) + return (['success' => false, 'message' => 'system error']); + killme(); + } + + if (($parent) && ($parent != $post_id)) { + // Store the comment signature information in case we need to relay to Diaspora + //$ditem = $datarray; + //$ditem['author'] = $observer; + //store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0)); + } else { + $r = q("select * from item where id = %d", + intval($post_id) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet($profile_uid, array('item' => array(encode_item($sync_item[0], true)))); + } + } + + $datarray['id'] = $post_id; + $datarray['llink'] = z_root() . '/display/' . gen_link_id($datarray['mid']); + + call_hooks('post_local_end', $datarray); + + if ($groupww) { + $nopush = false; + } + + if (!$nopush) { + Run::Summon(['Notifier', $notify_type, $post_id]); + } + logger('post_complete'); + + if ($moderated) { + info(t('Your post/comment is awaiting approval.') . EOL); + } + + // figure out how to return, depending on from whence we came + + if ($api_source) + return $post; + + if (intval($datarray['item_unpublished'])) { + info($draft_msg); + } + + if ($return_path) { + goaway(z_root() . "/" . $return_path); + } + + $json = array('success' => 1); + if (x($_REQUEST, 'jsreload') && strlen($_REQUEST['jsreload'])) + $json['reload'] = z_root() . '/' . $_REQUEST['jsreload']; + + logger('post_json: ' . print_r($json, true), LOGGER_DEBUG); + + echo json_encode($json); + killme(); + // NOTREACHED + } + + + public function get() + { + + + if ($this->return_404) { + notice(t('Not found')); + return; + } + + if ((!local_channel()) && (!remote_channel())) + return; + + // allow pinned items to be dropped. 'pin-' was prepended to the id of these + // items so that they would have a unique html id even if the pinned item + // was also displayed in a normal conversation on the same web page. + + $drop_id = str_replace('pin-', '', argv(2)); + + if ((argc() == 3) && (argv(1) === 'drop') && intval($drop_id)) { + + $i = q("select * from item where id = %d limit 1", + intval($drop_id) + ); + + if ($i) { + $can_delete = false; + $local_delete = false; + $regular_delete = false; + + if (local_channel() && local_channel() == $i[0]['uid']) { + $local_delete = true; + } + + $ob_hash = get_observer_hash(); + if ($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) { + $can_delete = true; + $regular_delete = true; + } + + // The site admin can delete any post/item on the site. + // If the item originated on this site+channel the deletion will propagate downstream. + // Otherwise just the local copy is removed. + + if (is_site_admin()) { + $local_delete = true; + if (intval($i[0]['item_origin'])) + $can_delete = true; + } + + + if (!($can_delete || $local_delete)) { + notice(t('Permission denied.') . EOL); + return; + } + + if ($i[0]['resource_type'] === 'event') { + // delete and sync the event separately + $r = q("SELECT * FROM event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + dbesc($i[0]['resource_id']), + intval($i[0]['uid']) + ); + if ($r && $regular_delete) { + $sync_event = $r[0]; + q("delete from event WHERE event_hash = '%s' AND uid = %d LIMIT 1", + dbesc($i[0]['resource_id']), + intval($i[0]['uid']) + ); + $sync_event['event_deleted'] = 1; + Libsync::build_sync_packet($i[0]['uid'], array('event' => array($sync_event))); + } + } + + if ($i[0]['resource_type'] === 'photo') { + attach_delete($i[0]['uid'], $i[0]['resource_id'], true); + $ch = channelx_by_n($i[0]['uid']); + if ($ch && $regular_delete) { + $sync = attach_export_data($ch, $i[0]['resource_id'], true); + if ($sync) { + Libsync::build_sync_packet($i[0]['uid'], array('file' => array($sync))); + } + } + } + + + // if this is a different page type or it's just a local delete + // but not by the item author or owner, do a simple deletion + + $complex = false; + + if (intval($i[0]['item_type']) || ($local_delete && (!$can_delete))) { + drop_item($i[0]['id']); + } else { + // complex deletion that needs to propagate and be performed in phases + drop_item($i[0]['id'], true, DROPITEM_PHASE1); + $complex = true; + } + + $r = q("select * from item where id = %d", + intval($i[0]['id']) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet($i[0]['uid'], array('item' => array(encode_item($sync_item[0], true)))); + } + + if ($complex) { + tag_deliver($i[0]['uid'], $i[0]['id']); + } + } + } + } + + + public function item_check_service_class($channel_id, $iswebpage) + { + $ret = array('success' => false, 'message' => ''); + + if ($iswebpage) { + $r = q("select count(i.id) as total from item i right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_id ) and i.parent=i.id and i.item_type = %d and i.item_deleted = 0 and i.uid= %d ", - intval(ITEM_TYPE_WEBPAGE), - intval($channel_id) - ); - } - else { - $r = q("select count(id) as total from item where parent = id and item_wall = 1 and uid = %d " . item_normal(), - intval($channel_id) - ); - } - - if(! $r) { - $ret['message'] = t('Unable to obtain post information from database.'); - return $ret; - } + intval(ITEM_TYPE_WEBPAGE), + intval($channel_id) + ); + } else { + $r = q("select count(id) as total from item where parent = id and item_wall = 1 and uid = %d " . item_normal(), + intval($channel_id) + ); + } + + if (!$r) { + $ret['message'] = t('Unable to obtain post information from database.'); + return $ret; + } - if (!$iswebpage) { - $max = engr_units_to_bytes(service_class_fetch($channel_id,'total_items')); - if(! service_class_allows($channel_id,'total_items',$r[0]['total'])) { - $result['message'] .= upgrade_message() . sprintf( t('You have reached your limit of %1$.0f top level posts.'),$max); - return $result; - } - } - else { - $max = engr_units_to_bytes(service_class_fetch($channel_id,'total_pages')); - if(! service_class_allows($channel_id,'total_pages',$r[0]['total'])) { - $result['message'] .= upgrade_message() . sprintf( t('You have reached your limit of %1$.0f webpages.'),$max); - return $result; - } - } - - $ret['success'] = true; - return $ret; - } - - function extract_bb_poll_data(&$body,$item) { + if (!$iswebpage) { + $max = engr_units_to_bytes(service_class_fetch($channel_id, 'total_items')); + if (!service_class_allows($channel_id, 'total_items', $r[0]['total'])) { + $result['message'] .= upgrade_message() . sprintf(t('You have reached your limit of %1$.0f top level posts.'), $max); + return $result; + } + } else { + $max = engr_units_to_bytes(service_class_fetch($channel_id, 'total_pages')); + if (!service_class_allows($channel_id, 'total_pages', $r[0]['total'])) { + $result['message'] .= upgrade_message() . sprintf(t('You have reached your limit of %1$.0f webpages.'), $max); + return $result; + } + } - $multiple = false; + $ret['success'] = true; + return $ret; + } - if (strpos($body,'[/question]') === false && strpos($body,'[/answer]') === false) { - return false; - } - if (strpos($body,'[nobb]') !== false) { - return false; - } + public function extract_bb_poll_data(&$body, $item) + { - $obj = []; - $ptr = []; - $matches = null; - $obj['type'] = 'Question'; + $multiple = false; - if (preg_match_all('/\[answer\](.*?)\[\/answer\]/ism',$body,$matches,PREG_SET_ORDER)) { - foreach ($matches as $match) { - $ptr[] = [ 'name' => $match[1], 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]]; - $body = str_replace('[answer]' . $match[1] . '[/answer]', EMPTY_STR, $body); - } - } + if (strpos($body, '[/question]') === false && strpos($body, '[/answer]') === false) { + return false; + } + if (strpos($body, '[nobb]') !== false) { + return false; + } - $matches = null; + $obj = []; + $ptr = []; + $matches = null; + $obj['type'] = 'Question'; - if (preg_match('/\[question\](.*?)\[\/question\]/ism',$body,$matches)) { - $obj['content'] = bbcode($matches[1]); - $body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body); - $obj['oneOf'] = $ptr; - } + if (preg_match_all('/\[answer\](.*?)\[\/answer\]/ism', $body, $matches, PREG_SET_ORDER)) { + foreach ($matches as $match) { + $ptr[] = ['name' => $match[1], 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; + $body = str_replace('[answer]' . $match[1] . '[/answer]', EMPTY_STR, $body); + } + } - $matches = null; - - if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism',$body,$matches)) { - $obj['content'] = bbcode($matches[1]); - $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body); - $obj['anyOf'] = $ptr; - } + $matches = null; - $matches = null; - - if (preg_match('/\[ends\](.*?)\[\/ends\]/ism',$body,$matches)) { - $obj['endTime'] = datetime_convert(date_default_timezone_get(),'UTC', $matches[1],ATOM_TIME); - $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body); - } + if (preg_match('/\[question\](.*?)\[\/question\]/ism', $body, $matches)) { + $obj['content'] = bbcode($matches[1]); + $body = str_replace('[question]' . $matches[1] . '[/question]', $matches[1], $body); + $obj['oneOf'] = $ptr; + } - if ($item['item_private']) { - $obj['to'] = Activity::map_acl($item); - } - else { - $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; - } - - return $obj; + $matches = null; - } + if (preg_match('/\[question=multiple\](.*?)\[\/question\]/ism', $body, $matches)) { + $obj['content'] = bbcode($matches[1]); + $body = str_replace('[question=multiple]' . $matches[1] . '[/question]', $matches[1], $body); + $obj['anyOf'] = $ptr; + } - function extract_poll_data($poll, $item) { + $matches = null; - $multiple = intval($poll['multiple_answers']); - $expire_value = intval($poll['expire_value']); - $expire_unit = $poll['expire_unit']; - $question = $poll['question']; - $answers = $poll['answers']; + if (preg_match('/\[ends\](.*?)\[\/ends\]/ism', $body, $matches)) { + $obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', $matches[1], ATOM_TIME); + $body = str_replace('[ends]' . $matches[1] . '[/ends]', EMPTY_STR, $body); + } - $obj = []; - $ptr = []; - $obj['type'] = 'Question'; - $obj['content'] = bbcode($question); + if ($item['item_private']) { + $obj['to'] = Activity::map_acl($item); + } else { + $obj['to'] = [ACTIVITY_PUBLIC_INBOX]; + } - foreach($answers as $answer) { - if(trim($answer)) - $ptr[] = [ 'name' => escape_tags($answer), 'type' => 'Note', 'replies' => [ 'type' => 'Collection', 'totalItems' => 0 ]]; - } + return $obj; - if($multiple) { - $obj['anyOf'] = $ptr; - } - else { - $obj['oneOf'] = $ptr; - } + } - $obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', 'now + ' . $expire_value . ' ' . $expire_unit, ATOM_TIME); + public function extract_poll_data($poll, $item) + { - if ($item['item_private']) { - $obj['to'] = Activity::map_acl($item); - } - else { - $obj['to'] = [ ACTIVITY_PUBLIC_INBOX ]; - } + $multiple = intval($poll['multiple_answers']); + $expire_value = intval($poll['expire_value']); + $expire_unit = $poll['expire_unit']; + $question = $poll['question']; + $answers = $poll['answers']; - return $obj; + $obj = []; + $ptr = []; + $obj['type'] = 'Question'; + $obj['content'] = bbcode($question); - } + foreach ($answers as $answer) { + if (trim($answer)) + $ptr[] = ['name' => escape_tags($answer), 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; + } + + if ($multiple) { + $obj['anyOf'] = $ptr; + } else { + $obj['oneOf'] = $ptr; + } + + $obj['endTime'] = datetime_convert(date_default_timezone_get(), 'UTC', 'now + ' . $expire_value . ' ' . $expire_unit, ATOM_TIME); + + if ($item['item_private']) { + $obj['to'] = Activity::map_acl($item); + } else { + $obj['to'] = [ACTIVITY_PUBLIC_INBOX]; + } + + return $obj; + + } } diff --git a/Zotlabs/Module/Jwks.php b/Zotlabs/Module/Jwks.php index 660b37568..8bb6de47b 100644 --- a/Zotlabs/Module/Jwks.php +++ b/Zotlabs/Module/Jwks.php @@ -5,57 +5,59 @@ namespace Zotlabs\Module; use Zotlabs\Lib\Keyutils; use Zotlabs\Web\Controller; -class Jwks extends Controller { +class Jwks extends Controller +{ - function init() { - - Keyutils::pemtome(get_config('system','pubkey'),$m,$e); + public function init() + { - /** - * RFC7518 - * - 6.3.1.1. "n" (Modulus) Parameter + Keyutils::pemtome(get_config('system', 'pubkey'), $m, $e); - The "n" (modulus) parameter contains the modulus value for the RSA - public key. It is represented as a Base64urlUInt-encoded value. + /** + * RFC7518 + * + * 6.3.1.1. "n" (Modulus) Parameter + * + * The "n" (modulus) parameter contains the modulus value for the RSA + * public key. It is represented as a Base64urlUInt-encoded value. + * + * Note that implementers have found that some cryptographic libraries + * prefix an extra zero-valued octet to the modulus representations they + * return, for instance, returning 257 octets for a 2048-bit key, rather + * than 256. Implementations using such libraries will need to take + * care to omit the extra octet from the base64url-encoded + * representation. + * + */ - Note that implementers have found that some cryptographic libraries - prefix an extra zero-valued octet to the modulus representations they - return, for instance, returning 257 octets for a 2048-bit key, rather - than 256. Implementations using such libraries will need to take - care to omit the extra octet from the base64url-encoded - representation. - * - */ + $l = strlen((string)$m); + if ($l & 1) { + $m = substr((string)$m, 1); + } - $l = strlen((string) $m); - if ($l & 1) { - $m = substr((string) $m,1); - } - - $keys = [ - [ - 'e' => base64url_encode($e), - 'n' => base64url_encode($m), - 'kty' => 'RSA', - 'kid' => '0', - ] - ]; + $keys = [ + [ + 'e' => base64url_encode($e), + 'n' => base64url_encode($m), + 'kty' => 'RSA', + 'kid' => '0', + ] + ]; - $ret = [ - 'keys' => $keys - ]; + $ret = [ + 'keys' => $keys + ]; - if (argc() > 1) { - $entry = intval(argv(1)); - if ($keys[$entry]) { - unset($keys[$entry]['kid']); - json_return_and_die($keys[$entry],'application/jwk+json'); - } - } + if (argc() > 1) { + $entry = intval(argv(1)); + if ($keys[$entry]) { + unset($keys[$entry]['kid']); + json_return_and_die($keys[$entry], 'application/jwk+json'); + } + } - json_return_and_die($ret,'application/jwk-set+json'); - - } + json_return_and_die($ret, 'application/jwk-set+json'); + + } } \ No newline at end of file diff --git a/Zotlabs/Module/Lang.php b/Zotlabs/Module/Lang.php index 9858beecd..46034a5ff 100644 --- a/Zotlabs/Module/Lang.php +++ b/Zotlabs/Module/Lang.php @@ -5,24 +5,26 @@ use App; use Zotlabs\Lib\Apps; use Zotlabs\Web\Controller; -class Lang extends Controller { +class Lang extends Controller +{ - function get() { + public function get() + { - if(local_channel()) { - if(! Apps::system_app_installed(local_channel(), 'Language')) { - //Do not display any associated widgets at this point - App::$pdl = ''; + if (local_channel()) { + if (!Apps::system_app_installed(local_channel(), 'Language')) { + //Do not display any associated widgets at this point + App::$pdl = ''; - $o = 'Language App (Not Installed):
      '; - $o .= t('Change UI language'); - return $o; - } - } + $o = 'Language App (Not Installed):
      '; + $o .= t('Change UI language'); + return $o; + } + } - nav_set_selected('Language'); - return lang_selector(); + nav_set_selected('Language'); + return lang_selector(); + + } - } - } diff --git a/Zotlabs/Module/Layouts.php b/Zotlabs/Module/Layouts.php index 034ca3cab..ebaa447f2 100644 --- a/Zotlabs/Module/Layouts.php +++ b/Zotlabs/Module/Layouts.php @@ -11,201 +11,204 @@ require_once('include/channel.php'); require_once('include/conversation.php'); require_once('include/acl_selectors.php'); -class Layouts extends Controller { +class Layouts extends Controller +{ - function init() { + public function init() + { - if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - App::$is_sys = true; - } - } + if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + App::$is_sys = true; + } + } - if(argc() > 1) - $which = argv(1); - else - return; + if (argc() > 1) + $which = argv(1); + else + return; - Libprofile::load($which); + Libprofile::load($which); - } + } - function get() { + public function get() + { - if(! App::$profile) { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } + if (!App::$profile) { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } - $which = argv(1); + $which = argv(1); - $_SESSION['return_url'] = App::$query_string; + $_SESSION['return_url'] = App::$query_string; - $uid = local_channel(); - $owner = 0; - $channel = null; - $observer = App::get_observer(); + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = App::get_observer(); - $channel = App::get_channel(); + $channel = App::get_channel(); - if(App::$is_sys && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - $uid = $owner = intval($sys['channel_id']); - $channel = $sys; - $observer = $sys; - } - } + if (App::$is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } - if(! $owner) { - // Figure out who the page owner is. - $r = q("select channel_id from channel where channel_address = '%s'", - dbesc($which) - ); - if($r) { - $owner = intval($r[0]['channel_id']); - } - } + if (!$owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if ($r) { + $owner = intval($r[0]['channel_id']); + } + } - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - $perms = get_all_perms($owner,$ob_hash); + $perms = get_all_perms($owner, $ob_hash); - if(! $perms['write_pages']) { - notice( t('Permission denied.') . EOL); - return; - } + if (!$perms['write_pages']) { + notice(t('Permission denied.') . EOL); + return; + } - // Block design features from visitors + // Block design features from visitors - if((! $uid) || ($uid != $owner)) { - notice( t('Permission denied.') . EOL); - return; - } + if ((!$uid) || ($uid != $owner)) { + notice(t('Permission denied.') . EOL); + return; + } - // Get the observer, check their permissions + // Get the observer, check their permissions - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - $perms = get_all_perms($owner,$ob_hash); + $perms = get_all_perms($owner, $ob_hash); - if(! $perms['write_pages']) { - notice( t('Permission denied.') . EOL); - return; - } + if (!$perms['write_pages']) { + notice(t('Permission denied.') . EOL); + return; + } - // This feature is not exposed in redbasic ui since it is not clear why one would want to - // download a json encoded pdl file - we dont have a possibility to import it. - // Use the buildin share/install feature instead. + // This feature is not exposed in redbasic ui since it is not clear why one would want to + // download a json encoded pdl file - we dont have a possibility to import it. + // Use the buildin share/install feature instead. - if((argc() > 3) && (argv(2) === 'share') && (argv(3))) { - $r = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + if ((argc() > 3) && (argv(2) === 'share') && (argv(3))) { + $r = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig left join item on item.id = iconfig.iid where uid = %d and mid = '%s' and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc", - intval($owner), - dbesc(argv(3)) - ); - if($r) { - header('Content-type: application/x-hubzilla-layout'); - header('Content-Disposition: attachment; filename="' . $r[0]['sid'] . '.pdl"'); - echo json_encode($r); - killme(); - } - } + intval($owner), + dbesc(argv(3)) + ); + if ($r) { + header('Content-type: application/x-hubzilla-layout'); + header('Content-Disposition: attachment; filename="' . $r[0]['sid'] . '.pdl"'); + echo json_encode($r); + killme(); + } + } - // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages - // Nickname is set to the observers xchan, and profile_uid to the owners. - // This lets you post pages at other people's channels. + // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages + // Nickname is set to the observers xchan, and profile_uid to the owners. + // This lets you post pages at other people's channels. - $x = array( - 'webpage' => ITEM_TYPE_PDL, - 'is_owner' => true, - 'nickname' => App::$profile['channel_address'], - 'showacl' => false, - 'hide_voting' => true, - 'hide_future' => true, - 'hide_expire' => true, - 'hide_location' => true, - 'hide_weblink' => true, - 'hide_attach' => true, - 'hide_preview' => true, - 'disable_comments' => true, - 'ptlabel' => t('Layout Name'), - 'profile_uid' => intval($owner), - 'expanded' => true, - 'placeholdertitle' => t('Layout Description (Optional)'), - 'novoting' => true, - 'bbco_autocomplete' => 'comanche' - ); + $x = array( + 'webpage' => ITEM_TYPE_PDL, + 'is_owner' => true, + 'nickname' => App::$profile['channel_address'], + 'showacl' => false, + 'hide_voting' => true, + 'hide_future' => true, + 'hide_expire' => true, + 'hide_location' => true, + 'hide_weblink' => true, + 'hide_attach' => true, + 'hide_preview' => true, + 'disable_comments' => true, + 'ptlabel' => t('Layout Name'), + 'profile_uid' => intval($owner), + 'expanded' => true, + 'placeholdertitle' => t('Layout Description (Optional)'), + 'novoting' => true, + 'bbco_autocomplete' => 'comanche' + ); - if($_REQUEST['title']) - $x['title'] = $_REQUEST['title']; - if($_REQUEST['body']) - $x['body'] = $_REQUEST['body']; - if($_REQUEST['pagetitle']) - $x['pagetitle'] = $_REQUEST['pagetitle']; + if ($_REQUEST['title']) + $x['title'] = $_REQUEST['title']; + if ($_REQUEST['body']) + $x['body'] = $_REQUEST['body']; + if ($_REQUEST['pagetitle']) + $x['pagetitle'] = $_REQUEST['pagetitle']; - $editor = status_editor($x); + $editor = status_editor($x); - $r = q("select iconfig.iid, iconfig.v, mid, title, body, mimetype, created, edited, item_type from iconfig + $r = q("select iconfig.iid, iconfig.v, mid, title, body, mimetype, created, edited, item_type from iconfig left join item on iconfig.iid = item.id where uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' and item_type = %d order by item.created desc", - intval($owner), - intval(ITEM_TYPE_PDL) - ); + intval($owner), + intval(ITEM_TYPE_PDL) + ); - $pages = null; + $pages = null; - if($r) { - $pages = []; - foreach($r as $rr) { - $element_arr = array( - 'type' => 'layout', - 'title' => $rr['title'], - 'body' => $rr['body'], - 'created' => $rr['created'], - 'edited' => $rr['edited'], - 'mimetype' => $rr['mimetype'], - 'pagetitle' => urldecode($rr['v']), - 'mid' => $rr['mid'] - ); - $pages[$rr['iid']][] = array( - 'url' => $rr['iid'], - 'title' => urldecode($rr['v']), - 'descr' => $rr['title'], - 'mid' => $rr['mid'], - 'created' => $rr['created'], - 'edited' => $rr['edited'], - 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]' - ); - } - } + if ($r) { + $pages = []; + foreach ($r as $rr) { + $element_arr = array( + 'type' => 'layout', + 'title' => $rr['title'], + 'body' => $rr['body'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'mimetype' => $rr['mimetype'], + 'pagetitle' => urldecode($rr['v']), + 'mid' => $rr['mid'] + ); + $pages[$rr['iid']][] = array( + 'url' => $rr['iid'], + 'title' => urldecode($rr['v']), + 'descr' => $rr['title'], + 'mid' => $rr['mid'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]' + ); + } + } - //Build the base URL for edit links - $url = z_root() . '/editlayout/' . $which; + //Build the base URL for edit links + $url = z_root() . '/editlayout/' . $which; - $o .= replace_macros(get_markup_template('layoutlist.tpl'), array( - '$title' => t('Layouts'), - '$create' => t('Create'), - '$help' => '', // array('text' => t('Help'), 'url' => 'help/comanche', 'title' => t('Comanche page description language help')), - '$editor' => $editor, - '$baseurl' => $url, - '$name' => t('Layout Name'), - '$descr' => t('Layout Description'), - '$created' => t('Created'), - '$edited' => t('Edited'), - '$edit' => t('Edit'), - '$share' => t('Share'), - '$download' => t('Download PDL file'), - '$pages' => $pages, - '$channel' => $which, - '$view' => t('View'), - )); + $o .= replace_macros(get_markup_template('layoutlist.tpl'), array( + '$title' => t('Layouts'), + '$create' => t('Create'), + '$help' => '', // array('text' => t('Help'), 'url' => 'help/comanche', 'title' => t('Comanche page description language help')), + '$editor' => $editor, + '$baseurl' => $url, + '$name' => t('Layout Name'), + '$descr' => t('Layout Description'), + '$created' => t('Created'), + '$edited' => t('Edited'), + '$edit' => t('Edit'), + '$share' => t('Share'), + '$download' => t('Download PDL file'), + '$pages' => $pages, + '$channel' => $which, + '$view' => t('View'), + )); - return $o; + return $o; - } + } } diff --git a/Zotlabs/Module/Linkinfo.php b/Zotlabs/Module/Linkinfo.php index a78eb24b5..1eb537089 100644 --- a/Zotlabs/Module/Linkinfo.php +++ b/Zotlabs/Module/Linkinfo.php @@ -12,589 +12,591 @@ use Zotlabs\Lib as Zlib; require_once('include/security.php'); -class Linkinfo extends Controller { +class Linkinfo extends Controller +{ - function get() { - - logger('linkinfo: ' . print_r($_REQUEST,true), LOGGER_DEBUG); - - $text = null; - $str_tags = ''; - $process_embed = true; - $process_oembed = (($_GET['oembed']) ? true : false); - $process_zotobj = true; + public function get() + { - if(local_channel()) { - $saved_oembed = ((get_pconfig(local_channel(),'system','linkinfo_embed',true)) ? true : false); - if ($saved_oembed !== $process_oembed) { - set_pconfig(local_channel(),'system','linkinfo_embed',intval($process_oembed)); - } - } + logger('linkinfo: ' . print_r($_REQUEST, true), LOGGER_DEBUG); - $br = "\n"; - - if (x($_GET,'binurl')) - $url = trim(hex2bin($_GET['binurl'])); - else - $url = trim($_GET['url']); - - if (substr($url,0,1) === '!') { - $process_embed = false; - $url = substr($url,1); - } + $text = null; + $str_tags = ''; + $process_embed = true; + $process_oembed = (($_GET['oembed']) ? true : false); + $process_zotobj = true; - $url = strip_zids($url); + if (local_channel()) { + $saved_oembed = ((get_pconfig(local_channel(), 'system', 'linkinfo_embed', true)) ? true : false); + if ($saved_oembed !== $process_oembed) { + set_pconfig(local_channel(), 'system', 'linkinfo_embed', intval($process_oembed)); + } + } - if (strpos($url,'geo:') === 0) { - if ($process_embed) { - echo $br . '[map=' . substr($url,4) . ']' . $br; - } - else { - echo $br . '[url]' . $url . '[/url]' . $br; - } - killme(); - } + $br = "\n"; - if (strpos($url,'tel:') === 0 || (is_phone_number($url) !== false)) { - $phone = $url; - if (strpos($url,'tel:') !== 0) { - $url = 'tel:' . is_phone_number($url); - } - echo $br . '[url=' . $url . ']' . $phone . '[/url]' . $br; - killme(); - } + if (x($_GET, 'binurl')) + $url = trim(hex2bin($_GET['binurl'])); + else + $url = trim($_GET['url']); - $m = parse_url($url); - - if (! $m['scheme']) { - if (strpos($url,'@')) { - $xc = discover_by_webbie($url); - if ($xc) { - $x = q("select * from xchan where xchan_hash = '%s'", - dbesc($xc) - ); - if ($x) { - $url = $x[0]['xchan_url']; - } - } - else { - echo $br . '[url=mailto:' . $url . ']' . $url . '[/url]' . $br; - killme(); - } - } - else { - $url = 'http://' . $url; - } - } - - if ($_GET['title']) - $title = strip_tags(trim($_GET['title'])); - - if ($_GET['description']) - $text = strip_tags(trim($_GET['description'])); - - if ($_GET['tags']) { - $arr_tags = str_getcsv($_GET['tags']); - if (count($arr_tags)) { - array_walk($arr_tags,'self::arr_add_hashes'); - $str_tags = $br . implode(' ',$arr_tags) . $br; - } - } - - logger('linkinfo: ' . $url, LOGGER_DEBUG); - - $zrl = is_matrix_url($url); + if (substr($url, 0, 1) === '!') { + $process_embed = false; + $url = substr($url, 1); + } - if (! $process_embed) { - if ($zrl) { - echo $br . '[zrl]' . $url . '[/zrl]' . $br; - } - else { - echo $br . '[url]' . $url . '[/url]' . $br; - } - killme(); - } + $url = strip_zids($url); - $result = z_fetch_url($url, false, 0, [ 'novalidate' => true, 'nobody' => true ] ); - if ($result['success']) { - $hdrs=[]; - $h = explode("\n",$result['header']); - foreach ($h as $l) { - list($k,$v) = array_map("trim", explode(":", trim($l), 2)); - $hdrs[strtolower($k)] = $v; - } - if (array_key_exists('content-type', $hdrs)) - $type = $hdrs['content-type']; - if ($type) { - if (stripos($type,'image/') !== false) { - $basename = basename($url); - - if ($zrl) - echo $br . '[zmg alt="' . $basename . '"]' . $url . '[/zmg]' . $br; - else - echo $br . '[img alt="' . $basename . '"]' . $url . '[/img]' . $br; - killme(); - } - if ((stripos($type,'video/') !== false) || ($type === 'application/ogg')) { - $thumb = self::get_video_poster($url); - if($thumb) { - if ($zrl) - echo $br . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . $br; - else - echo $br . '[video poster=\'' . $thumb . '\']' . $url . '[/video]' . $br; - killme(); - } - if ($zrl) - echo $br . '[zvideo]' . $url . '[/zvideo]' . $br; - else - echo $br . '[video]' . $url . '[/video]' . $br; - killme(); - } - if (stripos($type,'audio/') !== false) { - if ($zrl) - echo $br . '[zaudio]' . $url . '[/zaudio]' . $br; - else - echo $br . '[audio]' . $url . '[/audio]' . $br; - killme(); - } - if (strtolower($type) === 'text/calendar') { - $content = z_fetch_url($url,false,0,array('novalidate' => true)); - if ($content['success']) { - $ev = ical_to_ev($content['body']); - if ($ev) { - echo $br . format_event_bbcode($ev[0]) . $br; - killme(); - } - } - } - if (strtolower($type) === 'application/pdf' || strtolower($type) === 'application/x-pdf') { - echo $br . '[embed]' . $url . '[/embed]' . $br; - killme(); - } - } - } - - $template = $br . '[url=%s]%s[/url]%s' . $br; - - $arr = array('url' => $url, 'text' => ''); - - call_hooks('parse_link', $arr); - - if (strlen($arr['text'])) { - echo $arr['text']; - killme(); - } + if (strpos($url, 'geo:') === 0) { + if ($process_embed) { + echo $br . '[map=' . substr($url, 4) . ']' . $br; + } else { + echo $br . '[url]' . $url . '[/url]' . $br; + } + killme(); + } - if ($process_oembed) { - $x = oembed_process($url); - if ($x) { - echo $x; - killme(); - } - } - - if ($process_zotobj) { - $x = Activity::fetch($url, App::get_channel()); - $y = null; - if (is_array($x)) { - if (ActivityStreams::is_an_actor($x['type']) && $x['id']) { - if (check_siteallowed($x['id']) && check_channelallowed($x['id'])) { - $url = $x['url']; - if (is_array($url)) { - $url = $url[0]['href']; - } - $name = (($x['name']) ? $x['name'] . ' (' . $x['preferredUsername'] . ')' : $x['preferredUsername']); + if (strpos($url, 'tel:') === 0 || (is_phone_number($url) !== false)) { + $phone = $url; + if (strpos($url, 'tel:') !== 0) { + $url = 'tel:' . is_phone_number($url); + } + echo $br . '[url=' . $url . ']' . $phone . '[/url]' . $br; + killme(); + } - if (array_path_exists('icon/url',$x)) { - $text = $br . $br . '[zrl=' . $url . '][zmg=300x300]' . $x['icon']['url'] . '[/zmg][/zrl]' ; - } - $text .= $br . $br . '[zrl=' . $url . ']' . $name . '[/zrl]' . $br . $br; - echo $text; - killme(); - } - } - else { - $y = new ActivityStreams($x); - if ($y->is_valid() && $y->type === 'Announce' && is_array($y->obj) - && array_key_exists('object',$y->obj) && array_key_exists('actor',$y->obj)) { - // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) - // Reparse the encapsulated Activity and use that instead - logger('relayed activity',LOGGER_DEBUG); - $y = new ActivityStreams($y->obj); - } - } + $m = parse_url($url); - if ($y && $y->is_valid()) { - $z = Activity::decode_note($y); - $r = q("select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_hash = '%s' OR hubloc_id_url = '%s'", - dbesc(is_array($y->actor) ? $y->actor['id'] : $y->actor), - dbesc(is_array($y->actor) ? $y->actor['id'] : $y->actor) - ); + if (!$m['scheme']) { + if (strpos($url, '@')) { + $xc = discover_by_webbie($url); + if ($xc) { + $x = q("select * from xchan where xchan_hash = '%s'", + dbesc($xc) + ); + if ($x) { + $url = $x[0]['xchan_url']; + } + } else { + echo $br . '[url=mailto:' . $url . ']' . $url . '[/url]' . $br; + killme(); + } + } else { + $url = 'http://' . $url; + } + } - if ($r) { - $r = Libzot::zot_record_preferred($r); - if ($z) { - $z['author_xchan'] = $r['hubloc_hash']; - } - } + if ($_GET['title']) + $title = strip_tags(trim($_GET['title'])); - if ($z) { + if ($_GET['description']) + $text = strip_tags(trim($_GET['description'])); - // do not allow somebody to embed a post that was blocked by the site admin - // We *will* let them over-rule any blocks they created themselves - - if (check_siteallowed($r['hubloc_id_url']) && check_channelallowed($z['author_xchan'])) { - $s = new Zlib\Share($z); - echo $s->bbcode(); - killme(); - } - } - } - } - } + if ($_GET['tags']) { + $arr_tags = str_getcsv($_GET['tags']); + if (count($arr_tags)) { + array_walk($arr_tags, 'self::arr_add_hashes'); + $str_tags = $br . implode(' ', $arr_tags) . $br; + } + } + + logger('linkinfo: ' . $url, LOGGER_DEBUG); + + $zrl = is_matrix_url($url); + + if (!$process_embed) { + if ($zrl) { + echo $br . '[zrl]' . $url . '[/zrl]' . $br; + } else { + echo $br . '[url]' . $url . '[/url]' . $br; + } + killme(); + } + + $result = z_fetch_url($url, false, 0, ['novalidate' => true, 'nobody' => true]); + if ($result['success']) { + $hdrs = []; + $h = explode("\n", $result['header']); + foreach ($h as $l) { + list($k, $v) = array_map("trim", explode(":", trim($l), 2)); + $hdrs[strtolower($k)] = $v; + } + if (array_key_exists('content-type', $hdrs)) + $type = $hdrs['content-type']; + if ($type) { + if (stripos($type, 'image/') !== false) { + $basename = basename($url); + + if ($zrl) + echo $br . '[zmg alt="' . $basename . '"]' . $url . '[/zmg]' . $br; + else + echo $br . '[img alt="' . $basename . '"]' . $url . '[/img]' . $br; + killme(); + } + if ((stripos($type, 'video/') !== false) || ($type === 'application/ogg')) { + $thumb = self::get_video_poster($url); + if ($thumb) { + if ($zrl) + echo $br . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . $br; + else + echo $br . '[video poster=\'' . $thumb . '\']' . $url . '[/video]' . $br; + killme(); + } + if ($zrl) + echo $br . '[zvideo]' . $url . '[/zvideo]' . $br; + else + echo $br . '[video]' . $url . '[/video]' . $br; + killme(); + } + if (stripos($type, 'audio/') !== false) { + if ($zrl) + echo $br . '[zaudio]' . $url . '[/zaudio]' . $br; + else + echo $br . '[audio]' . $url . '[/audio]' . $br; + killme(); + } + if (strtolower($type) === 'text/calendar') { + $content = z_fetch_url($url, false, 0, array('novalidate' => true)); + if ($content['success']) { + $ev = ical_to_ev($content['body']); + if ($ev) { + echo $br . format_event_bbcode($ev[0]) . $br; + killme(); + } + } + } + if (strtolower($type) === 'application/pdf' || strtolower($type) === 'application/x-pdf') { + echo $br . '[embed]' . $url . '[/embed]' . $br; + killme(); + } + } + } + + $template = $br . '[url=%s]%s[/url]%s' . $br; + + $arr = array('url' => $url, 'text' => ''); + + call_hooks('parse_link', $arr); + + if (strlen($arr['text'])) { + echo $arr['text']; + killme(); + } + + if ($process_oembed) { + $x = oembed_process($url); + if ($x) { + echo $x; + killme(); + } + } + + if ($process_zotobj) { + $x = Activity::fetch($url, App::get_channel()); + $y = null; + if (is_array($x)) { + if (ActivityStreams::is_an_actor($x['type']) && $x['id']) { + if (check_siteallowed($x['id']) && check_channelallowed($x['id'])) { + $url = $x['url']; + if (is_array($url)) { + $url = $url[0]['href']; + } + $name = (($x['name']) ? $x['name'] . ' (' . $x['preferredUsername'] . ')' : $x['preferredUsername']); + + if (array_path_exists('icon/url', $x)) { + $text = $br . $br . '[zrl=' . $url . '][zmg=300x300]' . $x['icon']['url'] . '[/zmg][/zrl]'; + } + $text .= $br . $br . '[zrl=' . $url . ']' . $name . '[/zrl]' . $br . $br; + echo $text; + killme(); + } + } else { + $y = new ActivityStreams($x); + if ($y->is_valid() && $y->type === 'Announce' && is_array($y->obj) + && array_key_exists('object', $y->obj) && array_key_exists('actor', $y->obj)) { + // This is a relayed/forwarded Activity (as opposed to a shared/boosted object) + // Reparse the encapsulated Activity and use that instead + logger('relayed activity', LOGGER_DEBUG); + $y = new ActivityStreams($y->obj); + } + } + + if ($y && $y->is_valid()) { + $z = Activity::decode_note($y); + $r = q("select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_hash = '%s' OR hubloc_id_url = '%s'", + dbesc(is_array($y->actor) ? $y->actor['id'] : $y->actor), + dbesc(is_array($y->actor) ? $y->actor['id'] : $y->actor) + ); + + if ($r) { + $r = Libzot::zot_record_preferred($r); + if ($z) { + $z['author_xchan'] = $r['hubloc_hash']; + } + } + + if ($z) { + + // do not allow somebody to embed a post that was blocked by the site admin + // We *will* let them over-rule any blocks they created themselves + + if (check_siteallowed($r['hubloc_id_url']) && check_channelallowed($z['author_xchan'])) { + $s = new Zlib\Share($z); + echo $s->bbcode(); + killme(); + } + } + } + } + } - if ($url && $title && $text) { - - $text = $br . '[quote]' . trim($text) . '[/quote]' . $br; - - $title = str_replace(array("\r","\n"),array('',''),$title); - - $result = sprintf($template,$url,($title) ? $title : $url,$text) . $str_tags; - - logger('linkinfo (unparsed): returns: ' . $result); - - echo $result; - killme(); - } - - $siteinfo = self::parseurl_getsiteinfo($url); - - // If the site uses this platform, use zrl rather than url so they get zids sent to them by default - - if (is_matrix_url($url)) - $template = str_replace('url','zrl',$template); - - if ($siteinfo["title"] == "") { - echo sprintf($template,$url,$url,'') . $str_tags; - killme(); - } else { - $text = $siteinfo["text"]; - $title = $siteinfo["title"]; - } - - $image = ""; - - if (isset($siteinfo['images']) && is_array($siteinfo['images']) && count($siteinfo["images"])) { - /* Execute below code only if image is present in siteinfo */ - - $total_images = 0; - $max_images = get_config('system','max_bookmark_images'); - if ($max_images === false) - $max_images = 2; - else - $max_images = intval($max_images); - - foreach ($siteinfo["images"] as $imagedata) { - if ($url) { - $image .= sprintf('[url=%s]', $url); - } - $image .= '[img='.$imagedata["width"].'x'.$imagedata["height"].']'.$imagedata["src"].'[/img]'; - if ($url) { - $image .= '[/url]'; - } - $image .= "\n"; - $total_images ++; - if ($max_images && $max_images >= $total_images) - break; - } - } - - if (strlen($text)) { - $text = $br.'[quote]'.trim($text).'[/quote]'.$br ; - } - - if ($image) { - $text = $br.$br.$image.$text; - } - $title = str_replace(array("\r","\n"),array('',''),$title); - - $result = sprintf($template,$url,($title) ? $title : $url,$text) . $str_tags; - - logger('linkinfo: returns: ' . $result, LOGGER_DEBUG); - - echo trim($result); - killme(); - - } - - - public static function deletexnode(&$doc, $node) { - $xpath = new DomXPath($doc); - $list = $xpath->query("//".$node); - foreach ($list as $child) - $child->parentNode->removeChild($child); - } - - public static function completeurl($url, $scheme) { - $urlarr = parse_url($url); - - if (isset($urlarr["scheme"])) - return($url); - - $schemearr = parse_url($scheme); - - $complete = $schemearr["scheme"]."://".$schemearr["host"]; - - if ($schemearr["port"] != "") - $complete .= ":".$schemearr["port"]; - - if (strpos($urlarr['path'],'/') !== 0) - $complete .= '/'; - - $complete .= $urlarr["path"]; - - if ($urlarr["query"] != "") - $complete .= "?".$urlarr["query"]; - - if ($urlarr["fragment"] != "") - $complete .= "#".$urlarr["fragment"]; - - return($complete); - } + if ($url && $title && $text) { - public static function get_video_poster($url) { + $text = $br . '[quote]' . trim($text) . '[/quote]' . $br; - if(strpos($url,z_root() . '/cloud/') === false) { - return EMPTY_STR; - } - $m = parse_url($url,PHP_URL_PATH); - if($m) { - // strip leading '/cloud/' - $m = substr($m,7); - } - $nick = substr($m,0,strpos($m,'/')); - $p = substr($m,strpos($m,'/')+1); + $title = str_replace(array("\r", "\n"), array('', ''), $title); - // get the channel to check permissions - - $u = channelx_by_nick($nick); + $result = sprintf($template, $url, ($title) ? $title : $url, $text) . $str_tags; - if($u && $p) { + logger('linkinfo (unparsed): returns: ' . $result); - $sql_extra = permissions_sql(intval($u['channel_id'])); + echo $result; + killme(); + } - $r = q("select hash, content from attach where display_path = '%s' and uid = %d and os_storage = 1 $sql_extra limit 1", - dbesc($p), - intval($u['channel_id']) - ); - if($r) { - $path = dbunescbin($r[0]['content']); - if($path && @file_exists($path . '.thumb')) { - return z_root() . '/poster/' . $nick . '/' . $r[0]['hash']; - } - } - } - return EMPTY_STR; - } + $siteinfo = self::parseurl_getsiteinfo($url); - - public static function parseurl_getsiteinfo($url) { - $siteinfo = []; - - - $result = z_fetch_url($url,false,0,array('novalidate' => true)); - if (! $result['success']) - return $siteinfo; - - $header = $result['header']; - $body = $result['body']; - - // Check codepage in HTTP headers or HTML if not exist - $cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : ''); - if (empty($cp)) - $cp = (preg_match('/meta.+content=["|\']text\/html; charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'AUTO'); + // If the site uses this platform, use zrl rather than url so they get zids sent to them by default - $body = mb_convert_encoding($body, 'UTF-8', $cp); - $body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8"); - - $doc = new DOMDocument(); - @$doc->loadHTML($body); - - self::deletexnode($doc, 'style'); - self::deletexnode($doc, 'script'); - self::deletexnode($doc, 'option'); - self::deletexnode($doc, 'h1'); - self::deletexnode($doc, 'h2'); - self::deletexnode($doc, 'h3'); - self::deletexnode($doc, 'h4'); - self::deletexnode($doc, 'h5'); - self::deletexnode($doc, 'h6'); - self::deletexnode($doc, 'ol'); - self::deletexnode($doc, 'ul'); - - $xpath = new DomXPath($doc); - - //$list = $xpath->query("head/title"); - $list = $xpath->query("//title"); - foreach ($list as $node) - $siteinfo["title"] = html_entity_decode($node->nodeValue, ENT_QUOTES, "UTF-8"); - - //$list = $xpath->query("head/meta[@name]"); - $list = $xpath->query("//meta[@name]"); - foreach ($list as $node) { - $attr = []; - if ($node->attributes->length) - foreach ($node->attributes as $attribute) - $attr[$attribute->name] = $attribute->value; - - $attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8"); - - switch (strtolower($attr["name"])) { - case "fulltitle": - $siteinfo["title"] = trim($attr["content"]); - break; - case "description": - $siteinfo["text"] = trim($attr["content"]); - break; - case "thumbnail": - $siteinfo["image"] = $attr["content"]; - break; - case "twitter:image": - $siteinfo["image"] = $attr["content"]; - break; - case "twitter:image:src": - $siteinfo["image"] = $attr["content"]; - break; - case "twitter:card": - if (($siteinfo["type"] == "") || ($attr["content"] == "photo")) { - $siteinfo["type"] = $attr["content"]; - } - break; - case "twitter:description": - $siteinfo["text"] = trim($attr["content"]); - break; - case "twitter:title": - $siteinfo["title"] = trim($attr["content"]); - break; - case "dc.title": - $siteinfo["title"] = trim($attr["content"]); - break; - case "dc.description": - $siteinfo["text"] = trim($attr["content"]); - break; - case "keywords": - $keywords = explode(",", $attr["content"]); - break; - case "news_keywords": - $keywords = explode(",", $attr["content"]); - break; - } - } - - //$list = $xpath->query("head/meta[@property]"); - $list = $xpath->query("//meta[@property]"); - foreach ($list as $node) { - $attr = []; - if ($node->attributes->length) - foreach ($node->attributes as $attribute) - $attr[$attribute->name] = $attribute->value; - - $attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8"); - - switch (strtolower($attr["property"])) { - case "og:image": - $siteinfo["image"] = $attr["content"]; - break; - case "og:title": - $siteinfo["title"] = $attr["content"]; - break; - case "og:description": - $siteinfo["text"] = $attr["content"]; - break; - } - } - - if ($siteinfo["image"] == "") { - $list = $xpath->query("//img[@src]"); - foreach ($list as $node) { - $attr = []; - if ($node->attributes->length) - foreach ($node->attributes as $attribute) - $attr[$attribute->name] = $attribute->value; - - $src = self::completeurl($attr["src"], $url); - $photodata = @getimagesize($src); - - if (($photodata) && ($photodata[0] > 150) and ($photodata[1] > 150)) { - if ($photodata[0] > 300) { - $photodata[1] = round($photodata[1] * (300 / $photodata[0])); - $photodata[0] = 300; - } - if ($photodata[1] > 300) { - $photodata[0] = round($photodata[0] * (300 / $photodata[1])); - $photodata[1] = 300; - } - $siteinfo["images"][] = array("src"=>$src, - "width"=>$photodata[0], - "height"=>$photodata[1]); - } - - } - } else { - $src = self::completeurl($siteinfo["image"], $url); - - unset($siteinfo["image"]); - - $photodata = @getimagesize($src); - - if (($photodata) && ($photodata[0] > 10) and ($photodata[1] > 10)) - $siteinfo["images"][] = array("src"=>$src, - "width"=>$photodata[0], - "height"=>$photodata[1]); - } - - if ($siteinfo["text"] == "") { - $text = ""; - - $list = $xpath->query("//div[@class='article']"); - foreach ($list as $node) - if (strlen($node->nodeValue) > 40) - $text .= " ".trim($node->nodeValue); - - if ($text == "") { - $list = $xpath->query("//div[@class='content']"); - foreach ($list as $node) - if (strlen($node->nodeValue) > 40) - $text .= " ".trim($node->nodeValue); - } - - // If none text was found then take the paragraph content - if ($text == "") { - $list = $xpath->query("//p"); - foreach ($list as $node) - if (strlen($node->nodeValue) > 40) - $text .= " ".trim($node->nodeValue); - } - - if ($text != "") { - $text = trim(str_replace(array("\n", "\r"), array(" ", " "), $text)); - - while (strpos($text, " ")) - $text = trim(str_replace(" ", " ", $text)); - - $siteinfo["text"] = html_entity_decode(substr($text,0,350), ENT_QUOTES, "UTF-8").'...'; - } - } - - return($siteinfo); - } - + if (is_matrix_url($url)) + $template = str_replace('url', 'zrl', $template); - private static function arr_add_hashes(&$item,$k) { - if (substr($item,0,1) !== '#') { - $item = '#' . $item; - } - } + if ($siteinfo["title"] == "") { + echo sprintf($template, $url, $url, '') . $str_tags; + killme(); + } else { + $text = $siteinfo["text"]; + $title = $siteinfo["title"]; + } + + $image = ""; + + if (isset($siteinfo['images']) && is_array($siteinfo['images']) && count($siteinfo["images"])) { + /* Execute below code only if image is present in siteinfo */ + + $total_images = 0; + $max_images = get_config('system', 'max_bookmark_images'); + if ($max_images === false) + $max_images = 2; + else + $max_images = intval($max_images); + + foreach ($siteinfo["images"] as $imagedata) { + if ($url) { + $image .= sprintf('[url=%s]', $url); + } + $image .= '[img=' . $imagedata["width"] . 'x' . $imagedata["height"] . ']' . $imagedata["src"] . '[/img]'; + if ($url) { + $image .= '[/url]'; + } + $image .= "\n"; + $total_images++; + if ($max_images && $max_images >= $total_images) + break; + } + } + + if (strlen($text)) { + $text = $br . '[quote]' . trim($text) . '[/quote]' . $br; + } + + if ($image) { + $text = $br . $br . $image . $text; + } + $title = str_replace(array("\r", "\n"), array('', ''), $title); + + $result = sprintf($template, $url, ($title) ? $title : $url, $text) . $str_tags; + + logger('linkinfo: returns: ' . $result, LOGGER_DEBUG); + + echo trim($result); + killme(); + + } + + + public static function deletexnode(&$doc, $node) + { + $xpath = new DomXPath($doc); + $list = $xpath->query("//" . $node); + foreach ($list as $child) + $child->parentNode->removeChild($child); + } + + public static function completeurl($url, $scheme) + { + $urlarr = parse_url($url); + + if (isset($urlarr["scheme"])) + return ($url); + + $schemearr = parse_url($scheme); + + $complete = $schemearr["scheme"] . "://" . $schemearr["host"]; + + if ($schemearr["port"] != "") + $complete .= ":" . $schemearr["port"]; + + if (strpos($urlarr['path'], '/') !== 0) + $complete .= '/'; + + $complete .= $urlarr["path"]; + + if ($urlarr["query"] != "") + $complete .= "?" . $urlarr["query"]; + + if ($urlarr["fragment"] != "") + $complete .= "#" . $urlarr["fragment"]; + + return ($complete); + } + + public static function get_video_poster($url) + { + + if (strpos($url, z_root() . '/cloud/') === false) { + return EMPTY_STR; + } + $m = parse_url($url, PHP_URL_PATH); + if ($m) { + // strip leading '/cloud/' + $m = substr($m, 7); + } + $nick = substr($m, 0, strpos($m, '/')); + $p = substr($m, strpos($m, '/') + 1); + + // get the channel to check permissions + + $u = channelx_by_nick($nick); + + if ($u && $p) { + + $sql_extra = permissions_sql(intval($u['channel_id'])); + + $r = q("select hash, content from attach where display_path = '%s' and uid = %d and os_storage = 1 $sql_extra limit 1", + dbesc($p), + intval($u['channel_id']) + ); + if ($r) { + $path = dbunescbin($r[0]['content']); + if ($path && @file_exists($path . '.thumb')) { + return z_root() . '/poster/' . $nick . '/' . $r[0]['hash']; + } + } + } + return EMPTY_STR; + } + + + public static function parseurl_getsiteinfo($url) + { + $siteinfo = []; + + + $result = z_fetch_url($url, false, 0, array('novalidate' => true)); + if (!$result['success']) + return $siteinfo; + + $header = $result['header']; + $body = $result['body']; + + // Check codepage in HTTP headers or HTML if not exist + $cp = (preg_match('/Content-Type: text\/html; charset=(.+)\r\n/i', $header, $o) ? $o[1] : ''); + if (empty($cp)) + $cp = (preg_match('/meta.+content=["|\']text\/html; charset=([^"|\']+)/i', $body, $o) ? $o[1] : 'AUTO'); + + $body = mb_convert_encoding($body, 'UTF-8', $cp); + $body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8"); + + $doc = new DOMDocument(); + @$doc->loadHTML($body); + + self::deletexnode($doc, 'style'); + self::deletexnode($doc, 'script'); + self::deletexnode($doc, 'option'); + self::deletexnode($doc, 'h1'); + self::deletexnode($doc, 'h2'); + self::deletexnode($doc, 'h3'); + self::deletexnode($doc, 'h4'); + self::deletexnode($doc, 'h5'); + self::deletexnode($doc, 'h6'); + self::deletexnode($doc, 'ol'); + self::deletexnode($doc, 'ul'); + + $xpath = new DomXPath($doc); + + //$list = $xpath->query("head/title"); + $list = $xpath->query("//title"); + foreach ($list as $node) + $siteinfo["title"] = html_entity_decode($node->nodeValue, ENT_QUOTES, "UTF-8"); + + //$list = $xpath->query("head/meta[@name]"); + $list = $xpath->query("//meta[@name]"); + foreach ($list as $node) { + $attr = []; + if ($node->attributes->length) + foreach ($node->attributes as $attribute) + $attr[$attribute->name] = $attribute->value; + + $attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8"); + + switch (strtolower($attr["name"])) { + case "fulltitle": + $siteinfo["title"] = trim($attr["content"]); + break; + case "description": + $siteinfo["text"] = trim($attr["content"]); + break; + case "thumbnail": + $siteinfo["image"] = $attr["content"]; + break; + case "twitter:image": + $siteinfo["image"] = $attr["content"]; + break; + case "twitter:image:src": + $siteinfo["image"] = $attr["content"]; + break; + case "twitter:card": + if (($siteinfo["type"] == "") || ($attr["content"] == "photo")) { + $siteinfo["type"] = $attr["content"]; + } + break; + case "twitter:description": + $siteinfo["text"] = trim($attr["content"]); + break; + case "twitter:title": + $siteinfo["title"] = trim($attr["content"]); + break; + case "dc.title": + $siteinfo["title"] = trim($attr["content"]); + break; + case "dc.description": + $siteinfo["text"] = trim($attr["content"]); + break; + case "keywords": + $keywords = explode(",", $attr["content"]); + break; + case "news_keywords": + $keywords = explode(",", $attr["content"]); + break; + } + } + + //$list = $xpath->query("head/meta[@property]"); + $list = $xpath->query("//meta[@property]"); + foreach ($list as $node) { + $attr = []; + if ($node->attributes->length) + foreach ($node->attributes as $attribute) + $attr[$attribute->name] = $attribute->value; + + $attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8"); + + switch (strtolower($attr["property"])) { + case "og:image": + $siteinfo["image"] = $attr["content"]; + break; + case "og:title": + $siteinfo["title"] = $attr["content"]; + break; + case "og:description": + $siteinfo["text"] = $attr["content"]; + break; + } + } + + if ($siteinfo["image"] == "") { + $list = $xpath->query("//img[@src]"); + foreach ($list as $node) { + $attr = []; + if ($node->attributes->length) + foreach ($node->attributes as $attribute) + $attr[$attribute->name] = $attribute->value; + + $src = self::completeurl($attr["src"], $url); + $photodata = @getimagesize($src); + + if (($photodata) && ($photodata[0] > 150) and ($photodata[1] > 150)) { + if ($photodata[0] > 300) { + $photodata[1] = round($photodata[1] * (300 / $photodata[0])); + $photodata[0] = 300; + } + if ($photodata[1] > 300) { + $photodata[0] = round($photodata[0] * (300 / $photodata[1])); + $photodata[1] = 300; + } + $siteinfo["images"][] = array("src" => $src, + "width" => $photodata[0], + "height" => $photodata[1]); + } + + } + } else { + $src = self::completeurl($siteinfo["image"], $url); + + unset($siteinfo["image"]); + + $photodata = @getimagesize($src); + + if (($photodata) && ($photodata[0] > 10) and ($photodata[1] > 10)) + $siteinfo["images"][] = array("src" => $src, + "width" => $photodata[0], + "height" => $photodata[1]); + } + + if ($siteinfo["text"] == "") { + $text = ""; + + $list = $xpath->query("//div[@class='article']"); + foreach ($list as $node) + if (strlen($node->nodeValue) > 40) + $text .= " " . trim($node->nodeValue); + + if ($text == "") { + $list = $xpath->query("//div[@class='content']"); + foreach ($list as $node) + if (strlen($node->nodeValue) > 40) + $text .= " " . trim($node->nodeValue); + } + + // If none text was found then take the paragraph content + if ($text == "") { + $list = $xpath->query("//p"); + foreach ($list as $node) + if (strlen($node->nodeValue) > 40) + $text .= " " . trim($node->nodeValue); + } + + if ($text != "") { + $text = trim(str_replace(array("\n", "\r"), array(" ", " "), $text)); + + while (strpos($text, " ")) + $text = trim(str_replace(" ", " ", $text)); + + $siteinfo["text"] = html_entity_decode(substr($text, 0, 350), ENT_QUOTES, "UTF-8") . '...'; + } + } + + return ($siteinfo); + } + + + private static function arr_add_hashes(&$item, $k) + { + if (substr($item, 0, 1) !== '#') { + $item = '#' . $item; + } + } } diff --git a/Zotlabs/Module/Lists.php b/Zotlabs/Module/Lists.php index 599a19abb..1b5210087 100644 --- a/Zotlabs/Module/Lists.php +++ b/Zotlabs/Module/Lists.php @@ -11,399 +11,392 @@ use Zotlabs\Web\HTTPSig; use Zotlabs\Lib\Config; use Zotlabs\Lib\LDSignatures; -class Lists extends Controller { +class Lists extends Controller +{ - function init() { - if (ActivityStreams::is_as_request()) { - $item_id = argv(1); - if( ! $item_id) { - http_status_exit(404, 'Not found'); - } - $x = q("select * from pgrp where hash = '%s' limit 1", - dbesc($item_id) - ); - if (! $x) { - http_status_exit(404, 'Not found'); - } + public function init() + { + if (ActivityStreams::is_as_request()) { + $item_id = argv(1); + if (!$item_id) { + http_status_exit(404, 'Not found'); + } + $x = q("select * from pgrp where hash = '%s' limit 1", + dbesc($item_id) + ); + if (!$x) { + http_status_exit(404, 'Not found'); + } - $group = array_shift($x); + $group = array_shift($x); - // process an authenticated fetch + // process an authenticated fetch - $sigdata = HTTPSig::verify(EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { - http_status_exit(403, 'Permission denied'); - } - if (! check_siteallowed($sigdata['signer'])) { - http_status_exit(403, 'Permission denied'); - } - observer_auth($portable_id); - } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); - } + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (!check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (!check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + } elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); + } - if (! perm_is_allowed($group['uid'],get_observer_hash(),'view_contacts')) { - http_status_exit(403,'Permission denied'); - } + if (!perm_is_allowed($group['uid'], get_observer_hash(), 'view_contacts')) { + http_status_exit(403, 'Permission denied'); + } - $channel = channelx_by_n($group['uid']); + $channel = channelx_by_n($group['uid']); - if (! $channel) { - http_status_exit(404,'Not found'); - } + if (!$channel) { + http_status_exit(404, 'Not found'); + } - if (! $group['visible']) { - if ($channel['channel_hash'] !== get_observer_hash()) { - http_status_exit(403,'Permission denied'); - } - } + if (!$group['visible']) { + if ($channel['channel_hash'] !== get_observer_hash()) { + http_status_exit(403, 'Permission denied'); + } + } - $total = AccessList::members($group['uid'],$group['id'], true); - if ($total) { - App::set_pager_total($total); - App::set_pager_itemspage(100); - } + $total = AccessList::members($group['uid'], $group['id'], true); + if ($total) { + App::set_pager_total($total); + App::set_pager_itemspage(100); + } - if (App::$pager['unset'] && $total > 100) { - $ret = Activity::paged_collection_init($total,App::$query_string); - } - else { - $members = AccessList::members($group['uid'],$group['id'], false, App::$pager['start'], App::$pager['itemspage']); - $ret = Activity::encode_follow_collection($members, App::$query_string, 'OrderedCollection',$total); - } + if (App::$pager['unset'] && $total > 100) { + $ret = Activity::paged_collection_init($total, App::$query_string); + } else { + $members = AccessList::members($group['uid'], $group['id'], false, App::$pager['start'], App::$pager['itemspage']); + $ret = Activity::encode_follow_collection($members, App::$query_string, 'OrderedCollection', $total); + } - as_return_and_die($ret,$channel); + as_return_and_die($ret, $channel); - } + } - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - App::$profile_uid = local_channel(); - nav_set_selected('Access Lists'); - } + App::$profile_uid = local_channel(); + nav_set_selected('Access Lists'); + } - function post() { - - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - if ((argc() == 2) && (argv(1) === 'new')) { - check_form_security_token_redirectOnErr('/lists/new', 'group_edit'); - - $name = notags(trim($_POST['groupname'])); - $public = intval($_POST['public']); - $r = AccessList::add(local_channel(),$name,$public); - if ($r) { - info( t('Access list created.') . EOL ); - } - else { - notice( t('Could not create access list.') . EOL ); - } - goaway(z_root() . '/lists'); - - } - if ((argc() == 2) && (intval(argv(1)))) { - check_form_security_token_redirectOnErr('/lists', 'group_edit'); - - $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1", - intval(argv(1)), - intval(local_channel()) - ); - if (! $r) { - $r = q("select * from pgrp where id = %d limit 1", - intval(argv(1)) + public function post() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + if ((argc() == 2) && (argv(1) === 'new')) { + check_form_security_token_redirectOnErr('/lists/new', 'group_edit'); + + $name = notags(trim($_POST['groupname'])); + $public = intval($_POST['public']); + $r = AccessList::add(local_channel(), $name, $public); + if ($r) { + info(t('Access list created.') . EOL); + } else { + notice(t('Could not create access list.') . EOL); + } + goaway(z_root() . '/lists'); + + } + if ((argc() == 2) && (intval(argv(1)))) { + check_form_security_token_redirectOnErr('/lists', 'group_edit'); + + $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + if (!$r) { + $r = q("select * from pgrp where id = %d limit 1", + intval(argv(1)) + ); + if ($r) { + notice(t('Permission denied.') . EOL); + } else { + notice(t('Access list not found.') . EOL); + } + goaway(z_root() . '/connections'); + + } + $group = array_shift($r); + $groupname = notags(trim($_POST['groupname'])); + $public = intval($_POST['public']); + + if ((strlen($groupname)) && (($groupname != $group['gname']) || ($public != $group['visible']))) { + $r = q("UPDATE pgrp SET gname = '%s', visible = %d WHERE uid = %d AND id = %d", + dbesc($groupname), + intval($public), + intval(local_channel()), + intval($group['id']) + ); + if ($r) { + info(t('Access list updated.') . EOL); + } + Libsync::build_sync_packet(local_channel(), null, true); + } + + goaway(z_root() . '/lists/' . argv(1) . '/' . argv(2)); + } + return; + } + + public function get() + { + + $change = false; + + logger('mod_lists: ' . App::$cmd, LOGGER_DEBUG); + + + if (argc() > 2 && argv(1) === 'view') { + $grp = argv(2); + if ($grp) { + $r = q("select * from pgrp where hash = '%s' and deleted = 0", + dbesc($grp) + ); + if ($r) { + $uid = $r[0]['uid']; + if (local_channel() && local_channel() == $uid) { + goaway(z_root() . '/lists/' . $r[0]['id']); + } + if (!($r[0]['visible'] && perm_is_allowed($uid, get_observer_hash(), 'view_contacts'))) { + notice(t('Permission denied') . EOL); + return; + } + $members = []; + $memberlist = AccessList::members($uid, $r[0]['id']); + + if ($memberlist) { + foreach ($memberlist as $member) { + $members[] = micropro($member, true, 'mpgroup', 'card'); + } + } + $o = replace_macros(get_markup_template('listmembers.tpl'), [ + '$title' => t('List members'), + '$members' => $members + ]); + return $o; + } else { + notice(t('List not found') . EOL); + return; + } + } + } + + + if (!local_channel()) { + notice(t('Permission denied') . EOL); + return; + } + + + // Switch to text mode interface if we have more than 'n' contacts or group members, else loading avatars will lead to poor interactivity + + $switchtotext = get_pconfig(local_channel(), 'system', 'listedit_image_limit', get_config('system', 'listedit_image_limit', 1000)); + + if ((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) { + + $new = (((argc() == 2) && (argv(1) === 'new')) ? true : false); + + $groups = q("SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + intval(local_channel()) + ); + + $i = 0; + foreach ($groups as $group) { + $entries[$i]['name'] = $group['gname']; + $entries[$i]['id'] = $group['id']; + $entries[$i]['count'] = count(AccessList::members(local_channel(), $group['id'])); + $i++; + } + + $tpl = get_markup_template('privacy_groups.tpl'); + $o = replace_macros($tpl, [ + '$title' => t('Access Lists'), + '$add_new_label' => t('Create access list'), + '$new' => $new, + + // new group form + '$gname' => array('groupname', t('Access list name')), + '$public' => array('public', t('Members are visible to other channels'), false), + '$form_security_token' => get_form_security_token("group_edit"), + '$submit' => t('Submit'), + + // groups list + '$title' => t('Access Lists'), + '$name_label' => t('Name'), + '$count_label' => t('Members'), + '$entries' => $entries + ]); + + return $o; + + } + + $context = array('$submit' => t('Submit')); + $tpl = get_markup_template('group_edit.tpl'); + + if ((argc() == 3) && (argv(1) === 'drop')) { + check_form_security_token_redirectOnErr('/lists', 'group_drop', 't'); + + if (intval(argv(2))) { + $r = q("SELECT gname FROM pgrp WHERE id = %d AND uid = %d LIMIT 1", + intval(argv(2)), + intval(local_channel()) + ); + if ($r) + $result = AccessList::remove(local_channel(), $r[0]['gname']); + if ($result) + info(t('Access list removed.') . EOL); + else + notice(t('Unable to remove access list.') . EOL); + } + goaway(z_root() . '/lists'); + // NOTREACHED + } + + + if ((argc() > 2) && intval(argv(1)) && argv(2)) { + + check_form_security_token_ForbiddenOnErr('group_member_change', 't'); + + $r = q("SELECT abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 limit 1", + dbesc(base64url_decode(argv(2))), + intval(local_channel()) + ); + if (count($r)) + $change = base64url_decode(argv(2)); + + } + + if (argc() > 1) { + + require_once('include/acl_selectors.php'); + + if (strlen(argv(1)) <= 11 && intval(argv(1))) { + $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + } else { + $r = q("SELECT * FROM pgrp WHERE hash = '%s' AND uid = %d AND deleted = 0 LIMIT 1", + dbesc(argv(1)), + intval(local_channel()) + ); + } + + if (!$r) { + $r = q("SELECT * FROM pgrp WHERE id = %d AND deleted = 0 LIMIT 1", + intval(argv(1)), ); - if ($r) { - notice( t('Permission denied.') . EOL ); - } else { - notice( t('Access list not found.') . EOL ); - } - goaway(z_root() . '/connections'); - - } - $group = array_shift($r); - $groupname = notags(trim($_POST['groupname'])); - $public = intval($_POST['public']); - - if ((strlen($groupname)) && (($groupname != $group['gname']) || ($public != $group['visible']))) { - $r = q("UPDATE pgrp SET gname = '%s', visible = %d WHERE uid = %d AND id = %d", - dbesc($groupname), - intval($public), - intval(local_channel()), - intval($group['id']) - ); - if ($r) { - info( t('Access list updated.') . EOL ); - } - Libsync::build_sync_packet(local_channel(),null,true); - } - - goaway(z_root() . '/lists/' . argv(1) . '/' . argv(2)); - } - return; - } - - function get() { + if ($r) { + notice(t('Permission denied.') . EOL); + } else { + notice(t('Access list not found.') . EOL); + } + goaway(z_root() . '/connections'); + } + $group = $r[0]; - $change = false; - - logger('mod_lists: ' . App::$cmd,LOGGER_DEBUG); - + $members = AccessList::members(local_channel(), $group['id']); - if (argc() > 2 && argv(1) === 'view') { - $grp = argv(2); - if ($grp) { - $r = q("select * from pgrp where hash = '%s' and deleted = 0", - dbesc($grp) - ); - if ($r) { - $uid = $r[0]['uid']; - if (local_channel() && local_channel() == $uid) { - goaway(z_root() . '/lists/' . $r[0]['id']); - } - if (! ($r[0]['visible'] && perm_is_allowed($uid,get_observer_hash(),'view_contacts'))) { - notice( t('Permission denied') . EOL); - return; - } - $members = []; - $memberlist = AccessList::members($uid, $r[0]['id']); + $preselected = []; + if (count($members)) { + foreach ($members as $member) + if (!in_array($member['xchan_hash'], $preselected)) + $preselected[] = $member['xchan_hash']; + } - if ($memberlist) { - foreach ($memberlist as $member) { - $members[] = micropro($member,true,'mpgroup', 'card'); - } - } - $o = replace_macros(get_markup_template('listmembers.tpl'), [ - '$title' => t('List members'), - '$members' => $members - ]); - return $o; - } - else { - notice ( t('List not found') . EOL); - return; - } - } - } + if ($change) { + + if (in_array($change, $preselected)) { + AccessList::member_remove(local_channel(), $group['gname'], $change); + } else { + AccessList::member_add(local_channel(), $group['gname'], $change); + } + + $members = AccessList::members(local_channel(), $group['id']); + + $preselected = []; + if (count($members)) { + foreach ($members as $member) + $preselected[] = $member['xchan_hash']; + } + } + + $context = $context + array( + '$title' => sprintf(t('Access List: %s'), $group['gname']), + '$details_label' => t('Edit'), + '$gname' => array('groupname', t('Access list name: '), $group['gname'], ''), + '$gid' => $group['id'], + '$drop' => $drop_txt, + '$public' => array('public', t('Members are visible to other channels'), $group['visible'], ''), + '$form_security_token_edit' => get_form_security_token('group_edit'), + '$delete' => t('Delete access list'), + '$form_security_token_drop' => get_form_security_token("group_drop"), + ); + + } + + if (!isset($group)) + return; + + $groupeditor = array( + 'label_members' => t('List members'), + 'members' => [], + 'label_contacts' => t('Not in this list'), + 'contacts' => [], + ); + + $sec_token = addslashes(get_form_security_token('group_member_change')); + $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : 'card'); + foreach ($members as $member) { + if ($member['xchan_url']) { + $member['archived'] = (intval($member['abook_archived']) ? true : false); + $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;'; + $groupeditor['members'][] = micropro($member, true, 'mpgroup', $textmode); + } else + AccessList::member_remove(local_channel(), $group['gname'], $member['xchan_hash']); + } + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_self = 0 and abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc", + intval(local_channel()) + ); + + if (count($r)) { + $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : 'card'); + foreach ($r as $member) { + if (!in_array($member['xchan_hash'], $preselected)) { + $member['archived'] = (intval($member['abook_archived']) ? true : false); + $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;'; + $groupeditor['contacts'][] = micropro($member, true, 'mpall', $textmode); + } + } + } + + $context['$groupeditor'] = $groupeditor; + $context['$desc'] = t('Select a channel to toggle membership'); + + if ($change) { + $tpl = get_markup_template('groupeditor.tpl'); + echo replace_macros($tpl, $context); + killme(); + } + + return replace_macros($tpl, $context); + + } - - - if (! local_channel()) { - notice( t('Permission denied') . EOL); - return; - } - - - - // Switch to text mode interface if we have more than 'n' contacts or group members, else loading avatars will lead to poor interactivity - - $switchtotext = get_pconfig(local_channel(),'system','listedit_image_limit',get_config('system','listedit_image_limit', 1000)); - - if ((argc() == 1) || ((argc() == 2) && (argv(1) === 'new'))) { - - $new = (((argc() == 2) && (argv(1) === 'new')) ? true : false); - - $groups = q("SELECT id, gname FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", - intval(local_channel()) - ); - - $i = 0; - foreach ($groups as $group) { - $entries[$i]['name'] = $group['gname']; - $entries[$i]['id'] = $group['id']; - $entries[$i]['count'] = count(AccessList::members(local_channel(),$group['id'])); - $i++; - } - - $tpl = get_markup_template('privacy_groups.tpl'); - $o = replace_macros($tpl, [ - '$title' => t('Access Lists'), - '$add_new_label' => t('Create access list'), - '$new' => $new, - - // new group form - '$gname' => array('groupname',t('Access list name')), - '$public' => array('public',t('Members are visible to other channels'), false), - '$form_security_token' => get_form_security_token("group_edit"), - '$submit' => t('Submit'), - - // groups list - '$title' => t('Access Lists'), - '$name_label' => t('Name'), - '$count_label' => t('Members'), - '$entries' => $entries - ]); - - return $o; - - } - - $context = array('$submit' => t('Submit')); - $tpl = get_markup_template('group_edit.tpl'); - - if((argc() == 3) && (argv(1) === 'drop')) { - check_form_security_token_redirectOnErr('/lists', 'group_drop', 't'); - - if(intval(argv(2))) { - $r = q("SELECT gname FROM pgrp WHERE id = %d AND uid = %d LIMIT 1", - intval(argv(2)), - intval(local_channel()) - ); - if($r) - $result = AccessList::remove(local_channel(),$r[0]['gname']); - if($result) - info( t('Access list removed.') . EOL); - else - notice( t('Unable to remove access list.') . EOL); - } - goaway(z_root() . '/lists'); - // NOTREACHED - } - - - if((argc() > 2) && intval(argv(1)) && argv(2)) { - - check_form_security_token_ForbiddenOnErr('group_member_change', 't'); - - $r = q("SELECT abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 limit 1", - dbesc(base64url_decode(argv(2))), - intval(local_channel()) - ); - if(count($r)) - $change = base64url_decode(argv(2)); - - } - - if(argc() > 1) { - - require_once('include/acl_selectors.php'); - - if (strlen(argv(1)) <= 11 && intval(argv(1))) { - $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d AND deleted = 0 LIMIT 1", - intval(argv(1)), - intval(local_channel()) - ); - } - else { - $r = q("SELECT * FROM pgrp WHERE hash = '%s' AND uid = %d AND deleted = 0 LIMIT 1", - dbesc(argv(1)), - intval(local_channel()) - ); - } - - if(! $r) { - $r = q("SELECT * FROM pgrp WHERE id = %d AND deleted = 0 LIMIT 1", - intval(argv(1)), - ); - if ($r) { - notice( t('Permission denied.') . EOL ); - } - else { - notice( t('Access list not found.') . EOL ); - } - goaway(z_root() . '/connections'); - } - $group = $r[0]; - - $members = AccessList::members(local_channel(), $group['id']); - - $preselected = []; - if(count($members)) { - foreach($members as $member) - if(! in_array($member['xchan_hash'],$preselected)) - $preselected[] = $member['xchan_hash']; - } - - if($change) { - - if(in_array($change,$preselected)) { - AccessList::member_remove(local_channel(),$group['gname'],$change); - } - else { - AccessList::member_add(local_channel(),$group['gname'],$change); - } - - $members = AccessList::members(local_channel(), $group['id']); - - $preselected = []; - if(count($members)) { - foreach($members as $member) - $preselected[] = $member['xchan_hash']; - } - } - - $context = $context + array( - '$title' => sprintf(t('Access List: %s'), $group['gname']), - '$details_label' => t('Edit'), - '$gname' => array('groupname',t('Access list name: '),$group['gname'], ''), - '$gid' => $group['id'], - '$drop' => $drop_txt, - '$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''), - '$form_security_token_edit' => get_form_security_token('group_edit'), - '$delete' => t('Delete access list'), - '$form_security_token_drop' => get_form_security_token("group_drop"), - ); - - } - - if(! isset($group)) - return; - - $groupeditor = array( - 'label_members' => t('List members'), - 'members' => [], - 'label_contacts' => t('Not in this list'), - 'contacts' => [], - ); - - $sec_token = addslashes(get_form_security_token('group_member_change')); - $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : 'card'); - foreach($members as $member) { - if($member['xchan_url']) { - $member['archived'] = (intval($member['abook_archived']) ? true : false); - $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;'; - $groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode); - } - else - AccessList::member_remove(local_channel(),$group['gname'],$member['xchan_hash']); - } - - $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_self = 0 and abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc", - intval(local_channel()) - ); - - if(count($r)) { - $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : 'card'); - foreach($r as $member) { - if(! in_array($member['xchan_hash'],$preselected)) { - $member['archived'] = (intval($member['abook_archived']) ? true : false); - $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;'; - $groupeditor['contacts'][] = micropro($member,true,'mpall', $textmode); - } - } - } - - $context['$groupeditor'] = $groupeditor; - $context['$desc'] = t('Select a channel to toggle membership'); - - if($change) { - $tpl = get_markup_template('groupeditor.tpl'); - echo replace_macros($tpl, $context); - killme(); - } - - return replace_macros($tpl, $context); - - } - - } diff --git a/Zotlabs/Module/Lockview.php b/Zotlabs/Module/Lockview.php index cbca9cdd6..3e9056f94 100644 --- a/Zotlabs/Module/Lockview.php +++ b/Zotlabs/Module/Lockview.php @@ -5,172 +5,173 @@ use Zotlabs\Web\Controller; require_once('include/security.php'); -class Lockview extends Controller { +class Lockview extends Controller +{ - function get() { + public function get() + { - $atokens = []; + $atokens = []; - if(local_channel()) { - $at = q("select * from atoken where atoken_uid = %d", - intval(local_channel()) - ); - if($at) { - foreach($at as $t) { - $atokens[] = atoken_xchan($t); - } - } - } - - $type = ((argc() > 1) ? argv(1) : 0); - if (is_numeric($type)) { - $item_id = intval($type); - $type='item'; - } - else { - $item_id = ((argc() > 2) ? intval(argv(2)) : 0); - } - - if(! $item_id) - killme(); - - if (! in_array($type, array('item', 'photo', 'attach', 'event', 'menu_item', 'chatroom'))) - killme(); - - // we have different naming in in menu_item table and chatroom table - switch($type) { - case 'menu_item': - $id = 'mitem_id'; - break; - case 'chatroom': - $id = 'cr_id'; - break; - default: - $id = 'id'; - break; - } - - $r = q("SELECT * FROM %s WHERE $id = %d LIMIT 1", - dbesc($type), - intval($item_id) - ); - - if(! $r) - killme(); - - $item = $r[0]; - - // we have different naming in in menu_item table and chatroom table - switch($type) { - case 'menu_item': - $uid = $item['mitem_channel_id']; - break; - case 'chatroom': - $uid = $item['cr_uid']; - break; - default: - $uid = $item['uid']; - break; - } + if (local_channel()) { + $at = q("select * from atoken where atoken_uid = %d", + intval(local_channel()) + ); + if ($at) { + foreach ($at as $t) { + $atokens[] = atoken_xchan($t); + } + } + } - if ($type === 'item') { - $recips = get_iconfig($item['id'],'activitypub','recips'); - if ($recips) { - $o = ''; - $l = []; - if (isset($recips['to'])) { - if (! is_array($recips['to'])) { - $recips['to'] = [ $recips['to'] ]; - } - $l = array_merge($l,$recips['to']); - } - if (isset($recips['cc'])) { - if (! is_array($recips['cc'])) { - $recips['cc'] = [ $recips['cc'] ]; - } - $l = array_merge($l,$recips['cc']); - } - for ($x = 0; $x < count($l); $x ++) { - if($l[$x] !== ACTIVITY_PUBLIC_INBOX) { - $l[$x] = '' . $l[$x] . ''; - } - } - echo $o . implode(', ',$l); - killme(); - } - } + $type = ((argc() > 1) ? argv(1) : 0); + if (is_numeric($type)) { + $item_id = intval($type); + $type = 'item'; + } else { + $item_id = ((argc() > 2) ? intval(argv(2)) : 0); + } - - if(intval($item['item_private']) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) - && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { + if (!$item_id) + killme(); - if ($item['mid'] === $item['parent_mid']) { - echo ''; - killme(); - } - } - - $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 = ''; - $l = []; - - stringify_array_elms($allowed_groups,true); - stringify_array_elms($allowed_users,true); - stringify_array_elms($deny_groups,true); - stringify_array_elms($deny_users,true); - + if (!in_array($type, array('item', 'photo', 'attach', 'event', 'menu_item', 'chatroom'))) + killme(); - if(count($allowed_groups)) { - $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $allowed_groups) . " )"); - if($r) - foreach($r as $rr) - $l[] = ''; - } - if(count($allowed_users)) { - $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )"); - if($r) - foreach($r as $rr) - $l[] = ''; - if($atokens) { - foreach($atokens as $at) { - if(in_array("'" . $at['xchan_hash'] . "'",$allowed_users)) { - $l[] = ''; - } - } - } - } + // we have different naming in in menu_item table and chatroom table + switch ($type) { + case 'menu_item': + $id = 'mitem_id'; + break; + case 'chatroom': + $id = 'cr_id'; + break; + default: + $id = 'id'; + break; + } - if(count($deny_groups)) { - $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $deny_groups) . " )"); - if($r) - foreach($r as $rr) - $l[] = ''; - } - if(count($deny_users)) { - $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )"); - if($r) - foreach($r as $rr) - $l[] = ''; + $r = q("SELECT * FROM %s WHERE $id = %d LIMIT 1", + dbesc($type), + intval($item_id) + ); - if($atokens) { - foreach($atokens as $at) { - if(in_array("'" . $at['xchan_hash'] . "'",$deny_users)) { - $l[] = ''; - } - } - } + if (!$r) + killme(); + + $item = $r[0]; + + // we have different naming in in menu_item table and chatroom table + switch ($type) { + case 'menu_item': + $uid = $item['mitem_channel_id']; + break; + case 'chatroom': + $uid = $item['cr_uid']; + break; + default: + $uid = $item['uid']; + break; + } + + if ($type === 'item') { + $recips = get_iconfig($item['id'], 'activitypub', 'recips'); + if ($recips) { + $o = ''; + $l = []; + if (isset($recips['to'])) { + if (!is_array($recips['to'])) { + $recips['to'] = [$recips['to']]; + } + $l = array_merge($l, $recips['to']); + } + if (isset($recips['cc'])) { + if (!is_array($recips['cc'])) { + $recips['cc'] = [$recips['cc']]; + } + $l = array_merge($l, $recips['cc']); + } + for ($x = 0; $x < count($l); $x++) { + if ($l[$x] !== ACTIVITY_PUBLIC_INBOX) { + $l[$x] = '' . $l[$x] . ''; + } + } + echo $o . implode(', ', $l); + killme(); + } + } - } - - echo $o . implode($l); - killme(); - - - } - + if (intval($item['item_private']) && (!strlen($item['allow_cid'])) && (!strlen($item['allow_gid'])) + && (!strlen($item['deny_cid'])) && (!strlen($item['deny_gid']))) { + + if ($item['mid'] === $item['parent_mid']) { + echo ''; + killme(); + } + } + + $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 = ''; + $l = []; + + stringify_array_elms($allowed_groups, true); + stringify_array_elms($allowed_users, true); + stringify_array_elms($deny_groups, true); + stringify_array_elms($deny_users, true); + + + if (count($allowed_groups)) { + $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $allowed_groups) . " )"); + if ($r) + foreach ($r as $rr) + $l[] = ''; + } + if (count($allowed_users)) { + $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $allowed_users) . " )"); + if ($r) + foreach ($r as $rr) + $l[] = ''; + if ($atokens) { + foreach ($atokens as $at) { + if (in_array("'" . $at['xchan_hash'] . "'", $allowed_users)) { + $l[] = ''; + } + } + } + } + + if (count($deny_groups)) { + $r = q("SELECT gname FROM pgrp WHERE hash IN ( " . implode(', ', $deny_groups) . " )"); + if ($r) + foreach ($r as $rr) + $l[] = ''; + } + if (count($deny_users)) { + $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )"); + if ($r) + foreach ($r as $rr) + $l[] = ''; + + if ($atokens) { + foreach ($atokens as $at) { + if (in_array("'" . $at['xchan_hash'] . "'", $deny_users)) { + $l[] = ''; + } + } + } + + + } + + echo $o . implode($l); + killme(); + + + } + } diff --git a/Zotlabs/Module/Locs.php b/Zotlabs/Module/Locs.php index b6ecc9161..23a2211f0 100644 --- a/Zotlabs/Module/Locs.php +++ b/Zotlabs/Module/Locs.php @@ -6,133 +6,135 @@ use Zotlabs\Web\Controller; use Zotlabs\Daemon\Run; -class Locs extends Controller { +class Locs extends Controller +{ - function post() { - - if(! local_channel()) - return; - - $channel = App::get_channel(); - - if($_REQUEST['primary']) { - $hubloc_id = intval($_REQUEST['primary']); - if($hubloc_id) { - - $r = q("select hubloc_id from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1", - intval($hubloc_id), - dbesc($channel['channel_hash']) - ); - - if(! $r) { - notice( t('Location not found.') . EOL); - return; - } - - $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' ", - dbesc($channel['channel_hash']) - ); - $r = q("update hubloc set hubloc_primary = 1 where hubloc_id = %d and hubloc_hash = '%s'", - intval($hubloc_id), - dbesc($channel['channel_hash']) - ); + public function post() + { - $x = q("select * from hubloc where hubloc_id = %d and hubloc_hash = '%s' ", - intval($hubloc_id), - dbesc($channel['channel_hash']) - ); - if ($x) { - hubloc_change_primary($x[0]); - } + if (!local_channel()) + return; + + $channel = App::get_channel(); + + if ($_REQUEST['primary']) { + $hubloc_id = intval($_REQUEST['primary']); + if ($hubloc_id) { + + $r = q("select hubloc_id from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + + if (!$r) { + notice(t('Location not found.') . EOL); + return; + } + + $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' ", + dbesc($channel['channel_hash']) + ); + $r = q("update hubloc set hubloc_primary = 1 where hubloc_id = %d and hubloc_hash = '%s'", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + + $x = q("select * from hubloc where hubloc_id = %d and hubloc_hash = '%s' ", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + if ($x) { + hubloc_change_primary($x[0]); + } + + Run::Summon(['Notifier', 'refresh_all', $channel['channel_id']]); + return; + } + } + + + if ($_REQUEST['drop']) { + $hubloc_id = intval($_REQUEST['drop']); + + if ($hubloc_id) { + $r = q("select * from hubloc where hubloc_id = %d and hubloc_url != '%s' and hubloc_hash = '%s' limit 1", + intval($hubloc_id), + dbesc(z_root()), + dbesc($channel['channel_hash']) + ); + + if (!$r) { + notice(t('Location not found.') . EOL); + return; + } + if (intval($r[0]['hubloc_primary'])) { + $x = q("select hubloc_id from hubloc where hubloc_primary = 1 and hubloc_hash = '%s'", + dbesc($channel['channel_hash']) + ); + if (!$x) { + notice(t('Location lookup failed.')); + return; + } + if (count($x) == 1) { + notice(t('Please select another location to become primary before removing the primary location.') . EOL); + return; + } + } + + $r = q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d and hubloc_hash = '%s'", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + Run::Summon(['Notifier', 'refresh_all', $channel['channel_id']]); + return; + } + } + } + + + public function get() + { + + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + $channel = App::get_channel(); + + if ($_REQUEST['sync']) { + Run::Summon(['Notifier', 'refresh_all', $channel['channel_id']]); + info(t('Pushing location info') . EOL); + goaway(z_root() . '/locs'); + } + + + $r = q("select * from hubloc where hubloc_hash = '%s'", + dbesc($channel['channel_hash']) + ); + + if (!$r) { + notice(t('No locations found.') . EOL); + return; + } + + $o = replace_macros(get_markup_template('locmanage.tpl'), [ + '$header' => t('Manage Channel Locations'), + '$loc' => t('Location'), + '$addr' => t('Address'), + '$mkprm' => t('Primary'), + '$drop' => t('Drop'), + '$submit' => t('Submit'), + '$sync' => t('Publish these settings'), + '$sync_text' => t('Please wait several minutes between consecutive operations.'), + '$drop_text' => t('When possible, drop a location by logging into that website/hub and removing your channel.'), + '$last_resort' => t('Use this form to drop the location if the hub is no longer operating.'), + '$hubs' => $r, + '$base_url' => z_root() + ]); + + return $o; + } - Run::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); - return; - } - } - - - if($_REQUEST['drop']) { - $hubloc_id = intval($_REQUEST['drop']); - - if($hubloc_id) { - $r = q("select * from hubloc where hubloc_id = %d and hubloc_url != '%s' and hubloc_hash = '%s' limit 1", - intval($hubloc_id), - dbesc(z_root()), - dbesc($channel['channel_hash']) - ); - - if(! $r) { - notice( t('Location not found.') . EOL); - return; - } - if(intval($r[0]['hubloc_primary'])) { - $x = q("select hubloc_id from hubloc where hubloc_primary = 1 and hubloc_hash = '%s'", - dbesc($channel['channel_hash']) - ); - if(! $x) { - notice( t('Location lookup failed.')); - return; - } - if(count($x) == 1) { - notice( t('Please select another location to become primary before removing the primary location.') . EOL); - return; - } - } - - $r = q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d and hubloc_hash = '%s'", - intval($hubloc_id), - dbesc($channel['channel_hash']) - ); - Run::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); - return; - } - } - } - - - - function get() { - - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - $channel = App::get_channel(); - - if($_REQUEST['sync']) { - Run::Summon( [ 'Notifier', 'refresh_all', $channel['channel_id'] ] ); - info( t('Pushing location info') . EOL); - goaway(z_root() . '/locs'); - } - - - $r = q("select * from hubloc where hubloc_hash = '%s'", - dbesc($channel['channel_hash']) - ); - - if(! $r) { - notice( t('No locations found.') . EOL); - return; - } - - $o = replace_macros(get_markup_template('locmanage.tpl'), [ - '$header' => t('Manage Channel Locations'), - '$loc' => t('Location'), - '$addr' => t('Address'), - '$mkprm' => t('Primary'), - '$drop' => t('Drop'), - '$submit' => t('Submit'), - '$sync' => t('Publish these settings'), - '$sync_text' => t('Please wait several minutes between consecutive operations.'), - '$drop_text' => t('When possible, drop a location by logging into that website/hub and removing your channel.'), - '$last_resort' => t('Use this form to drop the location if the hub is no longer operating.'), - '$hubs' => $r, - '$base_url' => z_root() - ] ); - - return $o; - } - } diff --git a/Zotlabs/Module/Login.php b/Zotlabs/Module/Login.php index 8220ca11f..84b2f7b2b 100644 --- a/Zotlabs/Module/Login.php +++ b/Zotlabs/Module/Login.php @@ -4,15 +4,17 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Login extends Controller { +class Login extends Controller +{ - function get() { - if(local_channel()) - goaway(z_root()); - if(remote_channel() && $_SESSION['atoken']) - goaway(z_root()); + public function get() + { + if (local_channel()) + goaway(z_root()); + if (remote_channel() && $_SESSION['atoken']) + goaway(z_root()); + + return login(true); + } - return login(true); - } - } diff --git a/Zotlabs/Module/Logout.php b/Zotlabs/Module/Logout.php index 5dc512aaa..0d22c0d92 100644 --- a/Zotlabs/Module/Logout.php +++ b/Zotlabs/Module/Logout.php @@ -5,16 +5,17 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Logout extends Controller { +class Logout extends Controller +{ - function init() { - if($_SESSION['delegate'] && $_SESSION['delegate_push']) { - $_SESSION = $_SESSION['delegate_push']; - } - else { - App::$session->nuke(); - } - goaway(z_root()); + public function init() + { + if ($_SESSION['delegate'] && $_SESSION['delegate_push']) { + $_SESSION = $_SESSION['delegate_push']; + } else { + App::$session->nuke(); + } + goaway(z_root()); - } + } } diff --git a/Zotlabs/Module/Lostpass.php b/Zotlabs/Module/Lostpass.php index 1708bead9..372a9a7a1 100644 --- a/Zotlabs/Module/Lostpass.php +++ b/Zotlabs/Module/Lostpass.php @@ -6,139 +6,141 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Lostpass extends Controller { +class Lostpass extends Controller +{ - function post() { - - $loginame = notags(trim($_POST['login-name'])); - if(! $loginame) - goaway(z_root()); - - $r = q("SELECT * FROM account WHERE account_email = '%s' LIMIT 1", - dbesc($loginame) - ); - - if(! $r) { - notice( t('No valid account found.') . EOL); - goaway(z_root()); - } - - $aid = $r[0]['account_id']; - $email = $r[0]['account_email']; - - $hash = random_string(); - - $r = q("UPDATE account SET account_reset = '%s' WHERE account_id = %d", - dbesc($hash), - intval($aid) - ); - if($r) - info( t('Password reset request issued. Check your email.') . EOL); - - $email_tpl = get_intltext_template("lostpass_eml.tpl"); - $message = replace_macros($email_tpl, array( - '$sitename' => get_config('system','sitename'), - '$siteurl' => z_root(), - '$username' => sprintf( t('Site Member (%s)'), $email), - '$email' => $email, - '$reset_link' => z_root() . '/lostpass?verify=' . $hash - )); - - $subject = email_header_encode(sprintf( t('Password reset requested at %s'),get_config('system','sitename')), 'UTF-8'); - - $res = z_mail( - [ - 'toEmail' => $email, - 'messageSubject' => sprintf( t('Password reset requested at %s'), get_config('system','sitename')), - 'textVersion' => $message, - ] - ); + public function post() + { - goaway(z_root()); - } - - - function get() { - - - if(x($_GET,'verify')) { - $verify = $_GET['verify']; - - $r = q("SELECT * FROM account WHERE account_reset = '%s' LIMIT 1", - dbesc($verify) - ); - if(! $r) { - notice( t("Request could not be verified. (You may have previously submitted it.) Password reset failed.") . EOL); - goaway(z_root()); - return; - } - - $aid = $r[0]['account_id']; - $email = $r[0]['account_email']; - - $new_password = autoname(6) . mt_rand(100,9999); - - $salt = random_string(32); - $password_encoded = hash('whirlpool', $salt . $new_password); - - $r = q("UPDATE account SET account_salt = '%s', account_password = '%s', account_reset = '', account_flags = (account_flags & ~%d) where account_id = %d", - dbesc($salt), - dbesc($password_encoded), - intval(ACCOUNT_UNVERIFIED), - intval($aid) - ); - - if($r) { - $tpl = get_markup_template('pwdreset.tpl'); - $o .= replace_macros($tpl,array( - '$lbl1' => t('Password Reset'), - '$lbl2' => t('Your password has been reset as requested.'), - '$lbl3' => t('Your new password is'), - '$lbl4' => t('Save or copy your new password - and then'), - '$lbl5' => '' . t('click here to login') . '.', - '$lbl6' => t('Your password may be changed from the Settings page after successful login.'), - '$newpass' => $new_password, - '$baseurl' => z_root() - - )); - - info("Your password has been reset." . EOL); - - $email_tpl = get_intltext_template("passchanged_eml.tpl"); - $message = replace_macros($email_tpl, array( - '$sitename' => App::$config['sitename'], - '$siteurl' => z_root(), - '$username' => sprintf( t('Site Member (%s)'), $email), - '$email' => $email, - '$new_password' => $new_password, - '$uid' => $newuid ) - ); - - $res = z_mail( - [ - 'toEmail' => $email, - 'messageSubject' => sprintf( t('Your password has changed at %s'), get_config('system','sitename')), - 'textVersion' => $message, - ] - ); + $loginame = notags(trim($_POST['login-name'])); + if (!$loginame) + goaway(z_root()); + + $r = q("SELECT * FROM account WHERE account_email = '%s' LIMIT 1", + dbesc($loginame) + ); + + if (!$r) { + notice(t('No valid account found.') . EOL); + goaway(z_root()); + } + + $aid = $r[0]['account_id']; + $email = $r[0]['account_email']; + + $hash = random_string(); + + $r = q("UPDATE account SET account_reset = '%s' WHERE account_id = %d", + dbesc($hash), + intval($aid) + ); + if ($r) + info(t('Password reset request issued. Check your email.') . EOL); + + $email_tpl = get_intltext_template("lostpass_eml.tpl"); + $message = replace_macros($email_tpl, array( + '$sitename' => get_config('system', 'sitename'), + '$siteurl' => z_root(), + '$username' => sprintf(t('Site Member (%s)'), $email), + '$email' => $email, + '$reset_link' => z_root() . '/lostpass?verify=' . $hash + )); + + $subject = email_header_encode(sprintf(t('Password reset requested at %s'), get_config('system', 'sitename')), 'UTF-8'); + + $res = z_mail( + [ + 'toEmail' => $email, + 'messageSubject' => sprintf(t('Password reset requested at %s'), get_config('system', 'sitename')), + 'textVersion' => $message, + ] + ); + + goaway(z_root()); + } + + + public function get() + { + + + if (x($_GET, 'verify')) { + $verify = $_GET['verify']; + + $r = q("SELECT * FROM account WHERE account_reset = '%s' LIMIT 1", + dbesc($verify) + ); + if (!$r) { + notice(t("Request could not be verified. (You may have previously submitted it.) Password reset failed.") . EOL); + goaway(z_root()); + return; + } + + $aid = $r[0]['account_id']; + $email = $r[0]['account_email']; + + $new_password = autoname(6) . mt_rand(100, 9999); + + $salt = random_string(32); + $password_encoded = hash('whirlpool', $salt . $new_password); + + $r = q("UPDATE account SET account_salt = '%s', account_password = '%s', account_reset = '', account_flags = (account_flags & ~%d) where account_id = %d", + dbesc($salt), + dbesc($password_encoded), + intval(ACCOUNT_UNVERIFIED), + intval($aid) + ); + + if ($r) { + $tpl = get_markup_template('pwdreset.tpl'); + $o .= replace_macros($tpl, array( + '$lbl1' => t('Password Reset'), + '$lbl2' => t('Your password has been reset as requested.'), + '$lbl3' => t('Your new password is'), + '$lbl4' => t('Save or copy your new password - and then'), + '$lbl5' => '' . t('click here to login') . '.', + '$lbl6' => t('Your password may be changed from the Settings page after successful login.'), + '$newpass' => $new_password, + '$baseurl' => z_root() + + )); + + info("Your password has been reset." . EOL); + + $email_tpl = get_intltext_template("passchanged_eml.tpl"); + $message = replace_macros($email_tpl, array( + '$sitename' => App::$config['sitename'], + '$siteurl' => z_root(), + '$username' => sprintf(t('Site Member (%s)'), $email), + '$email' => $email, + '$new_password' => $new_password, + '$uid' => $newuid) + ); + + $res = z_mail( + [ + 'toEmail' => $email, + 'messageSubject' => sprintf(t('Your password has changed at %s'), get_config('system', 'sitename')), + 'textVersion' => $message, + ] + ); + + return $o; + } + + } else { + $tpl = get_markup_template('lostpass.tpl'); + + $o .= replace_macros($tpl, array( + '$title' => t('Forgot your Password?'), + '$desc' => t('Enter your email address and submit to have your password reset. Then check your email for further instructions.'), + '$name' => t('Email Address'), + '$submit' => t('Reset') + )); + + return $o; + } + + } - return $o; - } - - } - else { - $tpl = get_markup_template('lostpass.tpl'); - - $o .= replace_macros($tpl,array( - '$title' => t('Forgot your Password?'), - '$desc' => t('Enter your email address and submit to have your password reset. Then check your email for further instructions.'), - '$name' => t('Email Address'), - '$submit' => t('Reset') - )); - - return $o; - } - - } - } diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php index 591109b9c..99d8a4ca7 100644 --- a/Zotlabs/Module/Magic.php +++ b/Zotlabs/Module/Magic.php @@ -9,127 +9,129 @@ use Zotlabs\Lib\Libzot; use Zotlabs\Lib\SConfig; -class Magic extends Controller { +class Magic extends Controller +{ - function init() { - - $ret = [ - 'success' => false, - 'url' => '', - 'message' => '' - ]; - - logger('mod_magic: invoked', LOGGER_DEBUG); - - logger('args: ' . print_r($_REQUEST,true),LOGGER_DATA); - - $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : ''); - $bdest = ((x($_REQUEST,'bdest')) ? $_REQUEST['bdest'] : ''); - $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : ''); - $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0); - $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0); - $delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : ''); + public function init() + { - // bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing - - if ($bdest) { - $dest = hex2bin($bdest); - } - - $parsed = parse_url($dest); + $ret = [ + 'success' => false, + 'url' => '', + 'message' => '' + ]; - if (! $parsed) { - goaway($dest); - } - - $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); - $owapath = SConfig::get($basepath,'system','openwebauth', $basepath . '/owa'); - - // This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating. - // By default, we'll proceed without asking. - - $arr = [ - 'channel_id' => local_channel(), - 'destination' => $dest, - 'proceed' => true - ]; - - call_hooks('magic_auth',$arr); - $dest = $arr['destination']; - if (! $arr['proceed']) { - goaway($dest); - } - - if((get_observer_hash()) && (stripos($dest,z_root()) === 0)) { + logger('mod_magic: invoked', LOGGER_DEBUG); - // We are already authenticated on this site and a registered observer. - // First check if this is a delegate request on the local system and process accordingly. - // Otherwise redirect. - - if ($delegate) { + logger('args: ' . print_r($_REQUEST, true), LOGGER_DATA); - $r = q("select * from channel left join hubloc on channel_hash = hubloc_hash where hubloc_addr = '%s' limit 1", - dbesc($delegate) - ); - - if ($r) { - $c = array_shift($r); - if (perm_is_allowed($c['channel_id'],get_observer_hash(),'delegate')) { - $tmp = $_SESSION; - $_SESSION['delegate_push'] = $tmp; - $_SESSION['delegate_channel'] = $c['channel_id']; - $_SESSION['delegate'] = get_observer_hash(); - $_SESSION['account_id'] = intval($c['channel_account_id']); + $addr = ((x($_REQUEST, 'addr')) ? $_REQUEST['addr'] : ''); + $bdest = ((x($_REQUEST, 'bdest')) ? $_REQUEST['bdest'] : ''); + $dest = ((x($_REQUEST, 'dest')) ? $_REQUEST['dest'] : ''); + $rev = ((x($_REQUEST, 'rev')) ? intval($_REQUEST['rev']) : 0); + $owa = ((x($_REQUEST, 'owa')) ? intval($_REQUEST['owa']) : 0); + $delegate = ((x($_REQUEST, 'delegate')) ? $_REQUEST['delegate'] : ''); - change_channel($c['channel_id']); - } - } - } - - goaway($dest); - } - - if (local_channel()) { - $channel = App::get_channel(); - - // OpenWebAuth + // bdest is preferred as it is hex-encoded and can survive url rewrite and argument parsing - if ($owa) { + if ($bdest) { + $dest = hex2bin($bdest); + } - $dest = strip_zids($dest); - $dest = strip_query_param($dest,'f'); + $parsed = parse_url($dest); - // We now post to the OWA endpoint. This improves security by providing a signed digest - - $data = json_encode([ 'OpenWebAuth' => random_string() ]); - - $headers = []; - $headers['Accept'] = 'application/x-zot+json' ; - $headers['Content-Type'] = 'application/x-zot+json' ; - $headers['X-Open-Web-Auth'] = random_string(); - $headers['Digest'] = HTTPSig::generate_digest_header($data); - $headers['Host'] = $parsed['host']; - $headers['(request-target)'] = 'post ' . '/owa'; + if (!$parsed) { + goaway($dest); + } - $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); - $x = z_post_url($owapath,$data,$redirects,[ 'headers' => $headers ]); - logger('owa fetch returned: ' . print_r($x,true),LOGGER_DATA); - if ($x['success']) { - $j = json_decode($x['body'],true); - if ($j['success'] && $j['encrypted_token']) { - // decrypt the token using our private key - $token = ''; - openssl_private_decrypt(base64url_decode($j['encrypted_token']),$token,$channel['channel_prvkey']); - $x = strpbrk($dest,'?&'); - // redirect using the encrypted token which will be exchanged for an authenticated session - $args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : ''); - goaway($dest . $args); - } - } - } - } + $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); + $owapath = SConfig::get($basepath, 'system', 'openwebauth', $basepath . '/owa'); + + // This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating. + // By default, we'll proceed without asking. + + $arr = [ + 'channel_id' => local_channel(), + 'destination' => $dest, + 'proceed' => true + ]; + + call_hooks('magic_auth', $arr); + $dest = $arr['destination']; + if (!$arr['proceed']) { + goaway($dest); + } + + if ((get_observer_hash()) && (stripos($dest, z_root()) === 0)) { + + // We are already authenticated on this site and a registered observer. + // First check if this is a delegate request on the local system and process accordingly. + // Otherwise redirect. + + if ($delegate) { + + $r = q("select * from channel left join hubloc on channel_hash = hubloc_hash where hubloc_addr = '%s' limit 1", + dbesc($delegate) + ); + + if ($r) { + $c = array_shift($r); + if (perm_is_allowed($c['channel_id'], get_observer_hash(), 'delegate')) { + $tmp = $_SESSION; + $_SESSION['delegate_push'] = $tmp; + $_SESSION['delegate_channel'] = $c['channel_id']; + $_SESSION['delegate'] = get_observer_hash(); + $_SESSION['account_id'] = intval($c['channel_account_id']); + + change_channel($c['channel_id']); + } + } + } + + goaway($dest); + } + + if (local_channel()) { + $channel = App::get_channel(); + + // OpenWebAuth + + if ($owa) { + + $dest = strip_zids($dest); + $dest = strip_query_param($dest, 'f'); + + // We now post to the OWA endpoint. This improves security by providing a signed digest + + $data = json_encode(['OpenWebAuth' => random_string()]); + + $headers = []; + $headers['Accept'] = 'application/x-zot+json'; + $headers['Content-Type'] = 'application/x-zot+json'; + $headers['X-Open-Web-Auth'] = random_string(); + $headers['Digest'] = HTTPSig::generate_digest_header($data); + $headers['Host'] = $parsed['host']; + $headers['(request-target)'] = 'post ' . '/owa'; + + $headers = HTTPSig::create_sig($headers, $channel['channel_prvkey'], channel_url($channel), true, 'sha512'); + $x = z_post_url($owapath, $data, $redirects, ['headers' => $headers]); + logger('owa fetch returned: ' . print_r($x, true), LOGGER_DATA); + if ($x['success']) { + $j = json_decode($x['body'], true); + if ($j['success'] && $j['encrypted_token']) { + // decrypt the token using our private key + $token = ''; + openssl_private_decrypt(base64url_decode($j['encrypted_token']), $token, $channel['channel_prvkey']); + $x = strpbrk($dest, '?&'); + // redirect using the encrypted token which will be exchanged for an authenticated session + $args = (($x) ? '&owt=' . $token : '?f=&owt=' . $token) . (($delegate) ? '&delegate=1' : ''); + goaway($dest . $args); + } + } + } + } + + goaway($dest); + } - goaway($dest); - } - } diff --git a/Zotlabs/Module/Manage.php b/Zotlabs/Module/Manage.php index abc57f73e..f866edb13 100644 --- a/Zotlabs/Module/Manage.php +++ b/Zotlabs/Module/Manage.php @@ -7,195 +7,190 @@ use Zotlabs\Lib\PConfig; require_once('include/security.php'); -class Manage extends Controller { +class Manage extends Controller +{ - function get() { - - if ((! get_account_id()) || ($_SESSION['delegate'])) { - notice( t('Permission denied.') . EOL); - return; - } + public function get() + { - nav_set_selected('Manage'); - - - $change_channel = ((argc() > 1) ? intval(argv(1)) : 0); - - if (argc() > 2) { - if (argv(2) === 'default') { - $r = q("select channel_id from channel where channel_id = %d and channel_account_id = %d limit 1", - intval($change_channel), - intval(get_account_id()) - ); - if ($r) { - q("update account set account_default_channel = %d where account_id = %d", - intval($change_channel), - intval(get_account_id()) - ); - } - goaway(z_root() . '/manage'); - } - elseif (argv(2) === 'menu') { - $state = intval(PConfig::get($change_channel,'system','include_in_menu', 0)); - PConfig::set($change_channel,'system','include_in_menu',1 - $state); - goaway(z_root() . '/manage'); - } - - } + if ((!get_account_id()) || ($_SESSION['delegate'])) { + notice(t('Permission denied.') . EOL); + return; + } - - if ($change_channel) { + nav_set_selected('Manage'); - $r = change_channel($change_channel); - if ((argc() > 2) && !(argv(2) === 'default')) { - goaway(z_root() . '/' . implode('/',array_slice(App::$argv,2))); // Go to whatever is after /manage/, but with the new channel - } - elseif ($r && $r['channel_startpage']) { - goaway(z_root() . '/' . $r['channel_startpage']); // If nothing extra is specified, go to the default page - } - goaway(z_root()); - } - - $channels = null; - - $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ", - intval(get_account_id()) - ); - - $account = App::get_account(); - - if ($r && count($r)) { + $change_channel = ((argc() > 1) ? intval(argv(1)) : 0); - $channels = ((is_site_admin()) ? array_merge ([ get_sys_channel() ], $r) : $r); - for ($x = 0; $x < count($channels); $x ++) { - $channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']); - $channels[$x]['include_in_menu'] = intval(PConfig::get($channels[$x]['channel_id'],'system','include_in_menu',0)); - $channels[$x]['default'] = (($channels[$x]['channel_id'] == $account['account_default_channel']) ? "1" : ''); - $channels[$x]['default_links'] = '1'; - $channels[$x]['collections_label'] = t('Collection'); - $channels[$x]['forum_label'] = t('Group'); - - $c = q("SELECT id, item_wall FROM item + if (argc() > 2) { + if (argv(2) === 'default') { + $r = q("select channel_id from channel where channel_id = %d and channel_account_id = %d limit 1", + intval($change_channel), + intval(get_account_id()) + ); + if ($r) { + q("update account set account_default_channel = %d where account_id = %d", + intval($change_channel), + intval(get_account_id()) + ); + } + goaway(z_root() . '/manage'); + } elseif (argv(2) === 'menu') { + $state = intval(PConfig::get($change_channel, 'system', 'include_in_menu', 0)); + PConfig::set($change_channel, 'system', 'include_in_menu', 1 - $state); + goaway(z_root() . '/manage'); + } + + } + + + if ($change_channel) { + + $r = change_channel($change_channel); + + if ((argc() > 2) && !(argv(2) === 'default')) { + goaway(z_root() . '/' . implode('/', array_slice(App::$argv, 2))); // Go to whatever is after /manage/, but with the new channel + } elseif ($r && $r['channel_startpage']) { + goaway(z_root() . '/' . $r['channel_startpage']); // If nothing extra is specified, go to the default page + } + goaway(z_root()); + } + + $channels = null; + + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ", + intval(get_account_id()) + ); + + $account = App::get_account(); + + if ($r && count($r)) { + + $channels = ((is_site_admin()) ? array_merge([get_sys_channel()], $r) : $r); + for ($x = 0; $x < count($channels); $x++) { + $channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']); + $channels[$x]['include_in_menu'] = intval(PConfig::get($channels[$x]['channel_id'], 'system', 'include_in_menu', 0)); + $channels[$x]['default'] = (($channels[$x]['channel_id'] == $account['account_default_channel']) ? "1" : ''); + $channels[$x]['default_links'] = '1'; + $channels[$x]['collections_label'] = t('Collection'); + $channels[$x]['forum_label'] = t('Group'); + + $c = q("SELECT id, item_wall FROM item WHERE item_unseen = 1 and uid = %d " . item_normal(), - intval($channels[$x]['channel_id']) - ); - - if ($c) { - foreach ($c as $it) { - if (intval($it['item_wall'])) { - $channels[$x]['home'] ++; - } - else { - $channels[$x]['network'] ++; - } - } - } - - - $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", - intval($channels[$x]['channel_id']) - ); - - if ($intr) { - $channels[$x]['intros'] = intval($intr[0]['total']); - } - - $events = q("SELECT etype, dtstart, adjust FROM event + intval($channels[$x]['channel_id']) + ); + + if ($c) { + foreach ($c as $it) { + if (intval($it['item_wall'])) { + $channels[$x]['home']++; + } else { + $channels[$x]['network']++; + } + } + } + + + $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", + intval($channels[$x]['channel_id']) + ); + + if ($intr) { + $channels[$x]['intros'] = intval($intr[0]['total']); + } + + $events = q("SELECT etype, dtstart, adjust FROM event WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0 ORDER BY dtstart ASC ", - intval($channels[$x]['channel_id']), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) - ); - - if ($events) { - $channels[$x]['all_events'] = count($events); + intval($channels[$x]['channel_id']), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); - if ($channels[$x]['all_events']) { - $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); - foreach ($events as $e) { - $bd = false; - if ($e['etype'] === 'birthday') { - $channels[$x]['birthdays'] ++; - $bd = true; - } - else { - $channels[$x]['events'] ++; - } - if (datetime_convert('UTC', ((intval($e['adjust'])) ? date_default_timezone_get() : 'UTC'), $e['dtstart'], 'Y-m-d') === $str_now) { - $channels[$x]['all_events_today'] ++; - if ($bd) { - $channels[$x]['birthdays_today'] ++; - } - else { - $channels[$x]['events_today'] ++; - } - } - } - } - } - } + if ($events) { + $channels[$x]['all_events'] = count($events); - } - - $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0", - intval(get_account_id()) - ); - $limit = account_service_class_fetch(get_account_id(),'total_identities'); - if ($limit !== false) { - $channel_usage_message = sprintf( t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit); - } - else { - $channel_usage_message = ''; - } - - - $create = [ 'new_channel', t('Create a new channel'), t('Create New') ]; - - $delegates = null; + if ($channels[$x]['all_events']) { + $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); + foreach ($events as $e) { + $bd = false; + if ($e['etype'] === 'birthday') { + $channels[$x]['birthdays']++; + $bd = true; + } else { + $channels[$x]['events']++; + } + if (datetime_convert('UTC', ((intval($e['adjust'])) ? date_default_timezone_get() : 'UTC'), $e['dtstart'], 'Y-m-d') === $str_now) { + $channels[$x]['all_events_today']++; + if ($bd) { + $channels[$x]['birthdays_today']++; + } else { + $channels[$x]['events_today']++; + } + } + } + } + } + } - if (local_channel()) { - $delegates = q("select * from abook left join xchan on abook_xchan = xchan_hash where + } + + $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0", + intval(get_account_id()) + ); + $limit = account_service_class_fetch(get_account_id(), 'total_identities'); + if ($limit !== false) { + $channel_usage_message = sprintf(t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit); + } else { + $channel_usage_message = ''; + } + + + $create = ['new_channel', t('Create a new channel'), t('Create New')]; + + $delegates = null; + + if (local_channel()) { + $delegates = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_xchan in ( select xchan from abconfig where chan = %d and cat = 'system' and k = 'their_perms' and v like '%s' )", - intval(local_channel()), - intval(local_channel()), - dbesc('%delegate%') - ); - } - - if ($delegates) { - for ($x = 0; $x < count($delegates); $x ++) { - $delegates[$x]['link'] = 'magic?f=&bdest=' . bin2hex($delegates[$x]['xchan_url']) - . '&delegate=' . urlencode($delegates[$x]['xchan_addr']); - $delegates[$x]['channel_name'] = $delegates[$x]['xchan_name']; - $delegates[$x]['delegate'] = 1; - $delegates[$x]['collections_label'] = t('Collection'); - $delegates[$x]['forum_label'] = t('Group'); + intval(local_channel()), + intval(local_channel()), + dbesc('%delegate%') + ); + } + + if ($delegates) { + for ($x = 0; $x < count($delegates); $x++) { + $delegates[$x]['link'] = 'magic?f=&bdest=' . bin2hex($delegates[$x]['xchan_url']) + . '&delegate=' . urlencode($delegates[$x]['xchan_addr']); + $delegates[$x]['channel_name'] = $delegates[$x]['xchan_name']; + $delegates[$x]['delegate'] = 1; + $delegates[$x]['collections_label'] = t('Collection'); + $delegates[$x]['forum_label'] = t('Group'); + + } + } else { + $delegates = null; + } + + return replace_macros(get_markup_template('channels.tpl'), [ + '$header' => t('Channels'), + '$msg_selected' => t('Current Channel'), + '$selected' => local_channel(), + '$desc' => t('Switch to one of your channels by selecting it.'), + '$msg_default' => t('Default Login Channel'), + '$msg_make_default' => t('Make Default'), + '$msg_include' => t('Add to menu'), + '$msg_no_include' => t('Add to menu'), + '$create' => $create, + '$all_channels' => $channels, + '$mail_format' => t('%d new messages'), + '$intros_format' => t('%d new introductions'), + '$channel_usage_message' => $channel_usage_message, + '$delegated_desc' => t('Delegated Channel'), + '$delegates' => $delegates + ]); + } - } - } - else { - $delegates = null; - } - - return replace_macros(get_markup_template('channels.tpl'), [ - '$header' => t('Channels'), - '$msg_selected' => t('Current Channel'), - '$selected' => local_channel(), - '$desc' => t('Switch to one of your channels by selecting it.'), - '$msg_default' => t('Default Login Channel'), - '$msg_make_default' => t('Make Default'), - '$msg_include' => t('Add to menu'), - '$msg_no_include' => t('Add to menu'), - '$create' => $create, - '$all_channels' => $channels, - '$mail_format' => t('%d new messages'), - '$intros_format' => t('%d new introductions'), - '$channel_usage_message' => $channel_usage_message, - '$delegated_desc' => t('Delegated Channel'), - '$delegates' => $delegates - ]); - } - } diff --git a/Zotlabs/Module/Manifest.php b/Zotlabs/Module/Manifest.php index 778539748..67e271be1 100644 --- a/Zotlabs/Module/Manifest.php +++ b/Zotlabs/Module/Manifest.php @@ -6,55 +6,47 @@ use Zotlabs\Web\Controller; use Zotlabs\Lib\System; -class Manifest extends Controller { - - function init() { - $ret = [ - 'name' => System::get_platform_name(), - 'short_name' => System::get_platform_name(), - 'icons' => [ - [ 'src' => '/images/' . System::get_platform_name() . '-64' . '.png', 'sizes' => '64x64' ], - [ 'src' => '/images/' . System::get_platform_name() . '-192' . '.png', 'sizes' => '192x192' ], - [ 'src' => '/images/' . System::get_platform_name() . '-512' . '.png', 'sizes' => '512x512' ], - [ 'src' => '/images/' . System::get_platform_name() . '.svg', 'sizes' => '600x600' ], - ], - 'scope' => '/', - 'start_url' => z_root(), - 'display' => 'fullscreen', - 'orientation' => 'any', - 'theme_color' => 'blue', - 'background_color' => 'white', - 'share_target' => [ - 'action' => '/rpost', - 'method' => 'POST', - 'enctype' => 'multipart/form-data', - 'params' => [ - 'title' => 'title', - 'text' => 'body', - 'url' => 'url', - 'files' => [ - [ 'name' => 'userfile', - 'accept' => [ 'image/*', 'audio/*', 'video/*', 'text/*', 'application/*' ] - ] - ] - ] - ] - - ]; - - - json_return_and_die($ret,'application/manifest+json'); - } - - - - - - +class Manifest extends Controller +{ + public function init() + { + $ret = [ + 'name' => System::get_platform_name(), + 'short_name' => System::get_platform_name(), + 'icons' => [ + ['src' => '/images/' . System::get_platform_name() . '-64' . '.png', 'sizes' => '64x64'], + ['src' => '/images/' . System::get_platform_name() . '-192' . '.png', 'sizes' => '192x192'], + ['src' => '/images/' . System::get_platform_name() . '-512' . '.png', 'sizes' => '512x512'], + ['src' => '/images/' . System::get_platform_name() . '.svg', 'sizes' => '600x600'], + ], + 'scope' => '/', + 'start_url' => z_root(), + 'display' => 'fullscreen', + 'orientation' => 'any', + 'theme_color' => 'blue', + 'background_color' => 'white', + 'share_target' => [ + 'action' => '/rpost', + 'method' => 'POST', + 'enctype' => 'multipart/form-data', + 'params' => [ + 'title' => 'title', + 'text' => 'body', + 'url' => 'url', + 'files' => [ + ['name' => 'userfile', + 'accept' => ['image/*', 'audio/*', 'video/*', 'text/*', 'application/*'] + ] + ] + ] + ] + ]; + json_return_and_die($ret, 'application/manifest+json'); + } } diff --git a/Zotlabs/Module/Markup.php b/Zotlabs/Module/Markup.php index 1f43697f1..98301fccd 100644 --- a/Zotlabs/Module/Markup.php +++ b/Zotlabs/Module/Markup.php @@ -6,17 +6,19 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Markup extends Controller { +class Markup extends Controller +{ - function get() { + public function get() + { $desc = t('This app adds editor buttons for bold, italic, underline, quote, and possibly other common richtext constructs.'); $text = ''; - return $text; + return $text; - } + } } diff --git a/Zotlabs/Module/Menu.php b/Zotlabs/Module/Menu.php index a492c5d38..d810d1c8d 100644 --- a/Zotlabs/Module/Menu.php +++ b/Zotlabs/Module/Menu.php @@ -8,234 +8,231 @@ use Zotlabs\Lib\Libprofile; require_once('include/menu.php'); -class Menu extends Controller { +class Menu extends Controller +{ - function init() { + public function init() + { - if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - App::$is_sys = true; - } - } + if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + App::$is_sys = true; + } + } - if(argc() > 1) - $which = argv(1); - else - return; + if (argc() > 1) + $which = argv(1); + else + return; - Libprofile::load($which); + Libprofile::load($which); - } - - - function post() { - - if(! App::$profile) { - return; - } - - $which = argv(1); + } - $uid = App::$profile['channel_id']; - - if(array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) { - $sys = get_sys_channel(); - $uid = intval($sys['channel_id']); - App::$is_sys = true; - } - - if(! $uid) - return; - - $_REQUEST['menu_channel_id'] = $uid; - - if($_REQUEST['menu_bookmark']) - $_REQUEST['menu_flags'] |= MENU_BOOKMARK; - if($_REQUEST['menu_system']) - $_REQUEST['menu_flags'] |= MENU_SYSTEM; - - $menu_id = ((argc() > 1) ? intval(argv(1)) : 0); - if($menu_id) { - $_REQUEST['menu_id'] = intval(argv(1)); - $r = menu_edit($_REQUEST); - if($r) { - menu_sync_packet($uid,get_observer_hash(),$menu_id); - //info( t('Menu updated.') . EOL); - goaway(z_root() . '/mitem/' . $which . '/' . $menu_id . ((App::$is_sys) ? '?f=&sys=1' : '')); - } - else - notice( t('Unable to update menu.'). EOL); - } - else { - $r = menu_create($_REQUEST); - if($r) { - menu_sync_packet($uid,get_observer_hash(),$r); - - //info( t('Menu created.') . EOL); - goaway(z_root() . '/mitem/' . $which . '/' . $r . ((App::$is_sys) ? '?f=&sys=1' : '')); - } - else - notice( t('Unable to create menu.'). EOL); - - } - } - - - - - function get() { - + public function post() + { + + if (!App::$profile) { + return; + } + + $which = argv(1); - if(! App::$profile) { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } + $uid = App::$profile['channel_id']; - $which = argv(1); + if (array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) { + $sys = get_sys_channel(); + $uid = intval($sys['channel_id']); + App::$is_sys = true; + } - $_SESSION['return_url'] = App::$query_string; + if (!$uid) + return; - $uid = local_channel(); - $owner = 0; - $channel = null; - $observer = App::get_observer(); + $_REQUEST['menu_channel_id'] = $uid; - $channel = App::get_channel(); + if ($_REQUEST['menu_bookmark']) + $_REQUEST['menu_flags'] |= MENU_BOOKMARK; + if ($_REQUEST['menu_system']) + $_REQUEST['menu_flags'] |= MENU_SYSTEM; - if(App::$is_sys && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - $uid = $owner = intval($sys['channel_id']); - $channel = $sys; - $observer = $sys; - } - } + $menu_id = ((argc() > 1) ? intval(argv(1)) : 0); + if ($menu_id) { + $_REQUEST['menu_id'] = intval(argv(1)); + $r = menu_edit($_REQUEST); + if ($r) { + menu_sync_packet($uid, get_observer_hash(), $menu_id); + //info( t('Menu updated.') . EOL); + goaway(z_root() . '/mitem/' . $which . '/' . $menu_id . ((App::$is_sys) ? '?f=&sys=1' : '')); + } else + notice(t('Unable to update menu.') . EOL); + } else { + $r = menu_create($_REQUEST); + if ($r) { + menu_sync_packet($uid, get_observer_hash(), $r); - if(! $owner) { - // Figure out who the page owner is. - $r = channelx_by_nick($which); - if($r) { - $owner = intval($r['channel_id']); - } - } + //info( t('Menu created.') . EOL); + goaway(z_root() . '/mitem/' . $which . '/' . $r . ((App::$is_sys) ? '?f=&sys=1' : '')); + } else + notice(t('Unable to create menu.') . EOL); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + } + } - $perms = get_all_perms($owner,$ob_hash); - if(! $perms['write_pages']) { - notice( t('Permission denied.') . EOL); - return; - } + public function get() + { - // Get the observer, check their permissions - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + if (!App::$profile) { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } - $perms = get_all_perms($owner,$ob_hash); + $which = argv(1); - if(! $perms['write_pages']) { - notice( t('Permission denied.') . EOL); - return; - } + $_SESSION['return_url'] = App::$query_string; + + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = App::get_observer(); + + $channel = App::get_channel(); + + if (App::$is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } + + if (!$owner) { + // Figure out who the page owner is. + $r = channelx_by_nick($which); + if ($r) { + $owner = intval($r['channel_id']); + } + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner, $ob_hash); + + if (!$perms['write_pages']) { + notice(t('Permission denied.') . EOL); + return; + } + + // Get the observer, check their permissions + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner, $ob_hash); + + if (!$perms['write_pages']) { + notice(t('Permission denied.') . EOL); + return; + } + + if (argc() == 2) { + + $channel = (($sys) ? $sys : channelx_by_n($owner)); + + // list menus + $x = menu_list($owner); + if ($x) { + for ($y = 0; $y < count($x); $y++) { + $m = menu_fetch($x[$y]['menu_name'], $owner, get_observer_hash()); + if ($m) + $x[$y]['element'] = '[element]' . base64url_encode(json_encode(menu_element($channel, $m))) . '[/element]'; + $x[$y]['bookmark'] = (($x[$y]['menu_flags'] & MENU_BOOKMARK) ? true : false); + } + } + + $create = replace_macros(get_markup_template('menuedit.tpl'), array( + '$menu_name' => array('menu_name', t('Menu Name'), '', t('Unique name (not visible on webpage) - required'), '*'), + '$menu_desc' => array('menu_desc', t('Menu Title'), '', t('Visible on webpage - leave empty for no title'), ''), + '$menu_bookmark' => array('menu_bookmark', t('Allow Bookmarks'), 0, t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), + '$submit' => t('Submit and proceed'), + '$sys' => App::$is_sys, + '$nick' => $which, + '$display' => 'none' + )); + + $o = replace_macros(get_markup_template('menulist.tpl'), array( + '$title' => t('Menus'), + '$create' => $create, + '$menus' => $x, + '$nametitle' => t('Menu Name'), + '$desctitle' => t('Menu Title'), + '$edit' => t('Edit'), + '$drop' => t('Drop'), + '$created' => t('Created'), + '$edited' => t('Edited'), + '$new' => t('New'), + '$bmark' => t('Bookmarks allowed'), + '$hintnew' => t('Create'), + '$hintdrop' => t('Delete this menu'), + '$hintcontent' => t('Edit menu contents'), + '$hintedit' => t('Edit this menu'), + '$nick' => $which, + '$sys' => App::$is_sys + )); + + return $o; + + } + + if (argc() > 2) { + if (intval(argv(2))) { + + if (argc() == 4 && argv(3) == 'drop') { + menu_sync_packet($owner, get_observer_hash(), intval(argv(1)), true); + $r = menu_delete_id(intval(argv(2)), $owner); + if (!$r) + notice(t('Menu could not be deleted.') . EOL); + + goaway(z_root() . '/menu/' . $which . ((App::$is_sys) ? '?f=&sys=1' : '')); + } + + $m = menu_fetch_id(intval(argv(2)), $owner); + + if (!$m) { + notice(t('Menu not found.') . EOL); + return ''; + } + + $o = replace_macros(get_markup_template('menuedit.tpl'), array( + '$header' => t('Edit Menu'), + '$sys' => App::$is_sys, + '$menu_id' => intval(argv(2)), + '$menu_edit_link' => 'mitem/' . $which . '/' . intval(argv(1)) . ((App::$is_sys) ? '?f=&sys=1' : ''), + '$hintedit' => t('Add or remove entries to this menu'), + '$editcontents' => t('Edit menu contents'), + '$menu_name' => array('menu_name', t('Menu name'), $m['menu_name'], t('Must be unique, only seen by you'), '*'), + '$menu_desc' => array('menu_desc', t('Menu title'), $m['menu_desc'], t('Menu title as seen by others'), ''), + '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), (($m['menu_flags'] & MENU_BOOKMARK) ? 1 : 0), t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), + '$menu_system' => (($m['menu_flags'] & MENU_SYSTEM) ? 1 : 0), + '$nick' => $which, + '$submit' => t('Submit and proceed') + )); + + return $o; + + } else { + notice(t('Not found.') . EOL); + return; + } + } + + } - if(argc() == 2) { - - $channel = (($sys) ? $sys : channelx_by_n($owner)); - - // list menus - $x = menu_list($owner); - if($x) { - for($y = 0; $y < count($x); $y ++) { - $m = menu_fetch($x[$y]['menu_name'],$owner,get_observer_hash()); - if($m) - $x[$y]['element'] = '[element]' . base64url_encode(json_encode(menu_element($channel,$m))) . '[/element]'; - $x[$y]['bookmark'] = (($x[$y]['menu_flags'] & MENU_BOOKMARK) ? true : false); - } - } - - $create = replace_macros(get_markup_template('menuedit.tpl'), array( - '$menu_name' => array('menu_name', t('Menu Name'), '', t('Unique name (not visible on webpage) - required'), '*'), - '$menu_desc' => array('menu_desc', t('Menu Title'), '', t('Visible on webpage - leave empty for no title'), ''), - '$menu_bookmark' => array('menu_bookmark', t('Allow Bookmarks'), 0 , t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), - '$submit' => t('Submit and proceed'), - '$sys' => App::$is_sys, - '$nick' => $which, - '$display' => 'none' - )); - - $o = replace_macros(get_markup_template('menulist.tpl'),array( - '$title' => t('Menus'), - '$create' => $create, - '$menus' => $x, - '$nametitle' => t('Menu Name'), - '$desctitle' => t('Menu Title'), - '$edit' => t('Edit'), - '$drop' => t('Drop'), - '$created' => t('Created'), - '$edited' => t('Edited'), - '$new' => t('New'), - '$bmark' => t('Bookmarks allowed'), - '$hintnew' => t('Create'), - '$hintdrop' => t('Delete this menu'), - '$hintcontent' => t('Edit menu contents'), - '$hintedit' => t('Edit this menu'), - '$nick' => $which, - '$sys' => App::$is_sys - )); - - return $o; - - } - - if(argc() > 2) { - if(intval(argv(2))) { - - if(argc() == 4 && argv(3) == 'drop') { - menu_sync_packet($owner,get_observer_hash(),intval(argv(1)),true); - $r = menu_delete_id(intval(argv(2)),$owner); - if(!$r) - notice( t('Menu could not be deleted.'). EOL); - - goaway(z_root() . '/menu/' . $which . ((App::$is_sys) ? '?f=&sys=1' : '')); - } - - $m = menu_fetch_id(intval(argv(2)),$owner); - - if(! $m) { - notice( t('Menu not found.') . EOL); - return ''; - } - - $o = replace_macros(get_markup_template('menuedit.tpl'), array( - '$header' => t('Edit Menu'), - '$sys' => App::$is_sys, - '$menu_id' => intval(argv(2)), - '$menu_edit_link' => 'mitem/' . $which . '/' . intval(argv(1)) . ((App::$is_sys) ? '?f=&sys=1' : ''), - '$hintedit' => t('Add or remove entries to this menu'), - '$editcontents' => t('Edit menu contents'), - '$menu_name' => array('menu_name', t('Menu name'), $m['menu_name'], t('Must be unique, only seen by you'), '*'), - '$menu_desc' => array('menu_desc', t('Menu title'), $m['menu_desc'], t('Menu title as seen by others'), ''), - '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), (($m['menu_flags'] & MENU_BOOKMARK) ? 1 : 0), t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), - '$menu_system' => (($m['menu_flags'] & MENU_SYSTEM) ? 1 : 0), - '$nick' => $which, - '$submit' => t('Submit and proceed') - )); - - return $o; - - } - else { - notice( t('Not found.') . EOL); - return; - } - } - - } - } diff --git a/Zotlabs/Module/Mitem.php b/Zotlabs/Module/Mitem.php index 7d0204817..a9a34a160 100644 --- a/Zotlabs/Module/Mitem.php +++ b/Zotlabs/Module/Mitem.php @@ -10,266 +10,266 @@ require_once('include/menu.php'); require_once('include/acl_selectors.php'); -class Mitem extends Controller { +class Mitem extends Controller +{ - function init() { + public function init() + { - if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - App::$is_sys = true; - } - } + if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + App::$is_sys = true; + } + } - if(argc() > 1) - $which = argv(1); - else - return; + if (argc() > 1) + $which = argv(1); + else + return; - Libprofile::load($which); - - if(argc() < 3) - return; - - $m = menu_fetch_id(intval(argv(2)), App::$profile['channel_id']); - if(! $m) { - notice( t('Menu not found.') . EOL); - return ''; - } - App::$data['menu'] = $m; - - } - - function post() { - - if(! App::$profile) { - return; - } + Libprofile::load($which); - $which = argv(1); + if (argc() < 3) + return; + + $m = menu_fetch_id(intval(argv(2)), App::$profile['channel_id']); + if (!$m) { + notice(t('Menu not found.') . EOL); + return ''; + } + App::$data['menu'] = $m; + + } + + public function post() + { + + if (!App::$profile) { + return; + } + + $which = argv(1); - $uid = App::$profile['channel_id']; - - if(array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) { - $sys = get_sys_channel(); - $uid = intval($sys['channel_id']); - App::$is_sys = true; - } - - if(! $uid) - return; + $uid = App::$profile['channel_id']; + + if (array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) { + $sys = get_sys_channel(); + $uid = intval($sys['channel_id']); + App::$is_sys = true; + } + + if (!$uid) + return; - if(! App::$data['menu']) - return; - - if(!$_REQUEST['mitem_desc'] || !$_REQUEST['mitem_link']) { - notice( t('Unable to create element.') . EOL); - return; - } - - $_REQUEST['mitem_channel_id'] = $uid; - $_REQUEST['menu_id'] = App::$data['menu']['menu_id']; - - $_REQUEST['mitem_flags'] = 0; - if($_REQUEST['usezid']) - $_REQUEST['mitem_flags'] |= MENU_ITEM_ZID; - if($_REQUEST['newwin']) - $_REQUEST['mitem_flags'] |= MENU_ITEM_NEWWIN; - - - $mitem_id = ((argc() > 3) ? intval(argv(3)) : 0); - if($mitem_id) { - $_REQUEST['mitem_id'] = $mitem_id; - $r = menu_edit_item($_REQUEST['menu_id'],$uid,$_REQUEST); - if($r) { - menu_sync_packet($uid,get_observer_hash(),$_REQUEST['menu_id']); - //info( t('Menu element updated.') . EOL); - goaway(z_root() . '/mitem/' . $which . '/' . $_REQUEST['menu_id'] . ((App::$is_sys) ? '?f=&sys=1' : '')); - } - else - notice( t('Unable to update menu element.') . EOL); - - } - else { - $r = menu_add_item($_REQUEST['menu_id'],$uid,$_REQUEST); - if($r) { - menu_sync_packet($uid,get_observer_hash(),$_REQUEST['menu_id']); - //info( t('Menu element added.') . EOL); - if($_REQUEST['submit']) { - goaway(z_root() . '/menu/' . $which . ((App::$is_sys) ? '?f=&sys=1' : '')); - } - if($_REQUEST['submit-more']) { - goaway(z_root() . '/mitem/' . $which . '/' . $_REQUEST['menu_id'] . '?f=&display=block' . ((App::$is_sys) ? '&sys=1' : '') ); - } - } - else - notice( t('Unable to add menu element.') . EOL); - - } - - } - - - function get() { - - $uid = local_channel(); - $owner = App::$profile['channel_id']; - $channel = channelx_by_n($owner); - $observer = App::get_observer(); + if (!App::$data['menu']) + return; - $which = argv(1); + if (!$_REQUEST['mitem_desc'] || !$_REQUEST['mitem_link']) { + notice(t('Unable to create element.') . EOL); + return; + } - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - - if(App::$is_sys && is_site_admin()) { - $sys = get_sys_channel(); - $uid = intval($sys['channel_id']); - $channel = $sys; - $ob_hash = $sys['xchan_hash']; - } - - if(! $uid) { - notice( t('Permission denied.') . EOL); - return ''; - } - - if(argc() < 3 || (! App::$data['menu'])) { - notice( t('Not found.') . EOL); - return ''; - } - - $m = menu_fetch(App::$data['menu']['menu_name'],$owner,$ob_hash); - App::$data['menu_item'] = $m; - - $menu_list = menu_list($owner); - - foreach($menu_list as $menus) { - if($menus['menu_name'] != $m['menu']['menu_name']) - $menu_names[] = $menus['menu_name']; - } - - $acl = new AccessControl($channel); - - $lockstate = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'); - - if(argc() == 3) { - $r = q("select * from menu_item where mitem_menu_id = %d and mitem_channel_id = %d order by mitem_order asc, mitem_desc asc", - intval(App::$data['menu']['menu_id']), - intval($owner) - ); - - if($_GET['display']) { - $display = $_GET['display']; - } - else { - $display = (($r) ? 'none' : 'block'); - } + $_REQUEST['mitem_channel_id'] = $uid; + $_REQUEST['menu_id'] = App::$data['menu']['menu_id']; - $create = replace_macros(get_markup_template('mitemedit.tpl'), array( - '$menu_id' => App::$data['menu']['menu_id'], - '$permissions' => t('Menu Item Permissions'), - '$permdesc' => t("\x28click to open/close\x29"), - '$aclselect' => populate_acl($acl->get(),false), - '$allow_cid' => acl2json($acl->get()['allow_cid']), - '$allow_gid' => acl2json($acl->get()['allow_gid']), - '$deny_cid' => acl2json($acl->get()['deny_cid']), - '$deny_gid' => acl2json($acl->get()['deny_gid']), - '$mitem_desc' => array('mitem_desc', t('Link Name'), '', 'Visible name of the link','*'), - '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), '', t('Enter URL of the link or select a menu name to create a submenu'), '*', 'list="menu-names"'), - '$usezid' => array('usezid', t('Use magic-auth if available'), true, '', array(t('No'), t('Yes'))), - '$newwin' => array('newwin', t('Open link in new window'), false,'', array(t('No'), t('Yes'))), - '$mitem_order' => array('mitem_order', t('Order in list'),'0',t('Higher numbers will sink to bottom of listing')), - '$submit' => t('Submit and finish'), - '$submit_more' => t('Submit and continue'), - '$display' => $display, - '$lockstate' => $lockstate, - '$menu_names' => $menu_names, - '$nick' => $which, - '$sys' => App::$is_sys - )); - - $o .= replace_macros(get_markup_template('mitemlist.tpl'),array( - '$title' => t('Menu:'), - '$create' => $create, - '$nametitle' => t('Link Name'), - '$targettitle' => t('Link Target'), - '$menuname' => App::$data['menu']['menu_name'], - '$menudesc' => App::$data['menu']['menu_desc'], - '$edmenu' => t('Edit menu'), - '$menu_id' => App::$data['menu']['menu_id'], - '$mlist' => $r, - '$edit' => t('Edit element'), - '$drop' => t('Drop element'), - '$new' => t('New element'), - '$hintmenu' => t('Edit this menu container'), - '$hintnew' => t('Add menu element'), - '$hintdrop' => t('Delete this menu item'), - '$hintedit' => t('Edit this menu item'), - '$nick' => $which, - )); - - return $o; - } - - - if(argc() > 3) { + $_REQUEST['mitem_flags'] = 0; + if ($_REQUEST['usezid']) + $_REQUEST['mitem_flags'] |= MENU_ITEM_ZID; + if ($_REQUEST['newwin']) + $_REQUEST['mitem_flags'] |= MENU_ITEM_NEWWIN; + + + $mitem_id = ((argc() > 3) ? intval(argv(3)) : 0); + if ($mitem_id) { + $_REQUEST['mitem_id'] = $mitem_id; + $r = menu_edit_item($_REQUEST['menu_id'], $uid, $_REQUEST); + if ($r) { + menu_sync_packet($uid, get_observer_hash(), $_REQUEST['menu_id']); + //info( t('Menu element updated.') . EOL); + goaway(z_root() . '/mitem/' . $which . '/' . $_REQUEST['menu_id'] . ((App::$is_sys) ? '?f=&sys=1' : '')); + } else + notice(t('Unable to update menu element.') . EOL); + + } else { + $r = menu_add_item($_REQUEST['menu_id'], $uid, $_REQUEST); + if ($r) { + menu_sync_packet($uid, get_observer_hash(), $_REQUEST['menu_id']); + //info( t('Menu element added.') . EOL); + if ($_REQUEST['submit']) { + goaway(z_root() . '/menu/' . $which . ((App::$is_sys) ? '?f=&sys=1' : '')); + } + if ($_REQUEST['submit-more']) { + goaway(z_root() . '/mitem/' . $which . '/' . $_REQUEST['menu_id'] . '?f=&display=block' . ((App::$is_sys) ? '&sys=1' : '')); + } + } else + notice(t('Unable to add menu element.') . EOL); + + } + + } + + + public function get() + { + + $uid = local_channel(); + $owner = App::$profile['channel_id']; + $channel = channelx_by_n($owner); + $observer = App::get_observer(); + + $which = argv(1); + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if (App::$is_sys && is_site_admin()) { + $sys = get_sys_channel(); + $uid = intval($sys['channel_id']); + $channel = $sys; + $ob_hash = $sys['xchan_hash']; + } + + if (!$uid) { + notice(t('Permission denied.') . EOL); + return ''; + } + + if (argc() < 3 || (!App::$data['menu'])) { + notice(t('Not found.') . EOL); + return ''; + } + + $m = menu_fetch(App::$data['menu']['menu_name'], $owner, $ob_hash); + App::$data['menu_item'] = $m; + + $menu_list = menu_list($owner); + + foreach ($menu_list as $menus) { + if ($menus['menu_name'] != $m['menu']['menu_name']) + $menu_names[] = $menus['menu_name']; + } + + $acl = new AccessControl($channel); + + $lockstate = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'); + + if (argc() == 3) { + $r = q("select * from menu_item where mitem_menu_id = %d and mitem_channel_id = %d order by mitem_order asc, mitem_desc asc", + intval(App::$data['menu']['menu_id']), + intval($owner) + ); + + if ($_GET['display']) { + $display = $_GET['display']; + } else { + $display = (($r) ? 'none' : 'block'); + } + + $create = replace_macros(get_markup_template('mitemedit.tpl'), array( + '$menu_id' => App::$data['menu']['menu_id'], + '$permissions' => t('Menu Item Permissions'), + '$permdesc' => t("\x28click to open/close\x29"), + '$aclselect' => populate_acl($acl->get(), false), + '$allow_cid' => acl2json($acl->get()['allow_cid']), + '$allow_gid' => acl2json($acl->get()['allow_gid']), + '$deny_cid' => acl2json($acl->get()['deny_cid']), + '$deny_gid' => acl2json($acl->get()['deny_gid']), + '$mitem_desc' => array('mitem_desc', t('Link Name'), '', 'Visible name of the link', '*'), + '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), '', t('Enter URL of the link or select a menu name to create a submenu'), '*', 'list="menu-names"'), + '$usezid' => array('usezid', t('Use magic-auth if available'), true, '', array(t('No'), t('Yes'))), + '$newwin' => array('newwin', t('Open link in new window'), false, '', array(t('No'), t('Yes'))), + '$mitem_order' => array('mitem_order', t('Order in list'), '0', t('Higher numbers will sink to bottom of listing')), + '$submit' => t('Submit and finish'), + '$submit_more' => t('Submit and continue'), + '$display' => $display, + '$lockstate' => $lockstate, + '$menu_names' => $menu_names, + '$nick' => $which, + '$sys' => App::$is_sys + )); + + $o .= replace_macros(get_markup_template('mitemlist.tpl'), array( + '$title' => t('Menu:'), + '$create' => $create, + '$nametitle' => t('Link Name'), + '$targettitle' => t('Link Target'), + '$menuname' => App::$data['menu']['menu_name'], + '$menudesc' => App::$data['menu']['menu_desc'], + '$edmenu' => t('Edit menu'), + '$menu_id' => App::$data['menu']['menu_id'], + '$mlist' => $r, + '$edit' => t('Edit element'), + '$drop' => t('Drop element'), + '$new' => t('New element'), + '$hintmenu' => t('Edit this menu container'), + '$hintnew' => t('Add menu element'), + '$hintdrop' => t('Delete this menu item'), + '$hintedit' => t('Edit this menu item'), + '$nick' => $which, + )); + + return $o; + } + + + if (argc() > 3) { + + if (intval(argv(3))) { + + $m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1", + intval(argv(3)), + intval($owner) + ); + + if (!$m) { + notice(t('Menu item not found.') . EOL); + goaway(z_root() . '/menu/' . $which . ((App::$is_sys) ? '?f=&sys=1' : '')); + } + + $mitem = $m[0]; + + $lockstate = (($mitem['allow_cid'] || $mitem['allow_gid'] || $mitem['deny_cid'] || $mitem['deny_gid']) ? 'lock' : 'unlock'); + + if (argc() == 5 && argv(4) == 'drop') { + menu_sync_packet($owner, get_observer_hash(), $mitem['mitem_menu_id']); + $r = menu_del_item($mitem['mitem_menu_id'], $owner, intval(argv(3))); + menu_sync_packet($owner, get_observer_hash(), $mitem['mitem_menu_id']); + if ($r) + info(t('Menu item deleted.') . EOL); + else + notice(t('Menu item could not be deleted.') . EOL); + + goaway(z_root() . '/mitem/' . $which . '/' . $mitem['mitem_menu_id'] . ((App::$is_sys) ? '?f=&sys=1' : '')); + } + + // edit menu item + $o = replace_macros(get_markup_template('mitemedit.tpl'), array( + '$header' => t('Edit Menu Element'), + '$menu_id' => App::$data['menu']['menu_id'], + '$permissions' => t('Menu Item Permissions'), + '$permdesc' => t("\x28click to open/close\x29"), + '$aclselect' => populate_acl($mitem, false), + '$allow_cid' => acl2json($mitem['allow_cid']), + '$allow_gid' => acl2json($mitem['allow_gid']), + '$deny_cid' => acl2json($mitem['deny_cid']), + '$deny_gid' => acl2json($mitem['deny_gid']), + '$mitem_id' => intval(argv(3)), + '$mitem_desc' => array('mitem_desc', t('Link text'), $mitem['mitem_desc'], '', '*'), + '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), $mitem['mitem_link'], 'Enter URL of the link or select a menu name to create a submenu', '*', 'list="menu-names"'), + '$usezid' => array('usezid', t('Use magic-auth if available'), (($mitem['mitem_flags'] & MENU_ITEM_ZID) ? 1 : 0), '', array(t('No'), t('Yes'))), + '$newwin' => array('newwin', t('Open link in new window'), (($mitem['mitem_flags'] & MENU_ITEM_NEWWIN) ? 1 : 0), '', array(t('No'), t('Yes'))), + '$mitem_order' => array('mitem_order', t('Order in list'), $mitem['mitem_order'], t('Higher numbers will sink to bottom of listing')), + '$submit' => t('Submit'), + '$lockstate' => $lockstate, + '$menu_names' => $menu_names, + '$nick' => $which + )); + + return $o; + } + } + } - if(intval(argv(3))) { - - $m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1", - intval(argv(3)), - intval($owner) - ); - - if(! $m) { - notice( t('Menu item not found.') . EOL); - goaway(z_root() . '/menu/'. $which . ((App::$is_sys) ? '?f=&sys=1' : '')); - } - - $mitem = $m[0]; - - $lockstate = (($mitem['allow_cid'] || $mitem['allow_gid'] || $mitem['deny_cid'] || $mitem['deny_gid']) ? 'lock' : 'unlock'); - - if(argc() == 5 && argv(4) == 'drop') { - menu_sync_packet($owner,get_observer_hash(),$mitem['mitem_menu_id']); - $r = menu_del_item($mitem['mitem_menu_id'], $owner, intval(argv(3))); - menu_sync_packet($owner,get_observer_hash(),$mitem['mitem_menu_id']); - if($r) - info( t('Menu item deleted.') . EOL); - else - notice( t('Menu item could not be deleted.'). EOL); - - goaway(z_root() . '/mitem/' . $which . '/' . $mitem['mitem_menu_id'] . ((App::$is_sys) ? '?f=&sys=1' : '')); - } - - // edit menu item - $o = replace_macros(get_markup_template('mitemedit.tpl'), array( - '$header' => t('Edit Menu Element'), - '$menu_id' => App::$data['menu']['menu_id'], - '$permissions' => t('Menu Item Permissions'), - '$permdesc' => t("\x28click to open/close\x29"), - '$aclselect' => populate_acl($mitem,false), - '$allow_cid' => acl2json($mitem['allow_cid']), - '$allow_gid' => acl2json($mitem['allow_gid']), - '$deny_cid' => acl2json($mitem['deny_cid']), - '$deny_gid' => acl2json($mitem['deny_gid']), - '$mitem_id' => intval(argv(3)), - '$mitem_desc' => array('mitem_desc', t('Link text'), $mitem['mitem_desc'], '','*'), - '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), $mitem['mitem_link'], 'Enter URL of the link or select a menu name to create a submenu', '*', 'list="menu-names"'), - '$usezid' => array('usezid', t('Use magic-auth if available'), (($mitem['mitem_flags'] & MENU_ITEM_ZID) ? 1 : 0), '', array(t('No'), t('Yes'))), - '$newwin' => array('newwin', t('Open link in new window'), (($mitem['mitem_flags'] & MENU_ITEM_NEWWIN) ? 1 : 0),'', array(t('No'), t('Yes'))), - '$mitem_order' => array('mitem_order', t('Order in list'),$mitem['mitem_order'],t('Higher numbers will sink to bottom of listing')), - '$submit' => t('Submit'), - '$lockstate' => $lockstate, - '$menu_names' => $menu_names, - '$nick' => $which - )); - - return $o; - } - } - } - } diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php index fa80bf8c3..ababeae17 100644 --- a/Zotlabs/Module/Moderate.php +++ b/Zotlabs/Module/Moderate.php @@ -10,115 +10,115 @@ use Zotlabs\Daemon\Run; require_once('include/conversation.php'); -class Moderate extends Controller { +class Moderate extends Controller +{ - function get() { - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + public function get() + { + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - App::set_pager_itemspage(60); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + App::set_pager_itemspage(60); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - //show all items - if(argc() == 1) { - $r = q("select item.id as item_id, item.* from item where item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc $pager_sql", - intval(local_channel()), - intval(ITEM_MODERATED) - ); - if(! $r) { - info( t('No entries.') . EOL); - } + //show all items + if (argc() == 1) { + $r = q("select item.id as item_id, item.* from item where item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc $pager_sql", + intval(local_channel()), + intval(ITEM_MODERATED) + ); + if (!$r) { + info(t('No entries.') . EOL); + } - } + } - // show a single item - if(argc() == 2) { - $post_id = unpack_link_id(escape_tags(argv(1))); + // show a single item + if (argc() == 2) { + $post_id = unpack_link_id(escape_tags(argv(1))); - $r = q("select item.id as item_id, item.* from item where item.mid = '%s' and item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc $pager_sql", - dbesc($post_id), - intval(local_channel()), - intval(ITEM_MODERATED) - ); - } + $r = q("select item.id as item_id, item.* from item where item.mid = '%s' and item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc $pager_sql", + dbesc($post_id), + intval(local_channel()), + intval(ITEM_MODERATED) + ); + } - if(argc() > 2) { - $post_id = intval(argv(1)); - if(! $post_id) - goaway(z_root() . '/moderate'); + if (argc() > 2) { + $post_id = intval(argv(1)); + if (!$post_id) + goaway(z_root() . '/moderate'); - $action = argv(2); + $action = argv(2); - $r = q("select * from item where uid = %d and id = %d and item_blocked = %d limit 1", - intval(local_channel()), - intval($post_id), - intval(ITEM_MODERATED) - ); + $r = q("select * from item where uid = %d and id = %d and item_blocked = %d limit 1", + intval(local_channel()), + intval($post_id), + intval(ITEM_MODERATED) + ); - if($r) { - $item = $r[0]; + if ($r) { + $item = $r[0]; - if($action === 'approve') { - q("update item set item_blocked = 0 where uid = %d and id = %d", - intval(local_channel()), - intval($post_id) - ); + if ($action === 'approve') { + q("update item set item_blocked = 0 where uid = %d and id = %d", + intval(local_channel()), + intval($post_id) + ); - $item['item_blocked'] = 0; + $item['item_blocked'] = 0; - item_update_parent_commented($item); + item_update_parent_commented($item); - notice( t('Comment approved') . EOL); - } - elseif($action === 'drop') { - drop_item($post_id,false); - notice( t('Comment deleted') . EOL); - } + notice(t('Comment approved') . EOL); + } elseif ($action === 'drop') { + drop_item($post_id, false); + notice(t('Comment deleted') . EOL); + } - // refetch the item after changes have been made - - $r = q("select * from item where id = %d", - intval($post_id) - ); - if($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet(local_channel(),array('item' => array(encode_item($sync_item[0],true)))); - } - if($action === 'approve') { - if ($item['id'] !== $item['parent']) { - // if this is a group comment, call tag_deliver() to generate the associated - // Announce activity so microblog destinations will see it in their home timeline - $role = get_pconfig(local_channel(),'system','permissions_role'); - $rolesettings = PermissionRoles::role_perms($role); - $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; + // refetch the item after changes have been made - $is_group = (($channel_type === 'group') ? true : false); - if ($is_group) { - tag_deliver(local_channel(),$post_id); - } - } - Run::Summon( [ 'Notifier', 'comment-new', $post_id ] ); - } - goaway(z_root() . '/moderate'); - } - } + $r = q("select * from item where id = %d", + intval($post_id) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet(local_channel(), array('item' => array(encode_item($sync_item[0], true)))); + } + if ($action === 'approve') { + if ($item['id'] !== $item['parent']) { + // if this is a group comment, call tag_deliver() to generate the associated + // Announce activity so microblog destinations will see it in their home timeline + $role = get_pconfig(local_channel(), 'system', 'permissions_role'); + $rolesettings = PermissionRoles::role_perms($role); + $channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; - if($r) { - xchan_query($r); - $items = fetch_post_tags($r,true); - } - else { - $items = []; - } + $is_group = (($channel_type === 'group') ? true : false); + if ($is_group) { + tag_deliver(local_channel(), $post_id); + } + } + Run::Summon(['Notifier', 'comment-new', $post_id]); + } + goaway(z_root() . '/moderate'); + } + } - $o = conversation($items,'moderate',false,'traditional'); - $o .= alt_pager(count($items)); - return $o; + if ($r) { + xchan_query($r); + $items = fetch_post_tags($r, true); + } else { + $items = []; + } - } + $o = conversation($items, 'moderate', false, 'traditional'); + $o .= alt_pager(count($items)); + return $o; + + } } diff --git a/Zotlabs/Module/Mood.php b/Zotlabs/Module/Mood.php index aa759e8e5..407558a99 100644 --- a/Zotlabs/Module/Mood.php +++ b/Zotlabs/Module/Mood.php @@ -10,155 +10,156 @@ require_once('include/security.php'); require_once('include/bbcode.php'); -class Mood extends Controller { +class Mood extends Controller +{ - function init() { - - if(! local_channel()) - return; + public function init() + { - if(! Apps::system_app_installed(local_channel(), 'Mood')) { - return; - } - - $uid = local_channel(); - $channel = App::get_channel(); - $verb = notags(trim($_GET['verb'])); - - if(! $verb) - return; - - $verbs = get_mood_verbs(); - - if(! array_key_exists($verb,$verbs)) - return; - - $activity = ACTIVITY_MOOD . '#' . urlencode($verb); - - $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : 0); - - - logger('mood: verb ' . $verb, LOGGER_DEBUG); - - - if($parent) { - $r = q("select mid, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid + if (!local_channel()) + return; + + if (!Apps::system_app_installed(local_channel(), 'Mood')) { + return; + } + + $uid = local_channel(); + $channel = App::get_channel(); + $verb = notags(trim($_GET['verb'])); + + if (!$verb) + return; + + $verbs = get_mood_verbs(); + + if (!array_key_exists($verb, $verbs)) + return; + + $activity = ACTIVITY_MOOD . '#' . urlencode($verb); + + $parent = ((x($_GET, 'parent')) ? intval($_GET['parent']) : 0); + + + logger('mood: verb ' . $verb, LOGGER_DEBUG); + + + if ($parent) { + $r = q("select mid, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid from item where id = %d and parent = %d and uid = %d limit 1", - intval($parent), - intval($parent), - intval($uid) - ); - if(count($r)) { - $parent_mid = $r[0]['mid']; - $private = $r[0]['item_private']; - $allow_cid = $r[0]['allow_cid']; - $allow_gid = $r[0]['allow_gid']; - $deny_cid = $r[0]['deny_cid']; - $deny_gid = $r[0]['deny_gid']; - } - } - else { - - $private = 0; - - $allow_cid = $channel['channel_allow_cid']; - $allow_gid = $channel['channel_allow_gid']; - $deny_cid = $channel['channel_deny_cid']; - $deny_gid = $channel['channel_deny_gid']; - } - - $poster = App::get_observer(); - - $uuid = new_uuid(); - $mid = z_root() . '/item/' . $uuid; - - $action = sprintf( t('%1$s is %2$s','mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]' , $verbs[$verb]); - - $arr = []; - - $arr['aid'] = get_account_id(); - $arr['uid'] = $uid; - $arr['uuid'] = $uuid; - $arr['mid'] = $mid; - $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); - $arr['author_xchan'] = $poster['xchan_hash']; - $arr['owner_xchan'] = (($parent_mid) ? $r[0]['owner_xchan'] : $poster['xchan_hash']); - $arr['title'] = ''; - $arr['allow_cid'] = $allow_cid; - $arr['allow_gid'] = $allow_gid; - $arr['deny_cid'] = $deny_cid; - $arr['deny_gid'] = $deny_gid; - $arr['item_private'] = $private; - $arr['verb'] = $activity; - $arr['body'] = $action; - $arr['item_origin'] = 1; - $arr['item_wall'] = 1; - $arr['item_unseen'] = 1; - if(! $parent_mid) - $item['item_thread_top'] = 1; - - if ((! $arr['plink']) && intval($arr['item_thread_top'])) { - $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']); - } - - - $post = item_store($arr); - $item_id = $post['item_id']; - - if($item_id) { - Run::Summon( [ 'Notifier','activity', $item_id ] ); - } - - call_hooks('post_local_end', $arr); - - if($_SESSION['return_url']) - goaway(z_root() . '/' . $_SESSION['return_url']); - - return; - } - - - - function get() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + intval($parent), + intval($parent), + intval($uid) + ); + if (count($r)) { + $parent_mid = $r[0]['mid']; + $private = $r[0]['item_private']; + $allow_cid = $r[0]['allow_cid']; + $allow_gid = $r[0]['allow_gid']; + $deny_cid = $r[0]['deny_cid']; + $deny_gid = $r[0]['deny_gid']; + } + } else { - if(! Apps::system_app_installed(local_channel(), 'Mood')) { - //Do not display any associated widgets at this point - App::$pdl = ''; + $private = 0; - $o = 'Mood App (Not Installed):
      '; - $o .= t('Set your current mood and tell your friends'); - return $o; - } + $allow_cid = $channel['channel_allow_cid']; + $allow_gid = $channel['channel_allow_gid']; + $deny_cid = $channel['channel_deny_cid']; + $deny_gid = $channel['channel_deny_gid']; + } - nav_set_selected('Mood'); + $poster = App::get_observer(); + + $uuid = new_uuid(); + $mid = z_root() . '/item/' . $uuid; + + $action = sprintf(t('%1$s is %2$s', 'mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]', $verbs[$verb]); + + $arr = []; + + $arr['aid'] = get_account_id(); + $arr['uid'] = $uid; + $arr['uuid'] = $uuid; + $arr['mid'] = $mid; + $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); + $arr['author_xchan'] = $poster['xchan_hash']; + $arr['owner_xchan'] = (($parent_mid) ? $r[0]['owner_xchan'] : $poster['xchan_hash']); + $arr['title'] = ''; + $arr['allow_cid'] = $allow_cid; + $arr['allow_gid'] = $allow_gid; + $arr['deny_cid'] = $deny_cid; + $arr['deny_gid'] = $deny_gid; + $arr['item_private'] = $private; + $arr['verb'] = $activity; + $arr['body'] = $action; + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['item_unseen'] = 1; + if (!$parent_mid) + $item['item_thread_top'] = 1; + + if ((!$arr['plink']) && intval($arr['item_thread_top'])) { + $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']); + } + + + $post = item_store($arr); + $item_id = $post['item_id']; + + if ($item_id) { + Run::Summon(['Notifier', 'activity', $item_id]); + } + + call_hooks('post_local_end', $arr); + + if ($_SESSION['return_url']) + goaway(z_root() . '/' . $_SESSION['return_url']); + + return; + } + + + public function get() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + if (!Apps::system_app_installed(local_channel(), 'Mood')) { + //Do not display any associated widgets at this point + App::$pdl = ''; + + $o = 'Mood App (Not Installed):
      '; + $o .= t('Set your current mood and tell your friends'); + return $o; + } + + nav_set_selected('Mood'); + + $parent = ((x($_GET, 'parent')) ? intval($_GET['parent']) : '0'); + + $verbs = get_mood_verbs(); + + $shortlist = []; + foreach ($verbs as $k => $v) + if ($v !== 'NOTRANSLATION') + $shortlist[] = array($k, $v); + + + $tpl = get_markup_template('mood_content.tpl'); + + $o = replace_macros($tpl, array( + '$title' => t('Mood'), + '$desc' => t('Set your current mood and tell your friends'), + '$verbs' => $shortlist, + '$parent' => $parent, + '$submit' => t('Submit'), + )); + + return $o; + + } - $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0'); - - $verbs = get_mood_verbs(); - - $shortlist = []; - foreach($verbs as $k => $v) - if($v !== 'NOTRANSLATION') - $shortlist[] = array($k,$v); - - - $tpl = get_markup_template('mood_content.tpl'); - - $o = replace_macros($tpl,array( - '$title' => t('Mood'), - '$desc' => t('Set your current mood and tell your friends'), - '$verbs' => $shortlist, - '$parent' => $parent, - '$submit' => t('Submit'), - )); - - return $o; - - } - } diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php index 57d2f0073..6547ff392 100644 --- a/Zotlabs/Module/New_channel.php +++ b/Zotlabs/Module/New_channel.php @@ -11,197 +11,199 @@ require_once('include/channel.php'); require_once('include/permissions.php'); +class New_channel extends Controller +{ -class New_channel extends Controller { + public function init() + { - function init() { + $cmd = ((argc() > 1) ? argv(1) : ''); - $cmd = ((argc() > 1) ? argv(1) : ''); - - if($cmd === 'autofill.json') { - $result = array('error' => false, 'message' => ''); - $n = trim($_REQUEST['name']); + if ($cmd === 'autofill.json') { + $result = array('error' => false, 'message' => ''); + $n = trim($_REQUEST['name']); - $x = false; + $x = false; - if(get_config('system','unicode_usernames')) { - $x = punify(mb_strtolower($n)); - } + if (get_config('system', 'unicode_usernames')) { + $x = punify(mb_strtolower($n)); + } - if((! $x) || strlen($x) > 64) - $x = strtolower(URLify::transliterate($n)); - - $test = []; - - // first name - if(strpos($x,' ')) - $test[] = legal_webbie(substr($x,0,strpos($x,' '))); - if($test[0]) { - // first name plus first initial of last - $test[] = ((strpos($x,' ')) ? $test[0] . legal_webbie(trim(substr($x,strpos($x,' '),2))) : ''); - // first name plus random number - $test[] = $test[0] . mt_rand(1000,9999); - } - // fullname - $test[] = legal_webbie($x); - // fullname plus random number - $test[] = legal_webbie($x) . mt_rand(1000,9999); + if ((!$x) || strlen($x) > 64) + $x = strtolower(URLify::transliterate($n)); - json_return_and_die(check_webbie($test)); - } - - if($cmd === 'checkaddr.json') { - $result = array('error' => false, 'message' => ''); - $n = trim($_REQUEST['nick']); - if(! $n) { - $n = trim($_REQUEST['name']); - } + $test = []; - $x = false; + // first name + if (strpos($x, ' ')) + $test[] = legal_webbie(substr($x, 0, strpos($x, ' '))); + if ($test[0]) { + // first name plus first initial of last + $test[] = ((strpos($x, ' ')) ? $test[0] . legal_webbie(trim(substr($x, strpos($x, ' '), 2))) : ''); + // first name plus random number + $test[] = $test[0] . mt_rand(1000, 9999); + } + // fullname + $test[] = legal_webbie($x); + // fullname plus random number + $test[] = legal_webbie($x) . mt_rand(1000, 9999); - if(get_config('system','unicode_usernames')) { - $x = punify(mb_strtolower($n)); - } + json_return_and_die(check_webbie($test)); + } - if((! $x) || strlen($x) > 64) - $x = strtolower(URLify::transliterate($n)); + if ($cmd === 'checkaddr.json') { + $result = array('error' => false, 'message' => ''); + $n = trim($_REQUEST['nick']); + if (!$n) { + $n = trim($_REQUEST['name']); + } + + $x = false; + + if (get_config('system', 'unicode_usernames')) { + $x = punify(mb_strtolower($n)); + } + + if ((!$x) || strlen($x) > 64) + $x = strtolower(URLify::transliterate($n)); - $test = []; - - // first name - if(strpos($x,' ')) - $test[] = legal_webbie(substr($x,0,strpos($x,' '))); - if($test[0]) { - // first name plus first initial of last - $test[] = ((strpos($x,' ')) ? $test[0] . legal_webbie(trim(substr($x,strpos($x,' '),2))) : ''); - // first name plus random number - $test[] = $test[0] . mt_rand(1000,9999); - } + $test = []; - $n = legal_webbie($x); - if(strlen($n)) { - $test[] = $n; - $test[] = $n . mt_rand(1000,9999); - } - - for($y = 0; $y < 100; $y ++) - $test[] = 'id' . mt_rand(1000,9999); - - json_return_and_die(check_webbie($test)); - } - - - } - - function post() { - - $arr = $_POST; - - $acc = App::get_account(); - - if(local_channel()) { - $parent_channel = App::get_channel(); - if($parent_channel) { - $arr['parent_hash'] = $parent_channel['channel_hash']; - } - } + // first name + if (strpos($x, ' ')) + $test[] = legal_webbie(substr($x, 0, strpos($x, ' '))); + if ($test[0]) { + // first name plus first initial of last + $test[] = ((strpos($x, ' ')) ? $test[0] . legal_webbie(trim(substr($x, strpos($x, ' '), 2))) : ''); + // first name plus random number + $test[] = $test[0] . mt_rand(1000, 9999); + } - $arr['account_id'] = get_account_id(); - - // prevent execution by delegated channels as well as those not logged in. - // get_account_id() returns the account_id from the session. But \App::$account - // may point to the original authenticated account. - - if((! $acc) || ($acc['account_id'] != $arr['account_id'])) { - notice( t('Permission denied.') . EOL ); - return; - } - - $result = create_identity($arr); - - if(! $result['success']) { - notice($result['message']); - return; - } - - $newuid = $result['channel']['channel_id']; - - change_channel($result['channel']['channel_id']); - - $next_page = get_config('system', 'workflow_channel_next', 'profiles'); - goaway(z_root() . '/' . $next_page); - - } - - function get() { - - $acc = App::get_account(); - - if((! $acc) || $acc['account_id'] != get_account_id()) { - notice( t('Permission denied.') . EOL); - return; - } - - $default_role = ''; - $aid = get_account_id(); - if($aid) { - $r = q("select count(channel_id) as total from channel where channel_account_id = %d", - intval($aid) - ); - if($r && (! intval($r[0]['total']))) { - $default_role = get_config('system','default_permissions_role','social'); - } - - $limit = account_service_class_fetch(get_account_id(),'total_identities'); - - if($r && ($limit !== false)) { - $channel_usage_message = sprintf( t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit); - } - else { - $channel_usage_message = ''; - } - } + $n = legal_webbie($x); + if (strlen($n)) { + $test[] = $n; + $test[] = $n . mt_rand(1000, 9999); + } - $name_help = ''; - $name_help .= (($default_role) - ? t('Your real name is recommended.') - : t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"') - ); - $name_help .= ''; + for ($y = 0; $y < 100; $y++) + $test[] = 'id' . mt_rand(1000, 9999); - $nick_help = ''; - $nick_help .= t('This will be used to create a unique network address (like an email address).'); - if(! get_config('system','unicode_usernames')) { - $nick_help .= ' ' . t('Allowed characters are a-z 0-9, - and _'); - } - $nick_help .= ''; + json_return_and_die(check_webbie($test)); + } - $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" ); - $perm_roles = PermissionRoles::roles(); + } + + public function post() + { + + $arr = $_POST; + + $acc = App::get_account(); + + if (local_channel()) { + $parent_channel = App::get_channel(); + if ($parent_channel) { + $arr['parent_hash'] = $parent_channel['channel_hash']; + } + } + + $arr['account_id'] = get_account_id(); + + // prevent execution by delegated channels as well as those not logged in. + // get_account_id() returns the account_id from the session. But \App::$account + // may point to the original authenticated account. + + if ((!$acc) || ($acc['account_id'] != $arr['account_id'])) { + notice(t('Permission denied.') . EOL); + return; + } + + $result = create_identity($arr); + + if (!$result['success']) { + notice($result['message']); + return; + } + + $newuid = $result['channel']['channel_id']; + + change_channel($result['channel']['channel_id']); + + $next_page = get_config('system', 'workflow_channel_next', 'profiles'); + goaway(z_root() . '/' . $next_page); + + } + + public function get() + { + + $acc = App::get_account(); + + if ((!$acc) || $acc['account_id'] != get_account_id()) { + notice(t('Permission denied.') . EOL); + return; + } + + $default_role = ''; + $aid = get_account_id(); + if ($aid) { + $r = q("select count(channel_id) as total from channel where channel_account_id = %d", + intval($aid) + ); + if ($r && (!intval($r[0]['total']))) { + $default_role = get_config('system', 'default_permissions_role', 'social'); + } + + $limit = account_service_class_fetch(get_account_id(), 'total_identities'); + + if ($r && ($limit !== false)) { + $channel_usage_message = sprintf(t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit); + } else { + $channel_usage_message = ''; + } + } + + $name_help = ''; + $name_help .= (($default_role) + ? t('Your real name is recommended.') + : t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"') + ); + $name_help .= ''; + + $nick_help = ''; + $nick_help .= t('This will be used to create a unique network address (like an email address).'); + if (!get_config('system', 'unicode_usernames')) { + $nick_help .= ' ' . t('Allowed characters are a-z 0-9, - and _'); + } + $nick_help .= ''; + + $privacy_role = ((x($_REQUEST, 'permissions_role')) ? $_REQUEST['permissions_role'] : ""); + + $perm_roles = PermissionRoles::roles(); + + $name = array('name', t('Channel name'), ((x($_REQUEST, 'name')) ? $_REQUEST['name'] : ''), $name_help, "*"); + $nickhub = '@' . App::get_hostname(); + $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST, 'nickname')) ? $_REQUEST['nickname'] : ''), $nick_help, "*"); + $role = array('permissions_role', t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role compatible with your usage needs and privacy requirements.'), $perm_roles); + + $o = replace_macros(get_markup_template('new_channel.tpl'), array( + '$title' => t('Create a Channel'), + '$desc' => t('A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things.'), + '$label_import' => t('or import an existing channel from another location.'), + '$name' => $name, + '$role' => $role, + '$default_role' => $default_role, + '$nickname' => $nickname, + '$validate' => t('Validate'), + '$submit' => t('Create'), + '$channel_usage_message' => $channel_usage_message + )); + + return $o; + + } + - $name = array('name', t('Channel name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), $name_help, "*"); - $nickhub = '@' . App::get_hostname(); - $nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), $nick_help, "*"); - $role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role compatible with your usage needs and privacy requirements.'),$perm_roles); - - $o = replace_macros(get_markup_template('new_channel.tpl'), array( - '$title' => t('Create a Channel'), - '$desc' => t('A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things.') , - '$label_import' => t('or import an existing channel from another location.'), - '$name' => $name, - '$role' => $role, - '$default_role' => $default_role, - '$nickname' => $nickname, - '$validate' => t('Validate'), - '$submit' => t('Create'), - '$channel_usage_message' => $channel_usage_message - )); - - return $o; - - } - - } diff --git a/Zotlabs/Module/Notes.php b/Zotlabs/Module/Notes.php index e52742857..8a82ee113 100644 --- a/Zotlabs/Module/Notes.php +++ b/Zotlabs/Module/Notes.php @@ -5,48 +5,51 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; use Zotlabs\Lib\Apps; -class Notes extends Controller { +class Notes extends Controller +{ - function init() { - - if(! local_channel()) - return; - - $ret = array('success' => true); - if(array_key_exists('note_text',$_REQUEST)) { - $body = escape_tags($_REQUEST['note_text']); - - // I've had my notes vanish into thin air twice in four years. - // Provide a backup copy if there were contents previously - // and there are none being saved now. - - if(! $body) { - $old_text = get_pconfig(local_channel(),'notes','text'); - if($old_text) - set_pconfig(local_channel(),'notes','text.bak',$old_text); - } - set_pconfig(local_channel(),'notes','text',$body); + public function init() + { - - // push updates to channel clones - - if((argc() > 1) && (argv(1) === 'sync')) { - Libsync::build_sync_packet(); - } - - logger('notes saved.', LOGGER_DEBUG); - json_return_and_die($ret); - - } - } + if (!local_channel()) + return; - function get() { + $ret = array('success' => true); + if (array_key_exists('note_text', $_REQUEST)) { + $body = escape_tags($_REQUEST['note_text']); + + // I've had my notes vanish into thin air twice in four years. + // Provide a backup copy if there were contents previously + // and there are none being saved now. + + if (!$body) { + $old_text = get_pconfig(local_channel(), 'notes', 'text'); + if ($old_text) + set_pconfig(local_channel(), 'notes', 'text.bak', $old_text); + } + set_pconfig(local_channel(), 'notes', 'text', $body); + + + // push updates to channel clones + + if ((argc() > 1) && (argv(1) === 'sync')) { + Libsync::build_sync_packet(); + } + + logger('notes saved.', LOGGER_DEBUG); + json_return_and_die($ret); + + } + } + + public function get() + { $desc = t('This app allows you to create private notes for your personal use.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Notes'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Notes'))) { return $text; } @@ -59,5 +62,4 @@ class Notes extends Controller { } - } diff --git a/Zotlabs/Module/Notifications.php b/Zotlabs/Module/Notifications.php index becadcae2..b107c4d20 100644 --- a/Zotlabs/Module/Notifications.php +++ b/Zotlabs/Module/Notifications.php @@ -5,71 +5,71 @@ use Zotlabs\Web\Controller; require_once('include/bbcode.php'); -class Notifications extends Controller { +class Notifications extends Controller +{ - function get() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - + public function get() + { - nav_set_selected('Notifications'); - - $o = ''; - $notif_content = ''; - $notifications_available = false; + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - $n = q("select count(*) as total from notify where uid = %d and seen = 0", - intval(local_channel()) - ); - if($n && intval($n[0]['total']) > 49) { - $r = q("select * from notify where uid = %d + + nav_set_selected('Notifications'); + + $o = ''; + $notif_content = ''; + $notifications_available = false; + + $n = q("select count(*) as total from notify where uid = %d and seen = 0", + intval(local_channel()) + ); + if ($n && intval($n[0]['total']) > 49) { + $r = q("select * from notify where uid = %d and seen = 0 order by created desc limit 50", - intval(local_channel()) - ); - } - else { - $r1 = q("select * from notify where uid = %d + intval(local_channel()) + ); + } else { + $r1 = q("select * from notify where uid = %d and seen = 0 order by created desc limit 50", - intval(local_channel()) - ); + intval(local_channel()) + ); - $r2 = q("select * from notify where uid = %d + $r2 = q("select * from notify where uid = %d and seen = 1 order by created desc limit %d", - intval(local_channel()), - intval(50 - intval($n[0]['total'])) - ); - $r = array_merge($r1,$r2); - } - - if($r) { - $notifications_available = true; - foreach ($r as $rr) { - $x = strip_tags(bbcode($rr['msg'])); - $notif_content .= replace_macros(get_markup_template('notify.tpl'),array( - '$item_link' => z_root().'/notify/view/'. $rr['id'], - '$item_image' => $rr['photo'], - '$item_text' => $x, - '$item_when' => relative_date($rr['created']), - '$item_seen' => (($rr['seen']) ? true : false), - '$new' => t('New') - )); - } - } - else { - $notif_content = t('No more system notifications.'); - } - - $o .= replace_macros(get_markup_template('notifications.tpl'),array( - '$notif_header' => t('System Notifications'), - '$notif_link_mark_seen' => t('Mark all seen'), - '$notif_content' => $notif_content, - '$notifications_available' => $notifications_available, - )); - - return $o; - } - + intval(local_channel()), + intval(50 - intval($n[0]['total'])) + ); + $r = array_merge($r1, $r2); + } + + if ($r) { + $notifications_available = true; + foreach ($r as $rr) { + $x = strip_tags(bbcode($rr['msg'])); + $notif_content .= replace_macros(get_markup_template('notify.tpl'), array( + '$item_link' => z_root() . '/notify/view/' . $rr['id'], + '$item_image' => $rr['photo'], + '$item_text' => $x, + '$item_when' => relative_date($rr['created']), + '$item_seen' => (($rr['seen']) ? true : false), + '$new' => t('New') + )); + } + } else { + $notif_content = t('No more system notifications.'); + } + + $o .= replace_macros(get_markup_template('notifications.tpl'), array( + '$notif_header' => t('System Notifications'), + '$notif_link_mark_seen' => t('Mark all seen'), + '$notif_content' => $notif_content, + '$notifications_available' => $notifications_available, + )); + + return $o; + } + } diff --git a/Zotlabs/Module/Notify.php b/Zotlabs/Module/Notify.php index e66430849..02d91da3c 100644 --- a/Zotlabs/Module/Notify.php +++ b/Zotlabs/Module/Notify.php @@ -5,78 +5,80 @@ use App; use Zotlabs\Web\Controller; -class Notify extends Controller { +class Notify extends Controller +{ - function init() { - if (! local_channel()) { - return; - } + public function init() + { + if (!local_channel()) { + return; + } - $channel = App::get_channel(); - if (! $channel) { - return; - } + $channel = App::get_channel(); + if (!$channel) { + return; + } - if (argc() > 2 && argv(1) === 'view' && intval(argv(2))) { - $r = q("select * from notify where id = %d and uid = %d limit 1", - intval(argv(2)), - intval(local_channel()) - ); - if ($r) { - $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ]; - call_hooks('update_unseen',$x); - if ((! $_SESSION['sudo']) && ($x['update'] === 'unset' || intval($x['update']))) { - q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d", - dbesc($r[0]['parent']), - dbesc($r[0]['otype']), - dbesc($r[0]['link']), - intval(local_channel()) - ); - } - goaway($r[0]['link']); - } - notice( sprintf( t('A notification with that id was not found for channel \'%s\''), $channel['channel_name'])); - goaway(z_root()); - } - - - } - - - function get() { - if (! local_channel()) { - return login(); - } - - $notif_tpl = get_markup_template('notifications.tpl'); - - $not_tpl = get_markup_template('notify.tpl'); - - $r = q("SELECT * from notify where uid = %d and seen = 0 order by created desc", - intval(local_channel()) - ); - - if ($r) { - foreach ($r as $it) { - $notif_content .= replace_macros($not_tpl,array( - '$item_link' => z_root().'/notify/view/'. $it['id'], - '$item_image' => $it['photo'], - '$item_text' => strip_tags(bbcode($it['msg'])), - '$item_when' => relative_date($it['created']) - )); - } - } - else { - $notif_content .= t('No more system notifications.'); - } - - $o .= replace_macros($notif_tpl,array( - '$notif_header' => t('System Notifications'), - '$tabs' => '', // $tabs, - '$notif_content' => $notif_content, - )); - - return $o; - - } + if (argc() > 2 && argv(1) === 'view' && intval(argv(2))) { + $r = q("select * from notify where id = %d and uid = %d limit 1", + intval(argv(2)), + intval(local_channel()) + ); + if ($r) { + $x = ['channel_id' => local_channel(), 'update' => 'unset']; + call_hooks('update_unseen', $x); + if ((!$_SESSION['sudo']) && ($x['update'] === 'unset' || intval($x['update']))) { + q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d", + dbesc($r[0]['parent']), + dbesc($r[0]['otype']), + dbesc($r[0]['link']), + intval(local_channel()) + ); + } + goaway($r[0]['link']); + } + notice(sprintf(t('A notification with that id was not found for channel \'%s\''), $channel['channel_name'])); + goaway(z_root()); + } + + + } + + + public function get() + { + if (!local_channel()) { + return login(); + } + + $notif_tpl = get_markup_template('notifications.tpl'); + + $not_tpl = get_markup_template('notify.tpl'); + + $r = q("SELECT * from notify where uid = %d and seen = 0 order by created desc", + intval(local_channel()) + ); + + if ($r) { + foreach ($r as $it) { + $notif_content .= replace_macros($not_tpl, array( + '$item_link' => z_root() . '/notify/view/' . $it['id'], + '$item_image' => $it['photo'], + '$item_text' => strip_tags(bbcode($it['msg'])), + '$item_when' => relative_date($it['created']) + )); + } + } else { + $notif_content .= t('No more system notifications.'); + } + + $o .= replace_macros($notif_tpl, array( + '$notif_header' => t('System Notifications'), + '$tabs' => '', // $tabs, + '$notif_content' => $notif_content, + )); + + return $o; + + } } diff --git a/Zotlabs/Module/Nullbox.php b/Zotlabs/Module/Nullbox.php index b14fd5dc9..1f3e0ad1c 100644 --- a/Zotlabs/Module/Nullbox.php +++ b/Zotlabs/Module/Nullbox.php @@ -4,11 +4,13 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Nullbox extends Controller { +class Nullbox extends Controller +{ - function init() { - http_status_exit(404,'Permission Denied'); - } + public function init() + { + http_status_exit(404, 'Permission Denied'); + } } diff --git a/Zotlabs/Module/Oauthinfo.php b/Zotlabs/Module/Oauthinfo.php index 2d64b3b8e..d2205d4cf 100644 --- a/Zotlabs/Module/Oauthinfo.php +++ b/Zotlabs/Module/Oauthinfo.php @@ -3,20 +3,22 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Oauthinfo extends Controller { +class Oauthinfo extends Controller +{ - function init() { + public function init() + { - $ret = [ - 'issuer' => z_root(), - 'authorization_endpoint' => z_root() . '/authorize', - 'jwks_uri' => z_root() . '/jwks', - 'token_endpoint' => z_root() . '/token', - 'userinfo_endpoint' => z_root() . '/userinfo', - 'scopes_supported' => [ 'openid', 'profile', 'email' ], - 'response_types_supported' => [ 'code', 'token', 'id_token', 'code id_token', 'token id_token' ] - ]; + $ret = [ + 'issuer' => z_root(), + 'authorization_endpoint' => z_root() . '/authorize', + 'jwks_uri' => z_root() . '/jwks', + 'token_endpoint' => z_root() . '/token', + 'userinfo_endpoint' => z_root() . '/userinfo', + 'scopes_supported' => ['openid', 'profile', 'email'], + 'response_types_supported' => ['code', 'token', 'id_token', 'code id_token', 'token id_token'] + ]; - json_return_and_die($ret); - } + json_return_and_die($ret); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Oembed.php b/Zotlabs/Module/Oembed.php index 547c402f7..ee4c4e6e1 100644 --- a/Zotlabs/Module/Oembed.php +++ b/Zotlabs/Module/Oembed.php @@ -5,34 +5,32 @@ use Zotlabs\Web\Controller; require_once("include/oembed.php"); -class Oembed extends Controller { +class Oembed extends Controller +{ + + public function init() + { + // logger('mod_oembed ' . \App::$query_string, LOGGER_ALL); + + if (argc() > 1) { + if (argv(1) == 'b2h') { + $url = array("", trim(hex2bin($_REQUEST['url']))); + echo oembed_replacecb($url); + killme(); + } elseif (argv(1) == 'h2b') { + $text = trim(hex2bin($_REQUEST['text'])); + echo oembed_html2bbcode($text); + killme(); + } else { + echo ""; + $src = base64url_decode(argv(1)); + $j = oembed_fetch_url($src); + echo $j['html']; + // logger('mod-oembed ' . $h, LOGGER_ALL); + echo ""; + } + } + killme(); + } - function init(){ - // logger('mod_oembed ' . \App::$query_string, LOGGER_ALL); - - if(argc() > 1) { - if (argv(1) == 'b2h'){ - $url = array( "", trim(hex2bin($_REQUEST['url']))); - echo oembed_replacecb($url); - killme(); - } - - elseif (argv(1) == 'h2b'){ - $text = trim(hex2bin($_REQUEST['text'])); - echo oembed_html2bbcode($text); - killme(); - } - - else { - echo ""; - $src = base64url_decode(argv(1)); - $j = oembed_fetch_url($src); - echo $j['html']; - // logger('mod-oembed ' . $h, LOGGER_ALL); - echo ""; - } - } - killme(); - } - } diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php index 3ab9cdf95..918a81fea 100644 --- a/Zotlabs/Module/Oep.php +++ b/Zotlabs/Module/Oep.php @@ -8,625 +8,630 @@ require_once('include/security.php'); // oembed provider +class Oep extends Controller +{ + + public function init() + { + + logger('oep: ' . print_r($_REQUEST, true), LOGGER_DEBUG, LOG_INFO); + + $html = ((argc() > 1 && argv(1) === 'html') ? true : false); + if ($_REQUEST['url']) { + $_REQUEST['url'] = strip_zids($_REQUEST['url']); + $url = $_REQUEST['url']; + } + + if (!$url) + http_status_exit(404, 'Not found'); + + $maxwidth = $_REQUEST['maxwidth']; + $maxheight = $_REQUEST['maxheight']; + $format = $_REQUEST['format']; + if ($format && $format !== 'json') + http_status_exit(501, 'Not implemented'); + + if (fnmatch('*/photos/*/album/*', $url)) + $arr = $this->oep_album_reply($_REQUEST); + elseif (fnmatch('*/photos/*/image/*', $url)) + $arr = $this->oep_photo_reply($_REQUEST); + elseif (fnmatch('*/photos*', $url)) + $arr = $this->oep_phototop_reply($_REQUEST); + elseif (fnmatch('*/display/*', $url)) + $arr = $this->oep_display_reply($_REQUEST); + elseif (fnmatch('*/channel/*mid=*', $url)) + $arr = $this->oep_mid_reply($_REQUEST); + elseif (fnmatch('*/channel*', $url)) + $arr = $this->oep_profile_reply($_REQUEST); + elseif (fnmatch('*/profile/*', $url)) + $arr = $this->oep_profile_reply($_REQUEST); + elseif (fnmatch('*/cards/*', $url)) + $arr = $this->oep_cards_reply($_REQUEST); + elseif (fnmatch('*/articles/*', $url)) + $arr = $this->oep_articles_reply($_REQUEST); + + if ($arr) { + if ($html) { + if ($arr['type'] === 'rich') { + header('Content-Type: text/html'); + echo $arr['html']; + } + } else { + header('Content-Type: application/json+oembed'); + echo json_encode($arr); + } + killme(); + } + + http_status_exit(404, 'Not found'); + + } + + public function oep_display_reply($args) + { + + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + if (preg_match('#//(.*?)/display/(.*?)(&|\?|$)#', $url, $matches)) { + $res = $matches[2]; + } + + $res = unpack_link_id($res); + + $item_normal = item_normal(); + + $p = q("select * from item where mid like '%s' limit 1", + dbesc($res . '%') + ); + + if (!$p) + return; + + $c = channelx_by_n($p[0]['uid']); -class Oep extends Controller { + if (!($c && $res)) + return; - function init() { - - logger('oep: ' . print_r($_REQUEST,true), LOGGER_DEBUG, LOG_INFO); - - $html = ((argc() > 1 && argv(1) === 'html') ? true : false); - if($_REQUEST['url']) { - $_REQUEST['url'] = strip_zids($_REQUEST['url']); - $url = $_REQUEST['url']; - } - - if(! $url) - http_status_exit(404, 'Not found'); - - $maxwidth = $_REQUEST['maxwidth']; - $maxheight = $_REQUEST['maxheight']; - $format = $_REQUEST['format']; - if($format && $format !== 'json') - http_status_exit(501, 'Not implemented'); - - if(fnmatch('*/photos/*/album/*',$url)) - $arr = $this->oep_album_reply($_REQUEST); - elseif(fnmatch('*/photos/*/image/*',$url)) - $arr = $this->oep_photo_reply($_REQUEST); - elseif(fnmatch('*/photos*',$url)) - $arr = $this->oep_phototop_reply($_REQUEST); - elseif(fnmatch('*/display/*',$url)) - $arr = $this->oep_display_reply($_REQUEST); - elseif(fnmatch('*/channel/*mid=*',$url)) - $arr = $this->oep_mid_reply($_REQUEST); - elseif(fnmatch('*/channel*',$url)) - $arr = $this->oep_profile_reply($_REQUEST); - elseif(fnmatch('*/profile/*',$url)) - $arr = $this->oep_profile_reply($_REQUEST); - elseif(fnmatch('*/cards/*',$url)) - $arr = $this->oep_cards_reply($_REQUEST); - elseif(fnmatch('*/articles/*',$url)) - $arr = $this->oep_articles_reply($_REQUEST); - - if($arr) { - if($html) { - if($arr['type'] === 'rich') { - header('Content-Type: text/html'); - echo $arr['html']; - } - } - else { - header('Content-Type: application/json+oembed'); - echo json_encode($arr); - } - killme(); - } - - http_status_exit(404,'Not found'); - - } - - function oep_display_reply($args) { - - $ret = []; - $url = $args['url']; - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); + if (!perm_is_allowed($c[0]['channel_id'], get_observer_hash(), 'view_stream')) + return; - if(preg_match('#//(.*?)/display/(.*?)(&|\?|$)#',$url,$matches)) { - $res = $matches[2]; - } + $sql_extra = item_permissions_sql($c['channel_id']); - $res = unpack_link_id($res); + $p = q("select * from item where mid like '%s' and uid = %d $sql_extra $item_normal limit 1", + dbesc($res . '%'), + intval($c['channel_id']) + ); - $item_normal = item_normal(); + if (!$p) + return; - $p = q("select * from item where mid like '%s' limit 1", - dbesc($res . '%') - ); + xchan_query($p, true); + $p = fetch_post_tags($p, true); - if(! $p) - return; + // This function can get tripped up if the item is already a reshare + // (the multiple share declarations do not parse cleanly if nested) + // So build a template with a known nonsense string as the content, and then + // replace that known string with the actual rendered content, sending + // each content layer through bbcode() separately. - $c = channelx_by_n($p[0]['uid']); - - - if(! ($c && $res)) - return; - - if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_stream')) - return; - - $sql_extra = item_permissions_sql($c['channel_id']); - - $p = q("select * from item where mid like '%s' and uid = %d $sql_extra $item_normal limit 1", - dbesc($res . '%'), - intval($c['channel_id']) - ); - - if(! $p) - return; - - xchan_query($p,true); - $p = fetch_post_tags($p,true); - - // This function can get tripped up if the item is already a reshare - // (the multiple share declarations do not parse cleanly if nested) - // So build a template with a known nonsense string as the content, and then - // replace that known string with the actual rendered content, sending - // each content layer through bbcode() separately. - - $x = '2eGriplW^*Jmf4'; - - - $o = "[share author='".urlencode($p[0]['author']['xchan_name']). - "' profile='".$p[0]['author']['xchan_url'] . - "' portable_id='".$p[0]['author']['xchan_hash'] . - "' avatar='".$p[0]['author']['xchan_photo_s']. - "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . - "' posted='".$p[0]['created']. - "' message_id='".$p[0]['mid']."']"; - if($p[0]['title']) - $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n"; - - $o .= $x; - $o .= "[/share]"; - $o = bbcode($o); - - $o = str_replace($x,bbcode($p[0]['body']),$o); - - $ret['type'] = 'rich'; - - $w = (($maxwidth) ? $maxwidth : 640); - $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); - - $ret['html'] = '
      ' . $o . '
      '; - - $ret['width'] = $w; - $ret['height'] = $h; - - return $ret; - - } + $x = '2eGriplW^*Jmf4'; - function oep_cards_reply($args) { - - $ret = []; - $url = $args['url']; - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); + $o = "[share author='" . urlencode($p[0]['author']['xchan_name']) . + "' profile='" . $p[0]['author']['xchan_url'] . + "' portable_id='" . $p[0]['author']['xchan_hash'] . + "' avatar='" . $p[0]['author']['xchan_photo_s'] . + "' link='" . $p[0]['plink'] . + "' auth='" . (($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . + "' posted='" . $p[0]['created'] . + "' message_id='" . $p[0]['mid'] . "']"; + if ($p[0]['title']) + $o .= '[b]' . $p[0]['title'] . '[/b]' . "\r\n"; - if(preg_match('#//(.*?)/cards/(.*?)/(.*?)(&|\?|$)#',$url,$matches)) { - $nick = $matches[2]; - $res = $matches[3]; - } - if(! ($nick && $res)) - return $ret; + $o .= $x; + $o .= "[/share]"; + $o = bbcode($o); - $channel = channelx_by_nick($nick); + $o = str_replace($x, bbcode($p[0]['body']), $o); - if(! $channel) - return $ret; + $ret['type'] = 'rich'; + + $w = (($maxwidth) ? $maxwidth : 640); + $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); + + $ret['html'] = '
      ' . $o . '
      '; + + $ret['width'] = $w; + $ret['height'] = $h; + + return $ret; + + } - if(! perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_pages')) - return $ret; + public function oep_cards_reply($args) + { - $sql_extra = item_permissions_sql($channel['channel_id'],get_observer_hash()); + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); - $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1", - dbesc($res) - ); - if($r) { - $sql_extra .= " and item.id = " . intval($r[0]['iid']) . " "; - } - else { - return $ret; - } + if (preg_match('#//(.*?)/cards/(.*?)/(.*?)(&|\?|$)#', $url, $matches)) { + $nick = $matches[2]; + $res = $matches[3]; + } + if (!($nick && $res)) + return $ret; - $r = q("select * from item + $channel = channelx_by_nick($nick); + + if (!$channel) + return $ret; + + + if (!perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_pages')) + return $ret; + + $sql_extra = item_permissions_sql($channel['channel_id'], get_observer_hash()); + + $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1", + dbesc($res) + ); + if ($r) { + $sql_extra .= " and item.id = " . intval($r[0]['iid']) . " "; + } else { + return $ret; + } + + $r = q("select * from item where item.uid = %d and item_type = %d $sql_extra order by item.created desc", - intval($channel['channel_id']), - intval(ITEM_TYPE_CARD) - ); + intval($channel['channel_id']), + intval(ITEM_TYPE_CARD) + ); - $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0 + $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 and item.item_blocked = 0 "; - if($r) { - xchan_query($r); - $p = fetch_post_tags($r, true); - } + if ($r) { + xchan_query($r); + $p = fetch_post_tags($r, true); + } - $x = '2eGriplW^*Jmf4'; - - - $o = "[share author='".urlencode($p[0]['author']['xchan_name']). - "' profile='".$p[0]['author']['xchan_url'] . - "' portable_id='".$p[0]['author']['xchan_hash'] . - "' avatar='".$p[0]['author']['xchan_photo_s']. - "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . - "' posted='".$p[0]['created']. - "' message_id='".$p[0]['mid']."']"; - if($p[0]['title']) - $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n"; - - $o .= $x; - $o .= "[/share]"; - $o = bbcode($o); - - $o = str_replace($x,bbcode($p[0]['body']),$o); - - $ret['type'] = 'rich'; - - $w = (($maxwidth) ? $maxwidth : 640); - $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); - - $ret['html'] = '
      ' . $o . '
      '; - - $ret['width'] = $w; - $ret['height'] = $h; - - return $ret; - - } - - function oep_articles_reply($args) { - - $ret = []; - $url = $args['url']; - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); - - if(preg_match('#//(.*?)/articles/(.*?)/(.*?)(&|\?|$)#',$url,$matches)) { - $nick = $matches[2]; - $res = $matches[3]; - } - if(! ($nick && $res)) - return $ret; - - $channel = channelx_by_nick($nick); - - if(! $channel) - return $ret; + $x = '2eGriplW^*Jmf4'; - if(! perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_pages')) - return $ret; + $o = "[share author='" . urlencode($p[0]['author']['xchan_name']) . + "' profile='" . $p[0]['author']['xchan_url'] . + "' portable_id='" . $p[0]['author']['xchan_hash'] . + "' avatar='" . $p[0]['author']['xchan_photo_s'] . + "' link='" . $p[0]['plink'] . + "' auth='" . (($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . + "' posted='" . $p[0]['created'] . + "' message_id='" . $p[0]['mid'] . "']"; + if ($p[0]['title']) + $o .= '[b]' . $p[0]['title'] . '[/b]' . "\r\n"; - $sql_extra = item_permissions_sql($channel['channel_id'],get_observer_hash()); + $o .= $x; + $o .= "[/share]"; + $o = bbcode($o); - $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.v = '%s' limit 1", - dbesc($res) - ); - if($r) { - $sql_extra .= " and item.id = " . intval($r[0]['iid']) . " "; - } - else { - return $ret; - } + $o = str_replace($x, bbcode($p[0]['body']), $o); - $r = q("select * from item + $ret['type'] = 'rich'; + + $w = (($maxwidth) ? $maxwidth : 640); + $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); + + $ret['html'] = '
      ' . $o . '
      '; + + $ret['width'] = $w; + $ret['height'] = $h; + + return $ret; + + } + + public function oep_articles_reply($args) + { + + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + if (preg_match('#//(.*?)/articles/(.*?)/(.*?)(&|\?|$)#', $url, $matches)) { + $nick = $matches[2]; + $res = $matches[3]; + } + if (!($nick && $res)) + return $ret; + + $channel = channelx_by_nick($nick); + + if (!$channel) + return $ret; + + + if (!perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_pages')) + return $ret; + + $sql_extra = item_permissions_sql($channel['channel_id'], get_observer_hash()); + + $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'ARTICLE' and iconfig.v = '%s' limit 1", + dbesc($res) + ); + if ($r) { + $sql_extra .= " and item.id = " . intval($r[0]['iid']) . " "; + } else { + return $ret; + } + + $r = q("select * from item where item.uid = %d and item_type = %d $sql_extra order by item.created desc", - intval($channel['channel_id']), - intval(ITEM_TYPE_ARTICLE) - ); + intval($channel['channel_id']), + intval(ITEM_TYPE_ARTICLE) + ); - $item_normal = " and item.item_hidden = 0 and item.item_type in (0,7) and item.item_deleted = 0 + $item_normal = " and item.item_hidden = 0 and item.item_type in (0,7) and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 and item.item_blocked = 0 "; - if($r) { - xchan_query($r); - $p = fetch_post_tags($r, true); - } + if ($r) { + xchan_query($r); + $p = fetch_post_tags($r, true); + } - $x = '2eGriplW^*Jmf4'; + $x = '2eGriplW^*Jmf4'; - - $o = "[share author='".urlencode($p[0]['author']['xchan_name']). - "' profile='".$p[0]['author']['xchan_url'] . - "' portable_id='".$p[0]['author']['xchan_hash'] . - "' avatar='".$p[0]['author']['xchan_photo_s']. - "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . - "' posted='".$p[0]['created']. - "' message_id='".$p[0]['mid']."']"; - if($p[0]['title']) - $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n"; - $o .= $x; - $o .= "[/share]"; - $o = bbcode($o); - - $o = str_replace($x,bbcode($p[0]['body']),$o); - - $ret['type'] = 'rich'; - - $w = (($maxwidth) ? $maxwidth : 640); - $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); - - $ret['html'] = '
      ' . $o . '
      '; - - $ret['width'] = $w; - $ret['height'] = $h; - - return $ret; - - } + $o = "[share author='" . urlencode($p[0]['author']['xchan_name']) . + "' profile='" . $p[0]['author']['xchan_url'] . + "' portable_id='" . $p[0]['author']['xchan_hash'] . + "' avatar='" . $p[0]['author']['xchan_photo_s'] . + "' link='" . $p[0]['plink'] . + "' auth='" . (($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . + "' posted='" . $p[0]['created'] . + "' message_id='" . $p[0]['mid'] . "']"; + if ($p[0]['title']) + $o .= '[b]' . $p[0]['title'] . '[/b]' . "\r\n"; - - function oep_mid_reply($args) { - - $ret = []; - $url = $args['url']; - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); - - if(preg_match('#//(.*?)/(.*?)/(.*?)/(.*?)mid\=(.*?)(&|$)#',$url,$matches)) { - $chn = $matches[3]; - $res = $matches[5]; - } - - if(! ($chn && $res)) - return; - $c = q("select * from channel where channel_address = '%s' limit 1", - dbesc($chn) - ); - - if(! $c) - return; + $o .= $x; + $o .= "[/share]"; + $o = bbcode($o); - if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_stream')) - return; - - $sql_extra = item_permissions_sql($c[0]['channel_id']); - - $p = q("select * from item where mid = '%s' and uid = %d $sql_extra limit 1", - dbesc($res), - intval($c[0]['channel_id']) - ); - if(! $p) - return; - - xchan_query($p,true); - $p = fetch_post_tags($p,true); + $o = str_replace($x, bbcode($p[0]['body']), $o); - // This function can get tripped up if the item is already a reshare - // (the multiple share declarations do not parse cleanly if nested) - // So build a template with a known nonsense string as the content, and then - // replace that known string with the actual rendered content, sending - // each content layer through bbcode() separately. + $ret['type'] = 'rich'; - $x = '2eGriplW^*Jmf4'; - - $o = "[share author='".urlencode($p[0]['author']['xchan_name']). - "' profile='".$p[0]['author']['xchan_url'] . - "' portable_id='".$p[0]['author']['xchan_hash'] . - "' avatar='".$p[0]['author']['xchan_photo_s']. - "' link='".$p[0]['plink']. - "' auth='".(($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . - "' posted='".$p[0]['created']. - "' message_id='".$p[0]['mid']."']"; - if($p[0]['title']) - $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n"; - $o .= $x; - $o .= "[/share]"; - $o = bbcode($o); - - $o = str_replace($x,bbcode($p[0]['body']),$o); + $w = (($maxwidth) ? $maxwidth : 640); + $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); - $ret['type'] = 'rich'; - - $w = (($maxwidth) ? $maxwidth : 640); - $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); - - $ret['html'] = '
      ' . $o . '
      '; - - $ret['width'] = $w; - $ret['height'] = $h; - - return $ret; - - } - - function oep_profile_reply($args) { - - - require_once('include/channel.php'); + $ret['html'] = '
      ' . $o . '
      '; - $url = $args['url']; - - if(preg_match('#//(.*?)/(.*?)/(.*?)(/|\?|&|$)#',$url,$matches)) { - $chn = $matches[3]; - } - - if(! $chn) - return; - - $c = channelx_by_nick($chn); - - if(! $c) - return; - - - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); - - $width = 800; - $height = 375; - - if($maxwidth) { - $width = $maxwidth; - $height = (375 / 800) * $width; - } - if($maxheight) { - if($maxheight < $height) { - $width = (800 / 375) * $maxheight; - $height = $maxheight; - } - } - $ret = []; - - $ret['type'] = 'rich'; - $ret['width'] = intval($width); - $ret['height'] = intval($height); - - $ret['html'] = get_zcard_embed($c,get_observer_hash(),array('width' => $width, 'height' => $height)); - - return $ret; - - } - - function oep_album_reply($args) { - - $ret = []; - $url = $args['url']; - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); - - if(preg_match('|//(.*?)/(.*?)/(.*?)/album/|',$url,$matches)) { - $chn = $matches[3]; - $res = basename($url); - } - - if(! ($chn && $res)) - return; - $c = q("select * from channel where channel_address = '%s' limit 1", - dbesc($chn) - ); - - if(! $c) - return; - - if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files')) - return; + $ret['width'] = $w; + $ret['height'] = $h; - $sql_extra = permissions_sql($c[0]['channel_id']); - - $p = q("select resource_id from photo where album = '%s' and uid = %d and imgscale = 0 $sql_extra order by created desc limit 1", - dbesc($res), - intval($c[0]['channel_id']) - ); - if(! $p) - return; - - $res = $p[0]['resource_id']; - - $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc", - intval($c[0]['channel_id']), - dbesc($res) - ); - - if($r) { - foreach($r as $rr) { - $foundres = false; - if($maxheight && $rr['height'] > $maxheight) - continue; - if($maxwidth && $rr['width'] > $maxwidth) - continue; - $foundres = true; - break; - } - - if($foundres) { - $ret['type'] = 'link'; - $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale']; - $ret['thumbnail_width'] = $rr['width']; - $ret['thumbnail_height'] = $rr['height']; - } - - - } - return $ret; - - } - - - function oep_phototop_reply($args) { - - $ret = []; - $url = $args['url']; - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); - - if(preg_match('|//(.*?)/(.*?)/(.*?)$|',$url,$matches)) { - $chn = $matches[3]; - } - - if(! $chn) - return; - $c = q("select * from channel where channel_address = '%s' limit 1", - dbesc($chn) - ); - - if(! $c) - return; - - if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files')) - return; + return $ret; - $sql_extra = permissions_sql($c[0]['channel_id']); - - $p = q("select resource_id from photo where uid = %d and imgscale = 0 $sql_extra order by created desc limit 1", - intval($c[0]['channel_id']) - ); - if(! $p) - return; - - $res = $p[0]['resource_id']; - - $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc", - intval($c[0]['channel_id']), - dbesc($res) - ); - - if($r) { - foreach($r as $rr) { - $foundres = false; - if($maxheight && $rr['height'] > $maxheight) - continue; - if($maxwidth && $rr['width'] > $maxwidth) - continue; - $foundres = true; - break; - } - - if($foundres) { - $ret['type'] = 'link'; - $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale']; - $ret['thumbnail_width'] = $rr['width']; - $ret['thumbnail_height'] = $rr['height']; - } - - - } - return $ret; - - } - - - function oep_photo_reply($args) { - - $ret = []; - $url = $args['url']; - $maxwidth = intval($args['maxwidth']); - $maxheight = intval($args['maxheight']); - - if(preg_match('|//(.*?)/(.*?)/(.*?)/image/|',$url,$matches)) { - $chn = $matches[3]; - $res = basename($url); - } - - if(! ($chn && $res)) - return; - $c = q("select * from channel where channel_address = '%s' limit 1", - dbesc($chn) - ); - - if(! $c) - return; + } - if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files')) - return; - $sql_extra = permissions_sql($c[0]['channel_id']); - - - $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc", - intval($c[0]['channel_id']), - dbesc($res) - ); - - if($r) { - foreach($r as $rr) { - $foundres = false; - if($maxheight && $rr['height'] > $maxheight) - continue; - if($maxwidth && $rr['width'] > $maxwidth) - continue; - $foundres = true; - break; - } - - if($foundres) { - $ret['type'] = 'link'; - $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale']; - $ret['thumbnail_width'] = $rr['width']; - $ret['thumbnail_height'] = $rr['height']; - } - - - } - return $ret; - - } + public function oep_mid_reply($args) + { + + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + if (preg_match('#//(.*?)/(.*?)/(.*?)/(.*?)mid\=(.*?)(&|$)#', $url, $matches)) { + $chn = $matches[3]; + $res = $matches[5]; + } + + if (!($chn && $res)) + return; + $c = q("select * from channel where channel_address = '%s' limit 1", + dbesc($chn) + ); + + if (!$c) + return; + + if (!perm_is_allowed($c[0]['channel_id'], get_observer_hash(), 'view_stream')) + return; + + $sql_extra = item_permissions_sql($c[0]['channel_id']); + + $p = q("select * from item where mid = '%s' and uid = %d $sql_extra limit 1", + dbesc($res), + intval($c[0]['channel_id']) + ); + if (!$p) + return; + + xchan_query($p, true); + $p = fetch_post_tags($p, true); + + // This function can get tripped up if the item is already a reshare + // (the multiple share declarations do not parse cleanly if nested) + // So build a template with a known nonsense string as the content, and then + // replace that known string with the actual rendered content, sending + // each content layer through bbcode() separately. + + $x = '2eGriplW^*Jmf4'; + + $o = "[share author='" . urlencode($p[0]['author']['xchan_name']) . + "' profile='" . $p[0]['author']['xchan_url'] . + "' portable_id='" . $p[0]['author']['xchan_hash'] . + "' avatar='" . $p[0]['author']['xchan_photo_s'] . + "' link='" . $p[0]['plink'] . + "' auth='" . (($p[0]['author']['network'] === 'zot6') ? 'true' : 'false') . + "' posted='" . $p[0]['created'] . + "' message_id='" . $p[0]['mid'] . "']"; + if ($p[0]['title']) + $o .= '[b]' . $p[0]['title'] . '[/b]' . "\r\n"; + $o .= $x; + $o .= "[/share]"; + $o = bbcode($o); + + $o = str_replace($x, bbcode($p[0]['body']), $o); + + $ret['type'] = 'rich'; + + $w = (($maxwidth) ? $maxwidth : 640); + $h = (($maxheight) ? $maxheight : intval($w * 2 / 3)); + + $ret['html'] = '
      ' . $o . '
      '; + + $ret['width'] = $w; + $ret['height'] = $h; + + return $ret; + + } + + public function oep_profile_reply($args) + { + + + require_once('include/channel.php'); + + $url = $args['url']; + + if (preg_match('#//(.*?)/(.*?)/(.*?)(/|\?|&|$)#', $url, $matches)) { + $chn = $matches[3]; + } + + if (!$chn) + return; + + $c = channelx_by_nick($chn); + + if (!$c) + return; + + + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + $width = 800; + $height = 375; + + if ($maxwidth) { + $width = $maxwidth; + $height = (375 / 800) * $width; + } + if ($maxheight) { + if ($maxheight < $height) { + $width = (800 / 375) * $maxheight; + $height = $maxheight; + } + } + $ret = []; + + $ret['type'] = 'rich'; + $ret['width'] = intval($width); + $ret['height'] = intval($height); + + $ret['html'] = get_zcard_embed($c, get_observer_hash(), array('width' => $width, 'height' => $height)); + + return $ret; + + } + + public function oep_album_reply($args) + { + + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + if (preg_match('|//(.*?)/(.*?)/(.*?)/album/|', $url, $matches)) { + $chn = $matches[3]; + $res = basename($url); + } + + if (!($chn && $res)) + return; + $c = q("select * from channel where channel_address = '%s' limit 1", + dbesc($chn) + ); + + if (!$c) + return; + + if (!perm_is_allowed($c[0]['channel_id'], get_observer_hash(), 'view_files')) + return; + + $sql_extra = permissions_sql($c[0]['channel_id']); + + $p = q("select resource_id from photo where album = '%s' and uid = %d and imgscale = 0 $sql_extra order by created desc limit 1", + dbesc($res), + intval($c[0]['channel_id']) + ); + if (!$p) + return; + + $res = $p[0]['resource_id']; + + $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc", + intval($c[0]['channel_id']), + dbesc($res) + ); + + if ($r) { + foreach ($r as $rr) { + $foundres = false; + if ($maxheight && $rr['height'] > $maxheight) + continue; + if ($maxwidth && $rr['width'] > $maxwidth) + continue; + $foundres = true; + break; + } + + if ($foundres) { + $ret['type'] = 'link'; + $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale']; + $ret['thumbnail_width'] = $rr['width']; + $ret['thumbnail_height'] = $rr['height']; + } + + + } + return $ret; + + } + + + public function oep_phototop_reply($args) + { + + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + if (preg_match('|//(.*?)/(.*?)/(.*?)$|', $url, $matches)) { + $chn = $matches[3]; + } + + if (!$chn) + return; + $c = q("select * from channel where channel_address = '%s' limit 1", + dbesc($chn) + ); + + if (!$c) + return; + + if (!perm_is_allowed($c[0]['channel_id'], get_observer_hash(), 'view_files')) + return; + + $sql_extra = permissions_sql($c[0]['channel_id']); + + $p = q("select resource_id from photo where uid = %d and imgscale = 0 $sql_extra order by created desc limit 1", + intval($c[0]['channel_id']) + ); + if (!$p) + return; + + $res = $p[0]['resource_id']; + + $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc", + intval($c[0]['channel_id']), + dbesc($res) + ); + + if ($r) { + foreach ($r as $rr) { + $foundres = false; + if ($maxheight && $rr['height'] > $maxheight) + continue; + if ($maxwidth && $rr['width'] > $maxwidth) + continue; + $foundres = true; + break; + } + + if ($foundres) { + $ret['type'] = 'link'; + $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale']; + $ret['thumbnail_width'] = $rr['width']; + $ret['thumbnail_height'] = $rr['height']; + } + + + } + return $ret; + + } + + + public function oep_photo_reply($args) + { + + $ret = []; + $url = $args['url']; + $maxwidth = intval($args['maxwidth']); + $maxheight = intval($args['maxheight']); + + if (preg_match('|//(.*?)/(.*?)/(.*?)/image/|', $url, $matches)) { + $chn = $matches[3]; + $res = basename($url); + } + + if (!($chn && $res)) + return; + $c = q("select * from channel where channel_address = '%s' limit 1", + dbesc($chn) + ); + + if (!$c) + return; + + if (!perm_is_allowed($c[0]['channel_id'], get_observer_hash(), 'view_files')) + return; + + $sql_extra = permissions_sql($c[0]['channel_id']); + + + $r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc", + intval($c[0]['channel_id']), + dbesc($res) + ); + + if ($r) { + foreach ($r as $rr) { + $foundres = false; + if ($maxheight && $rr['height'] > $maxheight) + continue; + if ($maxwidth && $rr['width'] > $maxwidth) + continue; + $foundres = true; + break; + } + + if ($foundres) { + $ret['type'] = 'link'; + $ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale']; + $ret['thumbnail_width'] = $rr['width']; + $ret['thumbnail_height'] = $rr['height']; + } + + + } + return $ret; + + } } diff --git a/Zotlabs/Module/Oexchange.php b/Zotlabs/Module/Oexchange.php index 950965a95..69d290f5c 100644 --- a/Zotlabs/Module/Oexchange.php +++ b/Zotlabs/Module/Oexchange.php @@ -5,73 +5,75 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Oexchange extends Controller { +class Oexchange extends Controller +{ + + public function init() + { + + if ((argc() > 1) && (argv(1) === 'xrd')) { + echo replace_macros(get_markup_template('oexchange_xrd.tpl'), ['$base' => z_root()]); + killme(); + } + } + + public function get() + { + if (!local_channel()) { + if (remote_channel()) { + $observer = App::get_observer(); + if ($observer && $observer['xchan_url']) { + $parsed = @parse_url($observer['xchan_url']); + if (!$parsed) { + notice(t('Unable to find your site.') . EOL); + return; + } + $url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); + $url .= '/oexchange'; + $result = z_post_url($url, $_REQUEST); + json_return_and_die($result); + } + } + + return login(false); + } + + if ((argc() > 1) && argv(1) === 'done') { + info(t('Post successful.') . EOL); + return; + } + + $url = (((x($_REQUEST, 'url')) && strlen($_REQUEST['url'])) + ? urlencode(notags(trim($_REQUEST['url']))) : ''); + $title = (((x($_REQUEST, 'title')) && strlen($_REQUEST['title'])) + ? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : ''); + $description = (((x($_REQUEST, 'description')) && strlen($_REQUEST['description'])) + ? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : ''); + $tags = (((x($_REQUEST, 'tags')) && strlen($_REQUEST['tags'])) + ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : ''); + + $ret = z_fetch_url(z_root() . '/linkinfo?f=&url=' . $url . $title . $description . $tags); + + if ($ret['success']) { + $s = $ret['body']; + } + + if (!strlen($s)) { + return; + } + + $post = []; + + $post['profile_uid'] = local_channel(); + $post['return'] = '/oexchange/done'; + $post['body'] = $s; + $post['type'] = 'wall'; + + $_REQUEST = $post; + $mod = new Item(); + $mod->post(); + + } + - function init() { - - if ((argc() > 1) && (argv(1) === 'xrd')) { - echo replace_macros(get_markup_template('oexchange_xrd.tpl'), [ '$base' => z_root() ] ); - killme(); - } - } - - function get() { - if (! local_channel()) { - if (remote_channel()) { - $observer = App::get_observer(); - if ($observer && $observer['xchan_url']) { - $parsed = @parse_url($observer['xchan_url']); - if (! $parsed) { - notice( t('Unable to find your site.') . EOL); - return; - } - $url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); - $url .= '/oexchange'; - $result = z_post_url($url,$_REQUEST); - json_return_and_die($result); - } - } - - return login(false); - } - - if ((argc() > 1) && argv(1) === 'done') { - info( t('Post successful.') . EOL); - return; - } - - $url = (((x($_REQUEST,'url')) && strlen($_REQUEST['url'])) - ? urlencode(notags(trim($_REQUEST['url']))) : ''); - $title = (((x($_REQUEST,'title')) && strlen($_REQUEST['title'])) - ? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : ''); - $description = (((x($_REQUEST,'description')) && strlen($_REQUEST['description'])) - ? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : ''); - $tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags'])) - ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : ''); - - $ret = z_fetch_url(z_root() . '/linkinfo?f=&url=' . $url . $title . $description . $tags); - - if ($ret['success']) { - $s = $ret['body']; - } - - if (! strlen($s)) { - return; - } - - $post = []; - - $post['profile_uid'] = local_channel(); - $post['return'] = '/oexchange/done' ; - $post['body'] = $s; - $post['type'] = 'wall'; - - $_REQUEST = $post; - $mod = new Item(); - $mod->post(); - - } - - - } diff --git a/Zotlabs/Module/Online.php b/Zotlabs/Module/Online.php index 30cd8d95e..c3d46940b 100644 --- a/Zotlabs/Module/Online.php +++ b/Zotlabs/Module/Online.php @@ -3,13 +3,15 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Online extends Controller { +class Online extends Controller +{ - function init() { - $ret = [ 'result' => false ]; - if (argc() != 2) { - json_return_and_die($ret); - } - json_return_and_die(get_online_status(argv(1))); - } + public function init() + { + $ret = ['result' => false]; + if (argc() != 2) { + json_return_and_die($ret); + } + json_return_and_die(get_online_status(argv(1))); + } } diff --git a/Zotlabs/Module/Outbox.php b/Zotlabs/Module/Outbox.php index 53fcbf516..68c5d9399 100644 --- a/Zotlabs/Module/Outbox.php +++ b/Zotlabs/Module/Outbox.php @@ -15,61 +15,61 @@ use Zotlabs\Lib\Config; /** * Implements an ActivityPub outbox. */ +class Outbox extends Controller +{ + public function post() + { + if (argc() < 2) { + killme(); + } -class Outbox extends Controller { + $channel = channelx_by_nick(argv(1)); + if (!$channel) { + killme(); + } - function post() { - if (argc() < 2) { - killme(); - } + if (intval($channel['channel_system'])) { + killme(); + } - $channel = channelx_by_nick(argv(1)); - if (! $channel) { - killme(); - } + // At this point there is unlikely to be an authenticated observer using the C2S ActivityPub API. + // Mostly we're protecting the page from malicious mischief until the project's OAuth2 interface + // is linked to this page. - if (intval($channel['channel_system'])) { - killme(); - } + $observer = App::get_observer(); + if (!$observer) { + killme(); + } - // At this point there is unlikely to be an authenticated observer using the C2S ActivityPub API. - // Mostly we're protecting the page from malicious mischief until the project's OAuth2 interface - // is linked to this page. - - $observer = App::get_observer(); - if (! $observer) { - killme(); - } - - if ($observer['xchan_hash'] !== $channel['channel_hash']) { - if (! perm_is_allowed($channel['channel_id'],$observer['xchan_hash'],'post_wall')) { - logger('outbox post permission denied to ' . $observer['xchan_name']); - killme(); - } - } + if ($observer['xchan_hash'] !== $channel['channel_hash']) { + if (!perm_is_allowed($channel['channel_id'], $observer['xchan_hash'], 'post_wall')) { + logger('outbox post permission denied to ' . $observer['xchan_name']); + killme(); + } + } // disable C2S until we've fully tested it. -return; + return; - $data = file_get_contents('php://input'); - if (! $data) { - return; - } + $data = file_get_contents('php://input'); + if (!$data) { + return; + } - logger('outbox_activity: ' . jindent($data), LOGGER_DATA); - - $AS = new ActivityStreams($data); + logger('outbox_activity: ' . jindent($data), LOGGER_DATA); - if (! $AS->is_valid()) { - return; - } - - if (! PConfig::Get($channel['channel_id'],'system','activitypub',Config::Get('system','activitypub',ACTIVITYPUB_ENABLED))) { - return; - } - - logger('outbox_channel: ' . $channel['channel_address'],LOGGER_DEBUG); + $AS = new ActivityStreams($data); + + if (!$AS->is_valid()) { + return; + } + + if (!PConfig::Get($channel['channel_id'], 'system', 'activitypub', Config::Get('system', 'activitypub', ACTIVITYPUB_ENABLED))) { + return; + } + + logger('outbox_channel: ' . $channel['channel_address'], LOGGER_DEBUG); // switch ($AS->type) { // case 'Follow': @@ -105,209 +105,207 @@ return; // // } - // These activities require permissions + // These activities require permissions - $item = null; + $item = null; - switch ($AS->type) { - case 'Update': - if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { - // pretend this is an old cache entry to force an update of all the actor details - $AS->obj['cached'] = true; - $AS->obj['updated'] = datetime_convert('UTC','UTC','1980-01-01', ATOM_TIME); - Activity::actor_store($AS->obj['id'],$AS->obj); - break; - } - case 'Accept': - if (is_array($AS->obj) && array_key_exists('type',$AS->obj) && (ActivityStreams::is_an_actor($AS->obj['type']) || $AS->obj['type'] === 'Member')) { - break; - } - case 'Create': - case 'Like': - case 'Dislike': - case 'Announce': - case 'Reject': - case 'TentativeAccept': - case 'TentativeReject': - case 'Add': - case 'Arrive': - case 'Block': - case 'Flag': - case 'Ignore': - case 'Invite': - case 'Listen': - case 'Move': - case 'Offer': - case 'Question': - case 'Read': - case 'Travel': - case 'View': - case 'emojiReaction': - case 'EmojiReaction': - case 'EmojiReact': - // These require a resolvable object structure - if (is_array($AS->obj)) { - // The boolean flag enables html cache of the item - $item = Activity::decode_note($AS,true); - } - else { - logger('unresolved object: ' . print_r($AS->obj,true)); - } - break; - case 'Undo': - if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Follow') { - // do unfollow activity - Activity::unfollow($channel,$AS); - break; - } - case 'Leave': - if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { - // do unfollow activity - Activity::unfollow($channel,$AS); - break; - } - case 'Tombstone': - case 'Delete': - Activity::drop($channel,$observer_hash,$AS); - break; - case 'Move': - if($observer_hash && $observer_hash === $AS->actor - && is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStream::is_an_actor($AS->obj['type']) - && is_array($AS->tgt) && array_key_exists('type', $AS->tgt) && ActivityStream::is_an_actor($AS->tgt['type'])) { - ActivityPub::move($AS->obj,$AS->tgt); - } - break; - case 'Add': - case 'Remove': - default: - break; + switch ($AS->type) { + case 'Update': + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStreams::is_an_actor($AS->obj['type'])) { + // pretend this is an old cache entry to force an update of all the actor details + $AS->obj['cached'] = true; + $AS->obj['updated'] = datetime_convert('UTC', 'UTC', '1980-01-01', ATOM_TIME); + Activity::actor_store($AS->obj['id'], $AS->obj); + break; + } + case 'Accept': + if (is_array($AS->obj) && array_key_exists('type', $AS->obj) && (ActivityStreams::is_an_actor($AS->obj['type']) || $AS->obj['type'] === 'Member')) { + break; + } + case 'Create': + case 'Like': + case 'Dislike': + case 'Announce': + case 'Reject': + case 'TentativeAccept': + case 'TentativeReject': + case 'Add': + case 'Arrive': + case 'Block': + case 'Flag': + case 'Ignore': + case 'Invite': + case 'Listen': + case 'Move': + case 'Offer': + case 'Question': + case 'Read': + case 'Travel': + case 'View': + case 'emojiReaction': + case 'EmojiReaction': + case 'EmojiReact': + // These require a resolvable object structure + if (is_array($AS->obj)) { + // The boolean flag enables html cache of the item + $item = Activity::decode_note($AS, true); + } else { + logger('unresolved object: ' . print_r($AS->obj, true)); + } + break; + case 'Undo': + if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Follow') { + // do unfollow activity + Activity::unfollow($channel, $AS); + break; + } + case 'Leave': + if ($AS->obj && is_array($AS->obj) && array_key_exists('type', $AS->obj) && $AS->obj['type'] === 'Group') { + // do unfollow activity + Activity::unfollow($channel, $AS); + break; + } + case 'Tombstone': + case 'Delete': + Activity::drop($channel, $observer_hash, $AS); + break; + case 'Move': + if ($observer_hash && $observer_hash === $AS->actor + && is_array($AS->obj) && array_key_exists('type', $AS->obj) && ActivityStream::is_an_actor($AS->obj['type']) + && is_array($AS->tgt) && array_key_exists('type', $AS->tgt) && ActivityStream::is_an_actor($AS->tgt['type'])) { + ActivityPub::move($AS->obj, $AS->tgt); + } + break; + case 'Add': + case 'Remove': + default: + break; - } + } - if ($item) { - logger('parsed_item: ' . print_r($item,true),LOGGER_DATA); - Activity::store($channel,$observer_hash,$AS,$item); - } + if ($item) { + logger('parsed_item: ' . print_r($item, true), LOGGER_DATA); + Activity::store($channel, $observer_hash, $AS, $item); + } - http_status_exit(200,'OK'); - return; + http_status_exit(200, 'OK'); + return; - } + } - function get() { + public function get() + { - if (observer_prohibited(true)) { - killme(); - } + if (observer_prohibited(true)) { + killme(); + } - if (argc() < 2) { - killme(); - } + if (argc() < 2) { + killme(); + } - $channel = channelx_by_nick(argv(1)); - if (! $channel) { - killme(); - } + $channel = channelx_by_nick(argv(1)); + if (!$channel) { + killme(); + } // if (intval($channel['channel_system'])) { // killme(); // } - - if (ActivityStreams::is_as_request()) { - $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { - http_status_exit(403, 'Permission denied'); - } - if (! check_siteallowed($sigdata['signer'])) { - http_status_exit(403, 'Permission denied'); - } - observer_auth($portable_id); - } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); - } - $observer_hash = get_observer_hash(); + if (ActivityStreams::is_as_request()) { + $sigdata = HTTPSig::verify(($_SERVER['REQUEST_METHOD'] === 'POST') ? file_get_contents('php://input') : EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (!check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (!check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + } elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); + } - $params = []; - - $params['begin'] = ((x($_REQUEST,'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE); - $params['end'] = ((x($_REQUEST,'date_end')) ? $_REQUEST['date_end'] : ''); - $params['type'] = 'json'; - $params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0); - $params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0); - $params['direction'] = ((x($_REQUEST,'direction')) ? dbesc($_REQUEST['direction']) : 'desc'); // unimplemented - $params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : ''); - $params['compat'] = 1; + $observer_hash = get_observer_hash(); - - $total = items_fetch( - [ - 'total' => true, - 'wall' => '1', - 'datequery' => $params['end'], - 'datequery2' => $params['begin'], - 'direction' => dbesc($params['direction']), - 'pages' => $params['pages'], - 'order' => dbesc('post'), - 'top' => $params['top'], - 'cat' => $params['cat'], - 'compat' => $params['compat'] - ], $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module - ); + $params = []; - if ($total) { - App::set_pager_total($total); - App::set_pager_itemspage(100); - } + $params['begin'] = ((x($_REQUEST, 'date_begin')) ? $_REQUEST['date_begin'] : NULL_DATE); + $params['end'] = ((x($_REQUEST, 'date_end')) ? $_REQUEST['date_end'] : ''); + $params['type'] = 'json'; + $params['pages'] = ((x($_REQUEST, 'pages')) ? intval($_REQUEST['pages']) : 0); + $params['top'] = ((x($_REQUEST, 'top')) ? intval($_REQUEST['top']) : 0); + $params['direction'] = ((x($_REQUEST, 'direction')) ? dbesc($_REQUEST['direction']) : 'desc'); // unimplemented + $params['cat'] = ((x($_REQUEST, 'cat')) ? escape_tags($_REQUEST['cat']) : ''); + $params['compat'] = 1; - if (App::$pager['unset'] && $total > 100) { - $ret = Activity::paged_collection_init($total,App::$query_string); - } - else { - $items = items_fetch( - [ - 'wall' => '1', - 'datequery' => $params['end'], - 'datequery2' => $params['begin'], - 'records' => intval(App::$pager['itemspage']), - 'start' => intval(App::$pager['start']), - 'direction' => dbesc($params['direction']), - 'pages' => $params['pages'], - 'order' => dbesc('post'), - 'top' => $params['top'], - 'cat' => $params['cat'], - 'compat' => $params['compat'] - ], $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module - ); - if ($items && $observer_hash) { + $total = items_fetch( + [ + 'total' => true, + 'wall' => '1', + 'datequery' => $params['end'], + 'datequery2' => $params['begin'], + 'direction' => dbesc($params['direction']), + 'pages' => $params['pages'], + 'order' => dbesc('post'), + 'top' => $params['top'], + 'cat' => $params['cat'], + 'compat' => $params['compat'] + ], $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module + ); - // check to see if this observer is a connection. If not, register any items - // belonging to this channel for notification of deletion/expiration - - $x = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", - intval($channel['channel_id']), - dbesc($observer_hash) - ); - if (! $x) { - foreach ($items as $item) { - if (strpos($item['mid'], z_root()) === 0) { - ThreadListener::store($item['mid'],$observer_hash); - } - } - } - } + if ($total) { + App::set_pager_total($total); + App::set_pager_itemspage(100); + } - $ret = Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection',true, $total); - } + if (App::$pager['unset'] && $total > 100) { + $ret = Activity::paged_collection_init($total, App::$query_string); + } else { + $items = items_fetch( + [ + 'wall' => '1', + 'datequery' => $params['end'], + 'datequery2' => $params['begin'], + 'records' => intval(App::$pager['itemspage']), + 'start' => intval(App::$pager['start']), + 'direction' => dbesc($params['direction']), + 'pages' => $params['pages'], + 'order' => dbesc('post'), + 'top' => $params['top'], + 'cat' => $params['cat'], + 'compat' => $params['compat'] + ], $channel, $observer_hash, CLIENT_MODE_NORMAL, App::$module + ); - as_return_and_die($ret,$channel); - } - } + if ($items && $observer_hash) { + + // check to see if this observer is a connection. If not, register any items + // belonging to this channel for notification of deletion/expiration + + $x = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s'", + intval($channel['channel_id']), + dbesc($observer_hash) + ); + if (!$x) { + foreach ($items as $item) { + if (strpos($item['mid'], z_root()) === 0) { + ThreadListener::store($item['mid'], $observer_hash); + } + } + } + } + + $ret = Activity::encode_item_collection($items, App::$query_string, 'OrderedCollection', true, $total); + } + + as_return_and_die($ret, $channel); + } + } } diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php index 0bae6d0e8..c338be9e2 100644 --- a/Zotlabs/Module/Owa.php +++ b/Zotlabs/Module/Owa.php @@ -15,59 +15,60 @@ use Zotlabs\Web\Controller; * * This token may be exchanged for an authenticated cookie. */ +class Owa extends Controller +{ -class Owa extends Controller { + public function init() + { - function init() { + $ret = ['success' => false]; - $ret = [ 'success' => false ]; + if (array_key_exists('REDIRECT_REMOTE_USER', $_SERVER) && (!array_key_exists('HTTP_AUTHORIZATION', $_SERVER))) { + $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER']; + } - if (array_key_exists('REDIRECT_REMOTE_USER',$_SERVER) && (! array_key_exists('HTTP_AUTHORIZATION',$_SERVER))) { - $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER['REDIRECT_REMOTE_USER']; - } - - if (array_key_exists('HTTP_AUTHORIZATION',$_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']),0,9) === 'Signature') { - $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']); - if ($sigblock) { - $keyId = $sigblock['keyId']; - if ($keyId) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash + if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER) && substr(trim($_SERVER['HTTP_AUTHORIZATION']), 0, 9) === 'Signature') { + $sigblock = HTTPSig::parse_sigheader($_SERVER['HTTP_AUTHORIZATION']); + if ($sigblock) { + $keyId = $sigblock['keyId']; + if ($keyId) { + $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) and xchan_pubkey != '' ", - dbesc(str_replace('acct:','',$keyId)), - dbesc($keyId) - ); - if (! $r) { - $found = discover_by_webbie(str_replace('acct:','',$keyId)); - if ($found) { - $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash + dbesc(str_replace('acct:', '', $keyId)), + dbesc($keyId) + ); + if (!$r) { + $found = discover_by_webbie(str_replace('acct:', '', $keyId)); + if ($found) { + $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) and xchan_pubkey != '' ", - dbesc(str_replace('acct:','',$keyId)), - dbesc($keyId) - ); - } - } - if ($r) { - foreach ($r as $hubloc) { - $verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']); - if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (! $verified['content_signed']))) { - logger('OWA header: ' . print_r($verified,true),LOGGER_DATA); - logger('OWA success: ' . $hubloc['hubloc_addr'],LOGGER_DATA); - $ret['success'] = true; - $token = random_string(32); - Verify::create('owt',0,$token,$hubloc['hubloc_addr']); - $result = ''; - openssl_public_encrypt($token,$result,$hubloc['xchan_pubkey']); - $ret['encrypted_token'] = base64url_encode($result); - break; - } else { - logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']); - } - } - } - } - } - } - json_return_and_die($ret,'application/x-zot+json'); - } + dbesc(str_replace('acct:', '', $keyId)), + dbesc($keyId) + ); + } + } + if ($r) { + foreach ($r as $hubloc) { + $verified = HTTPSig::verify(file_get_contents('php://input'), $hubloc['xchan_pubkey']); + if ($verified && $verified['header_signed'] && $verified['header_valid'] && ($verified['content_valid'] || (!$verified['content_signed']))) { + logger('OWA header: ' . print_r($verified, true), LOGGER_DATA); + logger('OWA success: ' . $hubloc['hubloc_addr'], LOGGER_DATA); + $ret['success'] = true; + $token = random_string(32); + Verify::create('owt', 0, $token, $hubloc['hubloc_addr']); + $result = ''; + openssl_public_encrypt($token, $result, $hubloc['xchan_pubkey']); + $ret['encrypted_token'] = base64url_encode($result); + break; + } else { + logger('OWA fail: ' . $hubloc['hubloc_id'] . ' ' . $hubloc['hubloc_addr']); + } + } + } + } + } + } + json_return_and_die($ret, 'application/x-zot+json'); + } } diff --git a/Zotlabs/Module/Page.php b/Zotlabs/Module/Page.php index b6d21d043..20b582041 100644 --- a/Zotlabs/Module/Page.php +++ b/Zotlabs/Module/Page.php @@ -10,186 +10,186 @@ use Zotlabs\Lib\Libprofile; require_once('include/conversation.php'); -class Page extends Controller { +class Page extends Controller +{ - function init() { - // We need this to make sure the channel theme is always loaded. - - $which = argv(1); - $profile = 0; - Libprofile::load($which,$profile); - - - - if(App::$profile['profile_uid']) - head_set_icon(App::$profile['thumb']); - - // load the item here in the init function because we need to extract - // the page layout and initialise the correct theme. - - - $observer = App::get_observer(); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - - - // perm_is_allowed is denied unconditionally when 'site blocked to unauthenticated members'. - // This bypasses that restriction for sys channel (public) content - - if((! perm_is_allowed(App::$profile['profile_uid'],$ob_hash,'view_pages')) && (! is_sys_channel(App::$profile['profile_uid']))) { - notice( t('Permission denied.') . EOL); - return; - } - - if(argc() < 3) { - notice( t('Invalid item.') . EOL); - return; - } - - $channel_address = argv(1); - - // Always look first for the page name prefixed by the observer language; for instance page/nickname/de/foo - // followed by page/nickname/foo if that is not found. - // If your browser language is de and you want to access the default in this case, - // use page/nickname/-/foo to over-ride the language and access only the page with pagelink of 'foo' + public function init() + { + // We need this to make sure the channel theme is always loaded. - $page_name = ''; - $ignore_language = false; - - for($x = 2; $x < argc(); $x ++) { - if($page_name === '' && argv($x) === '-') { - $ignore_language = true; - continue; - } - if($page_name) - $page_name .= '/'; - $page_name .= argv($x); - } + $which = argv(1); + $profile = 0; + Libprofile::load($which, $profile); - // The page link title was stored in a urlencoded format - // php or the browser may/will have decoded it, so re-encode it for our search - - $page_id = urlencode($page_name); - $lang_page_id = urlencode(App::$language . '/' . $page_name); + if (App::$profile['profile_uid']) + head_set_icon(App::$profile['thumb']); - $u = q("select channel_id from channel where channel_address = '%s' limit 1", - dbesc($channel_address) - ); - - if(! $u) { - notice( t('Channel not found.') . EOL); - return; - } - - if($_REQUEST['rev']) - $revision = " and revision = " . intval($_REQUEST['rev']) . " "; - else - $revision = " order by revision desc "; - - require_once('include/security.php'); - $sql_options = item_permissions_sql($u[0]['channel_id']); + // load the item here in the init function because we need to extract + // the page layout and initialise the correct theme. - $r = null; - if(! $ignore_language) { - $r = q("select item.* from item left join iconfig on item.id = iconfig.iid + $observer = App::get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + + // perm_is_allowed is denied unconditionally when 'site blocked to unauthenticated members'. + // This bypasses that restriction for sys channel (public) content + + if ((!perm_is_allowed(App::$profile['profile_uid'], $ob_hash, 'view_pages')) && (!is_sys_channel(App::$profile['profile_uid']))) { + notice(t('Permission denied.') . EOL); + return; + } + + if (argc() < 3) { + notice(t('Invalid item.') . EOL); + return; + } + + $channel_address = argv(1); + + // Always look first for the page name prefixed by the observer language; for instance page/nickname/de/foo + // followed by page/nickname/foo if that is not found. + // If your browser language is de and you want to access the default in this case, + // use page/nickname/-/foo to over-ride the language and access only the page with pagelink of 'foo' + + $page_name = ''; + $ignore_language = false; + + for ($x = 2; $x < argc(); $x++) { + if ($page_name === '' && argv($x) === '-') { + $ignore_language = true; + continue; + } + if ($page_name) + $page_name .= '/'; + $page_name .= argv($x); + } + + + // The page link title was stored in a urlencoded format + // php or the browser may/will have decoded it, so re-encode it for our search + + $page_id = urlencode($page_name); + $lang_page_id = urlencode(App::$language . '/' . $page_name); + + $u = q("select channel_id from channel where channel_address = '%s' limit 1", + dbesc($channel_address) + ); + + if (!$u) { + notice(t('Channel not found.') . EOL); + return; + } + + if ($_REQUEST['rev']) + $revision = " and revision = " . intval($_REQUEST['rev']) . " "; + else + $revision = " order by revision desc "; + + require_once('include/security.php'); + $sql_options = item_permissions_sql($u[0]['channel_id']); + + $r = null; + + if (!$ignore_language) { + $r = q("select item.* from item left join iconfig on item.id = iconfig.iid where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0 and iconfig.k = 'WEBPAGE' and item_type = %d $sql_options $revision limit 1", - intval($u[0]['channel_id']), - dbesc($lang_page_id), - intval(ITEM_TYPE_WEBPAGE) - ); - } - if(! $r) { - $r = q("select item.* from item left join iconfig on item.id = iconfig.iid + intval($u[0]['channel_id']), + dbesc($lang_page_id), + intval(ITEM_TYPE_WEBPAGE) + ); + } + if (!$r) { + $r = q("select item.* from item left join iconfig on item.id = iconfig.iid where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0 and iconfig.k = 'WEBPAGE' and item_type = %d $sql_options $revision limit 1", - intval($u[0]['channel_id']), - dbesc($page_id), - intval(ITEM_TYPE_WEBPAGE) - ); - } - if(! $r) { - // no webpage by that name, but we do allow you to load/preview a layout using this module. Try that. - $r = q("select item.* from item left join iconfig on item.id = iconfig.iid + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_TYPE_WEBPAGE) + ); + } + if (!$r) { + // no webpage by that name, but we do allow you to load/preview a layout using this module. Try that. + $r = q("select item.* from item left join iconfig on item.id = iconfig.iid where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0 and iconfig.k = 'PDL' AND item_type = %d $sql_options $revision limit 1", - intval($u[0]['channel_id']), - dbesc($page_id), - intval(ITEM_TYPE_PDL) - ); - } - if(! $r) { - - // Check again with no permissions clause to see if it is a permissions issue - - $x = q("select item.* from item left join iconfig on item.id = iconfig.iid + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_TYPE_PDL) + ); + } + if (!$r) { + + // Check again with no permissions clause to see if it is a permissions issue + + $x = q("select item.* from item left join iconfig on item.id = iconfig.iid where item.uid = %d and iconfig.cat = 'system' and iconfig.v = '%s' and item.item_delayed = 0 and iconfig.k = 'WEBPAGE' and item_type = %d $revision limit 1", - intval($u[0]['channel_id']), - dbesc($page_id), - intval(ITEM_TYPE_WEBPAGE) - ); - - if($x) { - // Yes, it's there. You just aren't allowed to see it. - notice( t('Permission denied.') . EOL); - } - else { - notice( t('Page not found.') . EOL); - } - return; - } + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_TYPE_WEBPAGE) + ); + + if ($x) { + // Yes, it's there. You just aren't allowed to see it. + notice(t('Permission denied.') . EOL); + } else { + notice(t('Page not found.') . EOL); + } + return; + } + + if ($r[0]['title']) + App::$page['title'] = escape_tags($r[0]['title']); + + if ($r[0]['item_type'] == ITEM_TYPE_PDL) { + App::$comanche = new Comanche(); + App::$comanche->parse($r[0]['body']); + App::$pdl = $r[0]['body']; + } elseif ($r[0]['layout_mid']) { + $l = q("select body from item where mid = '%s' and uid = %d limit 1", + dbesc($r[0]['layout_mid']), + intval($u[0]['channel_id']) + ); + + if ($l) { + App::$comanche = new Comanche(); + App::$comanche->parse($l[0]['body']); + App::$pdl = $l[0]['body']; + } + } + + App::$data['webpage'] = $r; + + } + + public function get() + { + + $r = App::$data['webpage']; + if (!$r) + return; + + if ($r[0]['item_type'] == ITEM_TYPE_PDL) { + $r[0]['body'] = t('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); + $r[0]['mimetype'] = 'text/plain'; + $r[0]['title'] = ''; + + } + + xchan_query($r); + $r = fetch_post_tags($r, true); + + if ($r[0]['mimetype'] === 'application/x-pdl') + App::$page['pdl_content'] = true; + + $o .= prepare_page($r[0]); + return $o; + + } - if($r[0]['title']) - App::$page['title'] = escape_tags($r[0]['title']); - - if($r[0]['item_type'] == ITEM_TYPE_PDL) { - App::$comanche = new Comanche(); - App::$comanche->parse($r[0]['body']); - App::$pdl = $r[0]['body']; - } - elseif($r[0]['layout_mid']) { - $l = q("select body from item where mid = '%s' and uid = %d limit 1", - dbesc($r[0]['layout_mid']), - intval($u[0]['channel_id']) - ); - - if($l) { - App::$comanche = new Comanche(); - App::$comanche->parse($l[0]['body']); - App::$pdl = $l[0]['body']; - } - } - - App::$data['webpage'] = $r; - - } - - function get() { - - $r = App::$data['webpage']; - if(! $r) - return; - - if($r[0]['item_type'] == ITEM_TYPE_PDL) { - $r[0]['body'] = t('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); - $r[0]['mimetype'] = 'text/plain'; - $r[0]['title'] = ''; - - } - - xchan_query($r); - $r = fetch_post_tags($r,true); - - if($r[0]['mimetype'] === 'application/x-pdl') - App::$page['pdl_content'] = true; - - $o .= prepare_page($r[0]); - return $o; - - } - } diff --git a/Zotlabs/Module/Pconfig.php b/Zotlabs/Module/Pconfig.php index a340488f7..ee048fefa 100644 --- a/Zotlabs/Module/Pconfig.php +++ b/Zotlabs/Module/Pconfig.php @@ -6,141 +6,140 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; +class Pconfig extends Controller +{ -class Pconfig extends Controller { + public function post() + { - function post() { - - if (! local_channel()) { - return; - } - - if (isset($_SESSION['delegate']) && $_SESSION['delegate']) { - return; - } - - check_form_security_token_redirectOnErr('/pconfig', 'pconfig'); - - $cat = trim(escape_tags((isset($_POST['cat']) && $_POST['cat']) ? $_POST['cat'] : EMPTY_STR)); - $k = trim(escape_tags((isset($_POST['k']) && $_POST['k']) ? $_POST['k'] : EMPTY_STR)); - $v = trim((isset($_POST['v']) && $_POST['v']) ? $_POST['v'] : EMPTY_STR); - $aj = intval((isset($_POST['aj']) && $_POST['aj']) ? $_POST['aj'] : 0); + if (!local_channel()) { + return; + } - // Do not store "serialized" data received in the $_POST - - if (preg_match('|^a:[0-9]+:{.*}$|s',$v)) { - return; - } - - if (in_array(argv(2),$this->disallowed_pconfig())) { - notice( t('This setting requires special processing and editing has been blocked.') . EOL); - return; - } - - if (strpos($k,'password') !== false) { - $v = obscurify($v); - } - - set_pconfig(local_channel(),$cat,$k,$v); - Libsync::build_sync_packet(); - - if ($aj) { - killme(); - } + if (isset($_SESSION['delegate']) && $_SESSION['delegate']) { + return; + } - goaway(z_root() . '/pconfig/' . $cat . '/' . $k); - - } - - - function get() { - - if (! local_channel()) { - return login(); - } - - $content = '

      ' . t('Configuration Editor') . '

      '; - $content .= '
      ' . t('Warning: Changing some settings could render your channel inoperable. Please leave this page unless you are comfortable with and knowledgeable about how to correctly use this feature.') . '
      ' . EOL . EOL; - - - - if(argc() == 3) { - $content .= 'pconfig[' . local_channel() . ']' . EOL; - $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . ']' . EOL . EOL; - $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . '][' . escape_tags(argv(2)) . '] = ' . get_pconfig(local_channel(),escape_tags(argv(1)),escape_tags(argv(2))) . EOL; - - if(in_array(argv(2),$this->disallowed_pconfig())) { - notice( t('This setting requires special processing and editing has been blocked.') . EOL); - return $content; - } - else - $content .= $this->pconfig_form(escape_tags(argv(1)),escape_tags(argv(2))); - } - - - if(argc() == 2) { - $content .= 'pconfig[' . local_channel() . ']' . EOL; - load_pconfig(local_channel(),escape_tags(argv(1))); - if(App::$config[local_channel()][escape_tags(argv(1))]) { - foreach(App::$config[local_channel()][escape_tags(argv(1))] as $k => $x) { - $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . '][' . $k . '] = ' . escape_tags($x) . EOL; - } - } - } - - if(argc() == 1) { - - $r = q("select * from pconfig where uid = " . local_channel()); - if($r) { - foreach($r as $rr) { - $content .= 'pconfig[' . local_channel() . '][' . escape_tags($rr['cat']) . '][' . escape_tags($rr['k']) . '] = ' . escape_tags($rr['v']) . EOL; - } - } - } - return $content; - - } - - - function pconfig_form($cat,$k) { - - $o = '
      '; - $o .= ''; - - $v = get_pconfig(local_channel(),$cat,$k); - if(strpos($k,'password') !== false) - $v = unobscurify($v); - - $o .= ''; - $o .= ''; + check_form_security_token_redirectOnErr('/pconfig', 'pconfig'); - + $cat = trim(escape_tags((isset($_POST['cat']) && $_POST['cat']) ? $_POST['cat'] : EMPTY_STR)); + $k = trim(escape_tags((isset($_POST['k']) && $_POST['k']) ? $_POST['k'] : EMPTY_STR)); + $v = trim((isset($_POST['v']) && $_POST['v']) ? $_POST['v'] : EMPTY_STR); + $aj = intval((isset($_POST['aj']) && $_POST['aj']) ? $_POST['aj'] : 0); - if(strpos($v,"\n")) - $o .= ''; - else { - if (is_array($v)) { - $o .= '
      ' . "\n" . print_array($v) . '
      '; - $o .= ''; - } - else { - $o .= ''; - } - } - $o .= EOL . EOL; - $o .= ''; - $o .= '
      '; - - return $o; - - } + // Do not store "serialized" data received in the $_POST + + if (preg_match('|^a:[0-9]+:{.*}$|s', $v)) { + return; + } + + if (in_array(argv(2), $this->disallowed_pconfig())) { + notice(t('This setting requires special processing and editing has been blocked.') . EOL); + return; + } + + if (strpos($k, 'password') !== false) { + $v = obscurify($v); + } + + set_pconfig(local_channel(), $cat, $k, $v); + Libsync::build_sync_packet(); + + if ($aj) { + killme(); + } + + goaway(z_root() . '/pconfig/' . $cat . '/' . $k); + + } + public function get() + { + + if (!local_channel()) { + return login(); + } + + $content = '

      ' . t('Configuration Editor') . '

      '; + $content .= '
      ' . t('Warning: Changing some settings could render your channel inoperable. Please leave this page unless you are comfortable with and knowledgeable about how to correctly use this feature.') . '
      ' . EOL . EOL; + + + if (argc() == 3) { + $content .= 'pconfig[' . local_channel() . ']' . EOL; + $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . ']' . EOL . EOL; + $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . '][' . escape_tags(argv(2)) . '] = ' . get_pconfig(local_channel(), escape_tags(argv(1)), escape_tags(argv(2))) . EOL; + + if (in_array(argv(2), $this->disallowed_pconfig())) { + notice(t('This setting requires special processing and editing has been blocked.') . EOL); + return $content; + } else + $content .= $this->pconfig_form(escape_tags(argv(1)), escape_tags(argv(2))); + } + + + if (argc() == 2) { + $content .= 'pconfig[' . local_channel() . ']' . EOL; + load_pconfig(local_channel(), escape_tags(argv(1))); + if (App::$config[local_channel()][escape_tags(argv(1))]) { + foreach (App::$config[local_channel()][escape_tags(argv(1))] as $k => $x) { + $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . '][' . $k . '] = ' . escape_tags($x) . EOL; + } + } + } + + if (argc() == 1) { + + $r = q("select * from pconfig where uid = " . local_channel()); + if ($r) { + foreach ($r as $rr) { + $content .= 'pconfig[' . local_channel() . '][' . escape_tags($rr['cat']) . '][' . escape_tags($rr['k']) . '] = ' . escape_tags($rr['v']) . EOL; + } + } + } + return $content; + + } + + + public function pconfig_form($cat, $k) + { + + $o = '
      '; + $o .= ''; + + $v = get_pconfig(local_channel(), $cat, $k); + if (strpos($k, 'password') !== false) + $v = unobscurify($v); + + $o .= ''; + $o .= ''; + + + if (strpos($v, "\n")) + $o .= ''; + else { + if (is_array($v)) { + $o .= '
      ' . "\n" . print_array($v) . '
      '; + $o .= ''; + } else { + $o .= ''; + } + } + $o .= EOL . EOL; + $o .= ''; + $o .= '
      '; + + return $o; + + } + + + public function disallowed_pconfig() + { + return array( + 'permissions_role' + ); + } - function disallowed_pconfig() { - return array( - 'permissions_role' - ); - } - } diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php index 814c65281..6e58667aa 100644 --- a/Zotlabs/Module/Pdledit.php +++ b/Zotlabs/Module/Pdledit.php @@ -4,109 +4,112 @@ namespace Zotlabs\Module; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Pdledit extends Controller { +class Pdledit extends Controller +{ - function post() { - if(! local_channel()) - return; - if(! $_REQUEST['module']) - return; + public function post() + { + if (!local_channel()) + return; + if (!$_REQUEST['module']) + return; - if(! trim($_REQUEST['content'])) { - del_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl'); - goaway(z_root() . '/pdledit'); - } + if (!trim($_REQUEST['content'])) { + del_pconfig(local_channel(), 'system', 'mod_' . $_REQUEST['module'] . '.pdl'); + goaway(z_root() . '/pdledit'); + } - set_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl',escape_tags($_REQUEST['content'])); - Libsync::build_sync_packet(); - info( t('Layout updated.') . EOL); - goaway(z_root() . '/pdledit/' . $_REQUEST['module']); - } - - - function get() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + set_pconfig(local_channel(), 'system', 'mod_' . $_REQUEST['module'] . '.pdl', escape_tags($_REQUEST['content'])); + Libsync::build_sync_packet(); + info(t('Layout updated.') . EOL); + goaway(z_root() . '/pdledit/' . $_REQUEST['module']); + } - if(argc() > 2 && argv(2) === 'reset') { - del_pconfig(local_channel(),'system','mod_' . argv(1) . '.pdl'); - goaway(z_root() . '/pdledit'); - } - if(argc() > 1) - $module = 'mod_' . argv(1) . '.pdl'; - else { - $o .= '
      '; - $o .= '

      ' . t('Edit System Page Description') . '

      '; + public function get() + { - $edited = []; + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - $r = q("select k from pconfig where uid = %d and cat = 'system' and k like '%s' ", - intval(local_channel()), - dbesc('mod_%.pdl') - ); + if (argc() > 2 && argv(2) === 'reset') { + del_pconfig(local_channel(), 'system', 'mod_' . argv(1) . '.pdl'); + goaway(z_root() . '/pdledit'); + } - if($r) { - foreach($r as $rv) { - $edited[] = substr(str_replace('.pdl','',$rv['k']),4); - } - } - - $files = glob('Zotlabs/Module/*.php'); - if($files) { - foreach($files as $f) { - $name = lcfirst(basename($f,'.php')); - $x = theme_include('mod_' . $name . '.pdl'); - if($x) { - $o .= '' . $name . '' . ((in_array($name,$edited)) ? ' ' . t('(modified)') . ' ' . t('Reset') . '': '' ) . '
      '; - } - } - } - $addons = glob('addon/*/*.pdl'); - if($addons) { - foreach($addons as $a) { - $name = substr(basename($a, '.pdl'),4); - $o .= '' . $name . '' . ((in_array($name,$edited)) ? ' ' . t('(modified)') . ' ' . t('Reset') . '': '' ) . '
      '; - } - } + if (argc() > 1) + $module = 'mod_' . argv(1) . '.pdl'; + else { + $o .= '
      '; + $o .= '

      ' . t('Edit System Page Description') . '

      '; + + $edited = []; + + $r = q("select k from pconfig where uid = %d and cat = 'system' and k like '%s' ", + intval(local_channel()), + dbesc('mod_%.pdl') + ); + + if ($r) { + foreach ($r as $rv) { + $edited[] = substr(str_replace('.pdl', '', $rv['k']), 4); + } + } + + $files = glob('Zotlabs/Module/*.php'); + if ($files) { + foreach ($files as $f) { + $name = lcfirst(basename($f, '.php')); + $x = theme_include('mod_' . $name . '.pdl'); + if ($x) { + $o .= '' . $name . '' . ((in_array($name, $edited)) ? ' ' . t('(modified)') . ' ' . t('Reset') . '' : '') . '
      '; + } + } + } + $addons = glob('addon/*/*.pdl'); + if ($addons) { + foreach ($addons as $a) { + $name = substr(basename($a, '.pdl'), 4); + $o .= '' . $name . '' . ((in_array($name, $edited)) ? ' ' . t('(modified)') . ' ' . t('Reset') . '' : '') . '
      '; + } + } + + $o .= '
      '; + + // list module pdl files + return $o; + } + + $t = get_pconfig(local_channel(), 'system', $module); + $s = @file_get_contents(theme_include($module)); + if (!$s) { + $a = glob('addon/*/' . $module); + if ($a) + $s = @file_get_contents($a[0]); + } + if (!$t) { + $t = $s; + } + if (!$t) { + notice(t('Layout not found.') . EOL); + return ''; + } + + $o = replace_macros(get_markup_template('pdledit.tpl'), array( + '$header' => t('Edit System Page Description'), + '$mname' => t('Module Name:'), + '$help' => t('Layout Help'), + '$another' => t('Edit another layout'), + '$original' => t('System layout'), + '$module' => argv(1), + '$src' => $s, + '$content' => htmlspecialchars($t, ENT_COMPAT, 'UTF-8'), + '$submit' => t('Submit') + )); + + return $o; + } - $o .= '
      '; - - // list module pdl files - return $o; - } - - $t = get_pconfig(local_channel(),'system',$module); - $s = @file_get_contents(theme_include($module)); - if(! $s) { - $a = glob('addon/*/' . $module); - if($a) - $s = @file_get_contents($a[0]); - } - if(! $t) { - $t = $s; - } - if(! $t) { - notice( t('Layout not found.') . EOL); - return ''; - } - - $o = replace_macros(get_markup_template('pdledit.tpl'),array( - '$header' => t('Edit System Page Description'), - '$mname' => t('Module Name:'), - '$help' => t('Layout Help'), - '$another' => t('Edit another layout'), - '$original' => t('System layout'), - '$module' => argv(1), - '$src' => $s, - '$content' => htmlspecialchars($t,ENT_COMPAT,'UTF-8'), - '$submit' => t('Submit') - )); - - return $o; - } - } diff --git a/Zotlabs/Module/Photo.php b/Zotlabs/Module/Photo.php index 5db3e0870..43a0f8a5d 100644 --- a/Zotlabs/Module/Photo.php +++ b/Zotlabs/Module/Photo.php @@ -14,319 +14,314 @@ require_once('include/photo_factory.php'); require_once('include/photos.php'); -class Photo extends Controller { +class Photo extends Controller +{ - function init() { - - - if (ActivityStreams::is_as_request()) { - - $sigdata = HTTPSig::verify(EMPTY_STR); - if ($sigdata['portable_id'] && $sigdata['header_valid']) { - $portable_id = $sigdata['portable_id']; - if (! check_channelallowed($portable_id)) { - http_status_exit(403, 'Permission denied'); - } - if (! check_siteallowed($sigdata['signer'])) { - http_status_exit(403, 'Permission denied'); - } - observer_auth($portable_id); - } - elseif (Config::get('system','require_authenticated_fetch',false)) { - http_status_exit(403,'Permission denied'); - } - - $observer_xchan = get_observer_hash(); - $allowed = false; - - $bear = Activity::token_from_request(); - if ($bear) { - logger('bear: ' . $bear, LOGGER_DEBUG); - } - - $r = q("select * from item where resource_type = 'photo' and resource_id = '%s' limit 1", - dbesc(argv(1)) - ); - if ($r) { - $allowed = attach_can_view($r[0]['uid'],$observer_xchan,argv(1),$bear); - } - if (! $allowed) { - http_status_exit(404,'Permission denied.'); - } - $channel = channelx_by_n($r[0]['uid']); - - $obj = json_decode($r[0]['obj'],true); - - as_return_and_die($obj,$channel); - - } - - $prvcachecontrol = false; - $streaming = null; - $channel = null; - $person = 0; - - switch (argc()) { - case 4: - $person = argv(3); - $res = argv(2); - $type = argv(1); - break; - case 2: - $photo = argv(1); - break; - case 1: - default: - killme(); - } - - $token = ((isset($_REQUEST['token'])) ? $_REQUEST['token'] : EMPTY_STR); - $observer_xchan = get_observer_hash(); - - $default = z_root() . '/' . get_default_profile_photo(); - - if (isset($type)) { - - /** - * Profile photos - Access controls on default profile photos are not honoured since they need to be exchanged with remote sites. - * - */ - - if ($type === 'profile') { - switch ($res) { - case 'm': - $resolution = 5; - $default = z_root() . '/' . get_default_profile_photo(80); - break; - case 's': - $resolution = 6; - $default = z_root() . '/' . get_default_profile_photo(48); - break; - case 'l': - default: - $resolution = 4; - break; - } - } - - $uid = $person; - - $d = [ 'imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => '' ]; - call_hooks('get_profile_photo',$d); - - $resolution = $d['imgscale']; - $uid = $d['channel_id']; - $default = $d['default']; - $data = $d['data']; - $mimetype = $d['mimetype']; - - if (! $data) { - $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1", - intval($resolution), - intval($uid), - intval(PHOTO_PROFILE) - ); - if ($r) { - $data = dbunescbin($r[0]['content']); - $mimetype = $r[0]['mimetype']; - if (intval($r[0]['os_storage'])) { - $data = file_get_contents($data); - } - } - } - if (! $data) { - $data = fetch_image_from_url($default,$mimetype); - } - if (! $mimetype) { - $mimetype = 'image/png'; - } - } - else { - - $bear = Activity::token_from_request(); - if ($bear) { - logger('bear: ' . $bear, LOGGER_DEBUG); - } + public function init() + { - /** - * Other photos - */ - - /* Check for a cookie to indicate display pixel density, in order to detect high-resolution - displays. This procedure was derived from the "Retina Images" by Jeremey Worboys, - used in accordance with the Creative Commons Attribution 3.0 Unported License. - Project link: https://github.com/Retina-Images/Retina-Images - License link: http://creativecommons.org/licenses/by/3.0/ - */ + if (ActivityStreams::is_as_request()) { - $cookie_value = false; - if (isset($_COOKIE['devicePixelRatio'])) { - $cookie_value = intval($_COOKIE['devicePixelRatio']); - } - else { - // Force revalidation of cache on next request - $cache_directive = 'no-cache'; - $status = 'no cookie'; - } - - $resolution = 0; - - if (strpos($photo,'.') !== false) { - $photo = substr($photo,0,strpos($photo,'.')); - } - - if (substr($photo,-2,1) == '-') { - $resolution = intval(substr($photo,-1,1)); - $photo = substr($photo,0,-2); - // If viewing on a high-res screen, attempt to serve a higher resolution image: - if ($resolution == 2 && ($cookie_value > 1)) { - $resolution = 1; - } - } - - $r = q("SELECT uid, photo_usage FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", - dbesc($photo), - intval($resolution) - ); - if ($r) { + $sigdata = HTTPSig::verify(EMPTY_STR); + if ($sigdata['portable_id'] && $sigdata['header_valid']) { + $portable_id = $sigdata['portable_id']; + if (!check_channelallowed($portable_id)) { + http_status_exit(403, 'Permission denied'); + } + if (!check_siteallowed($sigdata['signer'])) { + http_status_exit(403, 'Permission denied'); + } + observer_auth($portable_id); + } elseif (Config::get('system', 'require_authenticated_fetch', false)) { + http_status_exit(403, 'Permission denied'); + } - $allowed = (-1); + $observer_xchan = get_observer_hash(); + $allowed = false; - if (intval($r[0]['photo_usage'])) { - $allowed = 1; - if (intval($r[0]['photo_usage']) === PHOTO_COVER) { - if ($resolution < PHOTO_RES_COVER_1200) { - $allowed = (-1); - } - } - if (intval($r[0]['photo_usage']) === PHOTO_PROFILE) { - if (! in_array($resolution,[4,5,6])) { - $allowed = (-1); - } - } - } + $bear = Activity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + } - if ($allowed === (-1)) { - $allowed = attach_can_view($r[0]['uid'],$observer_xchan,$photo,$bear); - } + $r = q("select * from item where resource_type = 'photo' and resource_id = '%s' limit 1", + dbesc(argv(1)) + ); + if ($r) { + $allowed = attach_can_view($r[0]['uid'], $observer_xchan, argv(1), $bear); + } + if (!$allowed) { + http_status_exit(404, 'Permission denied.'); + } + $channel = channelx_by_n($r[0]['uid']); - $channel = channelx_by_n($r[0]['uid']); + $obj = json_decode($r[0]['obj'], true); - // Now we'll see if we can access the photo - $e = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d $sql_extra LIMIT 1", - dbesc($photo), - intval($resolution) - ); + as_return_and_die($obj, $channel); - $exists = (($e) ? true : false); + } - if ($exists && $allowed) { - $data = dbunescbin($e[0]['content']); - $mimetype = $e[0]['mimetype']; - if (intval($e[0]['os_storage'])) { - $streaming = $data; - } + $prvcachecontrol = false; + $streaming = null; + $channel = null; + $person = 0; - if ($e[0]['allow_cid'] != '' || $e[0]['allow_gid'] != '' || $e[0]['deny_gid'] != '' || $e[0]['deny_gid'] != '') - $prvcachecontrol = 'no-store, no-cache, must-revalidate'; - } - else { - if (! $allowed) { - http_status_exit(403,'forbidden'); - } - if (! $exists) { - http_status_exit(404,'not found'); - } - } - } - } - - if (! isset($data)) { - if (isset($resolution)) { - switch ($resolution) { - case 4: - $data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(),$mimetype); - break; - case 5: - $data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(80),$mimetype); - break; - case 6: - $data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(48),$mimetype); - break; - default: - killme(); - } - } - } - - if (isset($res) && intval($res) && $res < 500) { - $ph = photo_factory($data, $mimetype); - if ($ph && $ph->is_valid()) { - $ph->scaleImageSquare($res); - $data = $ph->imageString(); - $mimetype = $ph->getType(); - } - } - - if (function_exists('header_remove')) { - header_remove('Pragma'); - header_remove('pragma'); - } - - header("Content-type: " . $mimetype); - - if ($prvcachecontrol) { - - // it is a private photo that they have permission to view. - // tell the browser and infrastructure caches not to cache it, - // in case permissions change before the next access. - - header("Cache-Control: no-store, no-cache, must-revalidate"); - - } - else { - // The cache default for public photos is 1 day to provide a privacy trade-off, - // as somebody reducing photo permissions on a photo that is already - // "in the wild" won't be able to stop the photo from being viewed - // for this amount amount of time once it is cached. - // The privacy expectations of your site members and their perception - // of privacy where it affects the entire project may be affected. - // This has performance considerations but we highly recommend you - // leave it alone. - - $cache = get_config('system','photo_cache_time'); - if (! $cache) { - $cache = (3600 * 24); // 1 day - } - header("Expires: " . gmdate("D, d M Y H:i:s", time() + $cache) . " GMT"); - // Set browser cache age as $cache. But set timeout of 'shared caches' - // much lower in the event that infrastructure caching is present. - $smaxage = intval($cache/12); - header('Cache-Control: s-maxage='.$smaxage.'; max-age=' . $cache . ';'); - - } + switch (argc()) { + case 4: + $person = argv(3); + $res = argv(2); + $type = argv(1); + break; + case 2: + $photo = argv(1); + break; + case 1: + default: + killme(); + } - // If it's a file resource, stream it. + $token = ((isset($_REQUEST['token'])) ? $_REQUEST['token'] : EMPTY_STR); + $observer_xchan = get_observer_hash(); + + $default = z_root() . '/' . get_default_profile_photo(); + + if (isset($type)) { + + /** + * Profile photos - Access controls on default profile photos are not honoured since they need to be exchanged with remote sites. + * + */ + + if ($type === 'profile') { + switch ($res) { + case 'm': + $resolution = 5; + $default = z_root() . '/' . get_default_profile_photo(80); + break; + case 's': + $resolution = 6; + $default = z_root() . '/' . get_default_profile_photo(48); + break; + case 'l': + default: + $resolution = 4; + break; + } + } + + $uid = $person; + + $d = ['imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => '']; + call_hooks('get_profile_photo', $d); + + $resolution = $d['imgscale']; + $uid = $d['channel_id']; + $default = $d['default']; + $data = $d['data']; + $mimetype = $d['mimetype']; + + if (!$data) { + $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1", + intval($resolution), + intval($uid), + intval(PHOTO_PROFILE) + ); + if ($r) { + $data = dbunescbin($r[0]['content']); + $mimetype = $r[0]['mimetype']; + if (intval($r[0]['os_storage'])) { + $data = file_get_contents($data); + } + } + } + if (!$data) { + $data = fetch_image_from_url($default, $mimetype); + } + if (!$mimetype) { + $mimetype = 'image/png'; + } + } else { + + $bear = Activity::token_from_request(); + if ($bear) { + logger('bear: ' . $bear, LOGGER_DEBUG); + } + + + /** + * Other photos + */ + + /* Check for a cookie to indicate display pixel density, in order to detect high-resolution + displays. This procedure was derived from the "Retina Images" by Jeremey Worboys, + used in accordance with the Creative Commons Attribution 3.0 Unported License. + Project link: https://github.com/Retina-Images/Retina-Images + License link: http://creativecommons.org/licenses/by/3.0/ + */ + + $cookie_value = false; + if (isset($_COOKIE['devicePixelRatio'])) { + $cookie_value = intval($_COOKIE['devicePixelRatio']); + } else { + // Force revalidation of cache on next request + $cache_directive = 'no-cache'; + $status = 'no cookie'; + } + + $resolution = 0; + + if (strpos($photo, '.') !== false) { + $photo = substr($photo, 0, strpos($photo, '.')); + } + + if (substr($photo, -2, 1) == '-') { + $resolution = intval(substr($photo, -1, 1)); + $photo = substr($photo, 0, -2); + // If viewing on a high-res screen, attempt to serve a higher resolution image: + if ($resolution == 2 && ($cookie_value > 1)) { + $resolution = 1; + } + } + + $r = q("SELECT uid, photo_usage FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", + dbesc($photo), + intval($resolution) + ); + if ($r) { + + $allowed = (-1); + + if (intval($r[0]['photo_usage'])) { + $allowed = 1; + if (intval($r[0]['photo_usage']) === PHOTO_COVER) { + if ($resolution < PHOTO_RES_COVER_1200) { + $allowed = (-1); + } + } + if (intval($r[0]['photo_usage']) === PHOTO_PROFILE) { + if (!in_array($resolution, [4, 5, 6])) { + $allowed = (-1); + } + } + } + + if ($allowed === (-1)) { + $allowed = attach_can_view($r[0]['uid'], $observer_xchan, $photo, $bear); + } + + $channel = channelx_by_n($r[0]['uid']); + + // Now we'll see if we can access the photo + $e = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d $sql_extra LIMIT 1", + dbesc($photo), + intval($resolution) + ); + + $exists = (($e) ? true : false); + + if ($exists && $allowed) { + $data = dbunescbin($e[0]['content']); + $mimetype = $e[0]['mimetype']; + if (intval($e[0]['os_storage'])) { + $streaming = $data; + } + + if ($e[0]['allow_cid'] != '' || $e[0]['allow_gid'] != '' || $e[0]['deny_gid'] != '' || $e[0]['deny_gid'] != '') + $prvcachecontrol = 'no-store, no-cache, must-revalidate'; + } else { + if (!$allowed) { + http_status_exit(403, 'forbidden'); + } + if (!$exists) { + http_status_exit(404, 'not found'); + } + } + } + } + + if (!isset($data)) { + if (isset($resolution)) { + switch ($resolution) { + case 4: + $data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(), $mimetype); + break; + case 5: + $data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(80), $mimetype); + break; + case 6: + $data = fetch_image_from_url(z_root() . '/' . get_default_profile_photo(48), $mimetype); + break; + default: + killme(); + } + } + } + + if (isset($res) && intval($res) && $res < 500) { + $ph = photo_factory($data, $mimetype); + if ($ph && $ph->is_valid()) { + $ph->scaleImageSquare($res); + $data = $ph->imageString(); + $mimetype = $ph->getType(); + } + } + + if (function_exists('header_remove')) { + header_remove('Pragma'); + header_remove('pragma'); + } + + header("Content-type: " . $mimetype); + + if ($prvcachecontrol) { + + // it is a private photo that they have permission to view. + // tell the browser and infrastructure caches not to cache it, + // in case permissions change before the next access. + + header("Cache-Control: no-store, no-cache, must-revalidate"); + + } else { + // The cache default for public photos is 1 day to provide a privacy trade-off, + // as somebody reducing photo permissions on a photo that is already + // "in the wild" won't be able to stop the photo from being viewed + // for this amount amount of time once it is cached. + // The privacy expectations of your site members and their perception + // of privacy where it affects the entire project may be affected. + // This has performance considerations but we highly recommend you + // leave it alone. + + $cache = get_config('system', 'photo_cache_time'); + if (!$cache) { + $cache = (3600 * 24); // 1 day + } + header("Expires: " . gmdate("D, d M Y H:i:s", time() + $cache) . " GMT"); + // Set browser cache age as $cache. But set timeout of 'shared caches' + // much lower in the event that infrastructure caching is present. + $smaxage = intval($cache / 12); + header('Cache-Control: s-maxage=' . $smaxage . '; max-age=' . $cache . ';'); + + } + + // If it's a file resource, stream it. + + if ($streaming && $channel) { + if (strpos($streaming, 'store') !== false) { + $istream = fopen($streaming, 'rb'); + } else { + $istream = fopen('store/' . $channel['channel_address'] . '/' . $streaming, 'rb'); + } + $ostream = fopen('php://output', 'wb'); + if ($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } + } else { + echo $data; + } + killme(); + } - if ($streaming && $channel) { - if (strpos($streaming,'store') !== false) { - $istream = fopen($streaming,'rb'); - } - else { - $istream = fopen('store/' . $channel['channel_address'] . '/' . $streaming,'rb'); - } - $ostream = fopen('php://output','wb'); - if ($istream && $ostream) { - pipe_streams($istream,$ostream); - fclose($istream); - fclose($ostream); - } - } - else { - echo $data; - } - killme(); - } - } diff --git a/Zotlabs/Module/Photomap.php b/Zotlabs/Module/Photomap.php index 275159ad6..a7d6ca1ae 100644 --- a/Zotlabs/Module/Photomap.php +++ b/Zotlabs/Module/Photomap.php @@ -5,20 +5,22 @@ use App; use Zotlabs\Web\Controller; use Zotlabs\Lib\Apps; -class Photomap extends Controller { +class Photomap extends Controller +{ - function get() { + public function get() + { $desc = t('This app provides a displayable map when viewing detail of photos that contain location information.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Photomap'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Photomap'))) { return $text; } - return $text . '

      ' . t('This app is currently installed.'); - } + return $text . '

      ' . t('This app is currently installed.'); + } } diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php index d811d0f15..4c8152d45 100644 --- a/Zotlabs/Module/Photos.php +++ b/Zotlabs/Module/Photos.php @@ -20,1415 +20,1401 @@ require_once('include/text.php'); require_once('include/conversation.php'); -class Photos extends Controller { +class Photos extends Controller +{ - function init() { - - if (observer_prohibited()) { - return; - } - - if (argc() > 1) { + public function init() + { - $nick = escape_tags(argv(1)); - - Libprofile::load($nick); - - $channelx = channelx_by_nick($nick); + if (observer_prohibited()) { + return; + } - $profile_uid = 0; - - if ($channelx) { - App::$data['channel'] = $channelx; - head_set_icon($channelx['xchan_photo_s']); - $profile_uid = $channelx['channel_id']; - } - - App::$page['htmlhead'] .= "" ; - App::$data['observer'] = App::get_observer(); - } - } - - - - function post() { - - logger('mod-photos: photos_post: begin' , LOGGER_DEBUG); - - logger('mod_photos: REQUEST ' . print_r($_REQUEST,true), LOGGER_DATA); - logger('mod_photos: FILES ' . print_r($_FILES,true), LOGGER_DATA); - - $ph = photo_factory(''); - - $phototypes = $ph->supportedTypes(); - - $page_owner_uid = App::$data['channel']['channel_id']; - - if (! perm_is_allowed($page_owner_uid,get_observer_hash(),'write_storage')) { - notice( t('Permission denied.') . EOL ); - killme_if_ajax(); - return; - } - - $acl = new AccessControl(App::$data['channel']); - - if ((argc() > 3) && (argv(2) === 'album')) { - - $album = argv(3); + if (argc() > 1) { - if (! photos_album_exists($page_owner_uid, get_observer_hash(), $album)) { - notice( t('Album not found.') . EOL); - goaway(z_root() . '/' . $_SESSION['photo_return']); - } - - - /* - * DELETE photo album and all its photos - */ - - if ($_REQUEST['dropalbum'] === t('Delete Album')) { - - $folder_hash = ''; - - $r = q("select hash from attach where is_dir = 1 and uid = %d and hash = '%s'", - intval($page_owner_uid), - dbesc($album) - ); - if (! $r) { - notice( t('Album not found.') . EOL); - return; - } - $folder_hash = $r[0]['hash']; - - - $res = []; - $admin_delete = false; + $nick = escape_tags(argv(1)); - // get the list of photos we are about to delete - - if (remote_channel() && (! local_channel())) { - $str = photos_album_get_db_idstr($page_owner_uid,$album,remote_channel()); - } - elseif (local_channel()) { - $str = photos_album_get_db_idstr(local_channel(),$album); - } - elseif (is_site_admin()) { - $str = photos_album_get_db_idstr_admin($page_owner_uid,$album); - $admin_delete = true; - } - else { - $str = null; - } - - if (! $str) { - goaway(z_root() . '/' . $_SESSION['photo_return']); - } - - $r = q("select id from item where resource_id in ( $str ) and resource_type = 'photo' and uid = %d " . item_normal(), - intval($page_owner_uid) - ); - if($r) { - foreach($r as $rv) { - attach_delete($page_owner_uid, $rv['resource_id'], true ); - } - } - - // remove the associated photos in case they weren't attached to an item (rare) - - q("delete from photo where resource_id in ( $str ) and uid = %d", - intval($page_owner_uid) - ); + Libprofile::load($nick); - q("delete from attach where hash in ( $str ) and uid = %d", - intval($page_owner_uid) - ); - - if ($folder_hash) { - attach_delete($page_owner_uid, $folder_hash, true ); + $channelx = channelx_by_nick($nick); - // Sync this action to channel clones, UNLESS it was an admin delete action. - // The admin only has authority to moderate content on their own site. - - if (! $admin_delete) { - $sync = attach_export_data(App::$data['channel'],$folder_hash, true); - if ($sync) { - Libsync::build_sync_packet($page_owner_uid, [ 'file' => [ $sync ] ]); - } - } - } - } - goaway(z_root() . '/photos/' . App::$data['channel']['channel_address']); - } - - if ((argc() > 2) && (x($_REQUEST,'delete')) && ($_REQUEST['delete'] === t('Delete Photo'))) { - // same as above but remove single photo + $profile_uid = 0; - $ob_hash = get_observer_hash(); + if ($channelx) { + App::$data['channel'] = $channelx; + head_set_icon($channelx['xchan_photo_s']); + $profile_uid = $channelx['channel_id']; + } - if (! $ob_hash) { - goaway(z_root() . '/' . $_SESSION['photo_return']); - } - - // query to verify ownership of the photo by this viewer - // We've already checked observer permissions to perfom this action - - // This implements the policy that remote channels (visitors and guests) - // which modify content can only modify their own content. - // The page owner can modify anything within their authority, including - // content published by others in their own channel pages. - // The site admin can of course modify anything on their own site for - // maintenance or legal compliance reasons. - - $r = q("SELECT id, resource_id FROM photo WHERE ( xchan = '%s' or uid = %d ) AND resource_id = '%s' LIMIT 1", - dbesc($ob_hash), - intval(local_channel()), - dbesc(argv(2)) - ); - - if ($r) { - attach_delete($page_owner_uid, $r[0]['resource_id'], true ); - $sync = attach_export_data(App::$data['channel'],$r[0]['resource_id'], true); - if ($sync) { - Libsync::build_sync_packet($page_owner_uid, [ 'file' => [ $sync ] ]); - } - } - elseif (is_site_admin()) { - // If the admin deletes a photo, don't check ownership or invoke clone sync - attach_delete($page_owner_uid, argv(2), true); - } - - goaway(z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $_SESSION['album_return']); - } - - // perform move_to_album - - if ((argc() > 2) && array_key_exists('move_to_album',$_POST)) { - - $m = q("select folder from attach where hash = '%s' and uid = %d limit 1", - dbesc(argv(2)), - intval($page_owner_uid) - ); - - // we should sanitize the post variable, but probably pointless because the move - // will fail if we can't find the target - - if (($m) && ($m[0]['folder'] != $_POST['move_to_album'])) { - attach_move($page_owner_uid,argv(2),$_POST['move_to_album']); - - $sync = attach_export_data(App::$data['channel'],argv(2),false); - if ($sync) { - Libsync::build_sync_packet($page_owner_uid, [ 'file' => [ $sync ] ]); - } - - // return if this is the only thing being edited - - if (! ($_POST['desc'] && $_POST['newtag'])) { - goaway(z_root() . '/' . $_SESSION['photo_return']); - } - } - } - - // this still needs some work - - if(defined('FIXED')) { - if((x($_POST,'rotate') !== false) && ( (intval($_POST['rotate']) == 1) || (intval($_POST['rotate']) == 2) )) { - logger('rotate'); - - $resource_id = argv(2); - - $r = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = 0 limit 1", - dbesc($resource_id), - intval($page_owner_uid) - ); - if ($r) { - - $ph = photo_factory(@file_get_contents(dbunescbin($r[0]['content'])), $r[0]['mimetype']); - if ($ph && $ph->is_valid()) { - $rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 ); - $ph->rotate($rotate_deg); - - $edited = datetime_convert(); - - q("update attach set filesize = %d, edited = '%s' where hash = '%s' and uid = %d", - strlen($ph->imageString()), - dbescdate($edited), - dbesc($resource_id), - intval($page_owner_uid) - ); - - $ph->saveImage(dbunescbin($r[0]['content'])); - - $arr = [ - 'aid' => get_account_id(), - 'uid' => intval($page_owner_uid), - 'resource_id' => dbesc($resource_id), - 'filename' => $r[0]['filename'], - 'imgscale' => 0, - 'album' => $r[0]['album'], - 'os_path' => $r[0]['os_path'], - 'os_storage' => 1, - 'os_syspath' => dbunescbin($r[0]['content']), - 'display_path' => $r[0]['display_path'], - 'photo_usage' => PHOTO_NORMAL, - 'edited' => dbescdate($edited) - ]; - - $ph->save($arr); - - unset($arr['os_syspath']); - - if($width > 1024 || $height > 1024) - $ph->scaleImage(1024); - $ph->storeThumbnail($arr, PHOTO_RES_1024); - - if($width > 640 || $height > 640) - $ph->scaleImage(640); - $ph->storeThumbnail($arr, PHOTO_RES_640); - - if($width > 320 || $height > 320) - $ph->scaleImage(320); - $ph->storeThumbnail($arr, PHOTO_RES_320); - } - } - }} // end FIXED + App::$page['htmlhead'] .= ""; + App::$data['observer'] = App::get_observer(); + } + } - // edit existing photo properties - - if (x($_POST,'item_id') !== false && intval($_POST['item_id'])) { + public function post() + { - $title = ((x($_POST,'title')) ? escape_tags(trim($_POST['title'])) : EMPTY_STR ); - $desc = ((x($_POST,'desc')) ? escape_tags(trim($_POST['desc'])) : EMPTY_STR ); - $body = ((x($_POST,'body')) ? trim($_POST['body']) : EMPTY_STR); - - $item_id = ((x($_POST,'item_id')) ? intval($_POST['item_id']) : 0); - $is_nsfw = ((x($_POST,'adult')) ? intval($_POST['adult']) : 0); + logger('mod-photos: photos_post: begin', LOGGER_DEBUG); - // convert any supplied posted permissions for storage - - $acl->set_from_array($_POST); - $perm = $acl->get(); - - $resource_id = argv(2); - - $p = q("SELECT mimetype, is_nsfw, filename, title, description, resource_id, imgscale, allow_cid, allow_gid, deny_cid, deny_gid FROM photo WHERE resource_id = '%s' AND uid = %d ORDER BY imgscale DESC", - dbesc($resource_id), - intval($page_owner_uid) - ); - if ($p) { - // update the photo structure with any of the changed elements which are common to all resolutions - $r = q("UPDATE photo SET title = '%s', description = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' WHERE resource_id = '%s' AND uid = %d", - dbesc($title), - dbesc($desc), - dbesc($perm['allow_cid']), - dbesc($perm['allow_gid']), - dbesc($perm['deny_cid']), - dbesc($perm['deny_gid']), - dbesc($resource_id), - intval($page_owner_uid) - ); - } - - $item_private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); - - $old_is_nsfw = $p[0]['is_nsfw']; - if ($old_is_nsfw != $is_nsfw) { - $r = q("update photo set is_nsfw = %d where resource_id = '%s' and uid = %d", - intval($is_nsfw), - dbesc($resource_id), - intval($page_owner_uid) - ); - } - - /* Don't make the item visible if the only change was the album name */ - - $visibility = 0; - if ($p[0]['description'] !== $desc || $p[0]['title'] !== $title || $body !== EMPTY_STR) { - $visibility = 1; - } + logger('mod_photos: REQUEST ' . print_r($_REQUEST, true), LOGGER_DATA); + logger('mod_photos: FILES ' . print_r($_FILES, true), LOGGER_DATA); - $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", - intval($item_id), - intval($page_owner_uid) - ); - if (! $r) { - logger('linked photo item not found.'); - notice ( t('linked item not found.') . EOL); - return; - } + $ph = photo_factory(''); - $linked_item = array_shift($r); - - // extract the original footer text - $footer_text = EMPTY_STR; - $orig_text = $linked_item['body']; - $matches = []; + $phototypes = $ph->supportedTypes(); - if (preg_match('/\[footer\](.*?)\[\/footer\]/ism',$orig_text,$matches)) { - $footer_text = $matches[0]; - } - - $body = cleanup_bbcode($body); - $tags = linkify_tags($body, $page_owner_uid); + $page_owner_uid = App::$data['channel']['channel_id']; - $post_tags = []; - if ($tags) { - foreach ($tags as $tag) { - $success = $tag['success']; - if ($success['replaced']) { - // suppress duplicate mentions/tags - $already_tagged = false; - foreach ($post_tags as $pt) { - if ($pt['term'] === $success['term'] && $pt['url'] === $success['url'] && intval($pt['ttype']) === intval($success['termtype'])) { - $already_tagged = true; - break; - } - } - if ($already_tagged) { - continue; - } + if (!perm_is_allowed($page_owner_uid, get_observer_hash(), 'write_storage')) { + notice(t('Permission denied.') . EOL); + killme_if_ajax(); + return; + } - $post_tags[] = [ - 'uid' => $page_owner_uid, - 'ttype' => $success['termtype'], - 'otype' => TERM_OBJ_POST, - 'term' => $success['term'], - 'url' => $success['url'] - ]; - } - } - } - if ($post_tags) { - q("delete from term where otype = 1 and oid = %d", - intval($linked_item['id']) - ); - foreach($post_tags as $t) { - q("insert into term (uid,oid,otype,ttype,term,url) + $acl = new AccessControl(App::$data['channel']); + + if ((argc() > 3) && (argv(2) === 'album')) { + + $album = argv(3); + + if (!photos_album_exists($page_owner_uid, get_observer_hash(), $album)) { + notice(t('Album not found.') . EOL); + goaway(z_root() . '/' . $_SESSION['photo_return']); + } + + + /* + * DELETE photo album and all its photos + */ + + if ($_REQUEST['dropalbum'] === t('Delete Album')) { + + $folder_hash = ''; + + $r = q("select hash from attach where is_dir = 1 and uid = %d and hash = '%s'", + intval($page_owner_uid), + dbesc($album) + ); + if (!$r) { + notice(t('Album not found.') . EOL); + return; + } + $folder_hash = $r[0]['hash']; + + + $res = []; + $admin_delete = false; + + // get the list of photos we are about to delete + + if (remote_channel() && (!local_channel())) { + $str = photos_album_get_db_idstr($page_owner_uid, $album, remote_channel()); + } elseif (local_channel()) { + $str = photos_album_get_db_idstr(local_channel(), $album); + } elseif (is_site_admin()) { + $str = photos_album_get_db_idstr_admin($page_owner_uid, $album); + $admin_delete = true; + } else { + $str = null; + } + + if (!$str) { + goaway(z_root() . '/' . $_SESSION['photo_return']); + } + + $r = q("select id from item where resource_id in ( $str ) and resource_type = 'photo' and uid = %d " . item_normal(), + intval($page_owner_uid) + ); + if ($r) { + foreach ($r as $rv) { + attach_delete($page_owner_uid, $rv['resource_id'], true); + } + } + + // remove the associated photos in case they weren't attached to an item (rare) + + q("delete from photo where resource_id in ( $str ) and uid = %d", + intval($page_owner_uid) + ); + + q("delete from attach where hash in ( $str ) and uid = %d", + intval($page_owner_uid) + ); + + if ($folder_hash) { + attach_delete($page_owner_uid, $folder_hash, true); + + // Sync this action to channel clones, UNLESS it was an admin delete action. + // The admin only has authority to moderate content on their own site. + + if (!$admin_delete) { + $sync = attach_export_data(App::$data['channel'], $folder_hash, true); + if ($sync) { + Libsync::build_sync_packet($page_owner_uid, ['file' => [$sync]]); + } + } + } + } + goaway(z_root() . '/photos/' . App::$data['channel']['channel_address']); + } + + if ((argc() > 2) && (x($_REQUEST, 'delete')) && ($_REQUEST['delete'] === t('Delete Photo'))) { + // same as above but remove single photo + + $ob_hash = get_observer_hash(); + + if (!$ob_hash) { + goaway(z_root() . '/' . $_SESSION['photo_return']); + } + + // query to verify ownership of the photo by this viewer + // We've already checked observer permissions to perfom this action + + // This implements the policy that remote channels (visitors and guests) + // which modify content can only modify their own content. + // The page owner can modify anything within their authority, including + // content published by others in their own channel pages. + // The site admin can of course modify anything on their own site for + // maintenance or legal compliance reasons. + + $r = q("SELECT id, resource_id FROM photo WHERE ( xchan = '%s' or uid = %d ) AND resource_id = '%s' LIMIT 1", + dbesc($ob_hash), + intval(local_channel()), + dbesc(argv(2)) + ); + + if ($r) { + attach_delete($page_owner_uid, $r[0]['resource_id'], true); + $sync = attach_export_data(App::$data['channel'], $r[0]['resource_id'], true); + if ($sync) { + Libsync::build_sync_packet($page_owner_uid, ['file' => [$sync]]); + } + } elseif (is_site_admin()) { + // If the admin deletes a photo, don't check ownership or invoke clone sync + attach_delete($page_owner_uid, argv(2), true); + } + + goaway(z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $_SESSION['album_return']); + } + + // perform move_to_album + + if ((argc() > 2) && array_key_exists('move_to_album', $_POST)) { + + $m = q("select folder from attach where hash = '%s' and uid = %d limit 1", + dbesc(argv(2)), + intval($page_owner_uid) + ); + + // we should sanitize the post variable, but probably pointless because the move + // will fail if we can't find the target + + if (($m) && ($m[0]['folder'] != $_POST['move_to_album'])) { + attach_move($page_owner_uid, argv(2), $_POST['move_to_album']); + + $sync = attach_export_data(App::$data['channel'], argv(2), false); + if ($sync) { + Libsync::build_sync_packet($page_owner_uid, ['file' => [$sync]]); + } + + // return if this is the only thing being edited + + if (!($_POST['desc'] && $_POST['newtag'])) { + goaway(z_root() . '/' . $_SESSION['photo_return']); + } + } + } + + // this still needs some work + + if (defined('FIXED')) { + if ((x($_POST, 'rotate') !== false) && ((intval($_POST['rotate']) == 1) || (intval($_POST['rotate']) == 2))) { + logger('rotate'); + + $resource_id = argv(2); + + $r = q("select * from photo where resource_id = '%s' and uid = %d and imgscale = 0 limit 1", + dbesc($resource_id), + intval($page_owner_uid) + ); + if ($r) { + + $ph = photo_factory(@file_get_contents(dbunescbin($r[0]['content'])), $r[0]['mimetype']); + if ($ph && $ph->is_valid()) { + $rotate_deg = ((intval($_POST['rotate']) == 1) ? 270 : 90); + $ph->rotate($rotate_deg); + + $edited = datetime_convert(); + + q("update attach set filesize = %d, edited = '%s' where hash = '%s' and uid = %d", + strlen($ph->imageString()), + dbescdate($edited), + dbesc($resource_id), + intval($page_owner_uid) + ); + + $ph->saveImage(dbunescbin($r[0]['content'])); + + $arr = [ + 'aid' => get_account_id(), + 'uid' => intval($page_owner_uid), + 'resource_id' => dbesc($resource_id), + 'filename' => $r[0]['filename'], + 'imgscale' => 0, + 'album' => $r[0]['album'], + 'os_path' => $r[0]['os_path'], + 'os_storage' => 1, + 'os_syspath' => dbunescbin($r[0]['content']), + 'display_path' => $r[0]['display_path'], + 'photo_usage' => PHOTO_NORMAL, + 'edited' => dbescdate($edited) + ]; + + $ph->save($arr); + + unset($arr['os_syspath']); + + if ($width > 1024 || $height > 1024) + $ph->scaleImage(1024); + $ph->storeThumbnail($arr, PHOTO_RES_1024); + + if ($width > 640 || $height > 640) + $ph->scaleImage(640); + $ph->storeThumbnail($arr, PHOTO_RES_640); + + if ($width > 320 || $height > 320) + $ph->scaleImage(320); + $ph->storeThumbnail($arr, PHOTO_RES_320); + } + } + } + } // end FIXED + + + // edit existing photo properties + + if (x($_POST, 'item_id') !== false && intval($_POST['item_id'])) { + + $title = ((x($_POST, 'title')) ? escape_tags(trim($_POST['title'])) : EMPTY_STR); + $desc = ((x($_POST, 'desc')) ? escape_tags(trim($_POST['desc'])) : EMPTY_STR); + $body = ((x($_POST, 'body')) ? trim($_POST['body']) : EMPTY_STR); + + $item_id = ((x($_POST, 'item_id')) ? intval($_POST['item_id']) : 0); + $is_nsfw = ((x($_POST, 'adult')) ? intval($_POST['adult']) : 0); + + // convert any supplied posted permissions for storage + + $acl->set_from_array($_POST); + $perm = $acl->get(); + + $resource_id = argv(2); + + $p = q("SELECT mimetype, is_nsfw, filename, title, description, resource_id, imgscale, allow_cid, allow_gid, deny_cid, deny_gid FROM photo WHERE resource_id = '%s' AND uid = %d ORDER BY imgscale DESC", + dbesc($resource_id), + intval($page_owner_uid) + ); + if ($p) { + // update the photo structure with any of the changed elements which are common to all resolutions + $r = q("UPDATE photo SET title = '%s', description = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' WHERE resource_id = '%s' AND uid = %d", + dbesc($title), + dbesc($desc), + dbesc($perm['allow_cid']), + dbesc($perm['allow_gid']), + dbesc($perm['deny_cid']), + dbesc($perm['deny_gid']), + dbesc($resource_id), + intval($page_owner_uid) + ); + } + + $item_private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); + + $old_is_nsfw = $p[0]['is_nsfw']; + if ($old_is_nsfw != $is_nsfw) { + $r = q("update photo set is_nsfw = %d where resource_id = '%s' and uid = %d", + intval($is_nsfw), + dbesc($resource_id), + intval($page_owner_uid) + ); + } + + /* Don't make the item visible if the only change was the album name */ + + $visibility = 0; + if ($p[0]['description'] !== $desc || $p[0]['title'] !== $title || $body !== EMPTY_STR) { + $visibility = 1; + } + + $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", + intval($item_id), + intval($page_owner_uid) + ); + if (!$r) { + logger('linked photo item not found.'); + notice(t('linked item not found.') . EOL); + return; + } + + $linked_item = array_shift($r); + + // extract the original footer text + $footer_text = EMPTY_STR; + $orig_text = $linked_item['body']; + $matches = []; + + if (preg_match('/\[footer\](.*?)\[\/footer\]/ism', $orig_text, $matches)) { + $footer_text = $matches[0]; + } + + $body = cleanup_bbcode($body); + $tags = linkify_tags($body, $page_owner_uid); + + $post_tags = []; + if ($tags) { + foreach ($tags as $tag) { + $success = $tag['success']; + if ($success['replaced']) { + // suppress duplicate mentions/tags + $already_tagged = false; + foreach ($post_tags as $pt) { + if ($pt['term'] === $success['term'] && $pt['url'] === $success['url'] && intval($pt['ttype']) === intval($success['termtype'])) { + $already_tagged = true; + break; + } + } + if ($already_tagged) { + continue; + } + + $post_tags[] = [ + 'uid' => $page_owner_uid, + 'ttype' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ]; + } + } + } + if ($post_tags) { + q("delete from term where otype = 1 and oid = %d", + intval($linked_item['id']) + ); + foreach ($post_tags as $t) { + q("insert into term (uid,oid,otype,ttype,term,url) values(%d,%d,%d,%d,'%s','%s') ", - intval($page_owner_uid), - intval($linked_item['id']), - intval(TERM_OBJ_POST), - intval($t['ttype']), - dbesc($t['term']), - dbesc($t['url']) - ); - } - } + intval($page_owner_uid), + intval($linked_item['id']), + intval(TERM_OBJ_POST), + intval($t['ttype']), + dbesc($t['term']), + dbesc($t['url']) + ); + } + } - $body = z_input_filter($body,'text/bbcode'); + $body = z_input_filter($body, 'text/bbcode'); - $obj = EMPTY_STR; + $obj = EMPTY_STR; - if (isset($linked_item['obj']) && strlen($linked_item['obj'])) { - $obj = json_decode($linked_item['obj'],true); - - $obj['name'] = (($title) ? $title : $p[0]['filename']); - $obj['summary'] = (($desc) ? $desc : $p[0]['filename']); - $obj['updated'] = datetime_convert('UTC','UTC','now',ATOM_TIME); - $obj['source'] = [ 'content' => $body, 'mediaType' => 'text/bbcode' ]; - $obj['content'] = bbcode($body . $footer_text, [ 'export' => true ]); - if (isset($obj['url']) && is_array($obj['url'])) { - for ($x = 0; $x < count($obj['url']); $x ++) { - $obj['url'][$x]['summary'] = $obj['summary']; - } - } - $obj = json_encode($obj); - } + if (isset($linked_item['obj']) && strlen($linked_item['obj'])) { + $obj = json_decode($linked_item['obj'], true); - // make sure the linked item has the same permissions as the photo regardless of any other changes - $x = q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', title = '%s', obj = '%s', body = '%s', edited = '%s', item_private = %d where id = %d", - dbesc($perm['allow_cid']), - dbesc($perm['allow_gid']), - dbesc($perm['deny_cid']), - dbesc($perm['deny_gid']), - dbesc(($desc) ? $desc : $p[0]['filename']), - dbesc($obj), - dbesc($body . $footer_text), - dbesc(datetime_convert()), - intval($acl->is_private()), - intval($item_id) - ); - - // make sure the attach has the same permissions as the photo regardless of any other changes - $x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d and is_photo = 1", - dbesc($perm['allow_cid']), - dbesc($perm['allow_gid']), - dbesc($perm['deny_cid']), - dbesc($perm['deny_gid']), - dbesc($resource_id), - intval($page_owner_uid) - ); - + $obj['name'] = (($title) ? $title : $p[0]['filename']); + $obj['summary'] = (($desc) ? $desc : $p[0]['filename']); + $obj['updated'] = datetime_convert('UTC', 'UTC', 'now', ATOM_TIME); + $obj['source'] = ['content' => $body, 'mediaType' => 'text/bbcode']; + $obj['content'] = bbcode($body . $footer_text, ['export' => true]); + if (isset($obj['url']) && is_array($obj['url'])) { + for ($x = 0; $x < count($obj['url']); $x++) { + $obj['url'][$x]['summary'] = $obj['summary']; + } + } + $obj = json_encode($obj); + } - if($visibility) { - Run::Summon( [ 'Notifier', 'edit_post', $item_id ] ); - } + // make sure the linked item has the same permissions as the photo regardless of any other changes + $x = q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', title = '%s', obj = '%s', body = '%s', edited = '%s', item_private = %d where id = %d", + dbesc($perm['allow_cid']), + dbesc($perm['allow_gid']), + dbesc($perm['deny_cid']), + dbesc($perm['deny_gid']), + dbesc(($desc) ? $desc : $p[0]['filename']), + dbesc($obj), + dbesc($body . $footer_text), + dbesc(datetime_convert()), + intval($acl->is_private()), + intval($item_id) + ); - $sync = attach_export_data(App::$data['channel'],$resource_id); - - if($sync) - Libsync::build_sync_packet($page_owner_uid, [ 'file' => [ $sync ] ]); - - goaway(z_root() . '/' . $_SESSION['photo_return']); - return; // NOTREACHED - - - } - - - /** - * default post action - upload a photo - */ - - $channel = App::$data['channel']; - $observer = App::$data['observer']; - - $_REQUEST['source'] = 'photos'; - require_once('include/attach.php'); - - if(! local_channel()) { - $_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']); - $_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']); - $_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']); - $_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']); - } - + // make sure the attach has the same permissions as the photo regardless of any other changes + $x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d and is_photo = 1", + dbesc($perm['allow_cid']), + dbesc($perm['allow_gid']), + dbesc($perm['deny_cid']), + dbesc($perm['deny_gid']), + dbesc($resource_id), + intval($page_owner_uid) + ); - $matches = []; - $partial = false; - if(array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { - $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); - if($pm) { - logger('Content-Range: ' . print_r($matches,true)); - $partial = true; - } - } + if ($visibility) { + Run::Summon(['Notifier', 'edit_post', $item_id]); + } - if($partial) { - $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + $sync = attach_export_data(App::$data['channel'], $resource_id); - if($x['partial']) { - header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($x); - } - else { - header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + if ($sync) + Libsync::build_sync_packet($page_owner_uid, ['file' => [$sync]]); - $_FILES['userfile'] = [ - 'name' => $x['name'], - 'type' => $x['type'], - 'tmp_name' => $x['tmp_name'], - 'error' => $x['error'], - 'size' => $x['size'] - ]; - } - } - else { - if(! array_key_exists('userfile',$_FILES)) { - $_FILES['userfile'] = [ - 'name' => $_FILES['files']['name'], - 'type' => $_FILES['files']['type'], - 'tmp_name' => $_FILES['files']['tmp_name'], - 'error' => $_FILES['files']['error'], - 'size' => $_FILES['files']['size'] - ]; - } - } + goaway(z_root() . '/' . $_SESSION['photo_return']); + return; // NOTREACHED - $r = attach_store($channel,get_observer_hash(), '', $_REQUEST); - - if(! $r['success']) { - notice($r['message'] . EOL); - if (is_ajax()) { - killme(); - } - goaway(z_root() . '/photos/' . App::$data['channel']['channel_address']); - } - if ($r['success'] && ! intval($r['data']['is_photo'])) { - notice( sprintf( t('%s: Unsupported photo type. Saved as file.'), escape_tags($r['data']['filename']))); - } - if (is_ajax()) { - killme(); - } - - goaway(z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $r['data']['folder']); - - } - - - - function get() { - - // URLs: - // photos/name - // photos/name/album/xxxxx (xxxxx is album name) - // photos/name/image/xxxxx - - - if(observer_prohibited()) { - notice( t('Public access denied.') . EOL); - return; - } - - $unsafe = 1 - get_safemode(); - - - if(! x(App::$data,'channel')) { - notice( t('No photos selected') . EOL ); - return; - } - - $ph = photo_factory(''); - $phototypes = $ph->supportedTypes(); - - $_SESSION['photo_return'] = App::$cmd; - - // - // Parse arguments - // - - $can_comment = perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),'post_comments'); - - if(argc() > 3) { - $datatype = argv(2); - $datum = argv(3); - } - else { - if(argc() > 2) { - $datatype = argv(2); - $datum = ''; - } - else - $datatype = 'summary'; - } - - if(argc() > 4) - $cmd = argv(4); - else - $cmd = 'view'; - - // - // Setup permissions structures - // - - $can_post = false; - $visitor = 0; - - - $owner_uid = App::$data['channel']['channel_id']; - $owner_aid = App::$data['channel']['channel_account_id']; - - $observer = App::get_observer(); - - $can_post = perm_is_allowed($owner_uid,$observer['xchan_hash'],'write_storage'); - $can_view = perm_is_allowed($owner_uid,$observer['xchan_hash'],'view_storage'); - - if(! $can_view) { - notice( t('Access to this item is restricted.') . EOL); - return; - } - - $sql_item = item_permissions_sql($owner_uid,get_observer_hash()); - $sql_extra = permissions_sql($owner_uid,get_observer_hash(),'photo'); - $sql_attach = permissions_sql($owner_uid,get_observer_hash(),'attach'); - nav_set_selected('Photos'); - - $o = ' + } + + + /** + * default post action - upload a photo + */ + + $channel = App::$data['channel']; + $observer = App::$data['observer']; + + $_REQUEST['source'] = 'photos'; + require_once('include/attach.php'); + + if (!local_channel()) { + $_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']); + $_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']); + $_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']); + $_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']); + } + + + $matches = []; + $partial = false; + + if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches, true)); + $partial = true; + } + } + + if ($partial) { + $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]); + + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($x); + } else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } else { + if (!array_key_exists('userfile', $_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $r = attach_store($channel, get_observer_hash(), '', $_REQUEST); + + if (!$r['success']) { + notice($r['message'] . EOL); + if (is_ajax()) { + killme(); + } + goaway(z_root() . '/photos/' . App::$data['channel']['channel_address']); + } + if ($r['success'] && !intval($r['data']['is_photo'])) { + notice(sprintf(t('%s: Unsupported photo type. Saved as file.'), escape_tags($r['data']['filename']))); + } + if (is_ajax()) { + killme(); + } + + goaway(z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $r['data']['folder']); + + } + + + public function get() + { + + // URLs: + // photos/name + // photos/name/album/xxxxx (xxxxx is album name) + // photos/name/image/xxxxx + + + if (observer_prohibited()) { + notice(t('Public access denied.') . EOL); + return; + } + + $unsafe = 1 - get_safemode(); + + + if (!x(App::$data, 'channel')) { + notice(t('No photos selected') . EOL); + return; + } + + $ph = photo_factory(''); + $phototypes = $ph->supportedTypes(); + + $_SESSION['photo_return'] = App::$cmd; + + // + // Parse arguments + // + + $can_comment = perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'post_comments'); + + if (argc() > 3) { + $datatype = argv(2); + $datum = argv(3); + } else { + if (argc() > 2) { + $datatype = argv(2); + $datum = ''; + } else + $datatype = 'summary'; + } + + if (argc() > 4) + $cmd = argv(4); + else + $cmd = 'view'; + + // + // Setup permissions structures + // + + $can_post = false; + $visitor = 0; + + + $owner_uid = App::$data['channel']['channel_id']; + $owner_aid = App::$data['channel']['channel_account_id']; + + $observer = App::get_observer(); + + $can_post = perm_is_allowed($owner_uid, $observer['xchan_hash'], 'write_storage'); + $can_view = perm_is_allowed($owner_uid, $observer['xchan_hash'], 'view_storage'); + + if (!$can_view) { + notice(t('Access to this item is restricted.') . EOL); + return; + } + + $sql_item = item_permissions_sql($owner_uid, get_observer_hash()); + $sql_extra = permissions_sql($owner_uid, get_observer_hash(), 'photo'); + $sql_attach = permissions_sql($owner_uid, get_observer_hash(), 'attach'); + + nav_set_selected('Photos'); + + $o = ' '; - $o .= "\r\n"; - - $_is_owner = (local_channel() && (local_channel() == $owner_uid)); - - /** - * Display upload form - */ - - if ($can_post) { - - $uploader = ''; - - $ret = array('post_url' => z_root() . '/photos/' . App::$data['channel']['channel_address'], - 'addon_text' => $uploader, - 'default_upload' => true); - - call_hooks('photo_upload_form',$ret); - - /* Show space usage */ - - $r = q("select sum(filesize) as total from photo where aid = %d and imgscale = 0 ", - intval(App::$data['channel']['channel_account_id']) - ); - - - $limit = engr_units_to_bytes(service_class_fetch(App::$data['channel']['channel_id'],'photo_upload_limit')); - if($limit !== false) { - $usage_message = sprintf( t("%1$.2f MB of %2$.2f MB photo storage used."), $r[0]['total'] / 1024000, $limit / 1024000 ); - } - else { - $usage_message = sprintf( t('%1$.2f MB photo storage used.'), $r[0]['total'] / 1024000 ); - } - - if($_is_owner) { - $channel = App::get_channel(); - - $acl = new AccessControl($channel); - $channel_acl = $acl->get(); - - $lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); - } - - $aclselect = (($_is_owner) ? populate_acl($channel_acl,false, PermissionDescription::fromGlobalPermission('view_storage')) : ''); - - // this is wrong but is to work around an issue with js_upload wherein it chokes if these variables - // don't exist. They really should be set to a parseable representation of the channel's default permissions - // which can be processed by getSelected() - - if(! $aclselect) { - $aclselect = ''; - } + $o .= "\r\n"; - $selname = ''; + $_is_owner = (local_channel() && (local_channel() == $owner_uid)); - if($datum) { - $h = attach_by_hash_nodata($datum,get_observer_hash()); - $selname = $h['data']['display_path']; - } + /** + * Display upload form + */ - - $albums = ((array_key_exists('albums', App::$data)) ? App::$data['albums'] : photos_albums_list(App::$data['channel'],App::$data['observer'])); - - if(! $selname) { - $def_album = get_pconfig(App::$data['channel']['channel_id'],'system','photo_path'); - if($def_album) { - $selname = filepath_macro($def_album); - $albums['album'][] = array('text' => $selname); - } - } - - $tpl = get_markup_template('photos_upload.tpl'); - $upload_form = replace_macros($tpl,array( - '$pagename' => t('Upload Photos'), - '$sessid' => session_id(), - '$usage' => $usage_message, - '$nickname' => App::$data['channel']['channel_address'], - '$newalbum_label' => t('Enter an album name'), - '$newalbum_placeholder' => t('or select an existing album (doubleclick)'), - '$visible' => array('visible', t('Create a status post for this upload'), 0, t('If multiple files are selected, the message will be repeated for each photo'), array(t('No'), t('Yes')), 'onclick="showHideBodyTextarea();"'), - '$caption' => array('description', t('Please briefly describe this photo for vision-impaired viewers')), - 'title' => [ 'title', t('Title (optional)') ], - '$body' => array('body', t('Your message (optional)'),'', 'This will only appear in the status post'), - '$albums' => $albums['albums'], - '$selname' => $selname, - '$permissions' => t('Permissions'), - '$aclselect' => $aclselect, - '$allow_cid' => acl2json($channel_acl['allow_cid']), - '$allow_gid' => acl2json($channel_acl['allow_gid']), - '$deny_cid' => acl2json($channel_acl['deny_cid']), - '$deny_gid' => acl2json($channel_acl['deny_gid']), - '$lockstate' => $lockstate, - '$uploader' => $ret['addon_text'], - '$default' => (($ret['default_upload']) ? true : false), - '$uploadurl' => $ret['post_url'], - '$submit' => t('Upload') - - )); - - } - - // - // dispatch request - // - - /* - * Display a single photo album - */ - - if($datatype === 'album') { + if ($can_post) { - head_add_link([ - 'rel' => 'alternate', - 'type' => 'application/json+oembed', - 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), - 'title' => 'oembed' - ]); + $uploader = ''; - if($x = photos_album_exists($owner_uid, get_observer_hash(), $datum)) { - App::set_pager_itemspage(60); - $album = $x['display_path']; - } - else { - goaway(z_root() . '/photos/' . App::$data['channel']['channel_address']); - } + $ret = array('post_url' => z_root() . '/photos/' . App::$data['channel']['channel_address'], + 'addon_text' => $uploader, + 'default_upload' => true); - if($_GET['order'] === 'posted') - $order = 'created ASC'; - elseif($_GET['order'] === 'name') - $order = 'filename ASC'; - else - $order = 'created DESC'; + call_hooks('photo_upload_form', $ret); - $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN + /* Show space usage */ + + $r = q("select sum(filesize) as total from photo where aid = %d and imgscale = 0 ", + intval(App::$data['channel']['channel_account_id']) + ); + + + $limit = engr_units_to_bytes(service_class_fetch(App::$data['channel']['channel_id'], 'photo_upload_limit')); + if ($limit !== false) { + $usage_message = sprintf(t("%1$.2f MB of %2$.2f MB photo storage used."), $r[0]['total'] / 1024000, $limit / 1024000); + } else { + $usage_message = sprintf(t('%1$.2f MB photo storage used.'), $r[0]['total'] / 1024000); + } + + if ($_is_owner) { + $channel = App::get_channel(); + + $acl = new AccessControl($channel); + $channel_acl = $acl->get(); + + $lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); + } + + $aclselect = (($_is_owner) ? populate_acl($channel_acl, false, PermissionDescription::fromGlobalPermission('view_storage')) : ''); + + // this is wrong but is to work around an issue with js_upload wherein it chokes if these variables + // don't exist. They really should be set to a parseable representation of the channel's default permissions + // which can be processed by getSelected() + + if (!$aclselect) { + $aclselect = ''; + } + + $selname = ''; + + if ($datum) { + $h = attach_by_hash_nodata($datum, get_observer_hash()); + $selname = $h['data']['display_path']; + } + + + $albums = ((array_key_exists('albums', App::$data)) ? App::$data['albums'] : photos_albums_list(App::$data['channel'], App::$data['observer'])); + + if (!$selname) { + $def_album = get_pconfig(App::$data['channel']['channel_id'], 'system', 'photo_path'); + if ($def_album) { + $selname = filepath_macro($def_album); + $albums['album'][] = array('text' => $selname); + } + } + + $tpl = get_markup_template('photos_upload.tpl'); + $upload_form = replace_macros($tpl, array( + '$pagename' => t('Upload Photos'), + '$sessid' => session_id(), + '$usage' => $usage_message, + '$nickname' => App::$data['channel']['channel_address'], + '$newalbum_label' => t('Enter an album name'), + '$newalbum_placeholder' => t('or select an existing album (doubleclick)'), + '$visible' => array('visible', t('Create a status post for this upload'), 0, t('If multiple files are selected, the message will be repeated for each photo'), array(t('No'), t('Yes')), 'onclick="showHideBodyTextarea();"'), + '$caption' => array('description', t('Please briefly describe this photo for vision-impaired viewers')), + 'title' => ['title', t('Title (optional)')], + '$body' => array('body', t('Your message (optional)'), '', 'This will only appear in the status post'), + '$albums' => $albums['albums'], + '$selname' => $selname, + '$permissions' => t('Permissions'), + '$aclselect' => $aclselect, + '$allow_cid' => acl2json($channel_acl['allow_cid']), + '$allow_gid' => acl2json($channel_acl['allow_gid']), + '$deny_cid' => acl2json($channel_acl['deny_cid']), + '$deny_gid' => acl2json($channel_acl['deny_gid']), + '$lockstate' => $lockstate, + '$uploader' => $ret['addon_text'], + '$default' => (($ret['default_upload']) ? true : false), + '$uploadurl' => $ret['post_url'], + '$submit' => t('Upload') + + )); + + } + + // + // dispatch request + // + + /* + * Display a single photo album + */ + + if ($datatype === 'album') { + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), + 'title' => 'oembed' + ]); + + if ($x = photos_album_exists($owner_uid, get_observer_hash(), $datum)) { + App::set_pager_itemspage(60); + $album = $x['display_path']; + } else { + goaway(z_root() . '/photos/' . App::$data['channel']['channel_address']); + } + + if ($_GET['order'] === 'posted') + $order = 'created ASC'; + elseif ($_GET['order'] === 'name') + $order = 'filename ASC'; + else + $order = 'created DESC'; + + $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN (SELECT resource_id, max(imgscale) imgscale FROM photo left join attach on folder = '%s' and photo.resource_id = attach.hash WHERE attach.uid = %d AND imgscale <= 4 AND photo_usage IN ( %d, %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale) ORDER BY $order LIMIT %d OFFSET %d", - dbesc($x['hash']), - intval($owner_uid), - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - intval(PHOTO_COVER), - intval($unsafe), - intval(App::$pager['itemspage']), - intval(App::$pager['start']) - ); + dbesc($x['hash']), + intval($owner_uid), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval(PHOTO_COVER), + intval($unsafe), + intval(App::$pager['itemspage']), + intval(App::$pager['start']) + ); - // edit album name - $album_edit = null; + // edit album name + $album_edit = null; - if($can_post) { - $album_e = $album; - $albums = ((array_key_exists('albums', App::$data)) ? App::$data['albums'] : photos_albums_list(App::$data['channel'],App::$data['observer'])); - - // @fixme - syncronise actions with DAV - - // $edit_tpl = get_markup_template('album_edit.tpl'); - // $album_edit = replace_macros($edit_tpl,array( - // '$nametext' => t('Enter a new album name'), - // '$name_placeholder' => t('or select an existing one (doubleclick)'), - // '$nickname' => App::$data['channel']['channel_address'], - // '$album' => $album_e, - // '$albums' => $albums['albums'], - // '$hexalbum' => bin2hex($album), - // '$submit' => t('Submit'), - // '$dropsubmit' => t('Delete Album') - // )); - - } - - $order = [ - [ t('Date descending'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $datum ], - [ t('Date ascending'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $datum . '?f=&order=posted'], - [ t('Name ascending'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $datum . '?f=&order=name'] - ]; - - - $photos = []; - if(count($r)) { - $twist = 'rotright'; - foreach($r as $rr) { - - if($twist == 'rotright') - $twist = 'rotleft'; - else - $twist = 'rotright'; - - $ext = $phototypes[$rr['mimetype']]; - - $imgalt_e = $rr['filename']; - $desc_e = $rr['description']; - - $imagelink = (z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'] - . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '')); - - $photos[] = array( - 'id' => $rr['id'], - 'twist' => ' ' . $twist . rand(2,4), - 'link' => $imagelink, - 'title' => t('View Photo'), - 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext, - 'alt' => $imgalt_e, - 'desc'=> $desc_e, - 'ext' => $ext, - 'hash'=> $rr['resource_id'], - 'unknown' => t('Unknown') - ); - } - } - - if($_REQUEST['aj']) { - if($photos) { - $o = replace_macros(get_markup_template('photosajax.tpl'),array( - '$photos' => $photos, - '$album_id' => $datum - )); - } - else { - $o = '
      '; - } - echo $o; - killme(); - } - else { - $o .= ""; - $tpl = get_markup_template('photo_album.tpl'); - $o .= replace_macros($tpl, array( - '$photos' => $photos, - '$album' => $album, - '$album_id' => $datum, - '$file_view' => t('View files'), - '$files_path' => z_root() . '/cloud/' . App::$data['channel']['channel_address'] . '/' . $x['display_path'], - '$album_edit' => array(t('Edit Album'), $album_edit), - '$can_post' => $can_post, - '$upload' => array(t('Add Photos'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/upload/' . $datum), - '$order' => $order, - '$sort' => t('Sort'), - '$upload_form' => $upload_form, - '$usage' => $usage_message - )); + if ($can_post) { + $album_e = $album; + $albums = ((array_key_exists('albums', App::$data)) ? App::$data['albums'] : photos_albums_list(App::$data['channel'], App::$data['observer'])); - return $o; - } - } - - /** - * Display one photo - */ - - if($datatype === 'image') { + // @fixme - syncronise actions with DAV - head_add_link([ - 'rel' => 'alternate', - 'type' => 'application/json+oembed', - 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), - 'title' => 'oembed' - ]); + // $edit_tpl = get_markup_template('album_edit.tpl'); + // $album_edit = replace_macros($edit_tpl,array( + // '$nametext' => t('Enter a new album name'), + // '$name_placeholder' => t('or select an existing one (doubleclick)'), + // '$nickname' => App::$data['channel']['channel_address'], + // '$album' => $album_e, + // '$albums' => $albums['albums'], + // '$hexalbum' => bin2hex($album), + // '$submit' => t('Submit'), + // '$dropsubmit' => t('Delete Album') + // )); - $x = q("select folder from attach where hash = '%s' and uid = %d $sql_attach limit 1", - dbesc($datum), - intval($owner_uid) - ); + } - // fetch image, item containing image, then comments - - $ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,description,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM photo WHERE uid = %d AND resource_id = '%s' + $order = [ + [t('Date descending'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $datum], + [t('Date ascending'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $datum . '?f=&order=posted'], + [t('Name ascending'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $datum . '?f=&order=name'] + ]; + + + $photos = []; + if (count($r)) { + $twist = 'rotright'; + foreach ($r as $rr) { + + if ($twist == 'rotright') + $twist = 'rotleft'; + else + $twist = 'rotright'; + + $ext = $phototypes[$rr['mimetype']]; + + $imgalt_e = $rr['filename']; + $desc_e = $rr['description']; + + $imagelink = (z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'] + . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '')); + + $photos[] = array( + 'id' => $rr['id'], + 'twist' => ' ' . $twist . rand(2, 4), + 'link' => $imagelink, + 'title' => t('View Photo'), + 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' . $ext, + 'alt' => $imgalt_e, + 'desc' => $desc_e, + 'ext' => $ext, + 'hash' => $rr['resource_id'], + 'unknown' => t('Unknown') + ); + } + } + + if ($_REQUEST['aj']) { + if ($photos) { + $o = replace_macros(get_markup_template('photosajax.tpl'), array( + '$photos' => $photos, + '$album_id' => $datum + )); + } else { + $o = '
      '; + } + echo $o; + killme(); + } else { + $o .= ""; + $tpl = get_markup_template('photo_album.tpl'); + $o .= replace_macros($tpl, array( + '$photos' => $photos, + '$album' => $album, + '$album_id' => $datum, + '$file_view' => t('View files'), + '$files_path' => z_root() . '/cloud/' . App::$data['channel']['channel_address'] . '/' . $x['display_path'], + '$album_edit' => array(t('Edit Album'), $album_edit), + '$can_post' => $can_post, + '$upload' => array(t('Add Photos'), z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/upload/' . $datum), + '$order' => $order, + '$sort' => t('Sort'), + '$upload_form' => $upload_form, + '$usage' => $usage_message + )); + + return $o; + } + } + + /** + * Display one photo + */ + + if ($datatype === 'image') { + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), + 'title' => 'oembed' + ]); + + $x = q("select folder from attach where hash = '%s' and uid = %d $sql_attach limit 1", + dbesc($datum), + intval($owner_uid) + ); + + // fetch image, item containing image, then comments + + $ph = q("SELECT id,aid,uid,xchan,resource_id,created,edited,title,description,album,filename,mimetype,height,width,filesize,imgscale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM photo WHERE uid = %d AND resource_id = '%s' $sql_extra ORDER BY imgscale ASC ", - intval($owner_uid), - dbesc($datum) - ); - - if(! ($ph && $x)) { - - /* Check again - this time without specifying permissions */ - - $ph = q("SELECT id FROM photo WHERE uid = %d AND resource_id = '%s' LIMIT 1", - intval($owner_uid), - dbesc($datum) - ); - if($ph) - notice( t('Permission denied. Access to this item may be restricted.') . EOL); - else - notice( t('Photo not available') . EOL ); - return; - } - - - - $prevlink = ''; - $nextlink = ''; - - if($_GET['order'] === 'posted') - $order = 'created ASC'; - elseif ($_GET['order'] === 'name') - $order = 'filename ASC'; - else - $order = 'created DESC'; - + intval($owner_uid), + dbesc($datum) + ); - $prvnxt = q("SELECT hash FROM attach WHERE folder = '%s' AND uid = %d AND is_photo = 1 + if (!($ph && $x)) { + + /* Check again - this time without specifying permissions */ + + $ph = q("SELECT id FROM photo WHERE uid = %d AND resource_id = '%s' LIMIT 1", + intval($owner_uid), + dbesc($datum) + ); + if ($ph) + notice(t('Permission denied. Access to this item may be restricted.') . EOL); + else + notice(t('Photo not available') . EOL); + return; + } + + + $prevlink = ''; + $nextlink = ''; + + if ($_GET['order'] === 'posted') + $order = 'created ASC'; + elseif ($_GET['order'] === 'name') + $order = 'filename ASC'; + else + $order = 'created DESC'; + + + $prvnxt = q("SELECT hash FROM attach WHERE folder = '%s' AND uid = %d AND is_photo = 1 $sql_attach ORDER BY $order ", - dbesc($x[0]['folder']), - intval($owner_uid) - ); + dbesc($x[0]['folder']), + intval($owner_uid) + ); - if(count($prvnxt)) { - for($z = 0; $z < count($prvnxt); $z++) { - if($prvnxt[$z]['hash'] == $ph[0]['resource_id']) { - $prv = $z - 1; - $nxt = $z + 1; - if($prv < 0) - $prv = count($prvnxt) - 1; - if($nxt >= count($prvnxt)) - $nxt = 0; - break; - } - } - - $prevlink = z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['hash'] . (($_GET['order']) ? '?f=&order=' . $_GET['order'] : ''); - $nextlink = z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['hash'] . (($_GET['order']) ? '?f=&order=' . $_GET['order'] : ''); - } - - - if(count($ph) == 1) - $hires = $lores = $ph[0]; - if(count($ph) > 1) { - if($ph[1]['imgscale'] == 2) { - // original is 640 or less, we can display it directly - $hires = $lores = $ph[0]; - } - else { - $hires = $ph[0]; - $lores = $ph[1]; - } - } - - $album_link = z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $x[0]['folder']; - $tools = Null; - $lock = Null; - - if($can_post && ($ph[0]['uid'] == $owner_uid)) { - $tools = array( - 'profile'=>array(z_root() . '/profile_photo/use/'.$ph[0]['resource_id'], t('Use as profile photo')), - 'cover'=>array(z_root() . '/cover_photo/use/'.$ph[0]['resource_id'], t('Use as cover photo')), - ); - } - - // lockstate - $lockstate = ( ( (strlen($ph[0]['allow_cid']) || strlen($ph[0]['allow_gid']) - || strlen($ph[0]['deny_cid']) || strlen($ph[0]['deny_gid'])) ) - ? array('lock', t('Private Photo')) - : array('unlock', Null)); - - App::$page['htmlhead'] .= ''; - - if($prevlink) - $prevlink = array($prevlink, t('Previous')); - - $photo = array( - 'href' => z_root() . '/photo/' . $hires['resource_id'] . '-' . $hires['imgscale'] . '.' . $phototypes[$hires['mimetype']], - 'title'=> t('View Full Size'), - 'src' => z_root() . '/photo/' . $lores['resource_id'] . '-' . $lores['imgscale'] . '.' . $phototypes[$lores['mimetype']] . '?f=&_u=' . datetime_convert('','','','ymdhis') - ); - - if($nextlink) - $nextlink = array($nextlink, t('Next')); - - - // Do we have an item for this photo? - - $linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo' and uid = %d + if (count($prvnxt)) { + for ($z = 0; $z < count($prvnxt); $z++) { + if ($prvnxt[$z]['hash'] == $ph[0]['resource_id']) { + $prv = $z - 1; + $nxt = $z + 1; + if ($prv < 0) + $prv = count($prvnxt) - 1; + if ($nxt >= count($prvnxt)) + $nxt = 0; + break; + } + } + + $prevlink = z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['hash'] . (($_GET['order']) ? '?f=&order=' . $_GET['order'] : ''); + $nextlink = z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['hash'] . (($_GET['order']) ? '?f=&order=' . $_GET['order'] : ''); + } + + + if (count($ph) == 1) + $hires = $lores = $ph[0]; + if (count($ph) > 1) { + if ($ph[1]['imgscale'] == 2) { + // original is 640 or less, we can display it directly + $hires = $lores = $ph[0]; + } else { + $hires = $ph[0]; + $lores = $ph[1]; + } + } + + $album_link = z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/album/' . $x[0]['folder']; + $tools = Null; + $lock = Null; + + if ($can_post && ($ph[0]['uid'] == $owner_uid)) { + $tools = array( + 'profile' => array(z_root() . '/profile_photo/use/' . $ph[0]['resource_id'], t('Use as profile photo')), + 'cover' => array(z_root() . '/cover_photo/use/' . $ph[0]['resource_id'], t('Use as cover photo')), + ); + } + + // lockstate + $lockstate = (((strlen($ph[0]['allow_cid']) || strlen($ph[0]['allow_gid']) + || strlen($ph[0]['deny_cid']) || strlen($ph[0]['deny_gid']))) + ? array('lock', t('Private Photo')) + : array('unlock', Null)); + + App::$page['htmlhead'] .= ''; + + if ($prevlink) + $prevlink = array($prevlink, t('Previous')); + + $photo = array( + 'href' => z_root() . '/photo/' . $hires['resource_id'] . '-' . $hires['imgscale'] . '.' . $phototypes[$hires['mimetype']], + 'title' => t('View Full Size'), + 'src' => z_root() . '/photo/' . $lores['resource_id'] . '-' . $lores['imgscale'] . '.' . $phototypes[$lores['mimetype']] . '?f=&_u=' . datetime_convert('', '', '', 'ymdhis') + ); + + if ($nextlink) + $nextlink = array($nextlink, t('Next')); + + + // Do we have an item for this photo? + + $linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo' and uid = %d $sql_item LIMIT 1", - dbesc($datum), - intval($owner_uid) - ); - - $map = null; - $link_item = null; - - if($linked_items) { - - xchan_query($linked_items); - $linked_items = fetch_post_tags($linked_items,true); - - $link_item = $linked_items[0]; - $item_normal = item_normal(); - - $r = q("select * from item where parent_mid = '%s' + dbesc($datum), + intval($owner_uid) + ); + + $map = null; + $link_item = null; + + if ($linked_items) { + + xchan_query($linked_items); + $linked_items = fetch_post_tags($linked_items, true); + + $link_item = $linked_items[0]; + $item_normal = item_normal(); + + $r = q("select * from item where parent_mid = '%s' $item_normal and uid = %d $sql_item ", - dbesc($link_item['mid']), - intval($link_item['uid']) - - ); - - if($r) { - xchan_query($r); - $items = fetch_post_tags($r,true); - $sorted_items = conv_sort($items,'commented'); - } - - $tags = []; - if($link_item['term']) { - $cnt = 0; - foreach($link_item['term'] as $t) { - $tags[$cnt] = array(0 => format_term_for_display($t)); - if($can_post && ($ph[0]['uid'] == $owner_uid)) { - $tags[$cnt][1] = 'tagrm/drop/' . $link_item['id'] . '/' . bin2hex($t['term']); //?f=&item=' . $link_item['id']; - $tags[$cnt][2] = t('Remove'); - } - $cnt ++; - } - } - - if((local_channel()) && (local_channel() == $link_item['uid'])) { - q("UPDATE item SET item_unseen = 0 WHERE parent = %d and uid = %d and item_unseen = 1", - intval($link_item['parent']), - intval(local_channel()) - ); - } - - if($link_item['coord'] && Apps::system_app_installed($owner_uid,'Photomap')) { - $map = generate_map($link_item['coord']); - } - } - - // logger('mod_photo: link_item' . print_r($link_item,true)); - - // FIXME - remove this when we move to conversation module - - $comment_items = $sorted_items[0]['children']; + dbesc($link_item['mid']), + intval($link_item['uid']) - $edit = null; - if($can_post) { + ); - $album_e = $ph[0]['album']; - $caption_e = $ph[0]['description']; - $aclselect_e = (($_is_owner) ? populate_acl($ph[0], true, PermissionDescription::fromGlobalPermission('view_storage')) : ''); - $albums = ((array_key_exists('albums', App::$data)) ? App::$data['albums'] : photos_albums_list(App::$data['channel'],App::$data['observer'])); - - $_SESSION['album_return'] = bin2hex($ph[0]['album']); + if ($r) { + xchan_query($r); + $items = fetch_post_tags($r, true); + $sorted_items = conv_sort($items, 'commented'); + } - $folder_list = attach_folder_select_list($ph[0]['uid']); - $edit_body = htmlspecialchars_decode(undo_post_tagging($link_item['body']),ENT_COMPAT); - // We will regenerate the body footer - $edit_body = preg_replace('/\[footer\](.*?)\[\/footer\]/ism','',$edit_body); + $tags = []; + if ($link_item['term']) { + $cnt = 0; + foreach ($link_item['term'] as $t) { + $tags[$cnt] = array(0 => format_term_for_display($t)); + if ($can_post && ($ph[0]['uid'] == $owner_uid)) { + $tags[$cnt][1] = 'tagrm/drop/' . $link_item['id'] . '/' . bin2hex($t['term']); //?f=&item=' . $link_item['id']; + $tags[$cnt][2] = t('Remove'); + } + $cnt++; + } + } - $edit = [ - 'edit' => t('Edit photo'), - 'id' => $link_item['id'], - 'albums' => $albums['albums'], - 'album' => $album_e, - 'album_select' => [ 'move_to_album', t('Move photo to album'), $x[0]['folder'], '', $folder_list ], - 'newalbum_label' => t('Enter a new album name'), - 'newalbum_placeholder' => t('or select an existing one (doubleclick)'), - 'nickname' => App::$data['channel']['channel_address'], - 'resource_id' => $ph[0]['resource_id'], - 'desc' => [ 'desc', t('Please briefly describe this photo for vision-impaired viewers'), $ph[0]['description'] ], - 'title' => [ 'title', t('Title (optional)'), $ph[0]['title'] ], - 'body' => [ 'body', t('Your message (optional)'),$edit_body, t('This will only appear in the optional status post attached to this photo') ], - 'tag_label' => t('Add a Tag'), - 'permissions' => t('Permissions'), - 'aclselect' => $aclselect_e, - 'allow_cid' => acl2json($ph[0]['allow_cid']), - 'allow_gid' => acl2json($ph[0]['allow_gid']), - 'deny_cid' => acl2json($ph[0]['deny_cid']), - 'deny_gid' => acl2json($ph[0]['deny_gid']), - 'lockstate' => $lockstate[0], - 'help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com'), - 'item_id' => ((count($linked_items)) ? $link_item['id'] : 0), - 'adult_enabled' => feature_enabled($owner_uid,'adult_photo_flagging'), - 'adult' => array('adult',t('Flag as adult in album view'), intval($ph[0]['is_nsfw']),''), - 'submit' => t('Submit'), - 'delete' => t('Delete Photo'), - 'expandform' => ((x($_GET,'expandform')) ? true : false) - ]; - } - - if(count($linked_items)) { - - $cmnt_tpl = get_markup_template('comment_item.tpl'); - $tpl = get_markup_template('photo_item.tpl'); - $return_url = App::$cmd; - - $like_tpl = get_markup_template('like_noshare.tpl'); - - $likebuttons = ''; - $ilike = false; - $inolike = false; + if ((local_channel()) && (local_channel() == $link_item['uid'])) { + q("UPDATE item SET item_unseen = 0 WHERE parent = %d and uid = %d and item_unseen = 1", + intval($link_item['parent']), + intval(local_channel()) + ); + } + + if ($link_item['coord'] && Apps::system_app_installed($owner_uid, 'Photomap')) { + $map = generate_map($link_item['coord']); + } + } + + // logger('mod_photo: link_item' . print_r($link_item,true)); + + // FIXME - remove this when we move to conversation module + + $comment_items = $sorted_items[0]['children']; + + $edit = null; + if ($can_post) { + + $album_e = $ph[0]['album']; + $caption_e = $ph[0]['description']; + $aclselect_e = (($_is_owner) ? populate_acl($ph[0], true, PermissionDescription::fromGlobalPermission('view_storage')) : ''); + $albums = ((array_key_exists('albums', App::$data)) ? App::$data['albums'] : photos_albums_list(App::$data['channel'], App::$data['observer'])); + + $_SESSION['album_return'] = bin2hex($ph[0]['album']); + + $folder_list = attach_folder_select_list($ph[0]['uid']); + $edit_body = htmlspecialchars_decode(undo_post_tagging($link_item['body']), ENT_COMPAT); + // We will regenerate the body footer + $edit_body = preg_replace('/\[footer\](.*?)\[\/footer\]/ism', '', $edit_body); + + $edit = [ + 'edit' => t('Edit photo'), + 'id' => $link_item['id'], + 'albums' => $albums['albums'], + 'album' => $album_e, + 'album_select' => ['move_to_album', t('Move photo to album'), $x[0]['folder'], '', $folder_list], + 'newalbum_label' => t('Enter a new album name'), + 'newalbum_placeholder' => t('or select an existing one (doubleclick)'), + 'nickname' => App::$data['channel']['channel_address'], + 'resource_id' => $ph[0]['resource_id'], + 'desc' => ['desc', t('Please briefly describe this photo for vision-impaired viewers'), $ph[0]['description']], + 'title' => ['title', t('Title (optional)'), $ph[0]['title']], + 'body' => ['body', t('Your message (optional)'), $edit_body, t('This will only appear in the optional status post attached to this photo')], + 'tag_label' => t('Add a Tag'), + 'permissions' => t('Permissions'), + 'aclselect' => $aclselect_e, + 'allow_cid' => acl2json($ph[0]['allow_cid']), + 'allow_gid' => acl2json($ph[0]['allow_gid']), + 'deny_cid' => acl2json($ph[0]['deny_cid']), + 'deny_gid' => acl2json($ph[0]['deny_gid']), + 'lockstate' => $lockstate[0], + 'help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com'), + 'item_id' => ((count($linked_items)) ? $link_item['id'] : 0), + 'adult_enabled' => feature_enabled($owner_uid, 'adult_photo_flagging'), + 'adult' => array('adult', t('Flag as adult in album view'), intval($ph[0]['is_nsfw']), ''), + 'submit' => t('Submit'), + 'delete' => t('Delete Photo'), + 'expandform' => ((x($_GET, 'expandform')) ? true : false) + ]; + } + + if (count($linked_items)) { + + $cmnt_tpl = get_markup_template('comment_item.tpl'); + $tpl = get_markup_template('photo_item.tpl'); + $return_url = App::$cmd; + + $like_tpl = get_markup_template('like_noshare.tpl'); + + $likebuttons = ''; + $ilike = false; + $inolike = false; - if ($items) { - foreach ($items as $i) { - if ($i['verb'] === 'Like' && $i['author_xchan'] === get_observer_hash() && $i['thr_parent'] = $link_item['mid']) { - $ilike = true; - } - if ($i['verb'] === 'Dislike' && $i['author_xchan'] === get_observer_hash() && $i['thr_parent'] === $link_item['mid']) { - $inolike = true; - } - } - } - - if($observer && ($can_post || $can_comment)) { - $likebuttons = [ - 'id' => $link_item['id'], - 'likethis' => t('I like this'), - 'ilike' => $ilike, - 'inolike' => $inolike, - 'nolike' => t('I don\'t like this'), - 'unlikethis' => t('Undo like'), - 'unnolike' => t('Undo dislike'), - 'share' => t('Share'), - 'wait' => t('Please wait') - ]; - } + if ($items) { + foreach ($items as $i) { + if ($i['verb'] === 'Like' && $i['author_xchan'] === get_observer_hash() && $i['thr_parent'] = $link_item['mid']) { + $ilike = true; + } + if ($i['verb'] === 'Dislike' && $i['author_xchan'] === get_observer_hash() && $i['thr_parent'] === $link_item['mid']) { + $inolike = true; + } + } + } - $comments = ''; - if(! $comment_items) { - if($observer && ($can_post || $can_comment)) { - $commentbox = replace_macros($cmnt_tpl,array( - '$return_path' => '', - '$mode' => 'photos', - '$jsreload' => $return_url, - '$type' => 'wall-comment', - '$id' => $link_item['id'], - '$parent' => $link_item['id'], - '$profile_uid' => $owner_uid, - '$mylink' => $observer['xchan_url'], - '$mytitle' => t('This is you'), - '$myphoto' => $observer['xchan_photo_s'], - '$comment' => t('Comment'), - '$submit' => t('Submit'), - '$preview' => t('Preview'), - '$auto_save_draft' => 'true', - '$ww' => '', - '$feature_encrypt' => false - )); - } - } - - $alike = []; - $dlike = []; - - $like = ''; - $dislike = ''; - - $conv_responses = [ - 'like' => [ 'title' => t('Likes','title') ], - 'dislike' => [ 'title' => t('Dislikes','title') ], - 'attendyes' => [ 'title' => t('Attending','title') ], - 'attendno' => [ 'title' => t('Not attending','title') ], - 'attendmaybe' => [ 'title' => t('Might attend' ,'title') ] - ]; - - if($r) { - - foreach($r as $item) { - builtin_activity_puller($item, $conv_responses); - } - - $like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : ''); - $like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : ''); + if ($observer && ($can_post || $can_comment)) { + $likebuttons = [ + 'id' => $link_item['id'], + 'likethis' => t('I like this'), + 'ilike' => $ilike, + 'inolike' => $inolike, + 'nolike' => t('I don\'t like this'), + 'unlikethis' => t('Undo like'), + 'unnolike' => t('Undo dislike'), + 'share' => t('Share'), + 'wait' => t('Please wait') + ]; + } - if(is_array($like_list) && (count($like_list) > MAX_LIKERS)) { - $like_list_part = array_slice($like_list, 0, MAX_LIKERS); - array_push($like_list_part, '' . t('View all') . ''); - } else { - $like_list_part = ''; - } - $like_button_label = tt('Like','Likes',$like_count,'noun'); - - $dislike_count = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid']] : ''); - $dislike_list = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid'] . '-l'] : ''); - $dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun'); - if (is_array($dislike_list) && (count($dislike_list) > MAX_LIKERS)) { - $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS); - array_push($dislike_list_part, '' . t('View all') . ''); - } else { - $dislike_list_part = ''; - } + $comments = ''; + if (!$comment_items) { + if ($observer && ($can_post || $can_comment)) { + $commentbox = replace_macros($cmnt_tpl, array( + '$return_path' => '', + '$mode' => 'photos', + '$jsreload' => $return_url, + '$type' => 'wall-comment', + '$id' => $link_item['id'], + '$parent' => $link_item['id'], + '$profile_uid' => $owner_uid, + '$mylink' => $observer['xchan_url'], + '$mytitle' => t('This is you'), + '$myphoto' => $observer['xchan_photo_s'], + '$comment' => t('Comment'), + '$submit' => t('Submit'), + '$preview' => t('Preview'), + '$auto_save_draft' => 'true', + '$ww' => '', + '$feature_encrypt' => false + )); + } + } - - - $like = ((isset($alike[$link_item['mid']])) ? format_like($alike[$link_item['mid']],$alike[$link_item['mid'] . '-l'],'like',$link_item['mid']) : ''); - $dislike = ((isset($dlike[$link_item['mid']])) ? format_like($dlike[$link_item['mid']],$dlike[$link_item['mid'] . '-l'],'dislike',$link_item['mid']) : ''); - - // display comments - - foreach ($comment_items as $item) { - $comment = ''; - $template = $tpl; - $sparkle = ''; - - if (! visible_activity($item)) { - continue; - } - - $profile_url = zid($item['author']['xchan_url']); - $profile_name = $item['author']['xchan_name']; - $profile_avatar = $item['author']['xchan_photo_m']; - - $profile_link = $profile_url; - - $drop = ''; - - if($observer['xchan_hash'] === $item['author_xchan'] || $observer['xchan_hash'] === $item['owner_xchan']) - $drop = replace_macros(get_markup_template('photo_drop.tpl'), array('$id' => $item['id'], '$delete' => t('Delete'))); - - - $name_e = $profile_name; - $title_e = $item['title']; - unobscure($item); - $body_e = prepare_text($item['body'],$item['mimetype']); - - $comments .= replace_macros($template,array( - '$id' => $item['id'], - '$mode' => 'photos', - '$profile_url' => $profile_link, - '$name' => $name_e, - '$thumb' => $profile_avatar, - '$sparkle' => $sparkle, - '$title' => $title_e, - '$body' => $body_e, - '$ago' => relative_date($item['created']), - '$indent' => (($item['parent'] != $item['id']) ? ' comment' : ''), - '$drop' => $drop, - '$comment' => $comment - )); - - } - - if($observer && ($can_post || $can_comment)) { - $commentbox = replace_macros($cmnt_tpl,array( - '$return_path' => '', - '$jsreload' => $return_url, - '$type' => 'wall-comment', - '$id' => $link_item['id'], - '$parent' => $link_item['id'], - '$profile_uid' => $owner_uid, - '$mylink' => $observer['xchan_url'], - '$mytitle' => t('This is you'), - '$myphoto' => $observer['xchan_photo_s'], - '$comment' => t('Comment'), - '$submit' => t('Submit'), - '$ww' => '' - )); - } - - } - $paginate = paginate($a); - } - - $album_e = [ $album_link, $ph[0]['album'] ]; - $like_e = $like; - $dislike_e = $dislike; - - - $response_verbs = array('like','dislike'); - - $responses = get_responses($conv_responses,$response_verbs,'',$link_item); - - $o .= replace_macros(get_markup_template('photo_view.tpl'), [ - '$id' => $ph[0]['id'], - '$album' => $album_e, - '$tools_label' => t('Photo Tools'), - '$tools' => $tools, - '$lock' => $lockstate[1], - '$photo' => $photo, - '$prevlink' => $prevlink, - '$nextlink' => $nextlink, - '$title' => $ph[0]['title'], - '$desc' => $ph[0]['description'], - '$filename' => $ph[0]['filename'], - '$unknown' => t('Unknown'), - '$tag_hdr' => t('In This Photo:'), - '$tags' => $tags, - 'responses' => $responses, - '$edit' => $edit, - '$map' => $map, - '$map_text' => t('Map'), - '$likebuttons' => $likebuttons, - '$like' => $like_e, - '$dislike' => $dislike_e, - '$like_count' => $like_count, - '$like_list' => $like_list, - '$like_list_part' => $like_list_part, - '$like_button_label' => $like_button_label, - '$like_modal_title' => t('Likes','noun'), - '$dislike_modal_title' => t('Dislikes','noun'), - '$dislike_count' => $dislike_count, - '$dislike_list' => $dislike_list, - '$dislike_list_part' => $dislike_list_part, - '$dislike_button_label' => $dislike_button_label, - '$modal_dismiss' => t('Close'), - '$comments' => $comments, - '$commentbox' => $commentbox, - '$paginate' => $paginate, - ]); - - App::$data['photo_html'] = $o; - return $o; - } - - // Default - show recent photos - - head_add_link([ - 'rel' => 'alternate', - 'type' => 'application/json+oembed', - 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), - 'title' => 'oembed' - ]); + $alike = []; + $dlike = []; - App::set_pager_itemspage(60); - - $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created, p.display_path FROM photo p + $like = ''; + $dislike = ''; + + $conv_responses = [ + 'like' => ['title' => t('Likes', 'title')], + 'dislike' => ['title' => t('Dislikes', 'title')], + 'attendyes' => ['title' => t('Attending', 'title')], + 'attendno' => ['title' => t('Not attending', 'title')], + 'attendmaybe' => ['title' => t('Might attend', 'title')] + ]; + + if ($r) { + + foreach ($r as $item) { + builtin_activity_puller($item, $conv_responses); + } + + $like_count = ((x($alike, $link_item['mid'])) ? $alike[$link_item['mid']] : ''); + $like_list = ((x($alike, $link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : ''); + + if (is_array($like_list) && (count($like_list) > MAX_LIKERS)) { + $like_list_part = array_slice($like_list, 0, MAX_LIKERS); + array_push($like_list_part, '' . t('View all') . ''); + } else { + $like_list_part = ''; + } + $like_button_label = tt('Like', 'Likes', $like_count, 'noun'); + + $dislike_count = ((x($dlike, $link_item['mid'])) ? $dlike[$link_item['mid']] : ''); + $dislike_list = ((x($dlike, $link_item['mid'])) ? $dlike[$link_item['mid'] . '-l'] : ''); + $dislike_button_label = tt('Dislike', 'Dislikes', $dislike_count, 'noun'); + if (is_array($dislike_list) && (count($dislike_list) > MAX_LIKERS)) { + $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS); + array_push($dislike_list_part, '' . t('View all') . ''); + } else { + $dislike_list_part = ''; + } + + + $like = ((isset($alike[$link_item['mid']])) ? format_like($alike[$link_item['mid']], $alike[$link_item['mid'] . '-l'], 'like', $link_item['mid']) : ''); + $dislike = ((isset($dlike[$link_item['mid']])) ? format_like($dlike[$link_item['mid']], $dlike[$link_item['mid'] . '-l'], 'dislike', $link_item['mid']) : ''); + + // display comments + + foreach ($comment_items as $item) { + $comment = ''; + $template = $tpl; + $sparkle = ''; + + if (!visible_activity($item)) { + continue; + } + + $profile_url = zid($item['author']['xchan_url']); + $profile_name = $item['author']['xchan_name']; + $profile_avatar = $item['author']['xchan_photo_m']; + + $profile_link = $profile_url; + + $drop = ''; + + if ($observer['xchan_hash'] === $item['author_xchan'] || $observer['xchan_hash'] === $item['owner_xchan']) + $drop = replace_macros(get_markup_template('photo_drop.tpl'), array('$id' => $item['id'], '$delete' => t('Delete'))); + + + $name_e = $profile_name; + $title_e = $item['title']; + unobscure($item); + $body_e = prepare_text($item['body'], $item['mimetype']); + + $comments .= replace_macros($template, array( + '$id' => $item['id'], + '$mode' => 'photos', + '$profile_url' => $profile_link, + '$name' => $name_e, + '$thumb' => $profile_avatar, + '$sparkle' => $sparkle, + '$title' => $title_e, + '$body' => $body_e, + '$ago' => relative_date($item['created']), + '$indent' => (($item['parent'] != $item['id']) ? ' comment' : ''), + '$drop' => $drop, + '$comment' => $comment + )); + + } + + if ($observer && ($can_post || $can_comment)) { + $commentbox = replace_macros($cmnt_tpl, array( + '$return_path' => '', + '$jsreload' => $return_url, + '$type' => 'wall-comment', + '$id' => $link_item['id'], + '$parent' => $link_item['id'], + '$profile_uid' => $owner_uid, + '$mylink' => $observer['xchan_url'], + '$mytitle' => t('This is you'), + '$myphoto' => $observer['xchan_photo_s'], + '$comment' => t('Comment'), + '$submit' => t('Submit'), + '$ww' => '' + )); + } + + } + $paginate = paginate($a); + } + + $album_e = [$album_link, $ph[0]['album']]; + $like_e = $like; + $dislike_e = $dislike; + + + $response_verbs = array('like', 'dislike'); + + $responses = get_responses($conv_responses, $response_verbs, '', $link_item); + + $o .= replace_macros(get_markup_template('photo_view.tpl'), [ + '$id' => $ph[0]['id'], + '$album' => $album_e, + '$tools_label' => t('Photo Tools'), + '$tools' => $tools, + '$lock' => $lockstate[1], + '$photo' => $photo, + '$prevlink' => $prevlink, + '$nextlink' => $nextlink, + '$title' => $ph[0]['title'], + '$desc' => $ph[0]['description'], + '$filename' => $ph[0]['filename'], + '$unknown' => t('Unknown'), + '$tag_hdr' => t('In This Photo:'), + '$tags' => $tags, + 'responses' => $responses, + '$edit' => $edit, + '$map' => $map, + '$map_text' => t('Map'), + '$likebuttons' => $likebuttons, + '$like' => $like_e, + '$dislike' => $dislike_e, + '$like_count' => $like_count, + '$like_list' => $like_list, + '$like_list_part' => $like_list_part, + '$like_button_label' => $like_button_label, + '$like_modal_title' => t('Likes', 'noun'), + '$dislike_modal_title' => t('Dislikes', 'noun'), + '$dislike_count' => $dislike_count, + '$dislike_list' => $dislike_list, + '$dislike_list_part' => $dislike_list_part, + '$dislike_button_label' => $dislike_button_label, + '$modal_dismiss' => t('Close'), + '$comments' => $comments, + '$commentbox' => $commentbox, + '$paginate' => $paginate, + ]); + + App::$data['photo_html'] = $o; + return $o; + } + + // Default - show recent photos + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), + 'title' => 'oembed' + ]); + + App::set_pager_itemspage(60); + + $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.album, p.imgscale, p.created, p.display_path FROM photo p INNER JOIN ( SELECT resource_id, max(imgscale) imgscale FROM photo WHERE photo.uid = %d AND photo_usage IN ( %d, %d ) AND is_nsfw = %d $sql_extra group by resource_id ) ph ON (p.resource_id = ph.resource_id and p.imgscale = ph.imgscale) ORDER by p.created DESC LIMIT %d OFFSET %d", - intval(App::$data['channel']['channel_id']), - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - intval($unsafe), - intval(App::$pager['itemspage']), - intval(App::$pager['start']) - ); - - $photos = []; - if($r) { - $twist = 'rotright'; - foreach($r as $rr) { + intval(App::$data['channel']['channel_id']), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval($unsafe), + intval(App::$pager['itemspage']), + intval(App::$pager['start']) + ); - if(! attach_can_view_folder(App::$data['channel']['channel_id'],get_observer_hash(),$rr['resource_id'])) - continue; + $photos = []; + if ($r) { + $twist = 'rotright'; + foreach ($r as $rr) { - if($twist == 'rotright') - $twist = 'rotleft'; - else - $twist = 'rotright'; - $ext = $phototypes[$rr['mimetype']]; - - $alt_e = $rr['filename']; - $name_e = dirname($rr['display_path']); + if (!attach_can_view_folder(App::$data['channel']['channel_id'], get_observer_hash(), $rr['resource_id'])) + continue; - $photos[] = [ - 'id' => $rr['id'], - 'twist' => ' ' . $twist . rand(2,4), - 'link' => z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'], - 'title' => t('View Photo'), - 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . ((($rr['imgscale']) == 6) ? 4 : $rr['imgscale']) . '.' . $ext, - 'alt' => $alt_e, - 'album' => [ 'name' => $name_e ], - ]; - } - } - - if($_REQUEST['aj']) { - if($photos) { - $o = replace_macros(get_markup_template('photosajax.tpl'), [ - '$photos' => $photos, - '$album_id' => bin2hex(t('Recent Photos')) - ]); - } - else { - $o = '
      '; - } - echo $o; - killme(); - } - else { + if ($twist == 'rotright') + $twist = 'rotleft'; + else + $twist = 'rotright'; + $ext = $phototypes[$rr['mimetype']]; - $o .= ""; + $alt_e = $rr['filename']; + $name_e = dirname($rr['display_path']); - $o .= replace_macros(get_markup_template('photos_recent.tpl'), [ - '$title' => t('Recent Photos'), - '$album_id' => bin2hex(t('Recent Photos')), - '$file_view' => t('View files'), - '$files_path' => z_root() . '/cloud/' . App::$data['channel']['channel_address'], - '$can_post' => $can_post, - '$upload' => t('Add Photos'), - '$photos' => $photos, - '$upload_form' => $upload_form, - '$usage' => $usage_message - ]); + $photos[] = [ + 'id' => $rr['id'], + 'twist' => ' ' . $twist . rand(2, 4), + 'link' => z_root() . '/photos/' . App::$data['channel']['channel_address'] . '/image/' . $rr['resource_id'], + 'title' => t('View Photo'), + 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . ((($rr['imgscale']) == 6) ? 4 : $rr['imgscale']) . '.' . $ext, + 'alt' => $alt_e, + 'album' => ['name' => $name_e], + ]; + } + } - return $o; - } - } + if ($_REQUEST['aj']) { + if ($photos) { + $o = replace_macros(get_markup_template('photosajax.tpl'), [ + '$photos' => $photos, + '$album_id' => bin2hex(t('Recent Photos')) + ]); + } else { + $o = '
      '; + } + echo $o; + killme(); + } else { + + $o .= ""; + + $o .= replace_macros(get_markup_template('photos_recent.tpl'), [ + '$title' => t('Recent Photos'), + '$album_id' => bin2hex(t('Recent Photos')), + '$file_view' => t('View files'), + '$files_path' => z_root() . '/cloud/' . App::$data['channel']['channel_address'], + '$can_post' => $can_post, + '$upload' => t('Add Photos'), + '$photos' => $photos, + '$upload_form' => $upload_form, + '$usage' => $usage_message + ]); + + return $o; + } + } } diff --git a/Zotlabs/Module/Pin.php b/Zotlabs/Module/Pin.php index 1daa7c524..a98b9aaec 100644 --- a/Zotlabs/Module/Pin.php +++ b/Zotlabs/Module/Pin.php @@ -10,54 +10,55 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Lib\PConfig; use Zotlabs\Web\Controller; -class Pin extends Controller { +class Pin extends Controller +{ - function init() { + public function init() + { - if(argc() !== 1) - http_status_exit(400, 'Bad request'); + if (argc() !== 1) + http_status_exit(400, 'Bad request'); - if(! local_channel()) - http_status_exit(403, 'Forbidden'); - } + if (!local_channel()) + http_status_exit(403, 'Forbidden'); + } - function post() { + public function post() + { - $item_id = intval($_POST['id']); + $item_id = intval($_POST['id']); - if ($item_id <= 0) { - http_status_exit(404, 'Not found'); - } - $channel = App::get_channel(); + if ($item_id <= 0) { + http_status_exit(404, 'Not found'); + } + $channel = App::get_channel(); - $r = q("SELECT * FROM item WHERE id = %d AND id = parent AND uid = %d AND owner_xchan = '%s' AND item_private = 0 LIMIT 1", - intval($item_id), - intval($channel['channel_id']), - dbesc($channel['channel_hash']) - ); - - if (!$r) { - notice( t('Unable to locate original post.')); - http_status_exit(404, 'Not found'); - } - else { - $pinned = PConfig::Get($channel['channel_id'], 'pinned', $r[0]['item_type'], []); - if (in_array($r[0]['mid'], $pinned)) { - $narr = []; - foreach ($pinned as $p) { - if ($p !== $r[0]['mid']) { - $narr[] = $r[0]['mid']; - } - } - } - else { - $narr = $pinned; - $narr[] = $r[0]['mid']; - } - PConfig::Set($channel['channel_id'], 'pinned', $r[0]['item_type'], $narr); - Libsync::build_sync_packet($channel['channel_id']); - } - } + $r = q("SELECT * FROM item WHERE id = %d AND id = parent AND uid = %d AND owner_xchan = '%s' AND item_private = 0 LIMIT 1", + intval($item_id), + intval($channel['channel_id']), + dbesc($channel['channel_hash']) + ); + + if (!$r) { + notice(t('Unable to locate original post.')); + http_status_exit(404, 'Not found'); + } else { + $pinned = PConfig::Get($channel['channel_id'], 'pinned', $r[0]['item_type'], []); + if (in_array($r[0]['mid'], $pinned)) { + $narr = []; + foreach ($pinned as $p) { + if ($p !== $r[0]['mid']) { + $narr[] = $r[0]['mid']; + } + } + } else { + $narr = $pinned; + $narr[] = $r[0]['mid']; + } + PConfig::Set($channel['channel_id'], 'pinned', $r[0]['item_type'], $narr); + Libsync::build_sync_packet($channel['channel_id']); + } + } } diff --git a/Zotlabs/Module/Ping.php b/Zotlabs/Module/Ping.php index 419e0ecc8..b343beddd 100644 --- a/Zotlabs/Module/Ping.php +++ b/Zotlabs/Module/Ping.php @@ -15,174 +15,174 @@ require_once('include/bbcode.php'); * Called from the client at regular intervals to check for updates from the server * */ +class Ping extends Controller +{ -class Ping extends Controller { + /** + * @brief do several updates when pinged. + * + * This function does several tasks. Whenever called it checks for new messages, + * introductions, notifications, etc. and returns a json with the results. + * + * @result JSON + */ - /** - * @brief do several updates when pinged. - * - * This function does several tasks. Whenever called it checks for new messages, - * introductions, notifications, etc. and returns a json with the results. - * - * @result JSON - */ + public function init() + { - function init() { + $result = []; + $notifs = []; - $result = []; - $notifs = []; + $result['notify'] = 0; + $result['home'] = 0; + $result['stream'] = 0; + $result['intros'] = 0; + $result['register'] = 0; + $result['moderate'] = 0; + $result['events'] = 0; + $result['events_today'] = 0; + $result['birthdays'] = 0; + $result['birthdays_today'] = 0; + $result['all_events'] = 0; + $result['all_events_today'] = 0; + $result['pubs'] = 0; + $result['files'] = 0; + $result['forums'] = 0; + $result['forums_sub'] = []; + $result['reports'] = 0; - $result['notify'] = 0; - $result['home'] = 0; - $result['stream'] = 0; - $result['intros'] = 0; - $result['register'] = 0; - $result['moderate'] = 0; - $result['events'] = 0; - $result['events_today'] = 0; - $result['birthdays'] = 0; - $result['birthdays_today'] = 0; - $result['all_events'] = 0; - $result['all_events_today'] = 0; - $result['pubs'] = 0; - $result['files'] = 0; - $result['forums'] = 0; - $result['forums_sub'] = []; - $result['reports'] = 0; - - $vnotify = false; - $evdays = 3; + $vnotify = false; + $evdays = 3; - $my_activity = 0; + $my_activity = 0; - $item_normal = item_normal(); + $item_normal = item_normal(); - if (local_channel()) { - $vnotify = get_pconfig(local_channel(),'system','vnotify'); - $evdays = intval(get_pconfig(local_channel(),'system','evdays')); - $ob_hash = get_observer_hash(); - } + if (local_channel()) { + $vnotify = get_pconfig(local_channel(), 'system', 'vnotify'); + $evdays = intval(get_pconfig(local_channel(), 'system', 'evdays')); + $ob_hash = get_observer_hash(); + } - // if unset show all visual notification types - if ($vnotify === false) { - $vnotify = (-1); - } - if ($evdays < 1) { - $evdays = 3; - } + // if unset show all visual notification types + if ($vnotify === false) { + $vnotify = (-1); + } + if ($evdays < 1) { + $evdays = 3; + } - /** - * If you have several windows open to this site and switch to a different channel - * in one of them, the others may get into a confused state showing you a page or options - * on that page which were only valid under the old identity. You session has changed. - * Therefore we send a notification of this fact back to the browser where it is picked up - * in javascript and which reloads the page it is on so that it is valid under the context - * of the now current channel. - */ + /** + * If you have several windows open to this site and switch to a different channel + * in one of them, the others may get into a confused state showing you a page or options + * on that page which were only valid under the old identity. You session has changed. + * Therefore we send a notification of this fact back to the browser where it is picked up + * in javascript and which reloads the page it is on so that it is valid under the context + * of the now current channel. + */ - $result['invalid'] = ((isset($_GET['uid']) && intval($_GET['uid'])) && (intval($_GET['uid']) != local_channel()) ? 1 : 0); + $result['invalid'] = ((isset($_GET['uid']) && intval($_GET['uid'])) && (intval($_GET['uid']) != local_channel()) ? 1 : 0); - // If we're currently installing, there won't be a populated database. - // So just send back what we have and stop here. - - if (App::$install) { - json_return_and_die($result); - } + // If we're currently installing, there won't be a populated database. + // So just send back what we have and stop here. - /** - * Update chat presence indication (if applicable) - */ + if (App::$install) { + json_return_and_die($result); + } - if (get_observer_hash() && (! $result['invalid'])) { - $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", - dbesc(get_observer_hash()), - dbesc($_SERVER['REMOTE_ADDR']) - ); - $basic_presence = false; - if ($r) { - $basic_presence = true; - q("update chatpresence set cp_last = '%s' where cp_id = %d", - dbesc(datetime_convert()), - intval($r[0]['cp_id']) - ); - } - if (! $basic_presence) { - q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client) + /** + * Update chat presence indication (if applicable) + */ + + if (get_observer_hash() && (!$result['invalid'])) { + $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + $basic_presence = false; + if ($r) { + $basic_presence = true; + q("update chatpresence set cp_last = '%s' where cp_id = %d", + dbesc(datetime_convert()), + intval($r[0]['cp_id']) + ); + } + if (!$basic_presence) { + q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client) values( '%s', '%s', '%s', '%s' ) ", - dbesc(get_observer_hash()), - dbesc(datetime_convert()), - dbesc('online'), - dbesc($_SERVER['REMOTE_ADDR']) - ); - } - } + dbesc(get_observer_hash()), + dbesc(datetime_convert()), + dbesc('online'), + dbesc($_SERVER['REMOTE_ADDR']) + ); + } + } - /** - * Chatpresence continued... if somebody hasn't pinged recently, they've most likely left the page - * and shouldn't count as online anymore. We allow an expection for bots. - */ + /** + * Chatpresence continued... if somebody hasn't pinged recently, they've most likely left the page + * and shouldn't count as online anymore. We allow an expection for bots. + */ - q("delete from chatpresence where cp_last < %s - INTERVAL %s and cp_client != 'auto' ", - db_utcnow(), db_quoteinterval('3 MINUTE') - ); + q("delete from chatpresence where cp_last < %s - INTERVAL %s and cp_client != 'auto' ", + db_utcnow(), db_quoteinterval('3 MINUTE') + ); - $sql_extra = ''; + $sql_extra = ''; - if (! ($vnotify & VNOTIFY_LIKE)) { - $sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') "; - } + if (!($vnotify & VNOTIFY_LIKE)) { + $sql_extra = " AND verb NOT IN ('" . dbesc(ACTIVITY_LIKE) . "', '" . dbesc(ACTIVITY_DISLIKE) . "') "; + } - $discover_tab_on = can_view_public_stream(); + $discover_tab_on = can_view_public_stream(); - $notify_pubs = ((local_channel()) ? ($vnotify & VNOTIFY_PUBS) && $discover_tab_on : $discover_tab_on); + $notify_pubs = ((local_channel()) ? ($vnotify & VNOTIFY_PUBS) && $discover_tab_on : $discover_tab_on); - if ($notify_pubs && local_channel() && ! Apps::system_app_installed(local_channel(),'Public Stream')) { - $notify_pubs = false; - } + if ($notify_pubs && local_channel() && !Apps::system_app_installed(local_channel(), 'Public Stream')) { + $notify_pubs = false; + } - $sys = get_sys_channel(); + $sys = get_sys_channel(); - $seenstr = EMPTY_STR; + $seenstr = EMPTY_STR; - if (local_channel()) { - $seen = PConfig::Get(local_channel(),'system','seen_items',[]); - if ($seen) { - $seenstr = " and not item.id in (" . implode(',',$seen) . ") "; - } - } + if (local_channel()) { + $seen = PConfig::Get(local_channel(), 'system', 'seen_items', []); + if ($seen) { + $seenstr = " and not item.id in (" . implode(',', $seen) . ") "; + } + } - $loadtime = get_loadtime('pubstream'); + $loadtime = get_loadtime('pubstream'); - if ($notify_pubs) { - $pubs = q("SELECT id, author_xchan from item + if ($notify_pubs) { + $pubs = q("SELECT id, author_xchan from item WHERE uid = %d AND created > '%s' $seenstr $item_normal $sql_extra", - intval($sys['channel_id']), - dbesc($loadtime) - ); + intval($sys['channel_id']), + dbesc($loadtime) + ); - if ($pubs) { - foreach($pubs as $p) { - if ($p['author_xchan'] === get_observer_hash()) { - $my_activity ++; - } - else { - $result['pubs'] ++; - } - } - } - } - - if ((argc() > 1) && (argv(1) === 'pubs') && ($notify_pubs)) { + if ($pubs) { + foreach ($pubs as $p) { + if ($p['author_xchan'] === get_observer_hash()) { + $my_activity++; + } else { + $result['pubs']++; + } + } + } + } - $local_result = []; + if ((argc() > 1) && (argv(1) === 'pubs') && ($notify_pubs)) { - $r = q("SELECT * FROM item + $local_result = []; + + $r = q("SELECT * FROM item WHERE uid = %d AND author_xchan != '%s' AND created > '%s' @@ -191,150 +191,149 @@ class Ping extends Controller { $sql_extra ORDER BY created DESC LIMIT 300", - intval($sys['channel_id']), - dbesc(get_observer_hash()), - dbesc($loadtime) - ); + intval($sys['channel_id']), + dbesc(get_observer_hash()), + dbesc($loadtime) + ); - if ($r) { - xchan_query($r); - foreach ($r as $rr) { - $rr['llink'] = str_replace('display/', 'pubstream/?f=&mid=', $rr['llink']); - $z = Enotify::format($rr); - if ($z) { - $local_result[] = $z; - } - } - } + if ($r) { + xchan_query($r); + foreach ($r as $rr) { + $rr['llink'] = str_replace('display/', 'pubstream/?f=&mid=', $rr['llink']); + $z = Enotify::format($rr); + if ($z) { + $local_result[] = $z; + } + } + } - json_return_and_die( [ 'notify' => $local_result ] ); - } + json_return_and_die(['notify' => $local_result]); + } - if ((! local_channel()) || ($result['invalid'])) { - json_return_and_die($result); - } + if ((!local_channel()) || ($result['invalid'])) { + json_return_and_die($result); + } - /** - * Everything following is only permitted under the context of a locally authenticated site member. - */ + /** + * Everything following is only permitted under the context of a locally authenticated site member. + */ - /** - * Handle "mark all xyz notifications read" requests. - */ + /** + * Handle "mark all xyz notifications read" requests. + */ - // mark all items read - if (x($_REQUEST, 'markRead') && local_channel() && (! $_SESSION['sudo'])) { - switch ($_REQUEST['markRead']) { - case 'stream': - $r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1", - intval(local_channel()) - ); - $_SESSION['loadtime_stream'] = datetime_convert(); - PConfig::Set(local_channel(),'system','loadtime_stream',$_SESSION['loadtime_stream']); - $_SESSION['loadtime_channel'] = datetime_convert(); - PConfig::Set(local_channel(),'system','loadtime_channel',$_SESSION['loadtime_channel']); - break; - case 'home': - $r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_wall = 1", - intval(local_channel()) - ); - $_SESSION['loadtime_channel'] = datetime_convert(); - PConfig::Set(local_channel(),'system','loadtime_channel',$_SESSION['loadtime_channel']); - break; - case 'all_events': - $r = q("UPDATE event SET dismissed = 1 WHERE uid = %d AND dismissed = 0 AND dtstart < '%s' AND dtstart > '%s' ", - intval(local_channel()), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) - ); - break; - case 'notify': - $r = q("update notify set seen = 1 where uid = %d", - intval(local_channel()) - ); - break; - case 'pubs': + // mark all items read + if (x($_REQUEST, 'markRead') && local_channel() && (!$_SESSION['sudo'])) { + switch ($_REQUEST['markRead']) { + case 'stream': + $r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1", + intval(local_channel()) + ); + $_SESSION['loadtime_stream'] = datetime_convert(); + PConfig::Set(local_channel(), 'system', 'loadtime_stream', $_SESSION['loadtime_stream']); + $_SESSION['loadtime_channel'] = datetime_convert(); + PConfig::Set(local_channel(), 'system', 'loadtime_channel', $_SESSION['loadtime_channel']); + break; + case 'home': + $r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND item_unseen = 1 AND item_wall = 1", + intval(local_channel()) + ); + $_SESSION['loadtime_channel'] = datetime_convert(); + PConfig::Set(local_channel(), 'system', 'loadtime_channel', $_SESSION['loadtime_channel']); + break; + case 'all_events': + $r = q("UPDATE event SET dismissed = 1 WHERE uid = %d AND dismissed = 0 AND dtstart < '%s' AND dtstart > '%s' ", + intval(local_channel()), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); + break; + case 'notify': + $r = q("update notify set seen = 1 where uid = %d", + intval(local_channel()) + ); + break; + case 'pubs': - $_SESSION['loadtime_pubstream'] = datetime_convert(); - PConfig::Set(local_channel(),'system','loadtime_pubstream',$_SESSION['loadtime_pubstream']); - break; - default: - break; - } - } + $_SESSION['loadtime_pubstream'] = datetime_convert(); + PConfig::Set(local_channel(), 'system', 'loadtime_pubstream', $_SESSION['loadtime_pubstream']); + break; + default: + break; + } + } - if (x($_REQUEST, 'markItemRead') && local_channel() && (! $_SESSION['sudo'])) { - $r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND parent = %d", - intval(local_channel()), - intval($_REQUEST['markItemRead']) - ); - $id = intval($_REQUEST['markItemRead']); - $seen = PConfig::Get(local_channel(),'system','seen_items',[]); - if (! in_array($id,$seen)) { - $seen[] = $id; - } - PConfig::Set(local_channel(),'system','seen_items',$seen); - } + if (x($_REQUEST, 'markItemRead') && local_channel() && (!$_SESSION['sudo'])) { + $r = q("UPDATE item SET item_unseen = 0 WHERE uid = %d AND parent = %d", + intval(local_channel()), + intval($_REQUEST['markItemRead']) + ); + $id = intval($_REQUEST['markItemRead']); + $seen = PConfig::Get(local_channel(), 'system', 'seen_items', []); + if (!in_array($id, $seen)) { + $seen[] = $id; + } + PConfig::Set(local_channel(), 'system', 'seen_items', $seen); + } - /** - * URL ping/something will return detail for "something", e.g. a json list with which to populate a notification - * dropdown menu. - */ - - if (argc() > 1 && argv(1) === 'notify') { + /** + * URL ping/something will return detail for "something", e.g. a json list with which to populate a notification + * dropdown menu. + */ - $t = q("SELECT * FROM notify WHERE uid = %d AND seen = 0 ORDER BY CREATED DESC", - intval(local_channel()) - ); + if (argc() > 1 && argv(1) === 'notify') { - if ($t) { - foreach ($t as $tt) { - $message = trim(strip_tags(bbcode($tt['msg']))); + $t = q("SELECT * FROM notify WHERE uid = %d AND seen = 0 ORDER BY CREATED DESC", + intval(local_channel()) + ); - if (strpos($message, $tt['xname']) === 0) - $message = substr($message, strlen($tt['xname']) + 1); + if ($t) { + foreach ($t as $tt) { + $message = trim(strip_tags(bbcode($tt['msg']))); + + if (strpos($message, $tt['xname']) === 0) + $message = substr($message, strlen($tt['xname']) + 1); - $mid = basename($tt['link']); - $mid = unpack_link_id($mid); + $mid = basename($tt['link']); + $mid = unpack_link_id($mid); - if (in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { - // we need the thread parent - $r = q("select thr_parent from item where mid = '%s' and uid = %d limit 1", - dbesc($mid), - intval(local_channel()) - ); + if (in_array($tt['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) { + // we need the thread parent + $r = q("select thr_parent from item where mid = '%s' and uid = %d limit 1", + dbesc($mid), + intval(local_channel()) + ); - $b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : gen_link_id($r[0]['thr_parent'])); - } - else { - $b64mid = ((strpos($mid, 'b64.') === 0) ? $mid : gen_link_id($mid)); - } + $b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : gen_link_id($r[0]['thr_parent'])); + } else { + $b64mid = ((strpos($mid, 'b64.') === 0) ? $mid : gen_link_id($mid)); + } - $notifs[] = array( - 'notify_link' => z_root() . '/notify/view/' . $tt['id'], - 'name' => $tt['xname'], - 'url' => $tt['url'], - 'photo' => $tt['photo'], - 'when' => relative_date($tt['created']), - 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'), - 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'), - 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'), - 'message' => $message - ); - } - } + $notifs[] = array( + 'notify_link' => z_root() . '/notify/view/' . $tt['id'], + 'name' => $tt['xname'], + 'url' => $tt['url'], + 'photo' => $tt['photo'], + 'when' => relative_date($tt['created']), + 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'), + 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'), + 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'), + 'message' => $message + ); + } + } - json_return_and_die( [ 'notify' => $notifs ] ); - } + json_return_and_die(['notify' => $notifs]); + } - if (argc() > 1 && (argv(1) === 'stream')) { - $local_result = []; + if (argc() > 1 && (argv(1) === 'stream')) { + $local_result = []; - $item_normal_moderate = $item_normal; - $loadtime = get_loadtime('stream'); - - $r = q("SELECT * FROM item + $item_normal_moderate = $item_normal; + $loadtime = get_loadtime('stream'); + + $r = q("SELECT * FROM item WHERE uid = %d AND author_xchan != '%s' AND changed > '%s' @@ -343,34 +342,34 @@ class Ping extends Controller { $sql_extra ORDER BY created DESC LIMIT 300", - intval(local_channel()), - dbesc($ob_hash), - dbesc($loadtime) - ); - if ($r) { - xchan_query($r); - foreach ($r as $item) { - $z = Enotify::format($item); + intval(local_channel()), + dbesc($ob_hash), + dbesc($loadtime) + ); + if ($r) { + xchan_query($r); + foreach ($r as $item) { + $z = Enotify::format($item); - if($z) { - $local_result[] = $z; - } - } - } + if ($z) { + $local_result[] = $z; + } + } + } - json_return_and_die( [ 'notify' => $local_result ] ); - } + json_return_and_die(['notify' => $local_result]); + } - if (argc() > 1 && (argv(1) === 'home')) { - $local_result = []; - $item_normal_moderate = $item_normal; + if (argc() > 1 && (argv(1) === 'home')) { + $local_result = []; + $item_normal_moderate = $item_normal; - $sql_extra .= " and item_wall = 1 "; - $item_normal_moderate = item_normal_moderate(); + $sql_extra .= " and item_wall = 1 "; + $item_normal_moderate = item_normal_moderate(); - $loadtime = get_loadtime('channel'); + $loadtime = get_loadtime('channel'); - $r = q("SELECT * FROM item + $r = q("SELECT * FROM item WHERE uid = %d AND author_xchan != '%s' AND changed > '%s' @@ -379,406 +378,398 @@ class Ping extends Controller { $sql_extra ORDER BY created DESC LIMIT 300", - intval(local_channel()), - dbesc($ob_hash), - dbesc($loadtime) - ); - if ($r) { - xchan_query($r); - foreach ($r as $item) { - $z = Enotify::format($item); + intval(local_channel()), + dbesc($ob_hash), + dbesc($loadtime) + ); + if ($r) { + xchan_query($r); + foreach ($r as $item) { + $z = Enotify::format($item); - if($z) { - $local_result[] = $z; - } - } - } + if ($z) { + $local_result[] = $z; + } + } + } - json_return_and_die( [ 'notify' => $local_result ] ); - } + json_return_and_die(['notify' => $local_result]); + } + if (argc() > 1 && (argv(1) === 'intros')) { + $local_result = []; - if (argc() > 1 && (argv(1) === 'intros')) { - $local_result = []; + $r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created DESC LIMIT 50", + intval(local_channel()) + ); - $r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created DESC LIMIT 50", - intval(local_channel()) - ); + if ($r) { + foreach ($r as $rr) { + $local_result[] = [ + 'notify_link' => z_root() . '/connections/' . $rr['abook_id'], + 'name' => $rr['xchan_name'], + 'addr' => $rr['xchan_addr'], + 'url' => $rr['xchan_url'], + 'photo' => $rr['xchan_photo_s'], + 'when' => relative_date($rr['abook_created']), + 'hclass' => ('notify-unseen'), + 'message' => t('added your channel') + ]; + } + } - if ($r) { - foreach ($r as $rr) { - $local_result[] = [ - 'notify_link' => z_root() . '/connections/' . $rr['abook_id'], - 'name' => $rr['xchan_name'], - 'addr' => $rr['xchan_addr'], - 'url' => $rr['xchan_url'], - 'photo' => $rr['xchan_photo_s'], - 'when' => relative_date($rr['abook_created']), - 'hclass' => ('notify-unseen'), - 'message' => t('added your channel') - ]; - } - } + json_return_and_die(['notify' => $local_result]); + } - json_return_and_die( [ 'notify' => $local_result ] ); - } + if ((argc() > 1 && (argv(1) === 'register')) && is_site_admin()) { + $result = []; - if( (argc() > 1 && (argv(1) === 'register')) && is_site_admin()) { - $result = []; + $r = q("SELECT account_email, account_created from account where (account_flags & %d) > 0", + intval(ACCOUNT_PENDING) + ); + if ($r) { + foreach ($r as $rr) { + $result[] = array( + 'notify_link' => z_root() . '/admin/accounts', + 'name' => $rr['account_email'], + 'addr' => $rr['account_email'], + 'url' => '', + 'photo' => z_root() . '/' . get_default_profile_photo(48), + 'when' => relative_date($rr['account_created']), + 'hclass' => ('notify-unseen'), + 'message' => t('requires approval') + ); + } + } - $r = q("SELECT account_email, account_created from account where (account_flags & %d) > 0", - intval(ACCOUNT_PENDING) - ); - if ($r) { - foreach ($r as $rr) { - $result[] = array( - 'notify_link' => z_root() . '/admin/accounts', - 'name' => $rr['account_email'], - 'addr' => $rr['account_email'], - 'url' => '', - 'photo' => z_root() . '/' . get_default_profile_photo(48), - 'when' => relative_date($rr['account_created']), - 'hclass' => ('notify-unseen'), - 'message' => t('requires approval') - ); - } - } + json_return_and_die(['notify' => $result]); + } - json_return_and_die( [ 'notify' => $result ] ); - } + if (argc() > 1 && (argv(1) === 'all_events')) { + $bd_format = t('g A l F d'); // 8 AM Friday January 18 - if (argc() > 1 && (argv(1) === 'all_events')) { - $bd_format = t('g A l F d') ; // 8 AM Friday January 18 + $result = []; - $result = []; - - $r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash + $r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0 and etype in ( 'event', 'birthday' ) ORDER BY dtstart DESC LIMIT 1000", - intval(local_channel()), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) - ); + intval(local_channel()), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); - if ($r) { - foreach ($r as $rr) { + if ($r) { + foreach ($r as $rr) { - $strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart']); - $today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false); - $when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : ''); + $strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart']); + $today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false); + $when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : ''); - $result[] = array( - 'notify_link' => z_root() . '/events', /// @FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'], - 'name' => $rr['xchan_name'], - 'addr' => $rr['xchan_addr'], - 'url' => $rr['xchan_url'], - 'photo' => $rr['xchan_photo_s'], - 'when' => $when, - 'hclass' => ('notify-unseen'), - 'message' => t('posted an event') - ); - } - } + $result[] = array( + 'notify_link' => z_root() . '/events', /// @FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'], + 'name' => $rr['xchan_name'], + 'addr' => $rr['xchan_addr'], + 'url' => $rr['xchan_url'], + 'photo' => $rr['xchan_photo_s'], + 'when' => $when, + 'hclass' => ('notify-unseen'), + 'message' => t('posted an event') + ); + } + } - json_return_and_die( [ 'notify' => $result ] ); - } + json_return_and_die(['notify' => $result]); + } - if (argc() > 1 && (argv(1) === 'files')) { - $result = []; + if (argc() > 1 && (argv(1) === 'files')) { + $result = []; - $r = q("SELECT item.created, xchan.xchan_name, xchan.xchan_addr, xchan.xchan_url, xchan.xchan_photo_s FROM item + $r = q("SELECT item.created, xchan.xchan_name, xchan.xchan_addr, xchan.xchan_url, xchan.xchan_photo_s FROM item LEFT JOIN xchan on author_xchan = xchan_hash WHERE item.verb = '%s' AND item.obj_type = '%s' AND item.uid = %d AND item.owner_xchan != '%s' AND item.item_unseen = 1", - dbesc(ACTIVITY_POST), - dbesc(ACTIVITY_OBJ_FILE), - intval(local_channel()), - dbesc($ob_hash) - ); - if ($r) { - foreach ($r as $rr) { - $result[] = array( - 'notify_link' => z_root() . '/sharedwithme', - 'name' => $rr['xchan_name'], - 'addr' => $rr['xchan_addr'], - 'url' => $rr['xchan_url'], - 'photo' => $rr['xchan_photo_s'], - 'when' => relative_date($rr['created']), - 'hclass' => ('notify-unseen'), - 'message' => t('shared a file with you') - ); - } - } + dbesc(ACTIVITY_POST), + dbesc(ACTIVITY_OBJ_FILE), + intval(local_channel()), + dbesc($ob_hash) + ); + if ($r) { + foreach ($r as $rr) { + $result[] = array( + 'notify_link' => z_root() . '/sharedwithme', + 'name' => $rr['xchan_name'], + 'addr' => $rr['xchan_addr'], + 'url' => $rr['xchan_url'], + 'photo' => $rr['xchan_photo_s'], + 'when' => relative_date($rr['created']), + 'hclass' => ('notify-unseen'), + 'message' => t('shared a file with you') + ); + } + } - json_return_and_die( [ 'notify' => $result ] ); - } + json_return_and_die(['notify' => $result]); + } - if (argc() > 1 && (argv(1) === 'reports') && is_site_admin()) { + if (argc() > 1 && (argv(1) === 'reports') && is_site_admin()) { - $local_result = []; + $local_result = []; - $r = q("SELECT item.created, xchan.xchan_name, xchan.xchan_addr, xchan.xchan_url, xchan.xchan_photo_s FROM item + $r = q("SELECT item.created, xchan.xchan_name, xchan.xchan_addr, xchan.xchan_url, xchan.xchan_photo_s FROM item LEFT JOIN xchan on author_xchan = xchan_hash WHERE item.type = '%s' AND item.item_unseen = 1", - dbesc(ITEM_TYPE_REPORT) - ); + dbesc(ITEM_TYPE_REPORT) + ); - if ($r) { - foreach ($r as $rv) { - $result[] = [ - 'notify_link' => z_root() . '/reports', - 'name' => $rv['xchan_name'], - 'addr' => $rv['xchan_addr'], - 'url' => $rv['xchan_url'], - 'photo' => $rv['xchan_photo_s'], - 'when' => relative_date($rv['created']), - 'hclass' => ('notify-unseen'), - 'message' => t('reported content') - ]; - } - } + if ($r) { + foreach ($r as $rv) { + $result[] = [ + 'notify_link' => z_root() . '/reports', + 'name' => $rv['xchan_name'], + 'addr' => $rv['xchan_addr'], + 'url' => $rv['xchan_url'], + 'photo' => $rv['xchan_photo_s'], + 'when' => relative_date($rv['created']), + 'hclass' => ('notify-unseen'), + 'message' => t('reported content') + ]; + } + } - json_return_and_die( [ 'notify' => $result ] ); - } + json_return_and_die(['notify' => $result]); + } + /** + * Normal ping - just the counts, no detail + */ - /** - * Normal ping - just the counts, no detail - */ + if ($vnotify & VNOTIFY_SYSTEM) { + $t = q("select count(*) as total from notify where uid = %d and seen = 0", + intval(local_channel()) + ); + if ($t) + $result['notify'] = intval($t[0]['total']); + } - - if ($vnotify & VNOTIFY_SYSTEM) { - $t = q("select count(*) as total from notify where uid = %d and seen = 0", - intval(local_channel()) - ); - if ($t) - $result['notify'] = intval($t[0]['total']); - } - - if ($vnotify & VNOTIFY_FILES) { - $files = q("SELECT count(id) as total FROM item + if ($vnotify & VNOTIFY_FILES) { + $files = q("SELECT count(id) as total FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s' AND item_unseen = 1", - dbesc(ACTIVITY_POST), - dbesc(ACTIVITY_OBJ_FILE), - intval(local_channel()), - dbesc($ob_hash) - ); - if ($files) - $result['files'] = intval($files[0]['total']); - } + dbesc(ACTIVITY_POST), + dbesc(ACTIVITY_OBJ_FILE), + intval(local_channel()), + dbesc($ob_hash) + ); + if ($files) + $result['files'] = intval($files[0]['total']); + } - if ($vnotify & VNOTIFY_NETWORK) { - $loadtime = get_loadtime('stream'); - $r = q("SELECT id, author_xchan FROM item + if ($vnotify & VNOTIFY_NETWORK) { + $loadtime = get_loadtime('stream'); + $r = q("SELECT id, author_xchan FROM item WHERE uid = %d and changed > '%s' $seenstr $item_normal $sql_extra ", - intval(local_channel()), - dbesc($loadtime) - ); + intval(local_channel()), + dbesc($loadtime) + ); - if($r) { - $arr = array('items' => $r); - call_hooks('network_ping', $arr); + if ($r) { + $arr = array('items' => $r); + call_hooks('network_ping', $arr); - foreach ($r as $it) { - if ($it['author_xchan'] === $ob_hash) { - $my_activity ++; - } - else { - $result['stream'] ++; - } - } - } - } - if (! ($vnotify & VNOTIFY_NETWORK)) { - $result['stream'] = 0; - } + foreach ($r as $it) { + if ($it['author_xchan'] === $ob_hash) { + $my_activity++; + } else { + $result['stream']++; + } + } + } + } + if (!($vnotify & VNOTIFY_NETWORK)) { + $result['stream'] = 0; + } - if ($vnotify & VNOTIFY_CHANNEL) { - $loadtime = get_loadtime('channel'); - $r = q("SELECT id, author_xchan FROM item + if ($vnotify & VNOTIFY_CHANNEL) { + $loadtime = get_loadtime('channel'); + $r = q("SELECT id, author_xchan FROM item WHERE item_wall = 1 and uid = %d and changed > '%s' $seenstr $item_normal $sql_extra ", - intval(local_channel()), - dbesc($loadtime) - ); + intval(local_channel()), + dbesc($loadtime) + ); - if ($r) { - foreach ($r as $it) { - if ($it['author_xchan'] === $ob_hash) { - $my_activity ++; - } - else { - $result['home'] ++; - } - } - } - } - if (! ($vnotify & VNOTIFY_CHANNEL)) { - $result['home'] = 0; - } + if ($r) { + foreach ($r as $it) { + if ($it['author_xchan'] === $ob_hash) { + $my_activity++; + } else { + $result['home']++; + } + } + } + } + if (!($vnotify & VNOTIFY_CHANNEL)) { + $result['home'] = 0; + } - if ($vnotify & VNOTIFY_INTRO) { - $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", - intval(local_channel()) - ); + if ($vnotify & VNOTIFY_INTRO) { + $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", + intval(local_channel()) + ); - if ($intr) - $result['intros'] = intval($intr[0]['total']); - } + if ($intr) + $result['intros'] = intval($intr[0]['total']); + } - $channel = App::get_channel(); + $channel = App::get_channel(); - if ($vnotify & VNOTIFY_REGISTER) { - if (App::$config['system']['register_policy'] == REGISTER_APPROVE && is_site_admin()) { - $regs = q("SELECT count(account_id) as total from account where (account_flags & %d) > 0", - intval(ACCOUNT_PENDING) - ); - if ($regs) - $result['register'] = intval($regs[0]['total']); - } - } + if ($vnotify & VNOTIFY_REGISTER) { + if (App::$config['system']['register_policy'] == REGISTER_APPROVE && is_site_admin()) { + $regs = q("SELECT count(account_id) as total from account where (account_flags & %d) > 0", + intval(ACCOUNT_PENDING) + ); + if ($regs) + $result['register'] = intval($regs[0]['total']); + } + } - if ($vnotify & VNOTIFY_REPORTS) { - if (is_site_admin()) { - $reps = q("SELECT count(id) as total from item where item_type = %d", - intval(ITEM_TYPE_REPORT) - ); - if ($reps) - $result['reports'] = intval($reps[0]['total']); - } - } + if ($vnotify & VNOTIFY_REPORTS) { + if (is_site_admin()) { + $reps = q("SELECT count(id) as total from item where item_type = %d", + intval(ITEM_TYPE_REPORT) + ); + if ($reps) + $result['reports'] = intval($reps[0]['total']); + } + } - if ($vnotify & (VNOTIFY_EVENT|VNOTIFY_EVENTTODAY|VNOTIFY_BIRTHDAY)) { - $events = q("SELECT etype, dtstart, adjust FROM event + if ($vnotify & (VNOTIFY_EVENT | VNOTIFY_EVENTTODAY | VNOTIFY_BIRTHDAY)) { + $events = q("SELECT etype, dtstart, adjust FROM event WHERE event.uid = %d AND dtstart < '%s' AND dtstart > '%s' and dismissed = 0 and etype in ( 'event', 'birthday' ) ORDER BY dtstart ASC ", - intval(local_channel()), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), - dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) - ); + intval(local_channel()), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); - if ($events) { - $result['all_events'] = count($events); + if ($events) { + $result['all_events'] = count($events); - if ($result['all_events']) { - $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); - foreach ($events as $x) { - $bd = false; - if ($x['etype'] === 'birthday') { - $result['birthdays'] ++; - $bd = true; - } - else { - $result['events'] ++; - } - if (datetime_convert('UTC', ((intval($x['adjust'])) ? date_default_timezone_get() : 'UTC'), $x['dtstart'], 'Y-m-d') === $str_now) { - $result['all_events_today'] ++; - if($bd) - $result['birthdays_today'] ++; - else - $result['events_today'] ++; - } - } - } - } - } + if ($result['all_events']) { + $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); + foreach ($events as $x) { + $bd = false; + if ($x['etype'] === 'birthday') { + $result['birthdays']++; + $bd = true; + } else { + $result['events']++; + } + if (datetime_convert('UTC', ((intval($x['adjust'])) ? date_default_timezone_get() : 'UTC'), $x['dtstart'], 'Y-m-d') === $str_now) { + $result['all_events_today']++; + if ($bd) + $result['birthdays_today']++; + else + $result['events_today']++; + } + } + } + } + } - if (! ($vnotify & VNOTIFY_EVENT)) - $result['all_events'] = $result['events'] = 0; - if (! ($vnotify & VNOTIFY_EVENTTODAY)) - $result['all_events_today'] = $result['events_today'] = 0; - if (! ($vnotify & VNOTIFY_BIRTHDAY)) - $result['birthdays'] = 0; + if (!($vnotify & VNOTIFY_EVENT)) + $result['all_events'] = $result['events'] = 0; + if (!($vnotify & VNOTIFY_EVENTTODAY)) + $result['all_events_today'] = $result['events_today'] = 0; + if (!($vnotify & VNOTIFY_BIRTHDAY)) + $result['birthdays'] = 0; + if ($vnotify & VNOTIFY_FORUMS) { + $forums = get_forum_channels(local_channel()); - if ($vnotify & VNOTIFY_FORUMS) { - $forums = get_forum_channels(local_channel()); + if ($forums) { - if ($forums) { + $perms_sql = item_permissions_sql(local_channel()) . item_normal(); + $fcount = count($forums); + $forums['total'] = 0; - $perms_sql = item_permissions_sql(local_channel()) . item_normal(); - $fcount = count($forums); - $forums['total'] = 0; + for ($x = 0; $x < $fcount; $x++) { + $ttype = TERM_FORUM; + $p = q("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . protect_sprintf(dbesc($forums[$x]['xchan_name'])) . "'"); - for ($x = 0; $x < $fcount; $x ++) { - $ttype = TERM_FORUM; - $p = q("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . protect_sprintf(dbesc($forums[$x]['xchan_name'])) . "'"); - - $p = ids_to_querystr($p, 'parent'); - $pquery = (($p) ? "OR parent IN ( $p )" : ''); + $p = ids_to_querystr($p, 'parent'); + $pquery = (($p) ? "OR parent IN ( $p )" : ''); - $r = q("select sum(item_unseen) as unseen from item + $r = q("select sum(item_unseen) as unseen from item where uid = %d and ( owner_xchan = '%s' $pquery ) and item_unseen = 1 $perms_sql ", - intval(local_channel()), - dbesc($forums[$x]['xchan_hash']) - ); - if ($r[0]['unseen']) { - $forums[$x]['notify_link'] = (($forums[$x]['private_forum']) ? $forums[$x]['xchan_url'] : z_root() . '/stream/?f=&pf=1&cid=' . $forums[$x]['abook_id']); - $forums[$x]['name'] = $forums[$x]['xchan_name']; - $forums[$x]['addr'] = $forums[$x]['xchan_addr']; - $forums[$x]['url'] = $forums[$x]['xchan_url']; - $forums[$x]['photo'] = $forums[$x]['xchan_photo_s']; - $forums[$x]['unseen'] = $r[0]['unseen']; - $forums[$x]['private_forum'] = (($forums[$x]['private_forum']) ? 'lock' : ''); - $forums[$x]['message'] = (($forums[$x]['private_forum']) ? t('Private group') : t('Public group')); + intval(local_channel()), + dbesc($forums[$x]['xchan_hash']) + ); + if ($r[0]['unseen']) { + $forums[$x]['notify_link'] = (($forums[$x]['private_forum']) ? $forums[$x]['xchan_url'] : z_root() . '/stream/?f=&pf=1&cid=' . $forums[$x]['abook_id']); + $forums[$x]['name'] = $forums[$x]['xchan_name']; + $forums[$x]['addr'] = $forums[$x]['xchan_addr']; + $forums[$x]['url'] = $forums[$x]['xchan_url']; + $forums[$x]['photo'] = $forums[$x]['xchan_photo_s']; + $forums[$x]['unseen'] = $r[0]['unseen']; + $forums[$x]['private_forum'] = (($forums[$x]['private_forum']) ? 'lock' : ''); + $forums[$x]['message'] = (($forums[$x]['private_forum']) ? t('Private group') : t('Public group')); - $forums['total'] = $forums['total'] + $r[0]['unseen']; + $forums['total'] = $forums['total'] + $r[0]['unseen']; - unset($forums[$x]['abook_id']); - unset($forums[$x]['xchan_hash']); - unset($forums[$x]['xchan_name']); - unset($forums[$x]['xchan_url']); - unset($forums[$x]['xchan_photo_s']); + unset($forums[$x]['abook_id']); + unset($forums[$x]['xchan_hash']); + unset($forums[$x]['xchan_name']); + unset($forums[$x]['xchan_url']); + unset($forums[$x]['xchan_photo_s']); - } - else { - unset($forums[$x]); - } - } - $result['forums'] = $forums['total']; - unset($forums['total']); + } else { + unset($forums[$x]); + } + } + $result['forums'] = $forums['total']; + unset($forums['total']); - $result['forums_sub'] = $forums; - } - } + $result['forums_sub'] = $forums; + } + } - // Mark all of the stream notifications seen if all three of them are caught up. - // This also resets the pconfig storage for items_seen - - if ((! $my_activity) && (! (intval($result['home']) + intval($result['stream']) + intval($result['pubs'])))) { - PConfig::Delete(local_channel(),'system','seen_items'); + // Mark all of the stream notifications seen if all three of them are caught up. + // This also resets the pconfig storage for items_seen - $_SESSION['loadtime_channel'] = datetime_convert(); - $_SESSION['loadtime_stream'] = datetime_convert(); - $_SESSION['loadtime_pubstream'] = datetime_convert(); - - PConfig::Set(local_channel(),'system','loadtime_channel', $_SESSION['loadtime_channel']); - PConfig::Set(local_channel(),'system','loadtime_stream', $_SESSION['loadtime_stream']); - PConfig::Set(local_channel(),'system','loadtime_pubstream', $_SESSION['loadtime_pubstream']); - } + if ((!$my_activity) && (!(intval($result['home']) + intval($result['stream']) + intval($result['pubs'])))) { + PConfig::Delete(local_channel(), 'system', 'seen_items'); - json_return_and_die($result); - } + $_SESSION['loadtime_channel'] = datetime_convert(); + $_SESSION['loadtime_stream'] = datetime_convert(); + $_SESSION['loadtime_pubstream'] = datetime_convert(); + + PConfig::Set(local_channel(), 'system', 'loadtime_channel', $_SESSION['loadtime_channel']); + PConfig::Set(local_channel(), 'system', 'loadtime_stream', $_SESSION['loadtime_stream']); + PConfig::Set(local_channel(), 'system', 'loadtime_pubstream', $_SESSION['loadtime_pubstream']); + } + + json_return_and_die($result); + } } diff --git a/Zotlabs/Module/Poco.php b/Zotlabs/Module/Poco.php index 90ae049b6..69b0cd39a 100644 --- a/Zotlabs/Module/Poco.php +++ b/Zotlabs/Module/Poco.php @@ -10,10 +10,12 @@ use Zotlabs\Web\Controller; require_once('include/socgraph.php'); -class Poco extends Controller { +class Poco extends Controller +{ + + public function init() + { + poco(); + } - function init() { - poco(); - } - } diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php index 173e02b6f..7dd7a0893 100644 --- a/Zotlabs/Module/Poke.php +++ b/Zotlabs/Module/Poke.php @@ -8,143 +8,145 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Poke extends Controller { +class Poke extends Controller +{ - function init() { + public function init() + { - $uid = local_channel(); - if (! $uid) { - return; - } + $uid = local_channel(); + if (!$uid) { + return; + } - if (! Apps::system_app_installed($uid, 'Poke')) { - return; - } - $channel = App::get_channel(); + if (!Apps::system_app_installed($uid, 'Poke')) { + return; + } + $channel = App::get_channel(); - $verbs = get_poke_verbs(); + $verbs = get_poke_verbs(); - if (isset($_REQUEST['pokeverb']) && array_key_exists(trim($_REQUEST['pokeverb']),$verbs)) { - set_pconfig($uid,'system','pokeverb',trim($_REQUEST['pokeverb'])); - return; - } + if (isset($_REQUEST['pokeverb']) && array_key_exists(trim($_REQUEST['pokeverb']), $verbs)) { + set_pconfig($uid, 'system', 'pokeverb', trim($_REQUEST['pokeverb'])); + return; + } - $verb = get_pconfig($uid,'system','pokeverb','poke'); - - if (! array_key_exists($verb,$verbs)) { - return; - } - - $activity = $verbs[$verb][0]; - - $xchan = trim($_REQUEST['xchan']); + $verb = get_pconfig($uid, 'system', 'pokeverb', 'poke'); - if (! $xchan) { - return; - } - - $r = q("SELECT * FROM xchan where xchan_hash = '%s' LIMIT 1", - dbesc($xchan) - ); - - if (! $r) { - logger('poke: no target.'); - return; - } - - $target = $r[0]; - $parent_item = null; - - $item_private = 1; - - if ($target) { - $allow_cid = '<' . $target['abook_xchan']. '>'; - $allow_gid = EMPTY_STR; - $deny_cid = EMPTY_STR; - $deny_gid = EMPTY_STR; - } - - $arr = []; - - $arr['item_wall'] = 1; - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['author_xchan'] = $channel['channel_hash']; - $arr['allow_cid'] = $allow_cid; - $arr['allow_gid'] = $allow_gid; - $arr['deny_cid'] = $deny_cid; - $arr['deny_gid'] = $deny_gid; - $arr['verb'] = 'Create'; - $arr['item_private'] = 1; - $arr['obj_type'] = 'Note'; - $arr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . $verbs[$verb][2] . ' ' . '[zrl=' . $target['xchan_url'] . ']' . $target['xchan_name'] . '[/zrl]'; - - - $arr['item_origin'] = 1; - $arr['item_wall'] = 1; + if (!array_key_exists($verb, $verbs)) { + return; + } - $obj = Activity::encode_item($arr,((get_config('system','activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); + $activity = $verbs[$verb][0]; - $i = post_activity_item($arr); + $xchan = trim($_REQUEST['xchan']); - if ($i['success']) { - $item_id = $i['item_id']; - $r = q("select * from item where id = %d", - intval($item_id) - ); - if ($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($uid, [ 'item' => [ encode_item($sync_item[0],true) ] ] ); - } - - info(sprintf( t('You %1$s %2$s'), $verbs[$verb][2], $target['xchan_name'])); - } + if (!$xchan) { + return; + } - json_return_and_die([ 'success' => true ]); - } - - - - function get() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + $r = q("SELECT * FROM xchan where xchan_hash = '%s' LIMIT 1", + dbesc($xchan) + ); - if(! Apps::system_app_installed(local_channel(), 'Poke')) { - $o = '' . t('Poke App (Not Installed)') . '
      '; - $o .= t('Poke or do something else to somebody'); - return $o; - } + if (!$r) { + logger('poke: no target.'); + return; + } - nav_set_selected('Poke'); - - $name = ''; - $id = ''; - - $verbs = get_poke_verbs(); - - $shortlist = []; - $current = get_pconfig(local_channel(),'system','pokeverb','poke'); - foreach($verbs as $k => $v) { - $shortlist[] = [ $k,$v[1], (($k === $current) ? true : false) ]; - } - - - $title = t('Poke'); - $desc = t('Poke, prod or do other things to somebody'); - - $o = replace_macros(get_markup_template('poke_content.tpl'),array( - '$title' => $title, - '$desc' => $desc, - '$clabel' => t('Recipient'), - '$choice' => t('Choose your default action'), - '$verbs' => $shortlist, - '$submit' => t('Submit'), - '$id' => $id - )); - - return $o; - } + $target = $r[0]; + $parent_item = null; + + $item_private = 1; + + if ($target) { + $allow_cid = '<' . $target['abook_xchan'] . '>'; + $allow_gid = EMPTY_STR; + $deny_cid = EMPTY_STR; + $deny_gid = EMPTY_STR; + } + + $arr = []; + + $arr['item_wall'] = 1; + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $channel['channel_hash']; + $arr['allow_cid'] = $allow_cid; + $arr['allow_gid'] = $allow_gid; + $arr['deny_cid'] = $deny_cid; + $arr['deny_gid'] = $deny_gid; + $arr['verb'] = 'Create'; + $arr['item_private'] = 1; + $arr['obj_type'] = 'Note'; + $arr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . $verbs[$verb][2] . ' ' . '[zrl=' . $target['xchan_url'] . ']' . $target['xchan_name'] . '[/zrl]'; + + + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + + $obj = Activity::encode_item($arr, ((get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); + + $i = post_activity_item($arr); + + if ($i['success']) { + $item_id = $i['item_id']; + $r = q("select * from item where id = %d", + intval($item_id) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet($uid, ['item' => [encode_item($sync_item[0], true)]]); + } + + info(sprintf(t('You %1$s %2$s'), $verbs[$verb][2], $target['xchan_name'])); + } + + json_return_and_die(['success' => true]); + } + + + public function get() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + if (!Apps::system_app_installed(local_channel(), 'Poke')) { + $o = '' . t('Poke App (Not Installed)') . '
      '; + $o .= t('Poke or do something else to somebody'); + return $o; + } + + nav_set_selected('Poke'); + + $name = ''; + $id = ''; + + $verbs = get_poke_verbs(); + + $shortlist = []; + $current = get_pconfig(local_channel(), 'system', 'pokeverb', 'poke'); + foreach ($verbs as $k => $v) { + $shortlist[] = [$k, $v[1], (($k === $current) ? true : false)]; + } + + + $title = t('Poke'); + $desc = t('Poke, prod or do other things to somebody'); + + $o = replace_macros(get_markup_template('poke_content.tpl'), array( + '$title' => $title, + '$desc' => $desc, + '$clabel' => t('Recipient'), + '$choice' => t('Choose your default action'), + '$verbs' => $shortlist, + '$submit' => t('Submit'), + '$id' => $id + )); + + return $o; + } } diff --git a/Zotlabs/Module/Poster.php b/Zotlabs/Module/Poster.php index f1aa2d6b5..cefe07075 100644 --- a/Zotlabs/Module/Poster.php +++ b/Zotlabs/Module/Poster.php @@ -6,37 +6,39 @@ use Zotlabs\Web\Controller; require_once('include/security.php'); -class Poster extends Controller { +class Poster extends Controller +{ - function init() { + public function init() + { - $nick = argv(1); - $hash = argv(2); + $nick = argv(1); + $hash = argv(2); - if (! ($nick && $hash)) { - return; - } + if (!($nick && $hash)) { + return; + } - $u = channelx_by_nick($nick); + $u = channelx_by_nick($nick); - if (! $u) { - return; - } + if (!$u) { + return; + } - $sql_extra = permissions_sql(intval($u['channel_id'])); + $sql_extra = permissions_sql(intval($u['channel_id'])); - $r = q("select content from attach where hash = '%s' and uid = %d and os_storage = 1 $sql_extra limit 1", - dbesc($hash), - intval($u['channel_id']) - ); - if ($r) { - $path = dbunescbin($r[0]['content']); - if ($path && @file_exists($path . '.thumb')) { - header('Content-Type: image/jpeg'); - echo file_get_contents($path . '.thumb'); - killme(); - } - } - killme(); - } + $r = q("select content from attach where hash = '%s' and uid = %d and os_storage = 1 $sql_extra limit 1", + dbesc($hash), + intval($u['channel_id']) + ); + if ($r) { + $path = dbunescbin($r[0]['content']); + if ($path && @file_exists($path . '.thumb')) { + header('Content-Type: image/jpeg'); + echo file_get_contents($path . '.thumb'); + killme(); + } + } + killme(); + } } diff --git a/Zotlabs/Module/Pretheme.php b/Zotlabs/Module/Pretheme.php index 129f8814d..8efe8fa64 100644 --- a/Zotlabs/Module/Pretheme.php +++ b/Zotlabs/Module/Pretheme.php @@ -4,27 +4,28 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Pretheme extends Controller { +class Pretheme extends Controller +{ + + public function init() + { + + if ($_REQUEST['theme']) { + $theme = $_REQUEST['theme']; + $info = get_theme_info($theme); + if ($info) { + // unfortunately there will be no translation for this string + $desc = $info['description']; + $version = $info['version']; + $credits = $info['credits']; + } else { + $desc = ''; + $version = ''; + $credits = ''; + } + echo json_encode(array('img' => get_theme_screenshot($theme), 'desc' => $desc, 'version' => $version, 'credits' => $credits)); + } + killme(); + } - function init() { - - if($_REQUEST['theme']) { - $theme = $_REQUEST['theme']; - $info = get_theme_info($theme); - if($info) { - // unfortunately there will be no translation for this string - $desc = $info['description']; - $version = $info['version']; - $credits = $info['credits']; - } - else { - $desc = ''; - $version = ''; - $credits = ''; - } - echo json_encode(array('img' => get_theme_screenshot($theme), 'desc' => $desc, 'version' => $version, 'credits' => $credits)); - } - killme(); - } - } diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php index c052f452f..da9bc1817 100644 --- a/Zotlabs/Module/Profile.php +++ b/Zotlabs/Module/Profile.php @@ -16,123 +16,122 @@ require_once('include/conversation.php'); require_once('include/acl_selectors.php'); - class Profile extends Controller { - function init() { - - if(argc() > 1) - $which = argv(1); - else { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } + public function init() + { - nav_set_selected('Profile'); - - $profile = ''; - $channel = App::get_channel(); - - if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { - $which = $channel['channel_address']; - $profile = argv(1); - $r = q("select profile_guid from profile where id = %d and uid = %d limit 1", - intval($profile), - intval(local_channel()) - ); - if(! $r) - $profile = ''; - $profile = $r[0]['profile_guid']; - } - - head_add_link( [ - 'rel' => 'alternate', - 'type' => 'application/atom+xml', - 'title' => t('Posts and comments'), - 'href' => z_root() . '/feed/' . $which - ]); + if (argc() > 1) + $which = argv(1); + else { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } - head_add_link( [ - 'rel' => 'alternate', - 'type' => 'application/atom+xml', - 'title' => t('Only posts'), - 'href' => z_root() . '/feed/' . $which . '?f=&top=1' - ]); + nav_set_selected('Profile'); + + $profile = ''; + $channel = App::get_channel(); + + if ((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + $r = q("select profile_guid from profile where id = %d and uid = %d limit 1", + intval($profile), + intval(local_channel()) + ); + if (!$r) + $profile = ''; + $profile = $r[0]['profile_guid']; + } + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/atom+xml', + 'title' => t('Posts and comments'), + 'href' => z_root() . '/feed/' . $which + ]); + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/atom+xml', + 'title' => t('Only posts'), + 'href' => z_root() . '/feed/' . $which . '?f=&top=1' + ]); - if(! $profile) { - $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", - dbesc(argv(1)) - ); - if($x) { - App::$profile = $x[0]; - } - } - - - if(ActivityStreams::is_as_request()) { - $chan = channelx_by_nick(argv(1)); - if(! $chan) - http_status_exit(404, 'Not found'); - $p = Activity::encode_person($chan,true,((get_config('system','activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); - if(! $p) { - http_status_exit(404, 'Not found'); - } - - as_return_and_die([ 'type' => 'Profile', 'describes' => $p ], $chan); - } - - Libprofile::load($which,$profile); - - } - - function get() { - - if(observer_prohibited(true)) { - return login(); - } - - $groups = []; + if (!$profile) { + $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", + dbesc(argv(1)) + ); + if ($x) { + App::$profile = $x[0]; + } + } + if (ActivityStreams::is_as_request()) { + $chan = channelx_by_nick(argv(1)); + if (!$chan) + http_status_exit(404, 'Not found'); + $p = Activity::encode_person($chan, true, ((get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); + if (!$p) { + http_status_exit(404, 'Not found'); + } - $tab = 'profile'; - $o = ''; - - if(! (perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(), 'view_profile'))) { - notice( t('Permission denied.') . EOL); - return; - } - + as_return_and_die(['type' => 'Profile', 'describes' => $p], $chan); + } + + Libprofile::load($which, $profile); + + } + + public function get() + { + + if (observer_prohibited(true)) { + return login(); + } + + $groups = []; - if(argc() > 2 && argv(2) === 'vcard') { - header('Content-type: text/vcard'); - header('Content-Disposition: attachment; filename="' . t('vcard') . '-' . $profile['channel_address'] . '.vcf"' ); - echo App::$profile['profile_vcard']; - killme(); - } - - $is_owner = ((local_channel()) && (local_channel() == App::$profile['profile_uid']) ? true : false); - - if(App::$profile['hidewall'] && (! $is_owner) && (! remote_channel())) { - notice( t('Permission denied.') . EOL); - return; - } - - head_add_link([ - 'rel' => 'alternate', - 'type' => 'application/json+oembed', - 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), - 'title' => 'oembed' - ]); + $tab = 'profile'; + $o = ''; + + if (!(perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_profile'))) { + notice(t('Permission denied.') . EOL); + return; + } + + + if (argc() > 2 && argv(2) === 'vcard') { + header('Content-type: text/vcard'); + header('Content-Disposition: attachment; filename="' . t('vcard') . '-' . $profile['channel_address'] . '.vcf"'); + echo App::$profile['profile_vcard']; + killme(); + } + + $is_owner = ((local_channel()) && (local_channel() == App::$profile['profile_uid']) ? true : false); + + if (App::$profile['hidewall'] && (!$is_owner) && (!remote_channel())) { + notice(t('Permission denied.') . EOL); + return; + } + + head_add_link([ + 'rel' => 'alternate', + 'type' => 'application/json+oembed', + 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . App::$query_string), + 'title' => 'oembed' + ]); + + $o .= Libprofile::advanced(); + call_hooks('profile_advanced', $o); + return $o; + + } - $o .= Libprofile::advanced(); - call_hooks('profile_advanced',$o); - return $o; - - } - } diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php index 79137d20a..44ca8e6d2 100644 --- a/Zotlabs/Module/Profile_photo.php +++ b/Zotlabs/Module/Profile_photo.php @@ -18,556 +18,552 @@ require_once('include/photo_factory.php'); require_once('include/photos.php'); -class Profile_photo extends Controller { - - - /* @brief Initalize the profile-photo edit view - * - * @return void - * - */ - - function init() { - - if(! local_channel()) { - return; - } - - $channel = App::get_channel(); - Libprofile::load($channel['channel_address']); - - } - - /* @brief Evaluate posted values - * - * @param $a Current application - * @return void - * - */ - - function post() { - - if (! local_channel()) { - return; - } - - check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); - - if ((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) { - - // logger('crop: ' . print_r($_POST,true)); - - // phase 2 - we have finished cropping - - if (argc() != 2) { - notice( t('Image uploaded but image cropping failed.') . EOL ); - return; - } - - $image_id = argv(1); - - if (substr($image_id,-2,1) == '-') { - $scale = substr($image_id,-1,1); - $image_id = substr($image_id,0,-2); - } - - // unless proven otherwise - $is_default_profile = 1; - - if ($_REQUEST['profile']) { - $r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1", - intval($_REQUEST['profile']), - intval(local_channel()) - ); - if ($r) { - $profile = array_shift($r); - if (! intval($profile['is_default'])) { - $is_default_profile = 0; - } - } - } - - $srcX = intval($_POST['xstart']); - $srcY = intval($_POST['ystart']); - $srcW = intval($_POST['xfinal']) - $srcX; - $srcH = intval($_POST['yfinal']) - $srcY; - - $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1", - dbesc($image_id), - dbesc(local_channel()), - intval($scale)); - if ($r) { - - $base_image = array_shift($r); - $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); - - $im = photo_factory($base_image['content'], $base_image['mimetype']); - if ($im &&$im->is_valid()) { - - $im->cropImage(300,$srcX,$srcY,$srcW,$srcH); - - $aid = get_account_id(); - - $p = [ - 'aid' => $aid, - 'uid' => local_channel(), - 'resource_id' => $base_image['resource_id'], - 'filename' => $base_image['filename'], - 'album' => t('Profile Photos'), - 'os_path' => $base_image['os_path'], - 'display_path' => $base_image['display_path'], - 'created' => $base_image['created'], - 'edited' => $base_image['edited'] - ]; - - $animated = get_config('system','animated_avatars',true); - - $p['imgscale'] = PHOTO_RES_PROFILE_300; - $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); - - $r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300, $animated); - - $im->scaleImage(80); - $p['imgscale'] = PHOTO_RES_PROFILE_80; - - $r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80, $animated); - - $im->scaleImage(48); - $p['imgscale'] = PHOTO_RES_PROFILE_48; - - $r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48, $animated); - - if ($r1 === false || $r2 === false || $r3 === false) { - // if one failed, delete them all so we can start over. - notice( t('Image resize failed.') . EOL ); - $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ", - dbesc($base_image['resource_id']), - local_channel(), - intval(PHOTO_RES_PROFILE_300), - intval(PHOTO_RES_PROFILE_80), - intval(PHOTO_RES_PROFILE_48) - ); - return; - } - - $channel = App::get_channel(); - - // If setting for the default profile, unset the profile photo flag from any other photos I own - - if ($is_default_profile) { - - $r = q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d", - dbesc(z_root() . '/photo/profile/l/' . local_channel()), - dbesc(z_root() . '/photo/profile/m/' . local_channel()), - intval(local_channel()) - ); +class Profile_photo extends Controller +{ - $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d + /* @brief Initalize the profile-photo edit view + * + * @return void + * + */ + + public function init() + { + + if (!local_channel()) { + return; + } + + $channel = App::get_channel(); + Libprofile::load($channel['channel_address']); + + } + + /* @brief Evaluate posted values + * + * @param $a Current application + * @return void + * + */ + + public function post() + { + + if (!local_channel()) { + return; + } + + check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); + + if ((array_key_exists('cropfinal', $_POST)) && (intval($_POST['cropfinal']) == 1)) { + + // logger('crop: ' . print_r($_POST,true)); + + // phase 2 - we have finished cropping + + if (argc() != 2) { + notice(t('Image uploaded but image cropping failed.') . EOL); + return; + } + + $image_id = argv(1); + + if (substr($image_id, -2, 1) == '-') { + $scale = substr($image_id, -1, 1); + $image_id = substr($image_id, 0, -2); + } + + // unless proven otherwise + $is_default_profile = 1; + + if ($_REQUEST['profile']) { + $r = q("select id, profile_guid, is_default, gender from profile where id = %d and uid = %d limit 1", + intval($_REQUEST['profile']), + intval(local_channel()) + ); + if ($r) { + $profile = array_shift($r); + if (!intval($profile['is_default'])) { + $is_default_profile = 0; + } + } + } + + $srcX = intval($_POST['xstart']); + $srcY = intval($_POST['ystart']); + $srcW = intval($_POST['xfinal']) - $srcX; + $srcH = intval($_POST['yfinal']) - $srcY; + + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND imgscale = %d LIMIT 1", + dbesc($image_id), + dbesc(local_channel()), + intval($scale)); + if ($r) { + + $base_image = array_shift($r); + $base_image['content'] = (($base_image['os_storage']) ? @file_get_contents(dbunescbin($base_image['content'])) : dbunescbin($base_image['content'])); + + $im = photo_factory($base_image['content'], $base_image['mimetype']); + if ($im && $im->is_valid()) { + + $im->cropImage(300, $srcX, $srcY, $srcW, $srcH); + + $aid = get_account_id(); + + $p = [ + 'aid' => $aid, + 'uid' => local_channel(), + 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], + 'album' => t('Profile Photos'), + 'os_path' => $base_image['os_path'], + 'display_path' => $base_image['display_path'], + 'created' => $base_image['created'], + 'edited' => $base_image['edited'] + ]; + + $animated = get_config('system', 'animated_avatars', true); + + $p['imgscale'] = PHOTO_RES_PROFILE_300; + $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); + + $r1 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_300, $animated); + + $im->scaleImage(80); + $p['imgscale'] = PHOTO_RES_PROFILE_80; + + $r2 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_80, $animated); + + $im->scaleImage(48); + $p['imgscale'] = PHOTO_RES_PROFILE_48; + + $r3 = $im->storeThumbnail($p, PHOTO_RES_PROFILE_48, $animated); + + if ($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice(t('Image resize failed.') . EOL); + $x = q("delete from photo where resource_id = '%s' and uid = %d and imgscale in ( %d, %d, %d ) ", + dbesc($base_image['resource_id']), + local_channel(), + intval(PHOTO_RES_PROFILE_300), + intval(PHOTO_RES_PROFILE_80), + intval(PHOTO_RES_PROFILE_48) + ); + return; + } + + $channel = App::get_channel(); + + // If setting for the default profile, unset the profile photo flag from any other photos I own + + if ($is_default_profile) { + + $r = q("update profile set photo = '%s', thumb = '%s' where is_default = 1 and uid = %d", + dbesc(z_root() . '/photo/profile/l/' . local_channel()), + dbesc(z_root() . '/photo/profile/m/' . local_channel()), + intval(local_channel()) + ); + + + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND resource_id != '%s' AND uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - dbesc($base_image['resource_id']), - intval(local_channel()) - ); - + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($base_image['resource_id']), + intval(local_channel()) + ); - send_profile_photo_activity($channel,$base_image,$profile); - - } - else { - $r = q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", - dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-4'), - dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-5'), - intval($_REQUEST['profile']), - intval(local_channel()) - ); - } - - // set $send to false in profiles_build_sync() to return the data - // so that we only send one sync packet. - $sync_profiles = profiles_build_sync(local_channel(),false); - - // We'll set the updated profile-photo timestamp even if it isn't the default profile, - // so that browsers will do a cache update unconditionally - // Also set links back to site-specific profile photo url in case it was - // changed to a generic URL by a clone operation. Otherwise the new photo may - // not get pushed to other sites correctly. - - $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' + send_profile_photo_activity($channel, $base_image, $profile); + + } else { + $r = q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", + dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-4'), + dbesc(z_root() . '/photo/' . $base_image['resource_id'] . '-5'), + intval($_REQUEST['profile']), + intval(local_channel()) + ); + } + + // set $send to false in profiles_build_sync() to return the data + // so that we only send one sync packet. + + $sync_profiles = profiles_build_sync(local_channel(), false); + + // We'll set the updated profile-photo timestamp even if it isn't the default profile, + // so that browsers will do a cache update unconditionally + // Also set links back to site-specific profile photo url in case it was + // changed to a generic URL by a clone operation. Otherwise the new photo may + // not get pushed to other sites correctly. + + $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'", - dbesc($im->getType()), - dbesc(datetime_convert()), - dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']), - dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']), - dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), - dbesc($channel['xchan_hash']) - ); + dbesc($im->getType()), + dbesc(datetime_convert()), + dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']), + dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']), + dbesc($channel['xchan_hash']) + ); - photo_profile_setperms(local_channel(),$base_image['resource_id'],$_REQUEST['profile']); + photo_profile_setperms(local_channel(), $base_image['resource_id'], $_REQUEST['profile']); - $sync = attach_export_data($channel,$base_image['resource_id']); - if ($sync) { - Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync), 'profile' => $sync_profiles)); - } + $sync = attach_export_data($channel, $base_image['resource_id']); + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync), 'profile' => $sync_profiles)); + } - // Similarly, tell the nav bar to bypass the cache and update the avatar image. - $_SESSION['reload_avatar'] = true; - - info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); - - // Update directory in background - Run::Summon( [ 'Directory', $channel['channel_id'] ] ); - - } - else { - notice( t('Unable to process image') . EOL); - } - } - - goaway(z_root() . '/profiles'); - } - - // A new photo was uploaded. Store it and save some important details - // in App::$data for use in the cropping function - - - $hash = photo_new_resource(); - $importing = false; - $smallest = 0; - + // Similarly, tell the nav bar to bypass the cache and update the avatar image. + $_SESSION['reload_avatar'] = true; - if ($_REQUEST['importfile']) { - $hash = $_REQUEST['importfile']; - $importing = true; - } - else { + info(t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); - $matches = []; - $partial = false; + // Update directory in background + Run::Summon(['Directory', $channel['channel_id']]); - if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { - $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); - if ($pm) { - logger('Content-Range: ' . print_r($matches,true), LOGGER_DEBUG); - $partial = true; - } - } + } else { + notice(t('Unable to process image') . EOL); + } + } - if ($partial) { - $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); + goaway(z_root() . '/profiles'); + } - if ($x['partial']) { - header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($x); - } - else { - header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + // A new photo was uploaded. Store it and save some important details + // in App::$data for use in the cropping function - $_FILES['userfile'] = [ - 'name' => $x['name'], - 'type' => $x['type'], - 'tmp_name' => $x['tmp_name'], - 'error' => $x['error'], - 'size' => $x['size'] - ]; - } - } - else { - if (! array_key_exists('userfile',$_FILES)) { - $_FILES['userfile'] = [ - 'name' => $_FILES['files']['name'], - 'type' => $_FILES['files']['type'], - 'tmp_name' => $_FILES['files']['tmp_name'], - 'error' => $_FILES['files']['error'], - 'size' => $_FILES['files']['size'] - ]; - } - } - $res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash)); - - logger('attach_store: ' . print_r($res,true), LOGGER_DEBUG); + $hash = photo_new_resource(); + $importing = false; + $smallest = 0; - json_return_and_die([ 'message' => $hash ]); - } - - if (($res && intval($res['data']['is_photo'])) || $importing) { - $i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale", - dbesc($hash), - intval(local_channel()) - ); - - if (! $i) { - notice( t('Image upload failed.') . EOL ); - return; - } - $os_storage = false; - - foreach ($i as $ii) { - if (intval($ii['imgscale']) < PHOTO_RES_640) { - $smallest = intval($ii['imgscale']); - $os_storage = intval($ii['os_storage']); - $imagedata = $ii['content']; - $filetype = $ii['mimetype']; - } - } - } - - $imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata)); - $ph = photo_factory($imagedata, $filetype); - - if (! $ph->is_valid()) { - notice( t('Unable to process image.') . EOL ); - return; - } - - return $this->profile_photo_crop_ui_head($ph, $hash, $smallest); - // This will "fall through" to the get() method, and since - // App::$data['imagecrop'] is set, it will proceed to cropping - // rather than present the upload form - } - - - /* @brief Generate content of profile-photo view - * - * @return void - * - */ - - - function get() { - - if (! local_channel()) { - notice( t('Permission denied.') . EOL ); - return; - } - - $channel = App::get_channel(); - $pf = 0; - $newuser = false; - - if (argc() == 2 && argv(1) === 'new') { - $newuser = true; - } - - if (argv(1) === 'use') { - if (argc() < 3) { - notice( t('Permission denied.') . EOL ); - return; - } + if ($_REQUEST['importfile']) { + $hash = $_REQUEST['importfile']; + $importing = true; + } else { + + $matches = []; + $partial = false; + + if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches); + if ($pm) { + logger('Content-Range: ' . print_r($matches, true), LOGGER_DEBUG); + $partial = true; + } + } + + if ($partial) { + $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]); + + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($x); + } else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } else { + if (!array_key_exists('userfile', $_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } + + $res = attach_store(App::get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash)); + + logger('attach_store: ' . print_r($res, true), LOGGER_DEBUG); + + json_return_and_die(['message' => $hash]); + } + + if (($res && intval($res['data']['is_photo'])) || $importing) { + $i = q("select * from photo where resource_id = '%s' and uid = %d order by imgscale", + dbesc($hash), + intval(local_channel()) + ); + + if (!$i) { + notice(t('Image upload failed.') . EOL); + return; + } + $os_storage = false; + + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { + $smallest = intval($ii['imgscale']); + $os_storage = intval($ii['os_storage']); + $imagedata = $ii['content']; + $filetype = $ii['mimetype']; + } + } + } + + $imagedata = (($os_storage) ? @file_get_contents(dbunescbin($imagedata)) : dbunescbin($imagedata)); + $ph = photo_factory($imagedata, $filetype); + + if (!$ph->is_valid()) { + notice(t('Unable to process image.') . EOL); + return; + } + + return $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + + // This will "fall through" to the get() method, and since + // App::$data['imagecrop'] is set, it will proceed to cropping + // rather than present the upload form + } + + + /* @brief Generate content of profile-photo view + * + * @return void + * + */ + + + public function get() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + $channel = App::get_channel(); + $pf = 0; + $newuser = false; + + if (argc() == 2 && argv(1) === 'new') { + $newuser = true; + } + + if (argv(1) === 'use') { + if (argc() < 3) { + notice(t('Permission denied.') . EOL); + return; + } $resource_id = argv(2); - - $pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0); - $c = q("select id, is_default from profile where uid = %d", - intval(local_channel()) - ); + $pf = (($_REQUEST['pf']) ? intval($_REQUEST['pf']) : 0); - $multi_profiles = true; + $c = q("select id, is_default from profile where uid = %d", + intval(local_channel()) + ); - if (($c) && (count($c) === 1) && (intval($c[0]['is_default']))) { - $_REQUEST['profile'] = $c[0]['id']; - $multi_profiles = false; - } - else { - $_REQUEST['profile'] = $pf; - } + $multi_profiles = true; - $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC", - intval(local_channel()), - dbesc($resource_id) - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - $havescale = false; - foreach ($r as $rr) { - if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) { - $havescale = true; - } - } - - // set an already loaded and cropped photo as profile photo - - if ($havescale) { - // unset any existing profile photos - $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE), - intval(local_channel()) - ); - - $r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'", - intval(PHOTO_PROFILE), - intval(local_channel()), - dbesc($resource_id) - ); - - $r = q("UPDATE xchan set xchan_photo_date = '%s' where xchan_hash = '%s'", - dbesc(datetime_convert()), - dbesc($channel['xchan_hash']) - ); - - photo_profile_setperms(local_channel(),$resource_id,$_REQUEST['profile']); + if (($c) && (count($c) === 1) && (intval($c[0]['is_default']))) { + $_REQUEST['profile'] = $c[0]['id']; + $multi_profiles = false; + } else { + $_REQUEST['profile'] = $pf; + } - $sync = attach_export_data($channel,$resource_id); - if ($sync) { - Libsync::build_sync_packet($channel['channel_id'],array('file' => array($sync))); - } + $r = q("SELECT id, album, imgscale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY imgscale ASC", + intval(local_channel()), + dbesc($resource_id) + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + $havescale = false; + foreach ($r as $rr) { + if ($rr['imgscale'] == PHOTO_RES_PROFILE_80) { + $havescale = true; + } + } - Run::Summon( [ 'Directory',local_channel() ] ); - goaway(z_root() . '/profiles'); - } - - $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", - intval($r[0]['id']), - intval(local_channel()) - - ); - if (! $r) { - notice( t('Photo not available.') . EOL ); - return; - } - - if (intval($r[0]['os_storage'])) { - $data = @file_get_contents(dbunescbin($r[0]['content'])); - } - else { - $data = dbunescbin($r[0]['content']); - } - - $ph = photo_factory($data, $r[0]['mimetype']); - $smallest = 0; - if ($ph->is_valid()) { - // go ahead as if we have just uploaded a new photo to crop - $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale", - dbesc($r[0]['resource_id']), - intval(local_channel()) - ); - - if ($i) { - $hash = $i[0]['resource_id']; - foreach ($i as $ii) { - if (intval($ii['imgscale']) < PHOTO_RES_640) { - $smallest = intval($ii['imgscale']); - } - } - } - } - - if ($multi_profiles) { - App::$data['importfile'] = $resource_id; - } - else { - $this->profile_photo_crop_ui_head($ph, $hash, $smallest); - } + // set an already loaded and cropped photo as profile photo - // falls through with App::$data['imagecrop'] set so we go straight to the cropping section + if ($havescale) { + // unset any existing profile photos + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval(local_channel()) + ); - } - - // present an upload form + $r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'", + intval(PHOTO_PROFILE), + intval(local_channel()), + dbesc($resource_id) + ); - $profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc", - intval(local_channel()) - ); + $r = q("UPDATE xchan set xchan_photo_date = '%s' where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($channel['xchan_hash']) + ); - if ($profiles) { - for ($x = 0; $x < count($profiles); $x ++) { - $profiles[$x]['selected'] = false; - if ($pf && $profiles[$x]['id'] == $pf) { - $profiles[$x]['selected'] = true; - } - if ((! $pf) && $profiles[$x]['is_default']) { - $profiles[$x]['selected'] = true; - } - } - } + photo_profile_setperms(local_channel(), $resource_id, $_REQUEST['profile']); - $importing = ((array_key_exists('importfile',App::$data)) ? true : false); - - if (! array_key_exists('imagecrop', App::$data)) { - - $tpl = get_markup_template('profile_photo.tpl'); - - $o .= replace_macros($tpl, [ - '$user' => App::$channel['channel_address'], - '$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')), - '$importfile' => (($importing) ? App::$data['importfile'] : ''), - '$lbl_upfile' => t('Upload File:'), - '$lbl_profiles' => t('Select a profile:'), - '$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')), - '$submit' => (($importing) ? t('Use') : t('Upload')), - '$profiles' => $profiles, - '$single' => ((count($profiles) == 1) ? true : false), - '$profile0' => $profiles[0], - '$embedPhotos' => t('Use a photo from your albums'), - '$embedPhotosModalTitle' => t('Use a photo from your albums'), - '$embedPhotosModalCancel' => t('Cancel'), - '$embedPhotosModalOK' => t('OK'), - '$modalchooseimages' => t('Choose images to embed'), - '$modalchoosealbum' => t('Choose an album'), - '$modaldiffalbum' => t('Choose a different album'), - '$modalerrorlist' => t('Error getting album list'), - '$modalerrorlink' => t('Error getting photo link'), - '$modalerroralbum' => t('Error getting album'), - '$form_security_token' => get_form_security_token("profile_photo"), - '$select' => t('Select previously uploaded photo'), - ]); - - call_hooks('profile_photo_content_end', $o); - return $o; - } - else { + $sync = attach_export_data($channel, $resource_id); + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } - // present a cropping form + Run::Summon(['Directory', local_channel()]); + goaway(z_root() . '/profiles'); + } - $filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution']; - $resolution = App::$data['imagecrop_resolution']; - $o .= replace_macros(get_markup_template('cropbody.tpl'), [ - '$filename' => $filename, - '$profile' => intval($_REQUEST['profile']), - '$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'], - '$image_url' => z_root() . '/photo/' . $filename, - '$title' => t('Crop Image'), - '$desc' => t('Please adjust the image cropping for optimum viewing.'), - '$form_security_token' => get_form_security_token("profile_photo"), - '$done' => t('Done Editing') - ]); - return $o; - } - } - - /* @brief Generate the UI for photo-cropping - * - * @param $ph Photo-Factory - * @return void - * - */ - - function profile_photo_crop_ui_head($ph, $hash, $smallest) { - $max_length = get_config('system','max_image_length', MAX_IMAGE_LENGTH); - if ($max_length > 0) { - $ph->scaleImage($max_length); - } - - App::$data['width'] = $ph->getWidth(); - App::$data['height'] = $ph->getHeight(); - - if (App::$data['width'] < 500 || App::$data['height'] < 500) { - $ph->scaleImageUp(400); - App::$data['width'] = $ph->getWidth(); - App::$data['height'] = $ph->getHeight(); - } - - App::$data['imagecrop'] = $hash; - App::$data['imagecrop_resolution'] = $smallest; - App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); - return; - } + $r = q("SELECT content, mimetype, resource_id, os_storage FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval(local_channel()) + + ); + if (!$r) { + notice(t('Photo not available.') . EOL); + return; + } + + if (intval($r[0]['os_storage'])) { + $data = @file_get_contents(dbunescbin($r[0]['content'])); + } else { + $data = dbunescbin($r[0]['content']); + } + + $ph = photo_factory($data, $r[0]['mimetype']); + $smallest = 0; + if ($ph->is_valid()) { + // go ahead as if we have just uploaded a new photo to crop + $i = q("select resource_id, imgscale from photo where resource_id = '%s' and uid = %d order by imgscale", + dbesc($r[0]['resource_id']), + intval(local_channel()) + ); + + if ($i) { + $hash = $i[0]['resource_id']; + foreach ($i as $ii) { + if (intval($ii['imgscale']) < PHOTO_RES_640) { + $smallest = intval($ii['imgscale']); + } + } + } + } + + if ($multi_profiles) { + App::$data['importfile'] = $resource_id; + } else { + $this->profile_photo_crop_ui_head($ph, $hash, $smallest); + } + + // falls through with App::$data['imagecrop'] set so we go straight to the cropping section + + } + + // present an upload form + + $profiles = q("select id, profile_name as name, is_default from profile where uid = %d order by id asc", + intval(local_channel()) + ); + + if ($profiles) { + for ($x = 0; $x < count($profiles); $x++) { + $profiles[$x]['selected'] = false; + if ($pf && $profiles[$x]['id'] == $pf) { + $profiles[$x]['selected'] = true; + } + if ((!$pf) && $profiles[$x]['is_default']) { + $profiles[$x]['selected'] = true; + } + } + } + + $importing = ((array_key_exists('importfile', App::$data)) ? true : false); + + if (!array_key_exists('imagecrop', App::$data)) { + + $tpl = get_markup_template('profile_photo.tpl'); + + $o .= replace_macros($tpl, [ + '$user' => App::$channel['channel_address'], + '$info' => ((count($profiles) > 1) ? t('Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile') : t('Your profile photo is visible to anybody on the internet and may be distributed to other websites.')), + '$importfile' => (($importing) ? App::$data['importfile'] : ''), + '$lbl_upfile' => t('Upload File:'), + '$lbl_profiles' => t('Select a profile:'), + '$title' => (($importing) ? t('Use Photo for Profile') : t('Change Profile Photo')), + '$submit' => (($importing) ? t('Use') : t('Upload')), + '$profiles' => $profiles, + '$single' => ((count($profiles) == 1) ? true : false), + '$profile0' => $profiles[0], + '$embedPhotos' => t('Use a photo from your albums'), + '$embedPhotosModalTitle' => t('Use a photo from your albums'), + '$embedPhotosModalCancel' => t('Cancel'), + '$embedPhotosModalOK' => t('OK'), + '$modalchooseimages' => t('Choose images to embed'), + '$modalchoosealbum' => t('Choose an album'), + '$modaldiffalbum' => t('Choose a different album'), + '$modalerrorlist' => t('Error getting album list'), + '$modalerrorlink' => t('Error getting photo link'), + '$modalerroralbum' => t('Error getting album'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$select' => t('Select previously uploaded photo'), + ]); + + call_hooks('profile_photo_content_end', $o); + return $o; + } else { + + // present a cropping form + + $filename = App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution']; + $resolution = App::$data['imagecrop_resolution']; + $o .= replace_macros(get_markup_template('cropbody.tpl'), [ + '$filename' => $filename, + '$profile' => intval($_REQUEST['profile']), + '$resource' => App::$data['imagecrop'] . '-' . App::$data['imagecrop_resolution'], + '$image_url' => z_root() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$done' => t('Done Editing') + ]); + return $o; + } + } + + /* @brief Generate the UI for photo-cropping + * + * @param $ph Photo-Factory + * @return void + * + */ + + public function profile_photo_crop_ui_head($ph, $hash, $smallest) + { + $max_length = get_config('system', 'max_image_length', MAX_IMAGE_LENGTH); + if ($max_length > 0) { + $ph->scaleImage($max_length); + } + + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); + + if (App::$data['width'] < 500 || App::$data['height'] < 500) { + $ph->scaleImageUp(400); + App::$data['width'] = $ph->getWidth(); + App::$data['height'] = $ph->getHeight(); + } + + App::$data['imagecrop'] = $hash; + App::$data['imagecrop_resolution'] = $smallest; + App::$page['htmlhead'] .= replace_macros(get_markup_template('crophead.tpl'), []); + return; + } } diff --git a/Zotlabs/Module/Profiles.php b/Zotlabs/Module/Profiles.php index 81099e416..232f7c0bf 100644 --- a/Zotlabs/Module/Profiles.php +++ b/Zotlabs/Module/Profiles.php @@ -10,511 +10,509 @@ use Zotlabs\Daemon\Run; use Sabre\VObject\Reader; -class Profiles extends Controller { +class Profiles extends Controller +{ - function init() { - - nav_set_selected('Profiles'); - - if(! local_channel()) { - return; - } - - if((argc() > 2) && (argv(1) === "drop") && intval(argv(2))) { - $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d AND is_default = 0 LIMIT 1", - intval(argv(2)), - intval(local_channel()) - ); - if(! $r) { - notice( t('Profile not found.') . EOL); - goaway(z_root() . '/profiles'); - } - $profile_guid = $r[0]['profile_guid']; - - check_form_security_token_redirectOnErr('/profiles', 'profile_drop', 't'); - - // move every contact using this profile as their default to the user default - - $r = q("UPDATE abook SET abook_profile = (SELECT profile_guid FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1) WHERE abook_profile = '%s' AND abook_channel = %d ", - intval(local_channel()), - dbesc($profile_guid), - intval(local_channel()) - ); - $r = q("DELETE FROM profile WHERE id = %d AND uid = %d", - intval(argv(2)), - intval(local_channel()) - ); - if($r) - info( t('Profile deleted.') . EOL); - - // @fixme this is a much more complicated sync - add any changed abook entries and - // also add deleted flag to profile structure - // profiles_build_sync is just here as a placeholder - it doesn't work at all here - - // profiles_build_sync(local_channel()); - - goaway(z_root() . '/profiles'); - return; // NOTREACHED - } - - - - - - if((argc() > 1) && (argv(1) === 'new')) { - - // check_form_security_token_redirectOnErr('/profiles', 'profile_new', 't'); - - $r0 = q("SELECT id FROM profile WHERE uid = %d", - intval(local_channel())); - $num_profiles = count($r0); - - $name = t('Profile-') . ($num_profiles + 1); - - $r1 = q("SELECT fullname, photo, thumb FROM profile WHERE uid = %d AND is_default = 1 LIMIT 1", - intval(local_channel())); - - $r2 = profile_store_lowlevel( - [ - 'aid' => intval(get_account_id()), - 'uid' => intval(local_channel()), - 'profile_guid' => new_uuid(), - 'profile_name' => $name, - 'fullname' => $r1[0]['fullname'], - 'photo' => $r1[0]['photo'], - 'thumb' => $r1[0]['thumb'] - ] - ); - - $r3 = q("SELECT id FROM profile WHERE uid = %d AND profile_name = '%s' LIMIT 1", - intval(local_channel()), - dbesc($name) - ); - - info( t('New profile created.') . EOL); - if(count($r3) == 1) - goaway(z_root() . '/profiles/' . $r3[0]['id']); - - goaway(z_root() . '/profiles'); - } - - if((argc() > 2) && (argv(1) === 'clone')) { - - check_form_security_token_redirectOnErr('/profiles', 'profile_clone', 't'); - - $r0 = q("SELECT id FROM profile WHERE uid = %d", - intval(local_channel())); - $num_profiles = count($r0); - - $name = t('Profile-') . ($num_profiles + 1); - $r1 = q("SELECT * FROM profile WHERE uid = %d AND id = %d LIMIT 1", - intval(local_channel()), - intval(argv(2)) - ); - if(! count($r1)) { - notice( t('Profile unavailable to clone.') . EOL); - App::$error = 404; - return; - } - unset($r1[0]['id']); - $r1[0]['is_default'] = 0; - $r1[0]['publish'] = 0; - $r1[0]['profile_name'] = $name; - $r1[0]['profile_guid'] = new_uuid(); - - create_table_from_array('profile', $r1[0]); - - $r3 = q("SELECT id FROM profile WHERE uid = %d AND profile_name = '%s' LIMIT 1", - intval(local_channel()), - dbesc($name) - ); - info( t('New profile created.') . EOL); - - profiles_build_sync(local_channel()); - - if(($r3) && (count($r3) == 1)) - goaway(z_root() . '/profiles/' . $r3[0]['id']); - - goaway(z_root() . '/profiles'); - - return; // NOTREACHED - } - - if((argc() > 2) && (argv(1) === 'export')) { - - $r1 = q("SELECT * FROM profile WHERE uid = %d AND id = %d LIMIT 1", - intval(local_channel()), - intval(argv(2)) - ); - if(! $r1) { - notice( t('Profile unavailable to export.') . EOL); - App::$error = 404; - return; - } - header('content-type: application/octet_stream'); - header('Content-Disposition: attachment; filename="' . $r1[0]['profile_name'] . '.json"' ); - - unset($r1[0]['id']); - unset($r1[0]['aid']); - unset($r1[0]['uid']); - unset($r1[0]['is_default']); - unset($r1[0]['publish']); - unset($r1[0]['profile_name']); - unset($r1[0]['profile_guid']); - echo json_encode($r1[0]); - killme(); - } - - if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) { - if(feature_enabled(local_channel(),'multi_profiles')) - $id = argv(1); - else { - $x = q("select id from profile where uid = %d and is_default = 1", - intval(local_channel()) - ); - if($x) - $id = $x[0]['id']; - } - $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", - intval($id), - intval(local_channel()) - ); - if(! count($r)) { - notice( t('Profile not found.') . EOL); - App::$error = 404; - return; - } - - $chan = App::get_channel(); - - Libprofile::load($chan['channel_address'],$r[0]['profile_guid']); - } - } - - function post() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - $namechanged = false; - - // import from json export file. - // Only import fields that are allowed on this hub - - if(x($_FILES,'userfile')) { - $src = $_FILES['userfile']['tmp_name']; - $filesize = intval($_FILES['userfile']['size']); - if($filesize) { - $j = @json_decode(@file_get_contents($src),true); - @unlink($src); - if($j) { - $fields = get_profile_fields_advanced(); - if($fields) { - foreach($j as $jj => $v) { - foreach($fields as $f => $n) { - if($jj == $f) { - $_POST[$f] = $v; - break; - } - } - } - } - } - } - } - - call_hooks('profile_post', $_POST); - - - if((argc() > 1) && (argv(1) !== "new") && intval(argv(1))) { - $orig = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", - intval(argv(1)), - intval(local_channel()) - ); - if(! count($orig)) { - notice( t('Profile not found.') . EOL); - return; - } - - check_form_security_token_redirectOnErr('/profiles', 'profile_edit'); - + public function init() + { - $is_default = (($orig[0]['is_default']) ? 1 : 0); - - $profile_name = notags(trim($_POST['profile_name'])); - if(! strlen($profile_name)) { - notice( t('Profile Name is required.') . EOL); - return; - } - - $dob = $_POST['dob'] ? escape_tags(trim($_POST['dob'])) : '0000-00-00'; - - $y = substr($dob,0,4); - if((! ctype_digit($y)) || ($y < 1900)) - $ignore_year = true; - else - $ignore_year = false; - - if($dob !== '0000-00-00') { - if(strpos($dob,'0000-') === 0) { - $ignore_year = true; - $dob = substr($dob,5); - } - $dob = datetime_convert('UTC','UTC',(($ignore_year) ? '1900-' . $dob : $dob),(($ignore_year) ? 'm-d' : 'Y-m-d')); - if($ignore_year) - $dob = '0000-' . $dob; - } - - $name = escape_tags(trim($_POST['name'])); - - if($orig[0]['fullname'] != $name) { - $namechanged = true; - - $v = validate_channelname($name); - if($v) { - notice($v); - $namechanged = false; - $name = $orig[0]['fullname']; - } - } - - $pdesc = escape_tags(trim($_POST['pdesc'])); - $gender = escape_tags(trim($_POST['gender'])); - $address = escape_tags(trim($_POST['address'])); - $locality = escape_tags(trim($_POST['locality'])); - $region = escape_tags(trim($_POST['region'])); - $postal_code = escape_tags(trim($_POST['postal_code'])); - $country_name = escape_tags(trim($_POST['country_name'])); - $keywords = escape_tags(trim($_POST['keywords'])); - $marital = escape_tags(trim($_POST['marital'])); - $howlong = escape_tags(trim($_POST['howlong'])); - $sexual = escape_tags(trim($_POST['sexual'])); - $pronouns = escape_tags(trim($_POST['pronouns'])); - $homepage = escape_tags(trim($_POST['homepage'])); - $hometown = escape_tags(trim($_POST['hometown'])); - $politic = escape_tags(trim($_POST['politic'])); - $religion = escape_tags(trim($_POST['religion'])); - - $likes = escape_tags(trim($_POST['likes'])); - $dislikes = escape_tags(trim($_POST['dislikes'])); - - $about = escape_tags(trim($_POST['about'])); - $interest = escape_tags(trim($_POST['interest'])); - $contact = escape_tags(trim($_POST['contact'])); - $channels = escape_tags(trim($_POST['channels'])); - $music = escape_tags(trim($_POST['music'])); - $book = escape_tags(trim($_POST['book'])); - $tv = escape_tags(trim($_POST['tv'])); - $film = escape_tags(trim($_POST['film'])); - $romance = escape_tags(trim($_POST['romance'])); - $work = escape_tags(trim($_POST['work'])); - $education = escape_tags(trim($_POST['education'])); - - $hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0); - - // start fresh and create a new vcard. - // @TODO: preserve the original guid or whatever else needs saving - // $orig_vcard = (($orig[0]['profile_vcard']) ? Reader::read($orig[0]['profile_vcard']) : null); + nav_set_selected('Profiles'); - $orig_vcard = null; + if (!local_channel()) { + return; + } - $channel = App::get_channel(); + if ((argc() > 2) && (argv(1) === "drop") && intval(argv(2))) { + $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d AND is_default = 0 LIMIT 1", + intval(argv(2)), + intval(local_channel()) + ); + if (!$r) { + notice(t('Profile not found.') . EOL); + goaway(z_root() . '/profiles'); + } + $profile_guid = $r[0]['profile_guid']; - $default_vcard_cat = ((defined('DEFAULT_VCARD_CAT')) ? DEFAULT_VCARD_CAT : 'HOME'); + check_form_security_token_redirectOnErr('/profiles', 'profile_drop', 't'); - $defcard = [ - 'fn' => $name, - 'title' => $pdesc, - 'photo' => $channel['xchan_photo_l'], - 'adr' => [], - 'adr_type' => [ $default_vcard_cat ], - 'url' => [ $homepage ], - 'url_type' => [ $default_vcard_cat ] - ]; + // move every contact using this profile as their default to the user default - $defcard['adr'][] = [ - 0 => '', - 1 => '', - 2 => $address, - 3 => $locality, - 4 => $region, - 5 => $postal_code, - 6 => $country_name - ]; - - $profile_vcard = update_vcard($defcard,$orig_vcard); + $r = q("UPDATE abook SET abook_profile = (SELECT profile_guid FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1) WHERE abook_profile = '%s' AND abook_channel = %d ", + intval(local_channel()), + dbesc($profile_guid), + intval(local_channel()) + ); + $r = q("DELETE FROM profile WHERE id = %d AND uid = %d", + intval(argv(2)), + intval(local_channel()) + ); + if ($r) + info(t('Profile deleted.') . EOL); - $orig_vcard = Reader::read($profile_vcard); + // @fixme this is a much more complicated sync - add any changed abook entries and + // also add deleted flag to profile structure + // profiles_build_sync is just here as a placeholder - it doesn't work at all here - $profile_vcard = update_vcard($_REQUEST,$orig_vcard); + // profiles_build_sync(local_channel()); + + goaway(z_root() . '/profiles'); + return; // NOTREACHED + } - require_once('include/text.php'); - linkify_tags($likes, local_channel()); - linkify_tags($dislikes, local_channel()); - linkify_tags($about, local_channel()); - linkify_tags($interest, local_channel()); - linkify_tags($interest, local_channel()); - linkify_tags($contact, local_channel()); - linkify_tags($channels, local_channel()); - linkify_tags($music, local_channel()); - linkify_tags($book, local_channel()); - linkify_tags($tv, local_channel()); - linkify_tags($film, local_channel()); - linkify_tags($romance, local_channel()); - linkify_tags($work, local_channel()); - linkify_tags($education, local_channel()); - - - $with = ((x($_POST,'with')) ? escape_tags(trim($_POST['with'])) : ''); - - if(! strlen($howlong)) - $howlong = NULL_DATE; - else - $howlong = datetime_convert(date_default_timezone_get(),'UTC',$howlong); - - // linkify the relationship target if applicable - - $withchanged = false; - - if(strlen($with)) { - if($with != strip_tags($orig[0]['partner'])) { - $withchanged = true; - $prf = ''; - $lookup = $with; - if(strpos($lookup,'@') === 0) - $lookup = substr($lookup,1); - $lookup = str_replace('_',' ', $lookup); - $newname = $lookup; - - $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_name = '%s' AND abook_channel = %d LIMIT 1", - dbesc($newname), - intval(local_channel()) - ); - if(! $r) { - $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_addr = '%s' AND abook_channel = %d LIMIT 1", - dbesc($lookup . '@%'), - intval(local_channel()) - ); - } - if($r) { - $prf = $r[0]['xchan_url']; - $newname = $r[0]['xchan_name']; - } - - - if($prf) { - $with = str_replace($lookup,'' . $newname . '', $with); - if(strpos($with,'@') === 0) - $with = substr($with,1); - } - } - else - $with = $orig[0]['partner']; - } - - $profile_fields_basic = get_profile_fields_basic(); - $profile_fields_advanced = get_profile_fields_advanced(); - $advanced = ((feature_enabled(local_channel(),'advanced_profiles')) ? true : false); - if($advanced) - $fields = $profile_fields_advanced; - else - $fields = $profile_fields_basic; - - $z = q("select * from profdef where true"); - if($z) { - foreach($z as $zz) { - if(array_key_exists($zz['field_name'],$fields)) { - $w = q("select * from profext where channel_id = %d and hash = '%s' and k = '%s' limit 1", - intval(local_channel()), - dbesc($orig[0]['profile_guid']), - dbesc($zz['field_name']) - ); - if($w) { - q("update profext set v = '%s' where id = %d", - dbesc(escape_tags(trim($_POST[$zz['field_name']]))), - intval($w[0]['id']) - ); - } - else { - q("insert into profext ( channel_id, hash, k, v ) values ( %d, '%s', '%s', '%s') ", - intval(local_channel()), - dbesc($orig[0]['profile_guid']), - dbesc($zz['field_name']), - dbesc(escape_tags(trim($_POST[$zz['field_name']]))) - ); - } - } - } - } - - $changes = []; - $value = ''; - if($is_default) { - if($marital != $orig[0]['marital']) { - $changes[] = '[color=#ff0000]♥[/color] ' . t('Marital Status'); - $value = $marital; - } - if($withchanged) { - $changes[] = '[color=#ff0000]♥[/color] ' . t('Romantic Partner'); - $value = strip_tags($with); - } - if($likes != $orig[0]['likes']) { - $changes[] = t('Likes'); - $value = $likes; - } - if($dislikes != $orig[0]['dislikes']) { - $changes[] = t('Dislikes'); - $value = $dislikes; - } - if($work != $orig[0]['employment']) { - $changes[] = t('Work/Employment'); - } - if($religion != $orig[0]['religion']) { - $changes[] = t('Religion'); - $value = $religion; - } - if($politic != $orig[0]['politic']) { - $changes[] = t('Political Views'); - $value = $politic; - } - if($gender != $orig[0]['gender']) { - $changes[] = t('Gender'); - $value = $gender; - } - if($sexual != $orig[0]['sexual']) { - $changes[] = t('Sexual Preference'); - $value = $sexual; - } - if($homepage != $orig[0]['homepage']) { - $changes[] = t('Homepage'); - $value = $homepage; - } - if($interest != $orig[0]['interest']) { - $changes[] = t('Interests'); - $value = $interest; - } - if($address != $orig[0]['address']) { - $changes[] = t('Address'); - // New address not sent in notifications, potential privacy issues - // in case this leaks to unintended recipients. Yes, it's in the public - // profile but that doesn't mean we have to broadcast it to everybody. - } - if($locality != $orig[0]['locality'] || $region != $orig[0]['region'] - || $country_name != $orig[0]['country_name']) { - $changes[] = t('Location'); - $comma1 = ((($locality) && ($region || $country_name)) ? ', ' : ' '); - $comma2 = (($region && $country_name) ? ', ' : ''); - $value = $locality . $comma1 . $region . $comma2 . $country_name; - } - - self::profile_activity($changes,$value); - - } - - $r = q("UPDATE profile + if ((argc() > 1) && (argv(1) === 'new')) { + + // check_form_security_token_redirectOnErr('/profiles', 'profile_new', 't'); + + $r0 = q("SELECT id FROM profile WHERE uid = %d", + intval(local_channel())); + $num_profiles = count($r0); + + $name = t('Profile-') . ($num_profiles + 1); + + $r1 = q("SELECT fullname, photo, thumb FROM profile WHERE uid = %d AND is_default = 1 LIMIT 1", + intval(local_channel())); + + $r2 = profile_store_lowlevel( + [ + 'aid' => intval(get_account_id()), + 'uid' => intval(local_channel()), + 'profile_guid' => new_uuid(), + 'profile_name' => $name, + 'fullname' => $r1[0]['fullname'], + 'photo' => $r1[0]['photo'], + 'thumb' => $r1[0]['thumb'] + ] + ); + + $r3 = q("SELECT id FROM profile WHERE uid = %d AND profile_name = '%s' LIMIT 1", + intval(local_channel()), + dbesc($name) + ); + + info(t('New profile created.') . EOL); + if (count($r3) == 1) + goaway(z_root() . '/profiles/' . $r3[0]['id']); + + goaway(z_root() . '/profiles'); + } + + if ((argc() > 2) && (argv(1) === 'clone')) { + + check_form_security_token_redirectOnErr('/profiles', 'profile_clone', 't'); + + $r0 = q("SELECT id FROM profile WHERE uid = %d", + intval(local_channel())); + $num_profiles = count($r0); + + $name = t('Profile-') . ($num_profiles + 1); + $r1 = q("SELECT * FROM profile WHERE uid = %d AND id = %d LIMIT 1", + intval(local_channel()), + intval(argv(2)) + ); + if (!count($r1)) { + notice(t('Profile unavailable to clone.') . EOL); + App::$error = 404; + return; + } + unset($r1[0]['id']); + $r1[0]['is_default'] = 0; + $r1[0]['publish'] = 0; + $r1[0]['profile_name'] = $name; + $r1[0]['profile_guid'] = new_uuid(); + + create_table_from_array('profile', $r1[0]); + + $r3 = q("SELECT id FROM profile WHERE uid = %d AND profile_name = '%s' LIMIT 1", + intval(local_channel()), + dbesc($name) + ); + info(t('New profile created.') . EOL); + + profiles_build_sync(local_channel()); + + if (($r3) && (count($r3) == 1)) + goaway(z_root() . '/profiles/' . $r3[0]['id']); + + goaway(z_root() . '/profiles'); + + return; // NOTREACHED + } + + if ((argc() > 2) && (argv(1) === 'export')) { + + $r1 = q("SELECT * FROM profile WHERE uid = %d AND id = %d LIMIT 1", + intval(local_channel()), + intval(argv(2)) + ); + if (!$r1) { + notice(t('Profile unavailable to export.') . EOL); + App::$error = 404; + return; + } + header('content-type: application/octet_stream'); + header('Content-Disposition: attachment; filename="' . $r1[0]['profile_name'] . '.json"'); + + unset($r1[0]['id']); + unset($r1[0]['aid']); + unset($r1[0]['uid']); + unset($r1[0]['is_default']); + unset($r1[0]['publish']); + unset($r1[0]['profile_name']); + unset($r1[0]['profile_guid']); + echo json_encode($r1[0]); + killme(); + } + + if (((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(), 'multi_profiles')) { + if (feature_enabled(local_channel(), 'multi_profiles')) + $id = argv(1); + else { + $x = q("select id from profile where uid = %d and is_default = 1", + intval(local_channel()) + ); + if ($x) + $id = $x[0]['id']; + } + $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", + intval($id), + intval(local_channel()) + ); + if (!count($r)) { + notice(t('Profile not found.') . EOL); + App::$error = 404; + return; + } + + $chan = App::get_channel(); + + Libprofile::load($chan['channel_address'], $r[0]['profile_guid']); + } + } + + public function post() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + $namechanged = false; + + // import from json export file. + // Only import fields that are allowed on this hub + + if (x($_FILES, 'userfile')) { + $src = $_FILES['userfile']['tmp_name']; + $filesize = intval($_FILES['userfile']['size']); + if ($filesize) { + $j = @json_decode(@file_get_contents($src), true); + @unlink($src); + if ($j) { + $fields = get_profile_fields_advanced(); + if ($fields) { + foreach ($j as $jj => $v) { + foreach ($fields as $f => $n) { + if ($jj == $f) { + $_POST[$f] = $v; + break; + } + } + } + } + } + } + } + + call_hooks('profile_post', $_POST); + + + if ((argc() > 1) && (argv(1) !== "new") && intval(argv(1))) { + $orig = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + if (!count($orig)) { + notice(t('Profile not found.') . EOL); + return; + } + + check_form_security_token_redirectOnErr('/profiles', 'profile_edit'); + + + $is_default = (($orig[0]['is_default']) ? 1 : 0); + + $profile_name = notags(trim($_POST['profile_name'])); + if (!strlen($profile_name)) { + notice(t('Profile Name is required.') . EOL); + return; + } + + $dob = $_POST['dob'] ? escape_tags(trim($_POST['dob'])) : '0000-00-00'; + + $y = substr($dob, 0, 4); + if ((!ctype_digit($y)) || ($y < 1900)) + $ignore_year = true; + else + $ignore_year = false; + + if ($dob !== '0000-00-00') { + if (strpos($dob, '0000-') === 0) { + $ignore_year = true; + $dob = substr($dob, 5); + } + $dob = datetime_convert('UTC', 'UTC', (($ignore_year) ? '1900-' . $dob : $dob), (($ignore_year) ? 'm-d' : 'Y-m-d')); + if ($ignore_year) + $dob = '0000-' . $dob; + } + + $name = escape_tags(trim($_POST['name'])); + + if ($orig[0]['fullname'] != $name) { + $namechanged = true; + + $v = validate_channelname($name); + if ($v) { + notice($v); + $namechanged = false; + $name = $orig[0]['fullname']; + } + } + + $pdesc = escape_tags(trim($_POST['pdesc'])); + $gender = escape_tags(trim($_POST['gender'])); + $address = escape_tags(trim($_POST['address'])); + $locality = escape_tags(trim($_POST['locality'])); + $region = escape_tags(trim($_POST['region'])); + $postal_code = escape_tags(trim($_POST['postal_code'])); + $country_name = escape_tags(trim($_POST['country_name'])); + $keywords = escape_tags(trim($_POST['keywords'])); + $marital = escape_tags(trim($_POST['marital'])); + $howlong = escape_tags(trim($_POST['howlong'])); + $sexual = escape_tags(trim($_POST['sexual'])); + $pronouns = escape_tags(trim($_POST['pronouns'])); + $homepage = escape_tags(trim($_POST['homepage'])); + $hometown = escape_tags(trim($_POST['hometown'])); + $politic = escape_tags(trim($_POST['politic'])); + $religion = escape_tags(trim($_POST['religion'])); + + $likes = escape_tags(trim($_POST['likes'])); + $dislikes = escape_tags(trim($_POST['dislikes'])); + + $about = escape_tags(trim($_POST['about'])); + $interest = escape_tags(trim($_POST['interest'])); + $contact = escape_tags(trim($_POST['contact'])); + $channels = escape_tags(trim($_POST['channels'])); + $music = escape_tags(trim($_POST['music'])); + $book = escape_tags(trim($_POST['book'])); + $tv = escape_tags(trim($_POST['tv'])); + $film = escape_tags(trim($_POST['film'])); + $romance = escape_tags(trim($_POST['romance'])); + $work = escape_tags(trim($_POST['work'])); + $education = escape_tags(trim($_POST['education'])); + + $hide_friends = ((intval($_POST['hide_friends'])) ? 1 : 0); + + // start fresh and create a new vcard. + // @TODO: preserve the original guid or whatever else needs saving + // $orig_vcard = (($orig[0]['profile_vcard']) ? Reader::read($orig[0]['profile_vcard']) : null); + + $orig_vcard = null; + + $channel = App::get_channel(); + + $default_vcard_cat = ((defined('DEFAULT_VCARD_CAT')) ? DEFAULT_VCARD_CAT : 'HOME'); + + $defcard = [ + 'fn' => $name, + 'title' => $pdesc, + 'photo' => $channel['xchan_photo_l'], + 'adr' => [], + 'adr_type' => [$default_vcard_cat], + 'url' => [$homepage], + 'url_type' => [$default_vcard_cat] + ]; + + $defcard['adr'][] = [ + 0 => '', + 1 => '', + 2 => $address, + 3 => $locality, + 4 => $region, + 5 => $postal_code, + 6 => $country_name + ]; + + $profile_vcard = update_vcard($defcard, $orig_vcard); + + $orig_vcard = Reader::read($profile_vcard); + + $profile_vcard = update_vcard($_REQUEST, $orig_vcard); + + + require_once('include/text.php'); + linkify_tags($likes, local_channel()); + linkify_tags($dislikes, local_channel()); + linkify_tags($about, local_channel()); + linkify_tags($interest, local_channel()); + linkify_tags($interest, local_channel()); + linkify_tags($contact, local_channel()); + linkify_tags($channels, local_channel()); + linkify_tags($music, local_channel()); + linkify_tags($book, local_channel()); + linkify_tags($tv, local_channel()); + linkify_tags($film, local_channel()); + linkify_tags($romance, local_channel()); + linkify_tags($work, local_channel()); + linkify_tags($education, local_channel()); + + + $with = ((x($_POST, 'with')) ? escape_tags(trim($_POST['with'])) : ''); + + if (!strlen($howlong)) + $howlong = NULL_DATE; + else + $howlong = datetime_convert(date_default_timezone_get(), 'UTC', $howlong); + + // linkify the relationship target if applicable + + $withchanged = false; + + if (strlen($with)) { + if ($with != strip_tags($orig[0]['partner'])) { + $withchanged = true; + $prf = ''; + $lookup = $with; + if (strpos($lookup, '@') === 0) + $lookup = substr($lookup, 1); + $lookup = str_replace('_', ' ', $lookup); + $newname = $lookup; + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_name = '%s' AND abook_channel = %d LIMIT 1", + dbesc($newname), + intval(local_channel()) + ); + if (!$r) { + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_addr = '%s' AND abook_channel = %d LIMIT 1", + dbesc($lookup . '@%'), + intval(local_channel()) + ); + } + if ($r) { + $prf = $r[0]['xchan_url']; + $newname = $r[0]['xchan_name']; + } + + + if ($prf) { + $with = str_replace($lookup, '' . $newname . '', $with); + if (strpos($with, '@') === 0) + $with = substr($with, 1); + } + } else + $with = $orig[0]['partner']; + } + + $profile_fields_basic = get_profile_fields_basic(); + $profile_fields_advanced = get_profile_fields_advanced(); + $advanced = ((feature_enabled(local_channel(), 'advanced_profiles')) ? true : false); + if ($advanced) + $fields = $profile_fields_advanced; + else + $fields = $profile_fields_basic; + + $z = q("select * from profdef where true"); + if ($z) { + foreach ($z as $zz) { + if (array_key_exists($zz['field_name'], $fields)) { + $w = q("select * from profext where channel_id = %d and hash = '%s' and k = '%s' limit 1", + intval(local_channel()), + dbesc($orig[0]['profile_guid']), + dbesc($zz['field_name']) + ); + if ($w) { + q("update profext set v = '%s' where id = %d", + dbesc(escape_tags(trim($_POST[$zz['field_name']]))), + intval($w[0]['id']) + ); + } else { + q("insert into profext ( channel_id, hash, k, v ) values ( %d, '%s', '%s', '%s') ", + intval(local_channel()), + dbesc($orig[0]['profile_guid']), + dbesc($zz['field_name']), + dbesc(escape_tags(trim($_POST[$zz['field_name']]))) + ); + } + } + } + } + + $changes = []; + $value = ''; + if ($is_default) { + if ($marital != $orig[0]['marital']) { + $changes[] = '[color=#ff0000]♥[/color] ' . t('Marital Status'); + $value = $marital; + } + if ($withchanged) { + $changes[] = '[color=#ff0000]♥[/color] ' . t('Romantic Partner'); + $value = strip_tags($with); + } + if ($likes != $orig[0]['likes']) { + $changes[] = t('Likes'); + $value = $likes; + } + if ($dislikes != $orig[0]['dislikes']) { + $changes[] = t('Dislikes'); + $value = $dislikes; + } + if ($work != $orig[0]['employment']) { + $changes[] = t('Work/Employment'); + } + if ($religion != $orig[0]['religion']) { + $changes[] = t('Religion'); + $value = $religion; + } + if ($politic != $orig[0]['politic']) { + $changes[] = t('Political Views'); + $value = $politic; + } + if ($gender != $orig[0]['gender']) { + $changes[] = t('Gender'); + $value = $gender; + } + if ($sexual != $orig[0]['sexual']) { + $changes[] = t('Sexual Preference'); + $value = $sexual; + } + if ($homepage != $orig[0]['homepage']) { + $changes[] = t('Homepage'); + $value = $homepage; + } + if ($interest != $orig[0]['interest']) { + $changes[] = t('Interests'); + $value = $interest; + } + if ($address != $orig[0]['address']) { + $changes[] = t('Address'); + // New address not sent in notifications, potential privacy issues + // in case this leaks to unintended recipients. Yes, it's in the public + // profile but that doesn't mean we have to broadcast it to everybody. + } + if ($locality != $orig[0]['locality'] || $region != $orig[0]['region'] + || $country_name != $orig[0]['country_name']) { + $changes[] = t('Location'); + $comma1 = ((($locality) && ($region || $country_name)) ? ', ' : ' '); + $comma2 = (($region && $country_name) ? ', ' : ''); + $value = $locality . $comma1 . $region . $comma2 . $country_name; + } + + self::profile_activity($changes, $value); + + } + + $r = q("UPDATE profile SET profile_name = '%s', fullname = '%s', pdesc = '%s', @@ -551,532 +549,534 @@ class Profiles extends Controller { hide_friends = %d, profile_vcard = '%s' WHERE id = %d AND uid = %d", - dbesc($profile_name), - dbesc($name), - dbesc($pdesc), - dbesc($gender), - dbesc($dob), - dbesc($address), - dbesc($locality), - dbesc($region), - dbesc($postal_code), - dbesc($country_name), - dbesc($marital), - dbesc($with), - dbesc($howlong), - dbesc($sexual), - dbesc($pronouns), - dbesc($homepage), - dbesc($hometown), - dbesc($politic), - dbesc($religion), - dbesc($keywords), - dbesc($likes), - dbesc($dislikes), - dbesc($about), - dbesc($interest), - dbesc($contact), - dbesc($channels), - dbesc($music), - dbesc($book), - dbesc($tv), - dbesc($film), - dbesc($romance), - dbesc($work), - dbesc($education), - intval($hide_friends), - dbesc($profile_vcard), - intval(argv(1)), - intval(local_channel()) - ); - - if($r) - info( t('Profile updated.') . EOL); - - $sync = q("select * from profile where id = %d and uid = %d limit 1", - intval(argv(1)), - intval(local_channel()) - ); - if($sync) { - Libsync::build_sync_packet(local_channel(),array('profile' => $sync)); - } + dbesc($profile_name), + dbesc($name), + dbesc($pdesc), + dbesc($gender), + dbesc($dob), + dbesc($address), + dbesc($locality), + dbesc($region), + dbesc($postal_code), + dbesc($country_name), + dbesc($marital), + dbesc($with), + dbesc($howlong), + dbesc($sexual), + dbesc($pronouns), + dbesc($homepage), + dbesc($hometown), + dbesc($politic), + dbesc($religion), + dbesc($keywords), + dbesc($likes), + dbesc($dislikes), + dbesc($about), + dbesc($interest), + dbesc($contact), + dbesc($channels), + dbesc($music), + dbesc($book), + dbesc($tv), + dbesc($film), + dbesc($romance), + dbesc($work), + dbesc($education), + intval($hide_friends), + dbesc($profile_vcard), + intval(argv(1)), + intval(local_channel()) + ); - if (is_sys_channel(local_channel())) { - set_config('system','siteinfo', $about); - } + if ($r) + info(t('Profile updated.') . EOL); - $channel = App::get_channel(); - - if($namechanged && $is_default) { - $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s'", - dbesc($name), - dbesc(datetime_convert()), - dbesc($channel['xchan_hash']) - ); - $r = q("UPDATE channel SET channel_name = '%s' WHERE channel_hash = '%s'", - dbesc($name), - dbesc($channel['xchan_hash']) - ); - if (is_sys_channel(local_channel())) { - set_config('system','sitename',$name); - } - } - - if($is_default) { - Run::Summon( [ 'Directory', local_channel() ] ); - goaway(z_root() . '/profiles/' . $sync[0]['id']); - } - } - } - - - function get() { - - $o = ''; - - $channel = App::get_channel(); - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - require_once('include/channel.php'); - - $profile_fields_basic = get_profile_fields_basic(); - $profile_fields_advanced = get_profile_fields_advanced(); - - if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) { - if(feature_enabled(local_channel(),'multi_profiles')) - $id = argv(1); - else { - $x = q("select id from profile where uid = %d and is_default = 1", - intval(local_channel()) - ); - if($x) - $id = $x[0]['id']; - } - $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", - intval($id), - intval(local_channel()) - ); - if(! $r) { - notice( t('Profile not found.') . EOL); - return; - } - - $editselect = 'none'; - - App::$page['htmlhead'] .= replace_macros(get_markup_template('profed_head.tpl'), array( - '$baseurl' => z_root(), - '$editselect' => $editselect, - )); - - $advanced = ((feature_enabled(local_channel(),'advanced_profiles')) ? true : false); - if($advanced) - $fields = $profile_fields_advanced; - else - $fields = $profile_fields_basic; - - $hide_friends = array( - 'hide_friends', - t('Hide your connections list from viewers of this profile'), - $r[0]['hide_friends'], - '', - array(t('No'),t('Yes')) - ); - - $q = q("select * from profdef where true"); - if($q) { - $extra_fields = []; - - foreach($q as $qq) { - $mine = q("select v from profext where k = '%s' and hash = '%s' and channel_id = %d limit 1", - dbesc($qq['field_name']), - dbesc($r[0]['profile_guid']), - intval(local_channel()) - ); - - if(array_key_exists($qq['field_name'],$fields)) { - $extra_fields[] = array($qq['field_name'],$qq['field_desc'],(($mine) ? $mine[0]['v'] : ''), $qq['field_help']); - } - } - } - - //logger('extra_fields: ' . print_r($extra_fields,true)); + $sync = q("select * from profile where id = %d and uid = %d limit 1", + intval(argv(1)), + intval(local_channel()) + ); + if ($sync) { + Libsync::build_sync_packet(local_channel(), array('profile' => $sync)); + } - $vc = $r[0]['profile_vcard']; - $vctmp = (($vc) ? Reader::read($vc) : null); - $vcard = (($vctmp) ? get_vcard_array($vctmp,$r[0]['id']) : [] ); - - $f = get_config('system','birthday_input_format'); - if(! $f) - $f = 'ymd'; - - $is_default = (($r[0]['is_default']) ? 1 : 0); - - $tpl = get_markup_template("profile_edit.tpl"); - $o .= replace_macros($tpl,array( - '$multi_profiles' => ((feature_enabled(local_channel(),'multi_profiles')) ? true : false), - '$form_security_token' => get_form_security_token("profile_edit"), - '$profile_clone_link' => 'profiles/clone/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_clone"), - '$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_drop"), - '$fields' => $fields, - '$vcard' => $vcard, - '$guid' => $r[0]['profile_guid'], - '$banner' => t('Edit Profile Details'), - '$submit' => t('Submit'), - '$viewprof' => t('View this profile'), - '$editvis' => t('Edit visibility'), - '$tools_label' => t('Profile Tools'), - '$coverpic' => t('Change cover photo'), - '$profpic' => t('Change profile photo'), - '$cr_prof' => t('Create a new profile using these settings'), - '$cl_prof' => t('Clone this profile'), - '$del_prof' => t('Delete this profile'), - '$addthing' => t('Add profile things'), - '$personal' => t('Personal'), - '$location' => t('Location'), - '$relation' => t('Relationship'), - '$miscellaneous'=> t('Miscellaneous'), - '$exportable' => feature_enabled(local_channel(),'profile_export'), - '$lbl_import' => t('Import profile from file'), - '$lbl_export' => t('Export profile to file'), - '$lbl_gender' => t('Your gender'), - '$lbl_marital' => t('Marital status'), - '$lbl_sexual' => t('Sexual preference'), - '$lbl_pronouns' => t('Pronouns'), - '$baseurl' => z_root(), - '$profile_id' => $r[0]['id'], - '$profile_name' => array('profile_name', t('Profile name'), $r[0]['profile_name'], t('Required'), '*'), - '$is_default' => $is_default, - '$default' => '', // t('This is your default profile.') . EOL . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))), - '$advanced' => $advanced, - '$name' => array('name', t('Your full name'), $r[0]['fullname'], t('Required'), '*'), - '$pdesc' => array('pdesc', t('Title/Description'), $r[0]['pdesc']), - '$dob' => dob($r[0]['dob']), - '$hide_friends' => $hide_friends, - '$address' => array('address', t('Street address'), $r[0]['address']), - '$locality' => array('locality', t('Locality/City'), $r[0]['locality']), - '$region' => array('region', t('Region/State'), $r[0]['region']), - '$postal_code' => array('postal_code', t('Postal/Zip code'), $r[0]['postal_code']), - '$country_name' => array('country_name', t('Country'), $r[0]['country_name']), - '$gender' => self::gender_selector($r[0]['gender']), - '$gender_min' => self::gender_selector_min($r[0]['gender']), - '$gender_text' => self::gender_text($r[0]['gender']), - '$marital' => self::marital_selector($r[0]['marital']), - '$marital_min' => self::marital_selector_min($r[0]['marital']), - '$with' => array('with', t("Who (if applicable)"), $r[0]['partner'], t('Examples: cathy123, Cathy Williams, cathy@example.com')), - '$howlong' => array('howlong', t('Since (date)'), ($r[0]['howlong'] <= NULL_DATE ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong']))), - '$sexual' => self::sexpref_selector($r[0]['sexual']), - '$sexual_min' => self::sexpref_selector_min($r[0]['sexual']), - '$pronouns' => self::pronouns_selector($r[0]['pronouns']), - '$pronouns_min' => self::pronouns_selector($r[0]['pronouns']), - '$about' => array('about', t('Tell us about yourself'), $r[0]['about']), - '$homepage' => array('homepage', t('Homepage URL'), $r[0]['homepage']), - '$hometown' => array('hometown', t('Hometown'), $r[0]['hometown']), - '$politic' => array('politic', t('Political views'), $r[0]['politic']), - '$religion' => array('religion', t('Religious views'), $r[0]['religion']), - '$keywords' => array('keywords', t('Keywords used in directory listings'), $r[0]['keywords'], t('Example: fishing photography software')), - '$likes' => array('likes', t('Likes'), $r[0]['likes']), - '$dislikes' => array('dislikes', t('Dislikes'), $r[0]['dislikes']), - '$music' => array('music', t('Musical interests'), $r[0]['music']), - '$book' => array('book', t('Books, literature'), $r[0]['book']), - '$tv' => array('tv', t('Television'), $r[0]['tv']), - '$film' => array('film', t('Film/Dance/Culture/Entertainment'), $r[0]['film']), - '$interest' => array('interest', t('Hobbies/Interests'), $r[0]['interest']), - '$romance' => array('romance',t('Love/Romance'), $r[0]['romance']), - '$employ' => array('work', t('Work/Employment'), $r[0]['employment']), - '$education' => array('education', t('School/Education'), $r[0]['education']), - '$contact' => array('contact', t('Contact information and social networks'), $r[0]['contact']), - '$channels' => array('channels', t('My other channels'), $r[0]['channels']), - '$extra_fields' => $extra_fields, - '$comms' => t('Communications'), - '$tel_label' => t('Phone'), - '$email_label' => t('Email'), - '$impp_label' => t('Instant messenger'), - '$url_label' => t('Website'), - '$adr_label' => t('Address'), - '$note_label' => t('Note'), - '$mobile' => t('Mobile'), - '$home' => t('Home'), - '$work' => t('Work'), - '$other' => t('Other'), - '$add_card' => t('Add Contact'), - '$add_field' => t('Add Field'), - '$create' => t('Create'), - '$update' => t('Update'), - '$delete' => t('Delete'), - '$cancel' => t('Cancel'), - )); - - $arr = array('profile' => $r[0], 'entry' => $o); - call_hooks('profile_edit', $arr); - - return $o; - } - else { - - $r = q("SELECT * FROM profile WHERE uid = %d", - local_channel()); - if($r) { - - $tpl = get_markup_template('profile_entry.tpl'); - foreach($r as $rr) { - $profiles .= replace_macros($tpl, array( - '$photo' => $rr['thumb'], - '$id' => $rr['id'], - '$alt' => t('Profile Image'), - '$profile_name' => $rr['profile_name'], - '$visible' => (($rr['is_default']) - ? '' . translate_scope(map_scope(PermissionLimits::Get($channel['channel_id'],'view_profile'))) . '' - : '' . t('Edit visibility') . '') - )); - } - - $tpl_header = get_markup_template('profile_listing_header.tpl'); - $o .= replace_macros($tpl_header,array( - '$header' => t('Edit Profiles'), - '$cr_new' => t('Create New'), - '$cr_new_link' => 'profiles/new?t=' . get_form_security_token("profile_new"), - '$profiles' => $profiles - )); - - } - return $o; - } - - } + if (is_sys_channel(local_channel())) { + set_config('system', 'siteinfo', $about); + } - static function profile_activity($changed, $value) { + $channel = App::get_channel(); - if(! local_channel() || ! is_array($changed) || ! count($changed)) - return; + if ($namechanged && $is_default) { + $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s'", + dbesc($name), + dbesc(datetime_convert()), + dbesc($channel['xchan_hash']) + ); + $r = q("UPDATE channel SET channel_name = '%s' WHERE channel_hash = '%s'", + dbesc($name), + dbesc($channel['xchan_hash']) + ); + if (is_sys_channel(local_channel())) { + set_config('system', 'sitename', $name); + } + } - if(! get_pconfig(local_channel(),'system','post_profilechange')) - return; - - $self = App::get_channel(); - - if(! $self) - return; - - $arr = []; - $uuid = new_uuid(); - $mid = z_root() . '/item/' . $uuid; - - $arr['uuid'] = $uuid; - $arr['mid'] = $arr['parent_mid'] = $mid; - $arr['uid'] = local_channel(); - $arr['aid'] = $self['channel_account_id']; - $arr['owner_xchan'] = $arr['author_xchan'] = $self['xchan_hash']; - - $arr['item_wall'] = 1; - $arr['item_origin'] = 1; - $arr['item_thread_top'] = 1; - $arr['verb'] = ACTIVITY_UPDATE; - $arr['obj_type'] = ACTIVITY_OBJ_PROFILE; - - $arr['plink'] = z_root() . '/channel/' . $self['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']); - - $A = '[url=' . z_root() . '/channel/' . $self['channel_address'] . ']' . $self['channel_name'] . '[/url]'; + if ($is_default) { + Run::Summon(['Directory', local_channel()]); + goaway(z_root() . '/profiles/' . $sync[0]['id']); + } + } + } - $changes = ''; - $t = count($changed); - $z = 0; - foreach($changed as $ch) { - if(strlen($changes)) { - if ($z == ($t - 1)) - $changes .= t(' and '); - else - $changes .= t(', '); - } - $z ++; - $changes .= $ch; - } + public function get() + { - $prof = '[url=' . z_root() . '/profile/' . $self['channel_address'] . ']' . t('public profile') . '[/url]'; + $o = ''; - if($t == 1 && strlen($value)) { - // if it's a url, the HTML quotes will mess it up, so link it and don't try and zidify it because we don't know what it points to. - $value = preg_replace_callback("/([^\]\='".'"'."]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ismu", 'red_zrl_callback', $value); - // take out the bookmark indicator - if(substr($value,0,2) === '#^') - $value = str_replace('#^','',$value); + $channel = App::get_channel(); - $message = sprintf( t('%1$s changed %2$s to “%3$s”'), $A, $changes, $value); - $message .= "\n\n" . sprintf( t('Visit %1$s\'s %2$s'), $A, $prof); - } - else { - $message = sprintf( t('%1$s has an updated %2$s, changing %3$s.'), $A, $prof, $changes); - } + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } - $arr['body'] = $message; + require_once('include/channel.php'); - $arr['obj'] = [ - 'type' => ACTIVITY_OBJ_PROFILE, - 'summary' => bbcode($message), - 'source' => [ 'mediaType' => 'text/bbcode', 'summary' => $message ], - 'id' => $self['xchan_url'], - 'url' => z_root() . '/profile/' . $self['channel_address'] - ]; + $profile_fields_basic = get_profile_fields_basic(); + $profile_fields_advanced = get_profile_fields_advanced(); - - $arr['allow_cid'] = $self['channel_allow_cid']; - $arr['allow_gid'] = $self['channel_allow_gid']; - $arr['deny_cid'] = $self['channel_deny_cid']; - $arr['deny_gid'] = $self['channel_deny_gid']; + if (((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(), 'multi_profiles')) { + if (feature_enabled(local_channel(), 'multi_profiles')) + $id = argv(1); + else { + $x = q("select id from profile where uid = %d and is_default = 1", + intval(local_channel()) + ); + if ($x) + $id = $x[0]['id']; + } + $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d LIMIT 1", + intval($id), + intval(local_channel()) + ); + if (!$r) { + notice(t('Profile not found.') . EOL); + return; + } - $res = item_store($arr); - $i = $res['item_id']; + $editselect = 'none'; - if($i) { - // FIXME - limit delivery in notifier.php to those specificed in the perms argument - Run::Summon( [ 'Notifier','activity', $i, 'PERMS_R_PROFILE' ] ); - } + App::$page['htmlhead'] .= replace_macros(get_markup_template('profed_head.tpl'), array( + '$baseurl' => z_root(), + '$editselect' => $editselect, + )); - } + $advanced = ((feature_enabled(local_channel(), 'advanced_profiles')) ? true : false); + if ($advanced) + $fields = $profile_fields_advanced; + else + $fields = $profile_fields_basic; -static function gender_selector($current="",$suffix="") { - $o = ''; - $select = array('', t('Male'), t('Female'), t('Currently Male'), t('Currently Female'), t('Mostly Male'), t('Mostly Female'), t('Transgender'), t('Intersex'), t('Transsexual'), t('Hermaphrodite'), t('Neuter'), t('Non-specific'), t('Other'), t('Undecided')); + $hide_friends = array( + 'hide_friends', + t('Hide your connections list from viewers of this profile'), + $r[0]['hide_friends'], + '', + array(t('No'), t('Yes')) + ); - call_hooks('gender_selector', $select); + $q = q("select * from profdef where true"); + if ($q) { + $extra_fields = []; - $o .= "'; - return $o; -} + foreach ($q as $qq) { + $mine = q("select v from profext where k = '%s' and hash = '%s' and channel_id = %d limit 1", + dbesc($qq['field_name']), + dbesc($r[0]['profile_guid']), + intval(local_channel()) + ); -static function gender_selector_min($current="",$suffix="") { - $o = ''; - $select = array('', t('Male'), t('Female'), t('Other')); + if (array_key_exists($qq['field_name'], $fields)) { + $extra_fields[] = array($qq['field_name'], $qq['field_desc'], (($mine) ? $mine[0]['v'] : ''), $qq['field_help']); + } + } + } - call_hooks('gender_selector_min', $select); + //logger('extra_fields: ' . print_r($extra_fields,true)); - $o .= "'; - return $o; -} + $vc = $r[0]['profile_vcard']; + $vctmp = (($vc) ? Reader::read($vc) : null); + $vcard = (($vctmp) ? get_vcard_array($vctmp, $r[0]['id']) : []); -static function pronouns_selector($current="",$suffix="") { - $o = ''; - $select = array('', t('He/Him'), t('She/Her'), t('They/Them')); + $f = get_config('system', 'birthday_input_format'); + if (!$f) + $f = 'ymd'; - call_hooks('pronouns_selector', $select); + $is_default = (($r[0]['is_default']) ? 1 : 0); - $o .= "'; - return $o; -} + $tpl = get_markup_template("profile_edit.tpl"); + $o .= replace_macros($tpl, array( + '$multi_profiles' => ((feature_enabled(local_channel(), 'multi_profiles')) ? true : false), + '$form_security_token' => get_form_security_token("profile_edit"), + '$profile_clone_link' => 'profiles/clone/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_clone"), + '$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' . get_form_security_token("profile_drop"), + '$fields' => $fields, + '$vcard' => $vcard, + '$guid' => $r[0]['profile_guid'], + '$banner' => t('Edit Profile Details'), + '$submit' => t('Submit'), + '$viewprof' => t('View this profile'), + '$editvis' => t('Edit visibility'), + '$tools_label' => t('Profile Tools'), + '$coverpic' => t('Change cover photo'), + '$profpic' => t('Change profile photo'), + '$cr_prof' => t('Create a new profile using these settings'), + '$cl_prof' => t('Clone this profile'), + '$del_prof' => t('Delete this profile'), + '$addthing' => t('Add profile things'), + '$personal' => t('Personal'), + '$location' => t('Location'), + '$relation' => t('Relationship'), + '$miscellaneous' => t('Miscellaneous'), + '$exportable' => feature_enabled(local_channel(), 'profile_export'), + '$lbl_import' => t('Import profile from file'), + '$lbl_export' => t('Export profile to file'), + '$lbl_gender' => t('Your gender'), + '$lbl_marital' => t('Marital status'), + '$lbl_sexual' => t('Sexual preference'), + '$lbl_pronouns' => t('Pronouns'), + '$baseurl' => z_root(), + '$profile_id' => $r[0]['id'], + '$profile_name' => array('profile_name', t('Profile name'), $r[0]['profile_name'], t('Required'), '*'), + '$is_default' => $is_default, + '$default' => '', // t('This is your default profile.') . EOL . translate_scope(map_scope(\Zotlabs\Access\PermissionLimits::Get($channel['channel_id'],'view_profile'))), + '$advanced' => $advanced, + '$name' => array('name', t('Your full name'), $r[0]['fullname'], t('Required'), '*'), + '$pdesc' => array('pdesc', t('Title/Description'), $r[0]['pdesc']), + '$dob' => dob($r[0]['dob']), + '$hide_friends' => $hide_friends, + '$address' => array('address', t('Street address'), $r[0]['address']), + '$locality' => array('locality', t('Locality/City'), $r[0]['locality']), + '$region' => array('region', t('Region/State'), $r[0]['region']), + '$postal_code' => array('postal_code', t('Postal/Zip code'), $r[0]['postal_code']), + '$country_name' => array('country_name', t('Country'), $r[0]['country_name']), + '$gender' => self::gender_selector($r[0]['gender']), + '$gender_min' => self::gender_selector_min($r[0]['gender']), + '$gender_text' => self::gender_text($r[0]['gender']), + '$marital' => self::marital_selector($r[0]['marital']), + '$marital_min' => self::marital_selector_min($r[0]['marital']), + '$with' => array('with', t("Who (if applicable)"), $r[0]['partner'], t('Examples: cathy123, Cathy Williams, cathy@example.com')), + '$howlong' => array('howlong', t('Since (date)'), ($r[0]['howlong'] <= NULL_DATE ? '' : datetime_convert('UTC', date_default_timezone_get(), $r[0]['howlong']))), + '$sexual' => self::sexpref_selector($r[0]['sexual']), + '$sexual_min' => self::sexpref_selector_min($r[0]['sexual']), + '$pronouns' => self::pronouns_selector($r[0]['pronouns']), + '$pronouns_min' => self::pronouns_selector($r[0]['pronouns']), + '$about' => array('about', t('Tell us about yourself'), $r[0]['about']), + '$homepage' => array('homepage', t('Homepage URL'), $r[0]['homepage']), + '$hometown' => array('hometown', t('Hometown'), $r[0]['hometown']), + '$politic' => array('politic', t('Political views'), $r[0]['politic']), + '$religion' => array('religion', t('Religious views'), $r[0]['religion']), + '$keywords' => array('keywords', t('Keywords used in directory listings'), $r[0]['keywords'], t('Example: fishing photography software')), + '$likes' => array('likes', t('Likes'), $r[0]['likes']), + '$dislikes' => array('dislikes', t('Dislikes'), $r[0]['dislikes']), + '$music' => array('music', t('Musical interests'), $r[0]['music']), + '$book' => array('book', t('Books, literature'), $r[0]['book']), + '$tv' => array('tv', t('Television'), $r[0]['tv']), + '$film' => array('film', t('Film/Dance/Culture/Entertainment'), $r[0]['film']), + '$interest' => array('interest', t('Hobbies/Interests'), $r[0]['interest']), + '$romance' => array('romance', t('Love/Romance'), $r[0]['romance']), + '$employ' => array('work', t('Work/Employment'), $r[0]['employment']), + '$education' => array('education', t('School/Education'), $r[0]['education']), + '$contact' => array('contact', t('Contact information and social networks'), $r[0]['contact']), + '$channels' => array('channels', t('My other channels'), $r[0]['channels']), + '$extra_fields' => $extra_fields, + '$comms' => t('Communications'), + '$tel_label' => t('Phone'), + '$email_label' => t('Email'), + '$impp_label' => t('Instant messenger'), + '$url_label' => t('Website'), + '$adr_label' => t('Address'), + '$note_label' => t('Note'), + '$mobile' => t('Mobile'), + '$home' => t('Home'), + '$work' => t('Work'), + '$other' => t('Other'), + '$add_card' => t('Add Contact'), + '$add_field' => t('Add Field'), + '$create' => t('Create'), + '$update' => t('Update'), + '$delete' => t('Delete'), + '$cancel' => t('Cancel'), + )); + + $arr = array('profile' => $r[0], 'entry' => $o); + call_hooks('profile_edit', $arr); + + return $o; + } else { + + $r = q("SELECT * FROM profile WHERE uid = %d", + local_channel()); + if ($r) { + + $tpl = get_markup_template('profile_entry.tpl'); + foreach ($r as $rr) { + $profiles .= replace_macros($tpl, array( + '$photo' => $rr['thumb'], + '$id' => $rr['id'], + '$alt' => t('Profile Image'), + '$profile_name' => $rr['profile_name'], + '$visible' => (($rr['is_default']) + ? '' . translate_scope(map_scope(PermissionLimits::Get($channel['channel_id'], 'view_profile'))) . '' + : '' . t('Edit visibility') . '') + )); + } + + $tpl_header = get_markup_template('profile_listing_header.tpl'); + $o .= replace_macros($tpl_header, array( + '$header' => t('Edit Profiles'), + '$cr_new' => t('Create New'), + '$cr_new_link' => 'profiles/new?t=' . get_form_security_token("profile_new"), + '$profiles' => $profiles + )); + + } + return $o; + } + + } + + public static function profile_activity($changed, $value) + { + + if (!local_channel() || !is_array($changed) || !count($changed)) + return; + + if (!get_pconfig(local_channel(), 'system', 'post_profilechange')) + return; + + $self = App::get_channel(); + + if (!$self) + return; + + $arr = []; + $uuid = new_uuid(); + $mid = z_root() . '/item/' . $uuid; + + $arr['uuid'] = $uuid; + $arr['mid'] = $arr['parent_mid'] = $mid; + $arr['uid'] = local_channel(); + $arr['aid'] = $self['channel_account_id']; + $arr['owner_xchan'] = $arr['author_xchan'] = $self['xchan_hash']; + + $arr['item_wall'] = 1; + $arr['item_origin'] = 1; + $arr['item_thread_top'] = 1; + $arr['verb'] = ACTIVITY_UPDATE; + $arr['obj_type'] = ACTIVITY_OBJ_PROFILE; + + $arr['plink'] = z_root() . '/channel/' . $self['channel_address'] . '/?f=&mid=' . urlencode($arr['mid']); + + $A = '[url=' . z_root() . '/channel/' . $self['channel_address'] . ']' . $self['channel_name'] . '[/url]'; -static function gender_text($current="",$suffix="") { - $o = ''; + $changes = ''; + $t = count($changed); + $z = 0; + foreach ($changed as $ch) { + if (strlen($changes)) { + if ($z == ($t - 1)) + $changes .= t(' and '); + else + $changes .= t(', '); + } + $z++; + $changes .= $ch; + } - if(! get_config('system','profile_gender_textfield')) - return $o; + $prof = '[url=' . z_root() . '/profile/' . $self['channel_address'] . ']' . t('public profile') . '[/url]'; - $o .= ""; - return $o; -} + if ($t == 1 && strlen($value)) { + // if it's a url, the HTML quotes will mess it up, so link it and don't try and zidify it because we don't know what it points to. + $value = preg_replace_callback("/([^\]\='" . '"' . "]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\pL\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ismu", 'red_zrl_callback', $value); + // take out the bookmark indicator + if (substr($value, 0, 2) === '#^') + $value = str_replace('#^', '', $value); + + $message = sprintf(t('%1$s changed %2$s to “%3$s”'), $A, $changes, $value); + $message .= "\n\n" . sprintf(t('Visit %1$s\'s %2$s'), $A, $prof); + } else { + $message = sprintf(t('%1$s has an updated %2$s, changing %3$s.'), $A, $prof, $changes); + } + + $arr['body'] = $message; + + $arr['obj'] = [ + 'type' => ACTIVITY_OBJ_PROFILE, + 'summary' => bbcode($message), + 'source' => ['mediaType' => 'text/bbcode', 'summary' => $message], + 'id' => $self['xchan_url'], + 'url' => z_root() . '/profile/' . $self['channel_address'] + ]; + $arr['allow_cid'] = $self['channel_allow_cid']; + $arr['allow_gid'] = $self['channel_allow_gid']; + $arr['deny_cid'] = $self['channel_deny_cid']; + $arr['deny_gid'] = $self['channel_deny_gid']; + + $res = item_store($arr); + $i = $res['item_id']; + + if ($i) { + // FIXME - limit delivery in notifier.php to those specificed in the perms argument + Run::Summon(['Notifier', 'activity', $i, 'PERMS_R_PROFILE']); + } + + } + + public static function gender_selector($current = "", $suffix = "") + { + $o = ''; + $select = array('', t('Male'), t('Female'), t('Currently Male'), t('Currently Female'), t('Mostly Male'), t('Mostly Female'), t('Transgender'), t('Intersex'), t('Transsexual'), t('Hermaphrodite'), t('Neuter'), t('Non-specific'), t('Other'), t('Undecided')); + + call_hooks('gender_selector', $select); + + $o .= "'; + return $o; + } + + public static function gender_selector_min($current = "", $suffix = "") + { + $o = ''; + $select = array('', t('Male'), t('Female'), t('Other')); + + call_hooks('gender_selector_min', $select); + + $o .= "'; + return $o; + } + + public static function pronouns_selector($current = "", $suffix = "") + { + $o = ''; + $select = array('', t('He/Him'), t('She/Her'), t('They/Them')); + + call_hooks('pronouns_selector', $select); + + $o .= "'; + return $o; + } + public static function gender_text($current = "", $suffix = "") + { + $o = ''; -static function sexpref_selector($current="",$suffix="") { - $o = ''; - $select = array('', t('Males'), t('Females'), t('Gay'), t('Lesbian'), t('No Preference'), t('Bisexual'), t('Autosexual'), t('Abstinent'), t('Virgin'), t('Deviant'), t('Fetish'), t('Oodles'), t('Nonsexual')); + if (!get_config('system', 'profile_gender_textfield')) + return $o; + + $o .= ""; + return $o; + } - call_hooks('sexpref_selector', $select); - - $o .= "'; - return $o; -} + public static function sexpref_selector($current = "", $suffix = "") + { + $o = ''; + $select = array('', t('Males'), t('Females'), t('Gay'), t('Lesbian'), t('No Preference'), t('Bisexual'), t('Autosexual'), t('Abstinent'), t('Virgin'), t('Deviant'), t('Fetish'), t('Oodles'), t('Nonsexual')); -static function sexpref_selector_min($current="",$suffix="") { - $o = ''; - $select = array('', t('Males'), t('Females'), t('Other')); + call_hooks('sexpref_selector', $select); - call_hooks('sexpref_selector_min', $select); - - $o .= "'; - return $o; -} + $o .= "'; + return $o; + } + public static function sexpref_selector_min($current = "", $suffix = "") + { + $o = ''; + $select = array('', t('Males'), t('Females'), t('Other')); -static function marital_selector($current="",$suffix="") { - $o = ''; - $select = array('', t('Single'), t('Lonely'), t('Available'), t('Unavailable'), t('Has crush'), t('Infatuated'), t('Dating'), t('Unfaithful'), t('Sex Addict'), t('Friends'), t('Friends/Benefits'), t('Casual'), t('Engaged'), t('Married'), t('Imaginarily married'), t('Partners'), t('Cohabiting'), t('Common law'), t('Happy'), t('Not looking'), t('Swinger'), t('Betrayed'), t('Separated'), t('Unstable'), t('Divorced'), t('Imaginarily divorced'), t('Widowed'), t('Uncertain'), t('It\'s complicated'), t('Don\'t care'), t('Ask me') ); + call_hooks('sexpref_selector_min', $select); - call_hooks('marital_selector', $select); - - $o .= "'; - return $o; -} - -static function marital_selector_min($current="",$suffix="") { - $o = ''; - $select = array('', t('Single'), t('Dating'), t('Cohabiting'), t('Married'), t('Separated'), t('Divorced'), t('Widowed'), t('It\'s complicated'), t('Other')); - - call_hooks('marital_selector_min', $select); - - $o .= "'; - return $o; -} + $o .= "'; + return $o; + } + public static function marital_selector($current = "", $suffix = "") + { + $o = ''; + $select = array('', t('Single'), t('Lonely'), t('Available'), t('Unavailable'), t('Has crush'), t('Infatuated'), t('Dating'), t('Unfaithful'), t('Sex Addict'), t('Friends'), t('Friends/Benefits'), t('Casual'), t('Engaged'), t('Married'), t('Imaginarily married'), t('Partners'), t('Cohabiting'), t('Common law'), t('Happy'), t('Not looking'), t('Swinger'), t('Betrayed'), t('Separated'), t('Unstable'), t('Divorced'), t('Imaginarily divorced'), t('Widowed'), t('Uncertain'), t('It\'s complicated'), t('Don\'t care'), t('Ask me')); + + call_hooks('marital_selector', $select); + + $o .= "'; + return $o; + } + + public static function marital_selector_min($current = "", $suffix = "") + { + $o = ''; + $select = array('', t('Single'), t('Dating'), t('Cohabiting'), t('Married'), t('Separated'), t('Divorced'), t('Widowed'), t('It\'s complicated'), t('Other')); + + call_hooks('marital_selector_min', $select); + + $o .= "'; + return $o; + } + - } diff --git a/Zotlabs/Module/Profperm.php b/Zotlabs/Module/Profperm.php index d211397fd..0d539655e 100644 --- a/Zotlabs/Module/Profperm.php +++ b/Zotlabs/Module/Profperm.php @@ -9,164 +9,166 @@ use Zotlabs\Lib\Libprofile; require_once('include/photos.php'); -class Profperm extends Controller { +class Profperm extends Controller +{ - function init() { - - if(! local_channel()) - return; - - $channel = App::get_channel(); - $which = $channel['channel_address']; - - $profile = App::$argv[1]; - - Libprofile::load($which,$profile); - - } - - - function get() { - - if(! local_channel()) { - notice( t('Permission denied') . EOL); - return; - } - - - if(argc() < 2) { - notice( t('Invalid profile identifier.') . EOL ); - return; - } - - // Switch to text mod interface if we have more than 'n' contacts or group members - - $switchtotext = get_pconfig(local_channel(),'system','groupedit_image_limit'); - if($switchtotext === false) - $switchtotext = get_config('system','groupedit_image_limit'); - if($switchtotext === false) - $switchtotext = 400; - - - if((argc() > 2) && intval(argv(1)) && intval(argv(2))) { - $r = q("SELECT abook_id FROM abook WHERE abook_id = %d and abook_channel = %d limit 1", - intval(argv(2)), - intval(local_channel()) - ); - if($r) - $change = intval(argv(2)); - } - - - if((argc() > 1) && (intval(argv(1)))) { - $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d AND is_default = 0 LIMIT 1", - intval(argv(1)), - intval(local_channel()) - ); - if(! $r) { - notice( t('Invalid profile identifier.') . EOL ); - return; - } - - $profile = $r[0]; - - $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", - intval(local_channel()), - dbesc($profile['profile_guid']) - ); - - $ingroup = []; - if($r) - foreach($r as $member) - $ingroup[] = $member['abook_id']; - - $members = $r; - - if($change) { - if(in_array($change,$ingroup)) { - q("UPDATE abook SET abook_profile = '' WHERE abook_id = %d AND abook_channel = %d", - intval($change), - intval(local_channel()) - ); - } - else { - q("UPDATE abook SET abook_profile = '%s' WHERE abook_id = %d AND abook_channel = %d", - dbesc($profile['profile_guid']), - intval($change), - intval(local_channel()) - ); - - } - - $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash + public function init() + { + + if (!local_channel()) + return; + + $channel = App::get_channel(); + $which = $channel['channel_address']; + + $profile = App::$argv[1]; + + Libprofile::load($which, $profile); + + } + + + public function get() + { + + if (!local_channel()) { + notice(t('Permission denied') . EOL); + return; + } + + + if (argc() < 2) { + notice(t('Invalid profile identifier.') . EOL); + return; + } + + // Switch to text mod interface if we have more than 'n' contacts or group members + + $switchtotext = get_pconfig(local_channel(), 'system', 'groupedit_image_limit'); + if ($switchtotext === false) + $switchtotext = get_config('system', 'groupedit_image_limit'); + if ($switchtotext === false) + $switchtotext = 400; + + + if ((argc() > 2) && intval(argv(1)) && intval(argv(2))) { + $r = q("SELECT abook_id FROM abook WHERE abook_id = %d and abook_channel = %d limit 1", + intval(argv(2)), + intval(local_channel()) + ); + if ($r) + $change = intval(argv(2)); + } + + + if ((argc() > 1) && (intval(argv(1)))) { + $r = q("SELECT * FROM profile WHERE id = %d AND uid = %d AND is_default = 0 LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + if (!$r) { + notice(t('Invalid profile identifier.') . EOL); + return; + } + + $profile = $r[0]; + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", + intval(local_channel()), + dbesc($profile['profile_guid']) + ); + + $ingroup = []; + if ($r) + foreach ($r as $member) + $ingroup[] = $member['abook_id']; + + $members = $r; + + if ($change) { + if (in_array($change, $ingroup)) { + q("UPDATE abook SET abook_profile = '' WHERE abook_id = %d AND abook_channel = %d", + intval($change), + intval(local_channel()) + ); + } else { + q("UPDATE abook SET abook_profile = '%s' WHERE abook_id = %d AND abook_channel = %d", + dbesc($profile['profile_guid']), + intval($change), + intval(local_channel()) + ); + + } + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", - intval(local_channel()), - dbesc($profile['profile_guid']) - ); - - $members = $r; - - $ingroup = []; - if(count($r)) - foreach($r as $member) - $ingroup[] = $member['abook_id']; - } - - $o .= '

      ' . t('Profile Visibility Editor') . '

      '; - - $o .= '

      ' . t('Profile') . ' \'' . $profile['profile_name'] . '\'

      '; - - $o .= '
      ' . t('Click on a contact to add or remove.') . '
      '; - - } - - $o .= '
      '; - if($change) - $o = ''; - - $o .= '
      '; - $o .= '

      ' . t('Visible To') . '

      '; - $o .= '
      '; - $o .= '
      '; - - $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); - - foreach($members as $member) { - if($member['xchan_url']) { - $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; - $o .= micropro($member,true,'mpprof', $textmode); - } - } - $o .= '
      '; - $o .= '
      '; - - $o .= '
      '; - $o .= '

      ' . t("All Connections") . '

      '; - $o .= '
      '; - $o .= '
      '; - - $r = abook_connections(local_channel()); - - if($r) { - $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); - foreach($r as $member) { - if(! in_array($member['abook_id'],$ingroup)) { - $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; - $o .= micropro($member,true,'mpprof',$textmode); - } - } - } - - $o .= '
      '; - - if($change) { - echo $o; - killme(); - } - $o .= '
      '; - return $o; - - } - - + intval(local_channel()), + dbesc($profile['profile_guid']) + ); + + $members = $r; + + $ingroup = []; + if (count($r)) + foreach ($r as $member) + $ingroup[] = $member['abook_id']; + } + + $o .= '

      ' . t('Profile Visibility Editor') . '

      '; + + $o .= '

      ' . t('Profile') . ' \'' . $profile['profile_name'] . '\'

      '; + + $o .= '
      ' . t('Click on a contact to add or remove.') . '
      '; + + } + + $o .= '
      '; + if ($change) + $o = ''; + + $o .= '
      '; + $o .= '

      ' . t('Visible To') . '

      '; + $o .= '
      '; + $o .= '
      '; + + $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); + + foreach ($members as $member) { + if ($member['xchan_url']) { + $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; + $o .= micropro($member, true, 'mpprof', $textmode); + } + } + $o .= '
      '; + $o .= '
      '; + + $o .= '
      '; + $o .= '

      ' . t("All Connections") . '

      '; + $o .= '
      '; + $o .= '
      '; + + $r = abook_connections(local_channel()); + + if ($r) { + $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); + foreach ($r as $member) { + if (!in_array($member['abook_id'], $ingroup)) { + $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; + $o .= micropro($member, true, 'mpprof', $textmode); + } + } + } + + $o .= '
      '; + + if ($change) { + echo $o; + killme(); + } + $o .= '
      '; + return $o; + + } + + } diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php index 6796db081..98f96504c 100644 --- a/Zotlabs/Module/Pubstream.php +++ b/Zotlabs/Module/Pubstream.php @@ -10,298 +10,293 @@ require_once('include/conversation.php'); require_once('include/acl_selectors.php'); -class Pubstream extends Controller { +class Pubstream extends Controller +{ - // State passed in from the Update module. - - public $profile_uid = 0; - public $loading = 0; - public $updating = 0; + // State passed in from the Update module. + + public $profile_uid = 0; + public $loading = 0; + public $updating = 0; + public function get() + { - function get() { + $o = EMPTY_STR; + $items = []; - $o = EMPTY_STR; - $items = []; - - if((observer_prohibited(true))) { - return login(); - } + if ((observer_prohibited(true))) { + return login(); + } - if(! intval(get_config('system','open_pubstream',0))) { - if(! local_channel()) { - return login(); - } - } + if (!intval(get_config('system', 'open_pubstream', 0))) { + if (!local_channel()) { + return login(); + } + } - $public_stream_mode = intval(get_config('system','public_stream_mode', PUBLIC_STREAM_NONE)); + $public_stream_mode = intval(get_config('system', 'public_stream_mode', PUBLIC_STREAM_NONE)); - if (! $public_stream_mode) { - return ''; - } - - $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : ''); - $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : ''); - $decoded = false; - - $mid = unpack_link_id($mid); + if (!$public_stream_mode) { + return ''; + } - $item_normal = item_normal(); - $item_normal_update = item_normal_update(); + $mid = ((x($_REQUEST, 'mid')) ? $_REQUEST['mid'] : ''); + $hashtags = ((x($_REQUEST, 'tag')) ? $_REQUEST['tag'] : ''); + $decoded = false; - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - $net = ((array_key_exists('net',$_REQUEST)) ? escape_tags($_REQUEST['net']) : ''); + $mid = unpack_link_id($mid); + + $item_normal = item_normal(); + $item_normal_update = item_normal_update(); + + $static = ((array_key_exists('static', $_REQUEST)) ? intval($_REQUEST['static']) : 0); + $net = ((array_key_exists('net', $_REQUEST)) ? escape_tags($_REQUEST['net']) : ''); - if(local_channel() && (! $this->updating)) { - - $channel = App::get_channel(); + if (local_channel() && (!$this->updating)) { - $channel_acl = array( - 'allow_cid' => $channel['channel_allow_cid'], - 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ); + $channel = App::get_channel(); - $x = array( - 'is_owner' => true, - 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), - 'default_location' => $channel['channel_location'], - 'nickname' => $channel['channel_address'], - 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => populate_acl($channel_acl,true,PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), - 'permissions' => $channel_acl, - 'bang' => '', - 'visitor' => true, - 'profile_uid' => local_channel(), - 'return_path' => 'channel/' . $channel['channel_address'], - 'expanded' => true, - 'editor_autocomplete' => true, - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true, - 'jotnets' => true, - 'reset' => t('Reset form') - ); - - $o = '
      '; - $o .= status_editor($x); - $o .= '
      '; - } - - if(! $this->updating && !$this->loading) { + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); - nav_set_selected(t('Public Stream')); + $x = array( + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), + 'permissions' => $channel_acl, + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_channel(), + 'return_path' => 'channel/' . $channel['channel_address'], + 'expanded' => true, + 'editor_autocomplete' => true, + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true, + 'jotnets' => true, + 'reset' => t('Reset form') + ); - if (! $mid) { - $_SESSION['loadtime_pubstream'] = datetime_convert(); - if (local_channel()) { - PConfig::Set(local_channel(),'system','loadtime_pubstream',$_SESSION['loadtime_pubstream']); - } - } - - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); - - $maxheight = get_config('system','home_divmore_height'); - if(! $maxheight) - $maxheight = 400; - - $o .= '
      ' . "\r\n"; - $o .= "\r\n"; - - // if we got a decoded hash we must encode it again before handing to javascript - $mid = gen_link_id($mid); + $o = '
      '; + $o .= status_editor($x); + $o .= '
      '; + } - App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( - '$baseurl' => z_root(), - '$pgtype' => 'pubstream', - '$uid' => ((local_channel()) ? local_channel() : '0'), - '$gid' => '0', - '$cid' => '0', - '$cmin' => '(-1)', - '$cmax' => '(-1)', - '$star' => '0', - '$liked' => '0', - '$conv' => '0', - '$spam' => '0', - '$fh' => '1', - '$dm' => '0', - '$nouveau' => '0', - '$wall' => '0', - '$draft' => '0', - '$list' => '0', - '$static' => $static, - '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), - '$search' => '', - '$xchan' => '', - '$order' => 'comment', - '$file' => '', - '$cats' => '', - '$tags' => (($hashtags) ? urlencode($hashtags) : ''), - '$dend' => '', - '$mid' => (($mid) ? urlencode($mid) : ''), - '$verb' => '', - '$net' => (($net) ? urlencode($net) : ''), - '$dbegin' => '' - )); - } - - if($this->updating && ! $this->loading) { - // only setup pagination on initial page view - $pager_sql = ''; - } - else { - $itemspage = ((local_channel()) ? get_pconfig(local_channel(),'system','itemspage', 20) : 20); - App::set_pager_itemspage($itemspage); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - } - - require_once('include/channel.php'); - require_once('include/security.php'); - - if ($public_stream_mode === PUBLIC_STREAM_SITE) { - $uids = " and item_private = 0 and item_wall = 1 "; - } - else { - $sys = get_sys_channel(); - $uids = " and item_private = 0 and item_wall = 0 and item.uid = " . intval($sys['channel_id']) . " "; - $sql_extra = item_permissions_sql($sys['channel_id']); - App::$data['firehose'] = intval($sys['channel_id']); - } - - if(get_config('system','public_list_mode')) - $page_mode = 'list'; - else - $page_mode = 'client'; + if (!$this->updating && !$this->loading) { + + nav_set_selected(t('Public Stream')); + + if (!$mid) { + $_SESSION['loadtime_pubstream'] = datetime_convert(); + if (local_channel()) { + PConfig::Set(local_channel(), 'system', 'loadtime_pubstream', $_SESSION['loadtime_pubstream']); + } + } + + $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1); + + $maxheight = get_config('system', 'home_divmore_height'); + if (!$maxheight) + $maxheight = 400; + + $o .= '
      ' . "\r\n"; + $o .= "\r\n"; + + // if we got a decoded hash we must encode it again before handing to javascript + $mid = gen_link_id($mid); + + App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), array( + '$baseurl' => z_root(), + '$pgtype' => 'pubstream', + '$uid' => ((local_channel()) ? local_channel() : '0'), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '(-1)', + '$cmax' => '(-1)', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '1', + '$dm' => '0', + '$nouveau' => '0', + '$wall' => '0', + '$draft' => '0', + '$list' => '0', + '$static' => $static, + '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), + '$search' => '', + '$xchan' => '', + '$order' => 'comment', + '$file' => '', + '$cats' => '', + '$tags' => (($hashtags) ? urlencode($hashtags) : ''), + '$dend' => '', + '$mid' => (($mid) ? urlencode($mid) : ''), + '$verb' => '', + '$net' => (($net) ? urlencode($net) : ''), + '$dbegin' => '' + )); + } + + if ($this->updating && !$this->loading) { + // only setup pagination on initial page view + $pager_sql = ''; + } else { + $itemspage = ((local_channel()) ? get_pconfig(local_channel(), 'system', 'itemspage', 20) : 20); + App::set_pager_itemspage($itemspage); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + } + + require_once('include/channel.php'); + require_once('include/security.php'); + + if ($public_stream_mode === PUBLIC_STREAM_SITE) { + $uids = " and item_private = 0 and item_wall = 1 "; + } else { + $sys = get_sys_channel(); + $uids = " and item_private = 0 and item_wall = 0 and item.uid = " . intval($sys['channel_id']) . " "; + $sql_extra = item_permissions_sql($sys['channel_id']); + App::$data['firehose'] = intval($sys['channel_id']); + } + + if (get_config('system', 'public_list_mode')) + $page_mode = 'list'; + else + $page_mode = 'client'; - if(x($hashtags)) { - $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); - } + if (x($hashtags)) { + $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); + } - $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : ''); - $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : ''); + $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : ''); + $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : ''); - if (isset(App::$profile) && isset(App::$profile['profile_uid'])) { - $abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " "; - } - - $simple_update = ((isset($_SESSION['loadtime_pubstream']) && $_SESSION['loadtime_pubstream']) ? " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime_pubstream']) . "' " : ''); - - if ($this->loading) { - $simple_update = ''; - } + if (isset(App::$profile) && isset(App::$profile['profile_uid'])) { + $abook_uids = " and abook.abook_channel = " . intval(App::$profile['profile_uid']) . " "; + } - if($static && $simple_update) - $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + $simple_update = ((isset($_SESSION['loadtime_pubstream']) && $_SESSION['loadtime_pubstream']) ? " AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime_pubstream']) . "' " : ''); - //logger('update: ' . $this->updating . ' load: ' . $this->loading); + if ($this->loading) { + $simple_update = ''; + } - if($this->updating) { - - $ordering = "commented"; - - if($this->loading) { - if($mid) { - $r = q("SELECT parent AS item_id FROM item + if ($static && $simple_update) + $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + + //logger('update: ' . $this->updating . ' load: ' . $this->loading); + + if ($this->updating) { + + $ordering = "commented"; + + if ($this->loading) { + if ($mid) { + $r = q("SELECT parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan $net_query WHERE mid like '%s' $uids $item_normal and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2 LIMIT 1", - dbesc($mid . '%') - ); - } - else { - // Fetch a page full of parent items for this page - $r = q("SELECT item.id AS item_id FROM item + dbesc($mid . '%') + ); + } else { + // Fetch a page full of parent items for this page + $r = q("SELECT item.id AS item_id FROM item left join abook on ( item.author_xchan = abook.abook_xchan $abook_uids ) $net_query WHERE true $uids and item.item_thread_top = 1 $item_normal and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2 ORDER BY $ordering DESC $pager_sql " - ); - } - } - elseif($this->updating) { - if($mid) { - $r = q("SELECT parent AS item_id FROM item + ); + } + } elseif ($this->updating) { + if ($mid) { + $r = q("SELECT parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan $net_query WHERE mid like '%s' $uids $item_normal_update $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2 LIMIT 1", - dbesc($mid . '%') - ); + dbesc($mid . '%') + ); - } - else { - $r = q("SELECT parent AS item_id FROM item + } else { + $r = q("SELECT parent AS item_id FROM item left join abook on item.author_xchan = abook.abook_xchan $net_query WHERE true $uids $item_normal_update $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra $net_query2" - ); - } - } + ); + } + } - // Then fetch all the children of the parents that are on this page - $parents_str = ''; - $update_unseen = ''; - - if($r) { - - $parents_str = ids_to_querystr($r,'item_id'); - - $items = q("SELECT item.*, item.id AS item_id FROM item + // Then fetch all the children of the parents that are on this page + $parents_str = ''; + $update_unseen = ''; + + if ($r) { + + $parents_str = ids_to_querystr($r, 'item_id'); + + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE true $uids $item_normal AND item.parent IN ( %s ) $sql_extra ", - dbesc($parents_str) - ); - - // use effective_uid param of xchan_query to help sort out comment permission - // for sys_channel owned items. + dbesc($parents_str) + ); - xchan_query($items,true,(($sys) ? local_channel() : 0)); - $items = fetch_post_tags($items,true); - $items = conv_sort($items,$ordering); - } - else { - $items = []; - } - - } + // use effective_uid param of xchan_query to help sort out comment permission + // for sys_channel owned items. - if ($mid && local_channel()) { - $ids = ids_to_array($items,'item_id'); - $seen = PConfig::Get(local_channel(),'system','seen_items',[]); - if (! $seen) { - $seen = []; - } - $seen = array_merge($ids,$seen); - PConfig::Set(local_channel(),'system','seen_items',$seen); - } + xchan_query($items, true, (($sys) ? local_channel() : 0)); + $items = fetch_post_tags($items, true); + $items = conv_sort($items, $ordering); + } else { + $items = []; + } - // fake it - $mode = ('pubstream'); - - $o .= conversation($items,$mode,$this->updating,$page_mode); + } - if($mid) - $o .= '
      '; - - if(($items) && (! $this->updating)) - $o .= alt_pager(count($items)); + if ($mid && local_channel()) { + $ids = ids_to_array($items, 'item_id'); + $seen = PConfig::Get(local_channel(), 'system', 'seen_items', []); + if (!$seen) { + $seen = []; + } + $seen = array_merge($ids, $seen); + PConfig::Set(local_channel(), 'system', 'seen_items', $seen); + } - return $o; - - } + // fake it + $mode = ('pubstream'); + + $o .= conversation($items, $mode, $this->updating, $page_mode); + + if ($mid) + $o .= '
      '; + + if (($items) && (!$this->updating)) + $o .= alt_pager(count($items)); + + return $o; + + } } diff --git a/Zotlabs/Module/Q.php b/Zotlabs/Module/Q.php index f58f9afc5..a45f8d2dc 100644 --- a/Zotlabs/Module/Q.php +++ b/Zotlabs/Module/Q.php @@ -7,26 +7,27 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; +class Q extends Controller +{ -class Q extends Controller { + public function init() + { - function init() { + $ret = ['success' => false]; - $ret = [ 'success' => false ]; + $h = argv(1); + if (!$h) { + json_return_and_die($ret); + } - $h = argv(1); - if(! $h) { - json_return_and_die($ret); - } - - $r = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0", - dbesc($h) - ); - if($r) { - $ret['success'] = true; - $ret['results'] = ids_to_array($r,'hubloc_id_url'); - } - json_return_and_die($ret); - } + $r = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_hash = '%s' and site_dead = 0", + dbesc($h) + ); + if ($r) { + $ret['success'] = true; + $ret['results'] = ids_to_array($r, 'hubloc_id_url'); + } + json_return_and_die($ret); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Randprof.php b/Zotlabs/Module/Randprof.php index 579fac256..2a6c838ee 100644 --- a/Zotlabs/Module/Randprof.php +++ b/Zotlabs/Module/Randprof.php @@ -5,15 +5,17 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Randprof extends Controller { +class Randprof extends Controller +{ + + public function init() + { + $x = random_profile(); + if ($x) + goaway(chanlink_hash($x)); + + /** FIXME this doesn't work at the moment as a fallback */ + goaway(z_root() . '/profile'); + } - function init() { - $x = random_profile(); - if($x) - goaway(chanlink_hash($x)); - - /** FIXME this doesn't work at the moment as a fallback */ - goaway(z_root() . '/profile'); - } - } diff --git a/Zotlabs/Module/React.php b/Zotlabs/Module/React.php index 732aafd19..6f69675d9 100644 --- a/Zotlabs/Module/React.php +++ b/Zotlabs/Module/React.php @@ -7,92 +7,93 @@ use Zotlabs\Lib\Activity; use Zotlabs\Daemon\Run; +class React extends Controller +{ -class React extends Controller { + public function get() + { - function get() { + if (!local_channel()) + return; - if(! local_channel()) - return; + $sys = get_sys_channel(); + $channel = App::get_channel(); - $sys = get_sys_channel(); - $channel = App::get_channel(); + $postid = $_REQUEST['postid']; - $postid = $_REQUEST['postid']; + if (!$postid) + return; - if(! $postid) - return; - - $emoji = $_REQUEST['emoji']; + $emoji = $_REQUEST['emoji']; - if($emoji) { + if ($emoji) { - $i = q("select * from item where id = %d and uid = %d", - intval($postid), - intval(local_channel()) - ); + $i = q("select * from item where id = %d and uid = %d", + intval($postid), + intval(local_channel()) + ); - if(! $i) { - // try the global public stream - $i = q("select * from item where id = %d and uid = %d", - intval($postid), - intval($sys['channel_id']) - ); - // try the local public stream - if (! $i) { - $i = q("select * from item where id = %d and item_wall = 1 and item_private = 0", - intval($postid) - ); - } - - if($i && local_channel() && (! is_sys_channel(local_channel()))) { - $i = [ copy_of_pubitem($channel, $i[0]['mid']) ]; - $postid = (($i) ? $i[0]['id'] : 0); - } - } + if (!$i) { + // try the global public stream + $i = q("select * from item where id = %d and uid = %d", + intval($postid), + intval($sys['channel_id']) + ); + // try the local public stream + if (!$i) { + $i = q("select * from item where id = %d and item_wall = 1 and item_private = 0", + intval($postid) + ); + } - if(! $i) { - return; - } + if ($i && local_channel() && (!is_sys_channel(local_channel()))) { + $i = [copy_of_pubitem($channel, $i[0]['mid'])]; + $postid = (($i) ? $i[0]['id'] : 0); + } + } - $item = array_shift($i); + if (!$i) { + return; + } - $n = [] ; - $n['aid'] = $channel['channel_account_id']; - $n['uid'] = $channel['channel_id']; - $n['item_origin'] = true; - $n['item_type'] = $item['item_type']; - $n['parent'] = $postid; - $n['parent_mid'] = $item['mid']; - $n['uuid'] = new_uuid(); - $n['mid'] = z_root() . '/item/' . $n['uuid']; - $n['verb'] = 'emojiReaction'; - $n['body'] = "\n\n" . '[img=32x32]' . z_root() . '/images/emoji/' . $emoji . '.png[/img]' . "\n\n"; - $n['author_xchan'] = $channel['channel_hash']; + $item = array_shift($i); - $n['obj'] = Activity::fetch_item( [ 'id' => $item['mid'] ] ); - $n['obj_type'] = ((array_path_exists('obj/type',$n)) ? $n['obj']['type'] : EMPTY_STR); + $n = []; + $n['aid'] = $channel['channel_account_id']; + $n['uid'] = $channel['channel_id']; + $n['item_origin'] = true; + $n['item_type'] = $item['item_type']; + $n['parent'] = $postid; + $n['parent_mid'] = $item['mid']; + $n['uuid'] = new_uuid(); + $n['mid'] = z_root() . '/item/' . $n['uuid']; + $n['verb'] = 'emojiReaction'; + $n['body'] = "\n\n" . '[img=32x32]' . z_root() . '/images/emoji/' . $emoji . '.png[/img]' . "\n\n"; + $n['author_xchan'] = $channel['channel_hash']; - $n['tgt_type'] = 'Image'; - - $n['target'] = [ - 'type' => 'Image', - 'name' => $emoji, - 'url' => z_root() . '/images/emoji/' . $emoji . '.png' - ]; - - $x = item_store($n); + $n['obj'] = Activity::fetch_item(['id' => $item['mid']]); + $n['obj_type'] = ((array_path_exists('obj/type', $n)) ? $n['obj']['type'] : EMPTY_STR); - retain_item($postid); + $n['tgt_type'] = 'Image'; - if($x['success']) { - $nid = $x['item_id']; - Run::Summon( [ 'Notifier', 'like', $nid ] ); - } + $n['target'] = [ + 'type' => 'Image', + 'name' => $emoji, + 'url' => z_root() . '/images/emoji/' . $emoji . '.png' + ]; - } + $x = item_store($n); - } + retain_item($postid); + + if ($x['success']) { + $nid = $x['item_id']; + Run::Summon(['Notifier', 'like', $nid]); + } + + } + + } } \ No newline at end of file diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php index 9b835d45b..e507328f6 100644 --- a/Zotlabs/Module/Register.php +++ b/Zotlabs/Module/Register.php @@ -6,308 +6,304 @@ use Zotlabs\Access\PermissionRoles; require_once('include/security.php'); -class Register extends Controller { +class Register extends Controller +{ - function init() { - - $result = null; - $cmd = ((argc() > 1) ? argv(1) : ''); - - // Provide a stored request for somebody desiring a connection - // when they first need to register someplace. Once they've - // created a channel, we'll try to revive the connection request - // and process it. - - if ($_REQUEST['connect']) { - $_SESSION['connect'] = $_REQUEST['connect']; - } - - switch ($cmd) { - case 'invite_check.json': - $result = check_account_invite($_REQUEST['invite_code']); - break; - case 'email_check.json': - $result = check_account_email($_REQUEST['email']); - break; - case 'password_check.json': - $result = check_account_password($_REQUEST['password1']); - break; - default: - break; - } - if ($result) { - json_return_and_die($result); - } - } - - - function post() { + public function init() + { - check_form_security_token_redirectOnErr('/register', 'register'); + $result = null; + $cmd = ((argc() > 1) ? argv(1) : ''); - $max_dailies = intval(get_config('system','max_daily_registrations')); - if ($max_dailies) { - $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s", - db_utcnow(), db_quoteinterval('1 day') - ); - if ($r && intval($r[0]['total']) >= $max_dailies) { - notice( t('Maximum daily site registrations exceeded. Please try again tomorrow.') . EOL); - return; - } - } - - if (! (isset($_POST['tos']) && intval($_POST['tos']))) { - notice( t('Please indicate acceptance of the Terms of Service. Registration failed.') . EOL); - return; - } - - $policy = get_config('system','register_policy'); - - $email_verify = get_config('system','verify_email'); - - - switch ($policy) { - - case REGISTER_OPEN: - $flags = ACCOUNT_OK; - break; - - case REGISTER_APPROVE: - $flags = ACCOUNT_BLOCKED | ACCOUNT_PENDING; - break; - - default: - case REGISTER_CLOSED: - if (! is_site_admin()) { - notice( t('Permission denied.') . EOL ); - return; - } - $flags = ACCOUNT_BLOCKED; - break; - } - - if ($email_verify && $policy == REGISTER_OPEN) { - $flags = $flags | ACCOUNT_UNVERIFIED; - } - - - if ((! $_POST['password']) || ($_POST['password'] !== $_POST['password2'])) { - notice( t('Passwords do not match.') . EOL); - return; - } - - $arr = $_POST; - $arr['account_flags'] = $flags; - - $result = create_account($arr); - - if (! $result['success']) { - notice($result['message']); - return; - } + // Provide a stored request for somebody desiring a connection + // when they first need to register someplace. Once they've + // created a channel, we'll try to revive the connection request + // and process it. - require_once('include/security.php'); - - - if ($_REQUEST['name']) { - set_aconfig($result['account']['account_id'],'register','channel_name',$_REQUEST['name']); - } - if ($_REQUEST['nickname']) { - set_aconfig($result['account']['account_id'],'register','channel_address',$_REQUEST['nickname']); - } - if ($_REQUEST['permissions_role']) { - set_aconfig($result['account']['account_id'],'register','permissions_role',$_REQUEST['permissions_role']); - } + if ($_REQUEST['connect']) { + $_SESSION['connect'] = $_REQUEST['connect']; + } - // At this point the account has been created without error. Purge any error messages from prior failed registration - // attempts which haven't yet been delivered to the browser and start fresh. If you're willing to figure out why they - // weren't delivered to the browser please adopt zap issue 34. - - $_SESSION['sysmsg'] = []; - - $using_invites = intval(get_config('system','invitation_only')); - $num_invites = intval(get_config('system','number_invites')); - $invite_code = ((x($_POST,'invite_code')) ? notags(trim($_POST['invite_code'])) : ''); - - if ($using_invites && $invite_code && defined('INVITE_WORKING')) { - q("delete from register where hash = '%s'", dbesc($invite_code)); - // @FIXME - this also needs to be considered when using 'invites_remaining' in mod/invite.php - set_aconfig($result['account']['account_id'],'system','invites_remaining',$num_invites); - } - - if ($policy == REGISTER_OPEN ) { - if ($email_verify) { - $res = verify_email_address($result); - } - else { - $res = send_register_success_email($result['email'],$result['password']); - } - if ($res) { - if ($invite_code) { - info( t('Registration successful. Continue to create your first channel...') . EOL ) ; - } - else { - info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ; - } - } - } - elseif ($policy == REGISTER_APPROVE) { - $res = send_reg_approval_email($result); - if ($res) { - info( t('Your registration is pending approval by the site owner.') . EOL ) ; - } - else { - notice( t('Your registration can not be processed.') . EOL); - } - goaway(z_root()); - } - - if ($email_verify) { - goaway(z_root() . '/email_validation/' . bin2hex($result['email'])); - } - - // fall through and authenticate if no approvals or verifications were required. - - authenticate_success($result['account'],null,true,false,true); - - $new_channel = false; - $next_page = 'new_channel'; - - if (get_config('system','auto_channel_create')) { - $new_channel = auto_channel_create($result['account']['account_id']); - if ($new_channel['success']) { - $channel_id = $new_channel['channel']['channel_id']; - change_channel($channel_id); - $next_page = '~'; - } - else { - $new_channel = false; - } - } - - $x = get_config('system','workflow_register_next'); - if ($x) { - $next_page = $x; - $_SESSION['workflow'] = true; - } - - unset($_SESSION['login_return_url']); - goaway(z_root() . '/' . $next_page); - - } - - - - function get() { - - $registration_is = EMPTY_STR; - $other_sites = false; - - if (intval(get_config('system','register_policy')) === REGISTER_CLOSED) { - notice( t('Registration on this website is disabled.') . EOL); - if (intval(get_config('system','directory_mode')) === DIRECTORY_MODE_STANDALONE) { - return EMPTY_STR; - } - else { - $other_sites = true; - } - } - - if (intval(get_config('system','register_policy')) == REGISTER_APPROVE) { - $registration_is = t('Registration on this website is by approval only.'); - $other_sites = true; - } - - $invitations = false; - - if (intval(get_config('system','invitation_only')) && defined('INVITE_WORKING')) { - $invitations = true; - $registration_is = t('Registration on this site is by invitation only.'); - $other_sites = true; - } - - $max_dailies = intval(get_config('system','max_daily_registrations')); - if ($max_dailies) { - $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s", - db_utcnow(), db_quoteinterval('1 day') - ); - if ($r && $r[0]['total'] >= $max_dailies) { - logger('max daily registrations exceeded.'); - notice( t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.') . EOL); - return; - } - } - - $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : ""); - - $perm_roles = PermissionRoles::roles(); - - // Configurable terms of service link - - $tosurl = get_config('system','tos_url'); - if (! $tosurl) { - $tosurl = z_root() . '/help/TermsOfService'; - } - - $toslink = '' . t('Terms of Service') . ''; - - // Configurable whether to restrict age or not - default is based on international legal requirements - // This can be relaxed if you are on a restricted server that does not share with public servers - - if (get_config('system','no_age_restriction')) { - $label_tos = sprintf( t('I accept the %s for this website'), $toslink); - } - else { - $age = get_config('system','minimum_age'); - if (! $age) { - $age = 13; - } - $label_tos = sprintf( t('I am over %s years of age and accept the %s for this website'), $age, $toslink); - } - - $enable_tos = 1 - intval(get_config('system','no_termsofservice')); - - $email = [ 'email', t('Your email address'), ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : ""), '' , '',' required ']; - $password = [ 'password', t('Choose a password'), '', '', '', ' required ' ]; - $password2 = [ 'password2', t('Please re-enter your password'), '', '', '', ' required ' ]; - $invite_code = [ 'invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : "")]; - $name = [ 'name', t('Your Name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Real names are preferred.') ]; - $nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl')); - $nickname = [ 'nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub)]; - $role = ['permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role for your usage needs and privacy requirements.'),$perm_roles]; - $tos = [ 'tos', $label_tos, '', '', [ t('no'), t('yes') ], ' required ' ]; + switch ($cmd) { + case 'invite_check.json': + $result = check_account_invite($_REQUEST['invite_code']); + break; + case 'email_check.json': + $result = check_account_email($_REQUEST['email']); + break; + case 'password_check.json': + $result = check_account_password($_REQUEST['password1']); + break; + default: + break; + } + if ($result) { + json_return_and_die($result); + } + } + + + public function post() + { + + check_form_security_token_redirectOnErr('/register', 'register'); + + $max_dailies = intval(get_config('system', 'max_daily_registrations')); + if ($max_dailies) { + $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s", + db_utcnow(), db_quoteinterval('1 day') + ); + if ($r && intval($r[0]['total']) >= $max_dailies) { + notice(t('Maximum daily site registrations exceeded. Please try again tomorrow.') . EOL); + return; + } + } + + if (!(isset($_POST['tos']) && intval($_POST['tos']))) { + notice(t('Please indicate acceptance of the Terms of Service. Registration failed.') . EOL); + return; + } + + $policy = get_config('system', 'register_policy'); + + $email_verify = get_config('system', 'verify_email'); + + + switch ($policy) { + + case REGISTER_OPEN: + $flags = ACCOUNT_OK; + break; + + case REGISTER_APPROVE: + $flags = ACCOUNT_BLOCKED | ACCOUNT_PENDING; + break; + + default: + case REGISTER_CLOSED: + if (!is_site_admin()) { + notice(t('Permission denied.') . EOL); + return; + } + $flags = ACCOUNT_BLOCKED; + break; + } + + if ($email_verify && $policy == REGISTER_OPEN) { + $flags = $flags | ACCOUNT_UNVERIFIED; + } + + + if ((!$_POST['password']) || ($_POST['password'] !== $_POST['password2'])) { + notice(t('Passwords do not match.') . EOL); + return; + } + + $arr = $_POST; + $arr['account_flags'] = $flags; + + $result = create_account($arr); + + if (!$result['success']) { + notice($result['message']); + return; + } + + require_once('include/security.php'); + + + if ($_REQUEST['name']) { + set_aconfig($result['account']['account_id'], 'register', 'channel_name', $_REQUEST['name']); + } + if ($_REQUEST['nickname']) { + set_aconfig($result['account']['account_id'], 'register', 'channel_address', $_REQUEST['nickname']); + } + if ($_REQUEST['permissions_role']) { + set_aconfig($result['account']['account_id'], 'register', 'permissions_role', $_REQUEST['permissions_role']); + } + + // At this point the account has been created without error. Purge any error messages from prior failed registration + // attempts which haven't yet been delivered to the browser and start fresh. If you're willing to figure out why they + // weren't delivered to the browser please adopt zap issue 34. + + $_SESSION['sysmsg'] = []; + + $using_invites = intval(get_config('system', 'invitation_only')); + $num_invites = intval(get_config('system', 'number_invites')); + $invite_code = ((x($_POST, 'invite_code')) ? notags(trim($_POST['invite_code'])) : ''); + + if ($using_invites && $invite_code && defined('INVITE_WORKING')) { + q("delete from register where hash = '%s'", dbesc($invite_code)); + // @FIXME - this also needs to be considered when using 'invites_remaining' in mod/invite.php + set_aconfig($result['account']['account_id'], 'system', 'invites_remaining', $num_invites); + } + + if ($policy == REGISTER_OPEN) { + if ($email_verify) { + $res = verify_email_address($result); + } else { + $res = send_register_success_email($result['email'], $result['password']); + } + if ($res) { + if ($invite_code) { + info(t('Registration successful. Continue to create your first channel...') . EOL); + } else { + info(t('Registration successful. Please check your email for validation instructions.') . EOL); + } + } + } elseif ($policy == REGISTER_APPROVE) { + $res = send_reg_approval_email($result); + if ($res) { + info(t('Your registration is pending approval by the site owner.') . EOL); + } else { + notice(t('Your registration can not be processed.') . EOL); + } + goaway(z_root()); + } + + if ($email_verify) { + goaway(z_root() . '/email_validation/' . bin2hex($result['email'])); + } + + // fall through and authenticate if no approvals or verifications were required. + + authenticate_success($result['account'], null, true, false, true); + + $new_channel = false; + $next_page = 'new_channel'; + + if (get_config('system', 'auto_channel_create')) { + $new_channel = auto_channel_create($result['account']['account_id']); + if ($new_channel['success']) { + $channel_id = $new_channel['channel']['channel_id']; + change_channel($channel_id); + $next_page = '~'; + } else { + $new_channel = false; + } + } + + $x = get_config('system', 'workflow_register_next'); + if ($x) { + $next_page = $x; + $_SESSION['workflow'] = true; + } + + unset($_SESSION['login_return_url']); + goaway(z_root() . '/' . $next_page); + + } + + + public function get() + { + + $registration_is = EMPTY_STR; + $other_sites = false; + + if (intval(get_config('system', 'register_policy')) === REGISTER_CLOSED) { + notice(t('Registration on this website is disabled.') . EOL); + if (intval(get_config('system', 'directory_mode')) === DIRECTORY_MODE_STANDALONE) { + return EMPTY_STR; + } else { + $other_sites = true; + } + } + + if (intval(get_config('system', 'register_policy')) == REGISTER_APPROVE) { + $registration_is = t('Registration on this website is by approval only.'); + $other_sites = true; + } + + $invitations = false; + + if (intval(get_config('system', 'invitation_only')) && defined('INVITE_WORKING')) { + $invitations = true; + $registration_is = t('Registration on this site is by invitation only.'); + $other_sites = true; + } + + $max_dailies = intval(get_config('system', 'max_daily_registrations')); + if ($max_dailies) { + $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s", + db_utcnow(), db_quoteinterval('1 day') + ); + if ($r && $r[0]['total'] >= $max_dailies) { + logger('max daily registrations exceeded.'); + notice(t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.') . EOL); + return; + } + } + + $privacy_role = ((x($_REQUEST, 'permissions_role')) ? $_REQUEST['permissions_role'] : ""); + + $perm_roles = PermissionRoles::roles(); + + // Configurable terms of service link + + $tosurl = get_config('system', 'tos_url'); + if (!$tosurl) { + $tosurl = z_root() . '/help/TermsOfService'; + } + + $toslink = '' . t('Terms of Service') . ''; + + // Configurable whether to restrict age or not - default is based on international legal requirements + // This can be relaxed if you are on a restricted server that does not share with public servers + + if (get_config('system', 'no_age_restriction')) { + $label_tos = sprintf(t('I accept the %s for this website'), $toslink); + } else { + $age = get_config('system', 'minimum_age'); + if (!$age) { + $age = 13; + } + $label_tos = sprintf(t('I am over %s years of age and accept the %s for this website'), $age, $toslink); + } + + $enable_tos = 1 - intval(get_config('system', 'no_termsofservice')); + + $email = ['email', t('Your email address'), ((x($_REQUEST, 'email')) ? strip_tags(trim($_REQUEST['email'])) : ""), '', '', ' required ']; + $password = ['password', t('Choose a password'), '', '', '', ' required ']; + $password2 = ['password2', t('Please re-enter your password'), '', '', '', ' required ']; + $invite_code = ['invite_code', t('Please enter your invitation code'), ((x($_REQUEST, 'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : "")]; + $name = ['name', t('Your Name'), ((x($_REQUEST, 'name')) ? $_REQUEST['name'] : ''), t('Real names are preferred.')]; + $nickhub = '@' . str_replace(array('http://', 'https://', '/'), '', get_config('system', 'baseurl')); + $nickname = ['nickname', t('Choose a short nickname'), ((x($_REQUEST, 'nickname')) ? $_REQUEST['nickname'] : ''), sprintf(t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub)]; + $role = ['permissions_role', t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role for your usage needs and privacy requirements.'), $perm_roles]; + $tos = ['tos', $label_tos, '', '', [t('no'), t('yes')], ' required ']; + + + $auto_create = (get_config('system', 'auto_channel_create') ? true : false); + $default_role = get_config('system', 'default_permissions_role'); + $email_verify = get_config('system', 'verify_email'); + + + $o = replace_macros(get_markup_template('register.tpl'), [ + '$form_security_token' => get_form_security_token("register"), + '$title' => t('Registration'), + '$reg_is' => $registration_is, + '$registertext' => bbcode(get_config('system', 'register_text')), + '$other_sites' => (($other_sites) ? t('Show affiliated sites - some of which may allow registration.') : EMPTY_STR), + '$invitations' => $invitations, + '$invite_code' => $invite_code, + '$auto_create' => $auto_create, + '$name' => $name, + '$role' => $role, + '$default_role' => $default_role, + '$nickname' => $nickname, + '$enable_tos' => $enable_tos, + '$tos' => $tos, + '$email' => $email, + '$pass1' => $password, + '$pass2' => $password2, + '$submit' => t('Register'), + '$verify_note' => (($email_verify) ? t('This site requires email verification. After completing this form, please check your email for further instructions.') : ''), + ]); + + return $o; + + } - $auto_create = (get_config('system','auto_channel_create') ? true : false); - $default_role = get_config('system','default_permissions_role'); - $email_verify = get_config('system','verify_email'); - - - $o = replace_macros(get_markup_template('register.tpl'), [ - '$form_security_token' => get_form_security_token("register"), - '$title' => t('Registration'), - '$reg_is' => $registration_is, - '$registertext' => bbcode(get_config('system','register_text')), - '$other_sites' => (($other_sites) ? t('Show affiliated sites - some of which may allow registration.') : EMPTY_STR), - '$invitations' => $invitations, - '$invite_code' => $invite_code, - '$auto_create' => $auto_create, - '$name' => $name, - '$role' => $role, - '$default_role' => $default_role, - '$nickname' => $nickname, - '$enable_tos' => $enable_tos, - '$tos' => $tos, - '$email' => $email, - '$pass1' => $password, - '$pass2' => $password2, - '$submit' => t('Register'), - '$verify_note' => (($email_verify) ? t('This site requires email verification. After completing this form, please check your email for further instructions.') : ''), - ] ); - - return $o; - - } - - } diff --git a/Zotlabs/Module/Regmod.php b/Zotlabs/Module/Regmod.php index f8c791957..1eea4d6be 100644 --- a/Zotlabs/Module/Regmod.php +++ b/Zotlabs/Module/Regmod.php @@ -6,39 +6,41 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Regmod extends Controller { +class Regmod extends Controller +{ - function get() { - - global $lang; - - $_SESSION['return_url'] = App::$cmd; - - if(! local_channel()) { - info( t('Please login.') . EOL); - return login(); - } - - if(! is_site_admin()) { - notice( t('Permission denied.') . EOL); - return ''; - } - - if(argc() != 3) - killme(); - - $cmd = argv(1); - $hash = argv(2); - - if($cmd === 'deny') { - if (! account_deny($hash)) killme(); - } - - if($cmd === 'allow') { - if (! account_allow($hash)) killme(); - } + public function get() + { + + global $lang; + + $_SESSION['return_url'] = App::$cmd; + + if (!local_channel()) { + info(t('Please login.') . EOL); + return login(); + } + + if (!is_site_admin()) { + notice(t('Permission denied.') . EOL); + return ''; + } + + if (argc() != 3) + killme(); + + $cmd = argv(1); + $hash = argv(2); + + if ($cmd === 'deny') { + if (!account_deny($hash)) killme(); + } + + if ($cmd === 'allow') { + if (!account_allow($hash)) killme(); + } + + goaway('/admin/accounts'); + } - goaway('/admin/accounts'); - } - } diff --git a/Zotlabs/Module/Regver.php b/Zotlabs/Module/Regver.php index d086db294..45eeed913 100644 --- a/Zotlabs/Module/Regver.php +++ b/Zotlabs/Module/Regver.php @@ -4,29 +4,31 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Regver extends Controller { +class Regver extends Controller +{ - function get() { - - $_SESSION['return_url'] = App::$cmd; - - if (argc() != 3) { - killme(); - } - - $cmd = argv(1); - $hash = argv(2); - - if ($cmd === 'deny') { - if (! account_deny($hash)) { - killme(); - } - } - - if ($cmd === 'allow') { - if (! account_approve($hash)) { - killme(); - } - } - } + public function get() + { + + $_SESSION['return_url'] = App::$cmd; + + if (argc() != 3) { + killme(); + } + + $cmd = argv(1); + $hash = argv(2); + + if ($cmd === 'deny') { + if (!account_deny($hash)) { + killme(); + } + } + + if ($cmd === 'allow') { + if (!account_approve($hash)) { + killme(); + } + } + } } diff --git a/Zotlabs/Module/Removeaccount.php b/Zotlabs/Module/Removeaccount.php index fbcc156d9..0ebaf3b5f 100644 --- a/Zotlabs/Module/Removeaccount.php +++ b/Zotlabs/Module/Removeaccount.php @@ -4,73 +4,76 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Removeaccount extends Controller { +class Removeaccount extends Controller +{ - function post() { - - if (! local_channel()) { - return; - } - - if ($_SESSION['delegate']) { - return; - } - - if ((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password'])))) { - return; - } - - if ((! x($_POST,'verify')) || (! strlen(trim($_POST['verify'])))) { - return; - } - - if ($_POST['verify'] !== $_SESSION['remove_account_verify']) { - return; - } - - $account = App::get_account(); - $account_id = get_account_id(); + public function post() + { - if (! ($account && $account_id)) { - return; - } + if (!local_channel()) { + return; + } - $x = account_verify_password($account['account_email'],$_POST['qxz_password']); - if (! ($x && $x['account'])) { - return; - } - - if ($account['account_password_changed'] > NULL_DATE) { - $d1 = datetime_convert('UTC','UTC','now - 48 hours'); - if ($account['account_password_changed'] > d1) { - notice( t('Account removals are not allowed within 48 hours of changing the account password.') . EOL); - return; - } - } + if ($_SESSION['delegate']) { + return; + } - account_remove($account_id); - } - - function get() { - - if (! local_channel()) { - goaway(z_root()); - } - - $hash = random_string(); - - $_SESSION['remove_account_verify'] = $hash; + if ((!x($_POST, 'qxz_password')) || (!strlen(trim($_POST['qxz_password'])))) { + return; + } + + if ((!x($_POST, 'verify')) || (!strlen(trim($_POST['verify'])))) { + return; + } + + if ($_POST['verify'] !== $_SESSION['remove_account_verify']) { + return; + } + + $account = App::get_account(); + $account_id = get_account_id(); + + if (!($account && $account_id)) { + return; + } + + $x = account_verify_password($account['account_email'], $_POST['qxz_password']); + if (!($x && $x['account'])) { + return; + } + + if ($account['account_password_changed'] > NULL_DATE) { + $d1 = datetime_convert('UTC', 'UTC', 'now - 48 hours'); + if ($account['account_password_changed'] > d1) { + notice(t('Account removals are not allowed within 48 hours of changing the account password.') . EOL); + return; + } + } + + account_remove($account_id); + } + + public function get() + { + + if (!local_channel()) { + goaway(z_root()); + } + + $hash = random_string(); + + $_SESSION['remove_account_verify'] = $hash; + + $o .= replace_macros(get_markup_template('removeaccount.tpl'), [ + '$basedir' => z_root(), + '$hash' => $hash, + '$title' => t('Remove This Account'), + '$desc' => [t('WARNING: '), t('This account and all its channels will be completely removed from this server. '), t('This action is permanent and can not be undone!')], + '$passwd' => t('Please enter your password for verification:'), + '$submit' => t('Remove Account') + ]); + + return $o; + } - $o .= replace_macros(get_markup_template('removeaccount.tpl'), [ - '$basedir' => z_root(), - '$hash' => $hash, - '$title' => t('Remove This Account'), - '$desc' => [ t('WARNING: '), t('This account and all its channels will be completely removed from this server. '), t('This action is permanent and can not be undone!') ], - '$passwd' => t('Please enter your password for verification:'), - '$submit' => t('Remove Account') - ]); - - return $o; - } - } diff --git a/Zotlabs/Module/Removeme.php b/Zotlabs/Module/Removeme.php index 11affb82a..52b8bbd78 100644 --- a/Zotlabs/Module/Removeme.php +++ b/Zotlabs/Module/Removeme.php @@ -4,73 +4,76 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Removeme extends Controller { +class Removeme extends Controller +{ - function post() { - - if (! local_channel()) { - return; - } - - if ($_SESSION['delegate']) { - return; - } - - if ((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password'])))) { - return; - } - - if ((! x($_POST,'verify')) || (! strlen(trim($_POST['verify'])))) { - return; - } - - if ($_POST['verify'] !== $_SESSION['remove_channel_verify']) { - return; - } - - $account = App::get_account(); + public function post() + { + + if (!local_channel()) { + return; + } + + if ($_SESSION['delegate']) { + return; + } + + if ((!x($_POST, 'qxz_password')) || (!strlen(trim($_POST['qxz_password'])))) { + return; + } + + if ((!x($_POST, 'verify')) || (!strlen(trim($_POST['verify'])))) { + return; + } + + if ($_POST['verify'] !== $_SESSION['remove_channel_verify']) { + return; + } + + $account = App::get_account(); + + if (!$account) { + return; + } + + $x = account_verify_password($account['account_email'], $_POST['qxz_password']); + if (!($x && $x['account'])) { + return; + } + + if ($account['account_password_changed'] > NULL_DATE) { + $d1 = datetime_convert('UTC', 'UTC', 'now - 48 hours'); + if ($account['account_password_changed'] > $d1) { + notice(t('Channel removals are not allowed within 48 hours of changing the account password.') . EOL); + return; + } + } + + channel_remove(local_channel(), true, true); + } + + + public function get() + { + + if (!local_channel()) { + goaway(z_root()); + } + + $hash = random_string(); + + $_SESSION['remove_channel_verify'] = $hash; + + $o .= replace_macros(get_markup_template('removeme.tpl'), [ + '$basedir' => z_root(), + '$hash' => $hash, + '$title' => t('Remove This Channel'), + '$desc' => [t('WARNING: '), t('This channel will be completely removed from this server. '), t('This action is permanent and can not be undone!')], + '$passwd' => t('Please enter your password for verification:'), + '$submit' => t('Remove Channel') + ]); + + return $o; + } - if (! $account) { - return; - } - - $x = account_verify_password($account['account_email'],$_POST['qxz_password']); - if (! ($x && $x['account'])) { - return; - } - - if ($account['account_password_changed'] > NULL_DATE) { - $d1 = datetime_convert('UTC','UTC','now - 48 hours'); - if($account['account_password_changed'] > $d1) { - notice( t('Channel removals are not allowed within 48 hours of changing the account password.') . EOL); - return; - } - } - - channel_remove(local_channel(),true,true); - } - - - function get() { - - if (! local_channel()) { - goaway(z_root()); - } - - $hash = random_string(); - - $_SESSION['remove_channel_verify'] = $hash; - - $o .= replace_macros(get_markup_template('removeme.tpl'), [ - '$basedir' => z_root(), - '$hash' => $hash, - '$title' => t('Remove This Channel'), - '$desc' => [ t('WARNING: '), t('This channel will be completely removed from this server. '), t('This action is permanent and can not be undone!') ], - '$passwd' => t('Please enter your password for verification:'), - '$submit' => t('Remove Channel') - ]); - - return $o; - } - } diff --git a/Zotlabs/Module/Rmagic.php b/Zotlabs/Module/Rmagic.php index a1697ce46..bdbe97ba9 100644 --- a/Zotlabs/Module/Rmagic.php +++ b/Zotlabs/Module/Rmagic.php @@ -4,85 +4,86 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Rmagic extends Controller { +class Rmagic extends Controller +{ - function init() { - - if (local_channel()) { - goaway(z_root()); - } - - $me = get_my_address(); - if ($me) { - $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", - dbesc($me) - ); - if ($r) { - if ($r[0]['hubloc_url'] === z_root()) { - goaway(z_root() . '/login'); - } - $dest = bin2hex(z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],App::$query_string)); - goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest); - } - } - } - - function post() { - - $address = trim($_REQUEST['address']); - - if (strpos($address,'@') === false) { - $arr = [ 'address' => $address ]; - call_hooks('reverse_magic_auth', $arr); - - // if they're still here... - notice( t('Authentication failed.') . EOL); - return; - } - else { - - // Presumed Red identity. Perform reverse magic auth - - if (strpos($address,'@') === false) { - notice('Invalid address.'); - return; - } - - $r = null; - if ($address) { - $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", - dbesc($address) - ); - } - if ($r) { - $url = $r[0]['hubloc_url']; - } - else { - $url = 'https://' . substr($address,strpos($address,'@')+1); - } - - if ($url) { - if ($_SESSION['return_url']) { - $dest = bin2hex(z_root() . '/' . str_replace('zid=','zid_=',$_SESSION['return_url'])); - } - else { - $dest = bin2hex(z_root() . '/' . str_replace([ 'rmagic', 'zid=' ] ,[ '', 'zid_='],App::$query_string)); - } - goaway($url . '/magic' . '?f=&owa=1&bdest=' . $dest); - } - } - } - - - function get() { - return replace_macros(get_markup_template('rmagic.tpl'), - [ - '$title' => t('Remote Authentication'), - '$address' => [ 'address', t('Enter your channel address (e.g. channel@example.com)'), '', '' ], - '$action' => 'rmagic', - '$method' => 'post', - '$submit' => t('Authenticate') - ] - ); - } + public function init() + { + + if (local_channel()) { + goaway(z_root()); + } + + $me = get_my_address(); + if ($me) { + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + dbesc($me) + ); + if ($r) { + if ($r[0]['hubloc_url'] === z_root()) { + goaway(z_root() . '/login'); + } + $dest = bin2hex(z_root() . '/' . str_replace(['rmagic', 'zid='], ['', 'zid_='], App::$query_string)); + goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&bdest=' . $dest); + } + } + } + + public function post() + { + + $address = trim($_REQUEST['address']); + + if (strpos($address, '@') === false) { + $arr = ['address' => $address]; + call_hooks('reverse_magic_auth', $arr); + + // if they're still here... + notice(t('Authentication failed.') . EOL); + return; + } else { + + // Presumed Red identity. Perform reverse magic auth + + if (strpos($address, '@') === false) { + notice('Invalid address.'); + return; + } + + $r = null; + if ($address) { + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + dbesc($address) + ); + } + if ($r) { + $url = $r[0]['hubloc_url']; + } else { + $url = 'https://' . substr($address, strpos($address, '@') + 1); + } + + if ($url) { + if ($_SESSION['return_url']) { + $dest = bin2hex(z_root() . '/' . str_replace('zid=', 'zid_=', $_SESSION['return_url'])); + } else { + $dest = bin2hex(z_root() . '/' . str_replace(['rmagic', 'zid='], ['', 'zid_='], App::$query_string)); + } + goaway($url . '/magic' . '?f=&owa=1&bdest=' . $dest); + } + } + } + + + public function get() + { + return replace_macros(get_markup_template('rmagic.tpl'), + [ + '$title' => t('Remote Authentication'), + '$address' => ['address', t('Enter your channel address (e.g. channel@example.com)'), '', ''], + '$action' => 'rmagic', + '$method' => 'post', + '$submit' => t('Authenticate') + ] + ); + } } diff --git a/Zotlabs/Module/Rpost.php b/Zotlabs/Module/Rpost.php index c4d2471d1..d708d8a6c 100644 --- a/Zotlabs/Module/Rpost.php +++ b/Zotlabs/Module/Rpost.php @@ -31,223 +31,219 @@ require_once('include/attach.php'); * type= choices are 'html' or 'bbcode', default is 'bbcode' * */ +class Rpost extends Controller +{ + public function get() + { -class Rpost extends Controller { + $o = ''; - function get() { - - $o = ''; - - if (! local_channel()) { - if (remote_channel()) { - // redirect to your own site. - // We can only do this with a GET request so you'll need to keep the text short or risk getting truncated - // by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin - // blocks them. - - $url = Libzot::get_rpost_path(App::get_observer()); - // make sure we're not looping to our own hub - if (($url) && (! stristr($url, App::get_hostname()))) { - foreach ($_GET as $key => $arg) { - if ($key === 'req') - continue; - $url .= '&' . $key . '=' . $arg; - } - goaway($url); - } - } - - // The login procedure is going to bugger our $_REQUEST variables - // so save them in the session. - - if (array_key_exists('body',$_REQUEST)) { - $_SESSION['rpost'] = $_REQUEST; - } - return login(); - } + if (!local_channel()) { + if (remote_channel()) { + // redirect to your own site. + // We can only do this with a GET request so you'll need to keep the text short or risk getting truncated + // by the wretched beast called 'suhosin'. All the browsers now allow long GET requests, but suhosin + // blocks them. - nav_set_selected('Post'); + $url = Libzot::get_rpost_path(App::get_observer()); + // make sure we're not looping to our own hub + if (($url) && (!stristr($url, App::get_hostname()))) { + foreach ($_GET as $key => $arg) { + if ($key === 'req') + continue; + $url .= '&' . $key . '=' . $arg; + } + goaway($url); + } + } - if (local_channel() && array_key_exists('userfile',$_FILES)) { - - $channel = App::get_channel(); - $observer = App::get_observer(); + // The login procedure is going to bugger our $_REQUEST variables + // so save them in the session. - $def_album = get_pconfig($channel['channel_id'],'system','photo_path'); - $def_attach = get_pconfig($channel['channel_id'],'system','attach_path'); - - $r = attach_store($channel, (($observer) ? $observer['xchan_hash'] : ''), '', [ - 'source' => 'editor', - 'visible' => 0, - 'album' => $def_album, - 'directory' => $def_attach, - 'flags' => 1, // indicates temporary permissions are created - 'allow_cid' => '<' . $channel['channel_hash'] . '>' - ]); + if (array_key_exists('body', $_REQUEST)) { + $_SESSION['rpost'] = $_REQUEST; + } + return login(); + } - if (! $r['success']) { - notice( $r['message'] . EOL); - } + nav_set_selected('Post'); - $s = EMPTY_STR; - - if (intval($r['data']['is_photo'])) { - $s .= "\n\n" . $r['body'] . "\n\n"; - } + if (local_channel() && array_key_exists('userfile', $_FILES)) { - $url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']; + $channel = App::get_channel(); + $observer = App::get_observer(); - if (strpos($r['data']['filetype'],'video') === 0) { - for ($n = 0; $n < 15; $n ++) { - $thumb = Linkinfo::get_video_poster($url); - if ($thumb) { - break; - } - sleep(1); - continue; - } + $def_album = get_pconfig($channel['channel_id'], 'system', 'photo_path'); + $def_attach = get_pconfig($channel['channel_id'], 'system', 'attach_path'); - if ($thumb) { - $s .= "\n\n" . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . "\n\n"; - } - else { - $s .= "\n\n" . '[zvideo]' . $url . '[/zvideo]' . "\n\n"; - } - } - if (strpos($r['data']['filetype'],'audio') === 0) { - $s .= "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n"; - } - if ($r['data']['filetype'] === 'image/svg+xml') { - $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - if ($x) { - $bb = svg2bb($x); - if ($bb) { - $s .= "\n\n" . $bb; - } - else { - logger('empty return from svgbb'); - } - } - else { - logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - } - } - if ($r['data']['filetype'] === 'text/vnd.abc' && addon_is_installed('abc')) { - $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - if ($x) { - $s .= "\n\n" . '[abc]' . $x . '[/abc]'; - } - else { - logger('unable to read ABC data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - } - } - if ($r['data']['filetype'] === 'text/calendar') { - $content = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - if ($content) { - $ev = ical_to_ev($content); - if ($ev) { - $s .= "\n\n" . format_event_bbcode($ev[0]) . "\n\n"; - } - } - } + $r = attach_store($channel, (($observer) ? $observer['xchan_hash'] : ''), '', [ + 'source' => 'editor', + 'visible' => 0, + 'album' => $def_album, + 'directory' => $def_attach, + 'flags' => 1, // indicates temporary permissions are created + 'allow_cid' => '<' . $channel['channel_hash'] . '>' + ]); - $s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; - $_REQUEST['body'] = ((array_key_exists('body',$_REQUEST)) ? $_REQUEST['body'] . $s : $s); - } + if (!$r['success']) { + notice($r['message'] . EOL); + } - // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables - - if ((! array_key_exists('body',$_REQUEST)) && (array_key_exists('rpost',$_SESSION))) { - $_REQUEST = $_SESSION['rpost']; - unset($_SESSION['rpost']); - } - - if (array_key_exists('channel',$_REQUEST)) { - $r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1", - intval(get_account_id()), - dbesc($_REQUEST['channel']) - ); - if ($r) { - require_once('include/security.php'); - $change = change_channel($r[0]['channel_id']); - } - } - - if ($_REQUEST['remote_return']) { - $_SESSION['remote_return'] = $_REQUEST['remote_return']; - } - - if (argc() > 1 && argv(1) === 'return') { - if($_SESSION['remote_return']) { - goaway($_SESSION['remote_return']); - } - goaway(z_root() . '/stream'); - } - - $plaintext = true; - - if (array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html' && isset($_REQUEST['body'])) { - require_once('include/html2bbcode.php'); - $_REQUEST['body'] = html2bbcode($_REQUEST['body']); - } - - $channel = App::get_channel(); + $s = EMPTY_STR; - $acl = new AccessControl($channel); - - if (array_key_exists('to',$_REQUEST) && $_REQUEST['to']) { - $acl->set([ 'allow_cid' => '<' . $_REQUEST['to'] . '>', - 'allow_gid' => EMPTY_STR, - 'deny_cid' => EMPTY_STR, - 'deny_gid' => EMPTY_STR ] - ); - } + if (intval($r['data']['is_photo'])) { + $s .= "\n\n" . $r['body'] . "\n\n"; + } - $channel_acl = $acl->get(); - - if ($_REQUEST['url']) { - $x = z_fetch_url(z_root() . '/linkinfo?f=&url=' . urlencode($_REQUEST['url']) . '&oembed=1&zotobj=1'); - if ($x['success']) { - $_REQUEST['body'] = $_REQUEST['body'] . $x['body']; - } - } + $url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']; - if ($_REQUEST['post_id']) { - $_REQUEST['body'] .= '[share=' . intval($_REQUEST['post_id']) . '][/share]'; - } - - $x = [ - 'is_owner' => true, - 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), - 'default_location' => $channel['channel_location'], - 'nickname' => $channel['channel_address'], - 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'), - 'acl' => populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), - 'permissions' => $channel_acl, - 'bang' => '', - 'visitor' => true, - 'profile_uid' => local_channel(), - 'title' => $_REQUEST['title'], - 'body' => $_REQUEST['body'], - 'attachment' => $_REQUEST['attachment'], - 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''), - 'return_path' => 'rpost/return', - 'bbco_autocomplete' => 'bbcode', - 'editor_autocomplete' => true, - 'bbcode' => true, - 'jotnets' => true, - 'reset' => t('Reset form') - ]; - - $editor = status_editor($x); - - $o .= replace_macros(get_markup_template('edpost_head.tpl'), [ - '$title' => t('Edit post'), - '$cancel' => '', - '$editor' => $editor - ]); + if (strpos($r['data']['filetype'], 'video') === 0) { + for ($n = 0; $n < 15; $n++) { + $thumb = Linkinfo::get_video_poster($url); + if ($thumb) { + break; + } + sleep(1); + continue; + } - return $o; - } + if ($thumb) { + $s .= "\n\n" . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . "\n\n"; + } else { + $s .= "\n\n" . '[zvideo]' . $url . '[/zvideo]' . "\n\n"; + } + } + if (strpos($r['data']['filetype'], 'audio') === 0) { + $s .= "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n"; + } + if ($r['data']['filetype'] === 'image/svg+xml') { + $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + if ($x) { + $bb = svg2bb($x); + if ($bb) { + $s .= "\n\n" . $bb; + } else { + logger('empty return from svgbb'); + } + } else { + logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + } + } + if ($r['data']['filetype'] === 'text/vnd.abc' && addon_is_installed('abc')) { + $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + if ($x) { + $s .= "\n\n" . '[abc]' . $x . '[/abc]'; + } else { + logger('unable to read ABC data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + } + } + if ($r['data']['filetype'] === 'text/calendar') { + $content = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + if ($content) { + $ev = ical_to_ev($content); + if ($ev) { + $s .= "\n\n" . format_event_bbcode($ev[0]) . "\n\n"; + } + } + } + + $s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; + $_REQUEST['body'] = ((array_key_exists('body', $_REQUEST)) ? $_REQUEST['body'] . $s : $s); + } + + // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables + + if ((!array_key_exists('body', $_REQUEST)) && (array_key_exists('rpost', $_SESSION))) { + $_REQUEST = $_SESSION['rpost']; + unset($_SESSION['rpost']); + } + + if (array_key_exists('channel', $_REQUEST)) { + $r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1", + intval(get_account_id()), + dbesc($_REQUEST['channel']) + ); + if ($r) { + require_once('include/security.php'); + $change = change_channel($r[0]['channel_id']); + } + } + + if ($_REQUEST['remote_return']) { + $_SESSION['remote_return'] = $_REQUEST['remote_return']; + } + + if (argc() > 1 && argv(1) === 'return') { + if ($_SESSION['remote_return']) { + goaway($_SESSION['remote_return']); + } + goaway(z_root() . '/stream'); + } + + $plaintext = true; + + if (array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html' && isset($_REQUEST['body'])) { + require_once('include/html2bbcode.php'); + $_REQUEST['body'] = html2bbcode($_REQUEST['body']); + } + + $channel = App::get_channel(); + + $acl = new AccessControl($channel); + + if (array_key_exists('to', $_REQUEST) && $_REQUEST['to']) { + $acl->set(['allow_cid' => '<' . $_REQUEST['to'] . '>', + 'allow_gid' => EMPTY_STR, + 'deny_cid' => EMPTY_STR, + 'deny_gid' => EMPTY_STR] + ); + } + + $channel_acl = $acl->get(); + + if ($_REQUEST['url']) { + $x = z_fetch_url(z_root() . '/linkinfo?f=&url=' . urlencode($_REQUEST['url']) . '&oembed=1&zotobj=1'); + if ($x['success']) { + $_REQUEST['body'] = $_REQUEST['body'] . $x['body']; + } + } + + if ($_REQUEST['post_id']) { + $_REQUEST['body'] .= '[share=' . intval($_REQUEST['post_id']) . '][/share]'; + } + + $x = [ + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), + 'permissions' => $channel_acl, + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_channel(), + 'title' => $_REQUEST['title'], + 'body' => $_REQUEST['body'], + 'attachment' => $_REQUEST['attachment'], + 'source' => ((x($_REQUEST, 'source')) ? strip_tags($_REQUEST['source']) : ''), + 'return_path' => 'rpost/return', + 'bbco_autocomplete' => 'bbcode', + 'editor_autocomplete' => true, + 'bbcode' => true, + 'jotnets' => true, + 'reset' => t('Reset form') + ]; + + $editor = status_editor($x); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), [ + '$title' => t('Edit post'), + '$cancel' => '', + '$editor' => $editor + ]); + + return $o; + } } diff --git a/Zotlabs/Module/Safe.php b/Zotlabs/Module/Safe.php index 586e79275..12525d045 100644 --- a/Zotlabs/Module/Safe.php +++ b/Zotlabs/Module/Safe.php @@ -4,20 +4,20 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Safe extends Controller { +class Safe extends Controller +{ - function init() { - - $x = get_safemode(); - if ($x) { - $_SESSION['safemode'] = 0; - } - else { - $_SESSION['safemode'] = 1; - } - goaway(z_root()); - } + public function init() + { + $x = get_safemode(); + if ($x) { + $_SESSION['safemode'] = 0; + } else { + $_SESSION['safemode'] = 1; + } + goaway(z_root()); + } } \ No newline at end of file diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php index 83200af07..d8fe3fbda 100644 --- a/Zotlabs/Module/Search.php +++ b/Zotlabs/Module/Search.php @@ -14,340 +14,339 @@ require_once('include/security.php'); require_once('include/conversation.php'); -class Search extends Controller { +class Search extends Controller +{ - // State passed in from the Update module. - - public $profile_uid = 0; - public $loading = 0; - public $updating = 0; + // State passed in from the Update module. + + public $profile_uid = 0; + public $loading = 0; + public $updating = 0; - function init() { - if (x($_REQUEST,'search')) { - App::$data['search'] = escape_tags($_REQUEST['search']); - } - } - - - function get() { - - if ((get_config('system','block_public')) || (get_config('system','block_public_search',1))) { - if ((! local_channel()) && (! remote_channel())) { - notice( t('Public access denied.') . EOL); - return; - } - } - - if ($this->loading) { - $_SESSION['loadtime'] = datetime_convert(); - } - nav_set_selected('Search'); - - $format = (($_REQUEST['format']) ? $_REQUEST['format'] : ''); - if ($format !== '') { - $this->updating = $this->loading = 1; - } - - $observer = App::get_observer(); - $observer_hash = (($observer) ? $observer['xchan_hash'] : ''); - - $o = '' . "\r\n"; - $o .= '
      ' . "\r\n"; - $o .= '

      ' . t('Search') . '

      '; - - if (x(App::$data,'search')) { - $search = trim(App::$data['search']); - } - else { - $search = ((x($_GET,'search')) ? trim(escape_tags(rawurldecode($_GET['search']))) : ''); - } - $tag = false; - if (x($_GET,'tag')) { - $tag = true; - $search = ((x($_GET,'tag')) ? trim(escape_tags(rawurldecode($_GET['tag']))) : ''); - } - - $static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0); - - $o .= search($search,'search-box','/search',((local_channel()) ? true : false)); - - // ActivityStreams object fetches from the navbar - - if (local_channel() && strpos($search,'https://') === 0 && (! $this->updating) && (! $this->loading)) { - logger('searching for ActivityPub'); - $channel = App::get_channel(); - $hash = EMPTY_STR; - $j = Activity::fetch($search,$channel); - if ($j) { - if (isset($j['type']) && ActivityStreams::is_an_actor($j['type'])) { - Activity::actor_store($j['id'],$j); - goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); - } - $AS = new ActivityStreams($j, null, true); - if ($AS->is_valid() && isset($AS->data['type'])) { - if (is_array($AS->obj)) { - // matches Collection and orderedCollection - if (isset($AS->obj['type']) && strpos($AS->obj['type'],'Collection') !== false) { - - // Collections are awkward to process because they can be huge. - // Our strategy is to limit a navbar search to 100 Collection items - // and only fetch the first 10 conversations in the foreground. - // We'll queue the rest, and then send you to a page where - // you can see something we've imported. - // In theory you'll start to see notifications as other conversations - // are fetched in the background while you're looking at the first ones. - - $max = intval(get_config('system','max_imported_search_collection',100)); - - if (intval($max)) { - $obj = new ASCollection($search, $channel, 0, $max); - $messages = $obj->get(); - // logger('received: ' . print_r($messages,true)); - $author = null; - if ($messages) { - logger('received ' . count($messages) . ' items from collection.', LOGGER_DEBUG); - $processed = 0; - foreach ($messages as $message) { - $processed ++; - // only process the first several items in the foreground and - // queue the remainder. - if ($processed > 10) { - - $fetch_url = ((is_string($message)) ? $message : EMPTY_STR); - $fetch_url = ((is_array($message) && array_key_exists('id',$message)) ? $message['id'] : $fetch_url); - - if (! $fetch_url) { - continue; - } - - $hash = new_uuid(); - Queue::insert( - [ - 'hash' => $hash, - 'account_id' => $channel['channel_account_id'], - 'channel_id' => $channel['channel_id'], - 'posturl' => $fetch_url, - 'notify' => EMPTY_STR, - 'msg' => EMPTY_STR, - 'driver' => 'asfetch' - ] - ); - continue; - } - - if (is_string($message)) { - $message = Activity::fetch($message,App::get_channel()); - } - $AS = new ActivityStreams($message,null,true); - if ($AS->is_valid() && is_array($AS->obj)) { - $item = Activity::decode_note($AS,true); - } - if ($item) { - if (! $author) { - $author = $item['author_xchan']; - } - Activity::store(App::get_channel(),get_observer_hash(),$AS,$item, true, true); - } - } - if ($hash) { - Run::Summon( [ 'Deliver', $hash ] ); - } - } - - // This will go to the right place most but not all of the time. - // It will go to a relevant place all of the time, so we'll use it. - - if ($author) { - goaway(z_root() . '/stream/?xchan=' . urlencode($author)); - } - goaway(z_root() . '/stream'); - } - } - else { - - // It wasn't a Collection object and wasn't an Actor object, - // so let's see if it decodes. The boolean flag enables html - // cache of the item - - $item = Activity::decode_note($AS,true); - if ($item) { - Activity::store(App::get_channel(),get_observer_hash(),$AS,$item, true, true); - goaway(z_root() . '/display/' . gen_link_id($item['mid'])); - } - } - } - } - } - } - - if (strpos($search,'#') === 0) { - $tag = true; - $search = substr($search,1); - } - if (strpos($search,'@') === 0) { - $search = substr($search,1); - goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); - } - if (strpos($search,'!') === 0) { - $search = substr($search,1); - goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); - } - if (strpos($search,'?') === 0) { - $search = substr($search,1); - goaway(z_root() . '/help' . '?f=1&navsearch=1&search=' . $search); - } - - // look for a naked webbie - if (strpos($search,'@') !== false && strpos($search,'http') !== 0) { - goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); - } - - if (! $search) { - return $o; - } - - if ($tag) { - $wildtag = str_replace('*','%',$search); - $sql_extra = sprintf(" AND item.id IN (select oid from term where otype = %d and ttype in ( %d , %d) and term like '%s') ", - intval(TERM_OBJ_POST), - intval(TERM_HASHTAG), - intval(TERM_COMMUNITYTAG), - dbesc(protect_sprintf($wildtag)) - ); - } - else { - $regstr = db_getfunc('REGEXP'); - $sql_extra = sprintf(" AND (item.title $regstr '%s' OR item.body $regstr '%s') ", dbesc(protect_sprintf(preg_quote($search))), dbesc(protect_sprintf(preg_quote($search)))); - } - - // Here is the way permissions work in the search module... - // Only public posts can be shown - // OR your own posts if you are a logged in member - // No items will be shown if the member has a blocked profile wall. - - - if ((! $this->updating) && (! $this->loading)) { - - $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 0); + public function init() + { + if (x($_REQUEST, 'search')) { + App::$data['search'] = escape_tags($_REQUEST['search']); + } + } - // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, - // because browser prefetching might change it on us. We have to deliver it with the page. - - $o .= '' . "\r\n"; - $o .= "\r\n"; - - App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), [ - '$baseurl' => z_root(), - '$pgtype' => 'search', - '$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'), - '$gid' => '0', - '$cid' => '0', - '$cmin' => '(-1)', - '$cmax' => '(-1)', - '$star' => '0', - '$liked' => '0', - '$conv' => '0', - '$spam' => '0', - '$fh' => '0', - '$dm' => '0', - '$nouveau' => '0', - '$wall' => '0', - '$draft' => '0', - '$static' => $static, - '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), - '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), - '$search' => (($tag) ? urlencode('#') : '') . $search, - '$xchan' => '', - '$order' => '', - '$file' => '', - '$cats' => '', - '$tags' => '', - '$mid' => '', - '$verb' => '', - '$net' => '', - '$dend' => '', - '$dbegin' => '' - ]); - - - } - - $item_normal = item_normal_search(); - $pub_sql = item_permissions_sql(0,$observer_hash); - - $sys = get_sys_channel(); - - if (($this->updating) && ($this->loading)) { - $itemspage = get_pconfig(local_channel(),'system','itemspage'); - App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - - if ($this->loading) { - $r = null; + public function get() + { - // if logged in locally, first look in the items you own - // and if this returns zero results, resort to searching elsewhere on the site. - // Ideally these results would be merged but this can be difficult - // and results in lots of duplicated content and/or messed up pagination - - if (local_channel()) { - $r = q("SELECT mid, MAX(id) as item_id from item where uid = %d + if ((get_config('system', 'block_public')) || (get_config('system', 'block_public_search', 1))) { + if ((!local_channel()) && (!remote_channel())) { + notice(t('Public access denied.') . EOL); + return; + } + } + + if ($this->loading) { + $_SESSION['loadtime'] = datetime_convert(); + } + nav_set_selected('Search'); + + $format = (($_REQUEST['format']) ? $_REQUEST['format'] : ''); + if ($format !== '') { + $this->updating = $this->loading = 1; + } + + $observer = App::get_observer(); + $observer_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $o = '' . "\r\n"; + $o .= '
      ' . "\r\n"; + $o .= '

      ' . t('Search') . '

      '; + + if (x(App::$data, 'search')) { + $search = trim(App::$data['search']); + } else { + $search = ((x($_GET, 'search')) ? trim(escape_tags(rawurldecode($_GET['search']))) : ''); + } + $tag = false; + if (x($_GET, 'tag')) { + $tag = true; + $search = ((x($_GET, 'tag')) ? trim(escape_tags(rawurldecode($_GET['tag']))) : ''); + } + + $static = ((array_key_exists('static', $_REQUEST)) ? intval($_REQUEST['static']) : 0); + + $o .= search($search, 'search-box', '/search', ((local_channel()) ? true : false)); + + // ActivityStreams object fetches from the navbar + + if (local_channel() && strpos($search, 'https://') === 0 && (!$this->updating) && (!$this->loading)) { + logger('searching for ActivityPub'); + $channel = App::get_channel(); + $hash = EMPTY_STR; + $j = Activity::fetch($search, $channel); + if ($j) { + if (isset($j['type']) && ActivityStreams::is_an_actor($j['type'])) { + Activity::actor_store($j['id'], $j); + goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); + } + $AS = new ActivityStreams($j, null, true); + if ($AS->is_valid() && isset($AS->data['type'])) { + if (is_array($AS->obj)) { + // matches Collection and orderedCollection + if (isset($AS->obj['type']) && strpos($AS->obj['type'], 'Collection') !== false) { + + // Collections are awkward to process because they can be huge. + // Our strategy is to limit a navbar search to 100 Collection items + // and only fetch the first 10 conversations in the foreground. + // We'll queue the rest, and then send you to a page where + // you can see something we've imported. + // In theory you'll start to see notifications as other conversations + // are fetched in the background while you're looking at the first ones. + + $max = intval(get_config('system', 'max_imported_search_collection', 100)); + + if (intval($max)) { + $obj = new ASCollection($search, $channel, 0, $max); + $messages = $obj->get(); + // logger('received: ' . print_r($messages,true)); + $author = null; + if ($messages) { + logger('received ' . count($messages) . ' items from collection.', LOGGER_DEBUG); + $processed = 0; + foreach ($messages as $message) { + $processed++; + // only process the first several items in the foreground and + // queue the remainder. + if ($processed > 10) { + + $fetch_url = ((is_string($message)) ? $message : EMPTY_STR); + $fetch_url = ((is_array($message) && array_key_exists('id', $message)) ? $message['id'] : $fetch_url); + + if (!$fetch_url) { + continue; + } + + $hash = new_uuid(); + Queue::insert( + [ + 'hash' => $hash, + 'account_id' => $channel['channel_account_id'], + 'channel_id' => $channel['channel_id'], + 'posturl' => $fetch_url, + 'notify' => EMPTY_STR, + 'msg' => EMPTY_STR, + 'driver' => 'asfetch' + ] + ); + continue; + } + + if (is_string($message)) { + $message = Activity::fetch($message, App::get_channel()); + } + $AS = new ActivityStreams($message, null, true); + if ($AS->is_valid() && is_array($AS->obj)) { + $item = Activity::decode_note($AS, true); + } + if ($item) { + if (!$author) { + $author = $item['author_xchan']; + } + Activity::store(App::get_channel(), get_observer_hash(), $AS, $item, true, true); + } + } + if ($hash) { + Run::Summon(['Deliver', $hash]); + } + } + + // This will go to the right place most but not all of the time. + // It will go to a relevant place all of the time, so we'll use it. + + if ($author) { + goaway(z_root() . '/stream/?xchan=' . urlencode($author)); + } + goaway(z_root() . '/stream'); + } + } else { + + // It wasn't a Collection object and wasn't an Actor object, + // so let's see if it decodes. The boolean flag enables html + // cache of the item + + $item = Activity::decode_note($AS, true); + if ($item) { + Activity::store(App::get_channel(), get_observer_hash(), $AS, $item, true, true); + goaway(z_root() . '/display/' . gen_link_id($item['mid'])); + } + } + } + } + } + } + + if (strpos($search, '#') === 0) { + $tag = true; + $search = substr($search, 1); + } + if (strpos($search, '@') === 0) { + $search = substr($search, 1); + goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); + } + if (strpos($search, '!') === 0) { + $search = substr($search, 1); + goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); + } + if (strpos($search, '?') === 0) { + $search = substr($search, 1); + goaway(z_root() . '/help' . '?f=1&navsearch=1&search=' . $search); + } + + // look for a naked webbie + if (strpos($search, '@') !== false && strpos($search, 'http') !== 0) { + goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); + } + + if (!$search) { + return $o; + } + + if ($tag) { + $wildtag = str_replace('*', '%', $search); + $sql_extra = sprintf(" AND item.id IN (select oid from term where otype = %d and ttype in ( %d , %d) and term like '%s') ", + intval(TERM_OBJ_POST), + intval(TERM_HASHTAG), + intval(TERM_COMMUNITYTAG), + dbesc(protect_sprintf($wildtag)) + ); + } else { + $regstr = db_getfunc('REGEXP'); + $sql_extra = sprintf(" AND (item.title $regstr '%s' OR item.body $regstr '%s') ", dbesc(protect_sprintf(preg_quote($search))), dbesc(protect_sprintf(preg_quote($search)))); + } + + // Here is the way permissions work in the search module... + // Only public posts can be shown + // OR your own posts if you are a logged in member + // No items will be shown if the member has a blocked profile wall. + + + if ((!$this->updating) && (!$this->loading)) { + + $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 0); + + + // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, + // because browser prefetching might change it on us. We have to deliver it with the page. + + $o .= '' . "\r\n"; + $o .= "\r\n"; + + App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"), [ + '$baseurl' => z_root(), + '$pgtype' => 'search', + '$uid' => ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : '0'), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '(-1)', + '$cmax' => '(-1)', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '0', + '$dm' => '0', + '$nouveau' => '0', + '$wall' => '0', + '$draft' => '0', + '$static' => $static, + '$list' => ((x($_REQUEST, 'list')) ? intval($_REQUEST['list']) : 0), + '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), + '$search' => (($tag) ? urlencode('#') : '') . $search, + '$xchan' => '', + '$order' => '', + '$file' => '', + '$cats' => '', + '$tags' => '', + '$mid' => '', + '$verb' => '', + '$net' => '', + '$dend' => '', + '$dbegin' => '' + ]); + + + } + + $item_normal = item_normal_search(); + $pub_sql = item_permissions_sql(0, $observer_hash); + + $sys = get_sys_channel(); + + if (($this->updating) && ($this->loading)) { + $itemspage = get_pconfig(local_channel(), 'system', 'itemspage'); + App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + + if ($this->loading) { + $r = null; + + // if logged in locally, first look in the items you own + // and if this returns zero results, resort to searching elsewhere on the site. + // Ideally these results would be merged but this can be difficult + // and results in lots of duplicated content and/or messed up pagination + + if (local_channel()) { + $r = q("SELECT mid, MAX(id) as item_id from item where uid = %d $item_normal $sql_extra group by mid, created order by created desc $pager_sql ", - intval(local_channel()) - ); - } - if (! $r) { - $r = q("SELECT mid, MAX(id) as item_id from item WHERE true $pub_sql + intval(local_channel()) + ); + } + if (!$r) { + $r = q("SELECT mid, MAX(id) as item_id from item WHERE true $pub_sql $item_normal $sql_extra group by mid, created order by created desc $pager_sql" - ); - } - if ($r) { - $str = ids_to_querystr($r,'item_id'); - $r = q("select *, id as item_id from item where id in ( " . $str . ") order by created desc "); - } - } - else { - $r = []; - } - - } - - if ($r) { - xchan_query($r); - $items = fetch_post_tags($r,true); - } else { - $items = []; - } + ); + } + if ($r) { + $str = ids_to_querystr($r, 'item_id'); + $r = q("select *, id as item_id from item where id in ( " . $str . ") order by created desc "); + } + } else { + $r = []; + } + + } + + if ($r) { + xchan_query($r); + $items = fetch_post_tags($r, true); + } else { + $items = []; + } + + if ($format == 'json') { + $result = []; + require_once('include/conversation.php'); + foreach ($items as $item) { + $item['html'] = zidify_links(bbcode($item['body'])); + $x = encode_item($item); + $x['html'] = prepare_text($item['body'], $item['mimetype']); + $result[] = $x; + } + json_return_and_die(array('success' => true, 'messages' => $result)); + } + + if ($tag) + $o .= '

      ' . sprintf(t('Items tagged with: %s'), $search) . '

      '; + else + $o .= '

      ' . sprintf(t('Search results for: %s'), $search) . '

      '; + + $o .= conversation($items, 'search', $this->updating, 'client'); + + $o .= '
      '; + + return $o; + } - if ($format == 'json') { - $result = []; - require_once('include/conversation.php'); - foreach ($items as $item) { - $item['html'] = zidify_links(bbcode($item['body'])); - $x = encode_item($item); - $x['html'] = prepare_text($item['body'],$item['mimetype']); - $result[] = $x; - } - json_return_and_die(array('success' => true,'messages' => $result)); - } - - if ($tag) - $o .= '

      ' . sprintf( t('Items tagged with: %s'), $search) . '

      '; - else - $o .= '

      ' . sprintf( t('Search results for: %s'), $search) . '

      '; - - $o .= conversation($items,'search',$this->updating,'client'); - - $o .= '
      '; - - return $o; - } - } diff --git a/Zotlabs/Module/Search_ac.php b/Zotlabs/Module/Search_ac.php index c548d6e47..8073d5bb1 100644 --- a/Zotlabs/Module/Search_ac.php +++ b/Zotlabs/Module/Search_ac.php @@ -6,95 +6,96 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; +class Search_ac extends Controller +{ -class Search_ac extends Controller { + public function init() + { - function init() { + if (!local_channel()) { + killme(); + } - if (! local_channel()) { - killme(); - } - - - $start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0); - $count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 100); - $search = (x($_REQUEST,'search') ? $_REQUEST['search'] : EMPTY_STR); - - if (x($_REQUEST,'query') && strlen($_REQUEST['query'])) { - $search = $_REQUEST['query']; - } - - $do_people = true; - $do_tags = true; - - if (substr($search,0,1) === '@') { - $do_tags = false; - $search = substr($search,1); - } - if (substr($search,0,1) === '#') { - $do_people = false; - $search = substr($search,1); - } + $start = (x($_REQUEST, 'start') ? $_REQUEST['start'] : 0); + $count = (x($_REQUEST, 'count') ? $_REQUEST['count'] : 100); + $search = (x($_REQUEST, 'search') ? $_REQUEST['search'] : EMPTY_STR); - // Priority to people searches - - if ($search) { - $people_sql_extra = protect_sprintf(" AND xchan_name LIKE '%" . dbesc($search) . "%' "); - $tag_sql_extra = protect_sprintf(" AND term LIKE '%" . dbesc($search) . "%' "); - } + if (x($_REQUEST, 'query') && strlen($_REQUEST['query'])) { + $search = $_REQUEST['query']; + } - $results = []; - - if ($do_people) { - $r = q("SELECT abook_id, xchan_name, xchan_photo_s, xchan_url, xchan_addr FROM abook + $do_people = true; + $do_tags = true; + + if (substr($search, 0, 1) === '@') { + $do_tags = false; + $search = substr($search, 1); + } + + if (substr($search, 0, 1) === '#') { + $do_people = false; + $search = substr($search, 1); + } + + // Priority to people searches + + if ($search) { + $people_sql_extra = protect_sprintf(" AND xchan_name LIKE '%" . dbesc($search) . "%' "); + $tag_sql_extra = protect_sprintf(" AND term LIKE '%" . dbesc($search) . "%' "); + } + + $results = []; + + if ($do_people) { + $r = q("SELECT abook_id, xchan_name, xchan_photo_s, xchan_url, xchan_addr FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d $people_sql_extra ORDER BY xchan_name ASC ", - intval(local_channel()) - ); - - if ($r) { - foreach ($r as $g) { - $results[] = [ - 'photo' => $g['xchan_photo_s'], - 'name' => '@' . $g['xchan_name'], - 'id' => $g['abook_id'], - 'link' => $g['xchan_url'], - 'label' => '', - 'nick' => '', - ]; - } - } - } + intval(local_channel()) + ); - if ($do_tags) { - $r = q("select distinct term, tid, url from term + if ($r) { + foreach ($r as $g) { + $results[] = [ + 'photo' => $g['xchan_photo_s'], + 'name' => '@' . $g['xchan_name'], + 'id' => $g['abook_id'], + 'link' => $g['xchan_url'], + 'label' => '', + 'nick' => '', + ]; + } + } + } + + if ($do_tags) { + $r = q("select distinct term, tid, url from term where ttype in ( %d, %d ) $tag_sql_extra group by term order by term asc", - intval(TERM_HASHTAG), - intval(TERM_COMMUNITYTAG) - ); - - if ($r) { - foreach ($r as $g) { - $results[] = [ - 'photo' => z_root() . '/images/hashtag.png', - 'name' => '#' . $g['term'], - 'id' => $g['tid'], - 'link' => $g['url'], - 'label' => '', - 'nick' => '', - ]; - } - } - } + intval(TERM_HASHTAG), + intval(TERM_COMMUNITYTAG) + ); + + if ($r) { + foreach ($r as $g) { + $results[] = [ + 'photo' => z_root() . '/images/hashtag.png', + 'name' => '#' . $g['term'], + 'id' => $g['tid'], + 'link' => $g['url'], + 'label' => '', + 'nick' => '', + ]; + } + } + } + + json_return_and_die([ + 'start' => $start, + 'count' => $count, + 'items' => $results, + ]); + + } - json_return_and_die( [ - 'start' => $start, - 'count' => $count, - 'items' => $results, - ]); - - } - } diff --git a/Zotlabs/Module/Secrets.php b/Zotlabs/Module/Secrets.php index b6f77270a..69b7b7358 100644 --- a/Zotlabs/Module/Secrets.php +++ b/Zotlabs/Module/Secrets.php @@ -6,23 +6,25 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Secrets extends Controller { +class Secrets extends Controller +{ - function get() { + public function get() + { $desc = t('This app allows you to protect messages with a secret passphrase. This only works across selected platforms.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Secrets'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Secrets'))) { return $text; } - $desc = t('This app is installed. A button to encrypt content may be found in the post editor.'); + $desc = t('This app is installed. A button to encrypt content may be found in the post editor.'); - $text = ''; + $text = ''; - return $text; + return $text; - } + } } diff --git a/Zotlabs/Module/Service_limits.php b/Zotlabs/Module/Service_limits.php index 315bf474d..1800bcd5e 100644 --- a/Zotlabs/Module/Service_limits.php +++ b/Zotlabs/Module/Service_limits.php @@ -3,29 +3,27 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; /** @file */ +class Service_limits extends Controller +{ + + public function get() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + $account = App::get_account(); + if ($account['account_service_class']) { + $x = get_config('service_class', $account['account_service_class']); + if ($x) { + $o = print_r($x, true); + return $o; + } + } + return t('No service class restrictions found.'); + } - -class Service_limits extends Controller { - - function get() { - - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - $account = App::get_account(); - if($account['account_service_class']) { - $x = get_config('service_class',$account['account_service_class']); - if($x) { - $o = print_r($x,true); - return $o; - } - } - return t('No service class restrictions found.'); - } - - - } diff --git a/Zotlabs/Module/Settings.php b/Zotlabs/Module/Settings.php index c55cd23b5..9627b83ed 100644 --- a/Zotlabs/Module/Settings.php +++ b/Zotlabs/Module/Settings.php @@ -7,79 +7,82 @@ use Zotlabs\Web\SubModule; require_once('include/security.php'); -class Settings extends Controller { +class Settings extends Controller +{ - private $sm = null; + private $sm = null; - function init() { + public function init() + { - if (! local_channel()) { - return; - } - - if ($_SESSION['delegate']) { - return; - } - - App::$profile_uid = local_channel(); - - // default is channel settings in the absence of other arguments - - if (argc() == 1) { - // We are setting these values - don't use the argc(), argv() functions here - App::$argc = 2; - App::$argv[] = 'channel'; - } + if (!local_channel()) { + return; + } - $this->sm = new SubModule(); - } - - - function post() { - - if (! local_channel()) { - return; - } - - if ($_SESSION['delegate']) { - return; - } - - // logger('mod_settings: ' . print_r($_REQUEST,true)); - - if (argc() > 1) { - if ($this->sm->call('post') !== false) { - return; - } - } - - goaway(z_root() . '/settings' ); - } - - - - function get() { - - nav_set_selected('Settings'); - - if ((! local_channel()) || ($_SESSION['delegate'])) { - notice( t('Permission denied.') . EOL ); - return login(); - } - - - $channel = App::get_channel(); - if ($channel) { - head_set_icon($channel['xchan_photo_s']); - } - - $o = $this->sm->call('get'); - if ($o !== false) { - return $o; - } + if ($_SESSION['delegate']) { + return; + } - $o = EMPTY_STR; - } + App::$profile_uid = local_channel(); + + // default is channel settings in the absence of other arguments + + if (argc() == 1) { + // We are setting these values - don't use the argc(), argv() functions here + App::$argc = 2; + App::$argv[] = 'channel'; + } + + $this->sm = new SubModule(); + } + + + public function post() + { + + if (!local_channel()) { + return; + } + + if ($_SESSION['delegate']) { + return; + } + + // logger('mod_settings: ' . print_r($_REQUEST,true)); + + if (argc() > 1) { + if ($this->sm->call('post') !== false) { + return; + } + } + + goaway(z_root() . '/settings'); + } + + + public function get() + { + + nav_set_selected('Settings'); + + if ((!local_channel()) || ($_SESSION['delegate'])) { + notice(t('Permission denied.') . EOL); + return login(); + } + + + $channel = App::get_channel(); + if ($channel) { + head_set_icon($channel['xchan_photo_s']); + } + + $o = $this->sm->call('get'); + if ($o !== false) { + return $o; + } + + $o = EMPTY_STR; + } } diff --git a/Zotlabs/Module/Settings/Account.php b/Zotlabs/Module/Settings/Account.php index 87a1b96ed..fad65f4e6 100644 --- a/Zotlabs/Module/Settings/Account.php +++ b/Zotlabs/Module/Settings/Account.php @@ -4,112 +4,114 @@ namespace Zotlabs\Module\Settings; use App; -class Account { +class Account +{ - function post() { - check_form_security_token_redirectOnErr('/settings/account', 'settings_account'); - - call_hooks('account_settings_post', $_POST); - - $errs = []; - - $email = ((x($_POST,'email')) ? trim(notags($_POST['email'])) : ''); + public function post() + { + check_form_security_token_redirectOnErr('/settings/account', 'settings_account'); - $account = App::get_account(); - if($email != $account['account_email']) { - if(! validate_email($email)) - $errs[] = t('Not valid email.'); - $adm = trim(get_config('system','admin_email')); - if(($adm) && (strcasecmp($email,$adm) == 0)) { - $errs[] = t('Protected email address. Cannot change to that email.'); - $email = App::$account['account_email']; - } - if(! $errs) { - $r = q("update account set account_email = '%s' where account_id = %d", - dbesc($email), - intval($account['account_id']) - ); - if(! $r) - $errs[] = t('System failure storing new email. Please try again.'); - } - } - - if($errs) { - foreach($errs as $err) - notice($err . EOL); - $errs = []; - } - - - if((x($_POST,'npassword')) || (x($_POST,'confirm'))) { - - $origpass = trim($_POST['origpass']); - - require_once('include/auth.php'); - if(! account_verify_password($email,$origpass)) { - $errs[] = t('Password verification failed.'); - } - - $newpass = trim($_POST['npassword']); - $confirm = trim($_POST['confirm']); - - if($newpass != $confirm ) { - $errs[] = t('Passwords do not match. Password unchanged.'); - } - - if((! x($newpass)) || (! x($confirm))) { - $errs[] = t('Empty passwords are not allowed. Password unchanged.'); - } - - if(! $errs) { - $salt = random_string(32); - $password_encoded = hash('whirlpool', $salt . $newpass); - $r = q("update account set account_salt = '%s', account_password = '%s', account_password_changed = '%s' + call_hooks('account_settings_post', $_POST); + + $errs = []; + + $email = ((x($_POST, 'email')) ? trim(notags($_POST['email'])) : ''); + + $account = App::get_account(); + if ($email != $account['account_email']) { + if (!validate_email($email)) + $errs[] = t('Not valid email.'); + $adm = trim(get_config('system', 'admin_email')); + if (($adm) && (strcasecmp($email, $adm) == 0)) { + $errs[] = t('Protected email address. Cannot change to that email.'); + $email = App::$account['account_email']; + } + if (!$errs) { + $r = q("update account set account_email = '%s' where account_id = %d", + dbesc($email), + intval($account['account_id']) + ); + if (!$r) + $errs[] = t('System failure storing new email. Please try again.'); + } + } + + if ($errs) { + foreach ($errs as $err) + notice($err . EOL); + $errs = []; + } + + + if ((x($_POST, 'npassword')) || (x($_POST, 'confirm'))) { + + $origpass = trim($_POST['origpass']); + + require_once('include/auth.php'); + if (!account_verify_password($email, $origpass)) { + $errs[] = t('Password verification failed.'); + } + + $newpass = trim($_POST['npassword']); + $confirm = trim($_POST['confirm']); + + if ($newpass != $confirm) { + $errs[] = t('Passwords do not match. Password unchanged.'); + } + + if ((!x($newpass)) || (!x($confirm))) { + $errs[] = t('Empty passwords are not allowed. Password unchanged.'); + } + + if (!$errs) { + $salt = random_string(32); + $password_encoded = hash('whirlpool', $salt . $newpass); + $r = q("update account set account_salt = '%s', account_password = '%s', account_password_changed = '%s' where account_id = %d", - dbesc($salt), - dbesc($password_encoded), - dbesc(datetime_convert()), - intval(get_account_id()) - ); - if($r) - info( t('Password changed.') . EOL); - else - $errs[] = t('Password update failed. Please try again.'); - } - } - - - if($errs) { - foreach($errs as $err) - notice($err . EOL); - } - goaway(z_root() . '/settings/account' ); - } - - - - function get() { - $account_settings = ""; - - call_hooks('account_settings', $account_settings); - - $email = App::$account['account_email']; + dbesc($salt), + dbesc($password_encoded), + dbesc(datetime_convert()), + intval(get_account_id()) + ); + if ($r) + info(t('Password changed.') . EOL); + else + $errs[] = t('Password update failed. Please try again.'); + } + } - $tpl = get_markup_template("settings_account.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_account"), - '$title' => t('Account Settings'), - '$origpass' => array('origpass', t('Current Password'), ' ',''), - '$password1'=> array('npassword', t('Enter New Password'), '', ''), - '$password2'=> array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')), - '$submit' => t('Submit'), - '$email' => array('email', t('Email Address:'), $email, ''), - '$removeme' => t('Remove Account'), - '$removeaccount' => t('Remove this account including all its channels'), - '$account_settings' => $account_settings - )); - return $o; - } + if ($errs) { + foreach ($errs as $err) + notice($err . EOL); + } + goaway(z_root() . '/settings/account'); + } + + + public function get() + { + $account_settings = ""; + + call_hooks('account_settings', $account_settings); + + $email = App::$account['account_email']; + + + $tpl = get_markup_template("settings_account.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_account"), + '$title' => t('Account Settings'), + '$origpass' => array('origpass', t('Current Password'), ' ', ''), + '$password1' => array('npassword', t('Enter New Password'), '', ''), + '$password2' => array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')), + '$submit' => t('Submit'), + '$email' => array('email', t('Email Address:'), $email, ''), + '$removeme' => t('Remove Account'), + '$removeaccount' => t('Remove this account including all its channels'), + '$account_settings' => $account_settings + )); + return $o; + } } diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php index 5cdc15418..e7ad638f9 100644 --- a/Zotlabs/Module/Settings/Channel.php +++ b/Zotlabs/Module/Settings/Channel.php @@ -13,723 +13,714 @@ use Zotlabs\Access\AccessControl; use Zotlabs\Daemon\Run; use Zotlabs\Lib\Permcat; -class Channel { +class Channel +{ - function post() { + public function post() + { - $channel = App::get_channel(); + $channel = App::get_channel(); - check_form_security_token_redirectOnErr('/settings', 'settings'); - - call_hooks('settings_post', $_POST); - - $set_perms = ''; - - $role = ((x($_POST,'permissions_role')) ? notags(trim($_POST['permissions_role'])) : ''); - $oldrole = get_pconfig(local_channel(),'system','permissions_role'); + check_form_security_token_redirectOnErr('/settings', 'settings'); - $forbidden_roles = [ 'collection', 'collection_restricted' ]; - if (in_array($role,$forbidden_roles) || in_array($oldrole,$forbidden_roles)) { - $role = $oldrole; - } + call_hooks('settings_post', $_POST); - if(($role != $oldrole) || ($role === 'custom')) { - - if($role === 'custom') { - $hide_presence = (((x($_POST,'hide_presence')) && (intval($_POST['hide_presence']) == 1)) ? 1: 0); - $def_group = ((x($_POST,'group-selection')) ? notags(trim($_POST['group-selection'])) : ''); - $r = q("update channel set channel_default_group = '%s' where channel_id = %d", - dbesc($def_group), - intval(local_channel()) - ); - - $global_perms = Permissions::Perms(); - - foreach($global_perms as $k => $v) { - PermissionLimits::Set(local_channel(),$k,intval($_POST[$k])); - } - $acl = new AccessControl($channel); - $acl->set_from_array($_POST); - $x = $acl->get(); - - $r = q("update channel set channel_allow_cid = '%s', channel_allow_gid = '%s', + $set_perms = ''; + + $role = ((x($_POST, 'permissions_role')) ? notags(trim($_POST['permissions_role'])) : ''); + $oldrole = get_pconfig(local_channel(), 'system', 'permissions_role'); + + $forbidden_roles = ['collection', 'collection_restricted']; + if (in_array($role, $forbidden_roles) || in_array($oldrole, $forbidden_roles)) { + $role = $oldrole; + } + + if (($role != $oldrole) || ($role === 'custom')) { + + if ($role === 'custom') { + $hide_presence = (((x($_POST, 'hide_presence')) && (intval($_POST['hide_presence']) == 1)) ? 1 : 0); + $def_group = ((x($_POST, 'group-selection')) ? notags(trim($_POST['group-selection'])) : ''); + $r = q("update channel set channel_default_group = '%s' where channel_id = %d", + dbesc($def_group), + intval(local_channel()) + ); + + $global_perms = Permissions::Perms(); + + foreach ($global_perms as $k => $v) { + PermissionLimits::Set(local_channel(), $k, intval($_POST[$k])); + } + $acl = new AccessControl($channel); + $acl->set_from_array($_POST); + $x = $acl->get(); + + $r = q("update channel set channel_allow_cid = '%s', channel_allow_gid = '%s', channel_deny_cid = '%s', channel_deny_gid = '%s' where channel_id = %d", - dbesc($x['allow_cid']), - dbesc($x['allow_gid']), - dbesc($x['deny_cid']), - dbesc($x['deny_gid']), - intval(local_channel()) - ); - } - else { - $role_permissions = PermissionRoles::role_perms($_POST['permissions_role']); - if(! $role_permissions) { - notice('Permissions category could not be found.'); - return; - } - $hide_presence = 1 - (intval($role_permissions['online'])); - if($role_permissions['default_collection']) { - $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", - intval(local_channel()), - dbesc( t('Friends') ) - ); - if(! $r) { + dbesc($x['allow_cid']), + dbesc($x['allow_gid']), + dbesc($x['deny_cid']), + dbesc($x['deny_gid']), + intval(local_channel()) + ); + } else { + $role_permissions = PermissionRoles::role_perms($_POST['permissions_role']); + if (!$role_permissions) { + notice('Permissions category could not be found.'); + return; + } + $hide_presence = 1 - (intval($role_permissions['online'])); + if ($role_permissions['default_collection']) { + $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", + intval(local_channel()), + dbesc(t('Friends')) + ); + if (!$r) { - AccessList::add(local_channel(), t('Friends')); - AccessList::member_add(local_channel(),t('Friends'),$channel['channel_hash']); - $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", - intval(local_channel()), - dbesc( t('Friends') ) - ); - } - if($r) { - q("update channel set channel_default_group = '%s', channel_allow_gid = '%s', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d", - dbesc($r[0]['hash']), - dbesc('<' . $r[0]['hash'] . '>'), - intval(local_channel()) - ); - } - else { - notice( sprintf('Default access list \'%s\' not found. Please create and re-submit permission change.', t('Friends')) . EOL); - return; - } - } - // no default permissions - else { - q("update channel set channel_default_group = '', channel_allow_gid = '', channel_allow_cid = '', channel_deny_gid = '', + AccessList::add(local_channel(), t('Friends')); + AccessList::member_add(local_channel(), t('Friends'), $channel['channel_hash']); + $r = q("select hash from pgrp where uid = %d and gname = '%s' limit 1", + intval(local_channel()), + dbesc(t('Friends')) + ); + } + if ($r) { + q("update channel set channel_default_group = '%s', channel_allow_gid = '%s', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d", + dbesc($r[0]['hash']), + dbesc('<' . $r[0]['hash'] . '>'), + intval(local_channel()) + ); + } else { + notice(sprintf('Default access list \'%s\' not found. Please create and re-submit permission change.', t('Friends')) . EOL); + return; + } + } // no default permissions + else { + q("update channel set channel_default_group = '', channel_allow_gid = '', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d", - intval(local_channel()) - ); - } + intval(local_channel()) + ); + } - if($role_permissions['perms_connect']) { - $x = Permissions::FilledPerms($role_permissions['perms_connect']); - $str = Permissions::serialise($x); - set_abconfig(local_channel(),$channel['channel_hash'],'system','my_perms',$str); + if ($role_permissions['perms_connect']) { + $x = Permissions::FilledPerms($role_permissions['perms_connect']); + $str = Permissions::serialise($x); + set_abconfig(local_channel(), $channel['channel_hash'], 'system', 'my_perms', $str); - $autoperms = intval($role_permissions['perms_auto']); - } + $autoperms = intval($role_permissions['perms_auto']); + } - if($role_permissions['limits']) { - foreach($role_permissions['limits'] as $k => $v) { - PermissionLimits::Set(local_channel(),$k,$v); - } - } - if(array_key_exists('directory_publish',$role_permissions)) { - $publish = intval($role_permissions['directory_publish']); - } - } - - set_pconfig(local_channel(),'system','hide_online_status',$hide_presence); - set_pconfig(local_channel(),'system','permissions_role',$role); - } + if ($role_permissions['limits']) { + foreach ($role_permissions['limits'] as $k => $v) { + PermissionLimits::Set(local_channel(), $k, $v); + } + } + if (array_key_exists('directory_publish', $role_permissions)) { + $publish = intval($role_permissions['directory_publish']); + } + } - // The post_comments permission is critical to privacy so we always allow you to set it, no matter what - // permission role is in place. - - $post_comments = array_key_exists('post_comments',$_POST) ? intval($_POST['post_comments']) : PERMS_SPECIFIC; - PermissionLimits::Set(local_channel(),'post_comments',$post_comments); + set_pconfig(local_channel(), 'system', 'hide_online_status', $hide_presence); + set_pconfig(local_channel(), 'system', 'permissions_role', $role); + } - $post_mail = array_key_exists('post_mail',$_POST) ? intval($_POST['post_mail']) : PERMS_SPECIFIC; - PermissionLimits::Set(local_channel(),'post_mail',$post_mail); + // The post_comments permission is critical to privacy so we always allow you to set it, no matter what + // permission role is in place. + + $post_comments = array_key_exists('post_comments', $_POST) ? intval($_POST['post_comments']) : PERMS_SPECIFIC; + PermissionLimits::Set(local_channel(), 'post_comments', $post_comments); + + $post_mail = array_key_exists('post_mail', $_POST) ? intval($_POST['post_mail']) : PERMS_SPECIFIC; + PermissionLimits::Set(local_channel(), 'post_mail', $post_mail); + $publish = (((x($_POST, 'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1 : 0); + $username = ((x($_POST, 'username')) ? escape_tags(trim($_POST['username'])) : ''); + $timezone = ((x($_POST, 'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); + $defloc = ((x($_POST, 'defloc')) ? notags(trim($_POST['defloc'])) : ''); + $openid = ((x($_POST, 'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); + $maxreq = ((x($_POST, 'maxreq')) ? intval($_POST['maxreq']) : 0); + $expire = ((x($_POST, 'expire')) ? intval($_POST['expire']) : 0); + $evdays = ((x($_POST, 'evdays')) ? intval($_POST['evdays']) : 3); + $photo_path = ((x($_POST, 'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : ''); + $attach_path = ((x($_POST, 'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : ''); + $noindex = ((x($_POST, 'noindex')) ? intval($_POST['noindex']) : 0); + $channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']), ENT_QUOTES) : ''); - $publish = (((x($_POST,'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0); - $username = ((x($_POST,'username')) ? escape_tags(trim($_POST['username'])) : ''); - $timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); - $defloc = ((x($_POST,'defloc')) ? notags(trim($_POST['defloc'])) : ''); - $openid = ((x($_POST,'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); - $maxreq = ((x($_POST,'maxreq')) ? intval($_POST['maxreq']) : 0); - $expire = ((x($_POST,'expire')) ? intval($_POST['expire']) : 0); - $evdays = ((x($_POST,'evdays')) ? intval($_POST['evdays']) : 3); - $photo_path = ((x($_POST,'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : ''); - $attach_path = ((x($_POST,'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : ''); - $noindex = ((x($_POST,'noindex')) ? intval($_POST['noindex']) : 0); - $channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : ''); - - $expire_items = ((x($_POST,'expire_items')) ? intval($_POST['expire_items']) : 0); - $expire_starred = ((x($_POST,'expire_starred')) ? intval($_POST['expire_starred']) : 0); - $expire_photos = ((x($_POST,'expire_photos'))? intval($_POST['expire_photos']) : 0); - $expire_network_only = ((x($_POST,'expire_network_only'))? intval($_POST['expire_network_only']) : 0); - - $allow_location = (((x($_POST,'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1: 0); - - $blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted! - $unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0); - $cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0); - $suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0); + $expire_items = ((x($_POST, 'expire_items')) ? intval($_POST['expire_items']) : 0); + $expire_starred = ((x($_POST, 'expire_starred')) ? intval($_POST['expire_starred']) : 0); + $expire_photos = ((x($_POST, 'expire_photos')) ? intval($_POST['expire_photos']) : 0); + $expire_network_only = ((x($_POST, 'expire_network_only')) ? intval($_POST['expire_network_only']) : 0); + + $allow_location = (((x($_POST, 'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1 : 0); + + $blocktags = (((x($_POST, 'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0 : 1); // this setting is inverted! + $unkmail = (((x($_POST, 'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1 : 0); + $cntunkmail = ((x($_POST, 'cntunkmail')) ? intval($_POST['cntunkmail']) : 0); + $suggestme = ((x($_POST, 'suggestme')) ? intval($_POST['suggestme']) : 0); // $anymention = ((x($_POST,'anymention')) ? intval($_POST['anymention']) : 0); - $hyperdrive = ((x($_POST,'hyperdrive')) ? intval($_POST['hyperdrive']) : 0); - $activitypub = ((x($_POST,'activitypub')) ? intval($_POST['activitypub']) : 0); - $tag_username = ((x($_POST,'tag_username')) ? intval($_POST['tag_username']) : 0); - $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0); - $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0); - $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0); - $adult = (($_POST['adult'] == 1) ? 1 : 0); - $defpermcat = ((x($_POST,'defpermcat')) ? notags(trim($_POST['defpermcat'])) : 'default'); + $hyperdrive = ((x($_POST, 'hyperdrive')) ? intval($_POST['hyperdrive']) : 0); + $activitypub = ((x($_POST, 'activitypub')) ? intval($_POST['activitypub']) : 0); + $tag_username = ((x($_POST, 'tag_username')) ? intval($_POST['tag_username']) : 0); + $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1 : 0); + $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1 : 0); + $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1 : 0); + $adult = (($_POST['adult'] == 1) ? 1 : 0); + $defpermcat = ((x($_POST, 'defpermcat')) ? notags(trim($_POST['defpermcat'])) : 'default'); - $hide_friends = 1 - intval($_POST['hide_friends']); + $hide_friends = 1 - intval($_POST['hide_friends']); - $cal_first_day = (((x($_POST,'first_day')) && intval($_POST['first_day']) >= 0 && intval($_POST['first_day']) < 7) ? intval($_POST['first_day']) : 0); - $mailhost = ((array_key_exists('mailhost',$_POST)) ? notags(trim($_POST['mailhost'])) : ''); - $profile_assign = ((x($_POST,'profile_assign')) ? notags(trim($_POST['profile_assign'])) : ''); - $permit_all_mentions = (($_POST['permit_all_mentions'] == 1) ? 1: 0); - $close_comment_days = (($_POST['close_comments']) ? intval($_POST['close_comments']) : 0); - if ($close_comment_days) { - set_pconfig(local_channel(),'system','close_comments', $close_comment_days . ' days'); - } - else { - set_pconfig(local_channel(),'system','close_comments', EMPTY_STR); - } - // allow a permission change to over-ride the autoperms setting from the form + $cal_first_day = (((x($_POST, 'first_day')) && intval($_POST['first_day']) >= 0 && intval($_POST['first_day']) < 7) ? intval($_POST['first_day']) : 0); + $mailhost = ((array_key_exists('mailhost', $_POST)) ? notags(trim($_POST['mailhost'])) : ''); + $profile_assign = ((x($_POST, 'profile_assign')) ? notags(trim($_POST['profile_assign'])) : ''); + $permit_all_mentions = (($_POST['permit_all_mentions'] == 1) ? 1 : 0); + $close_comment_days = (($_POST['close_comments']) ? intval($_POST['close_comments']) : 0); + if ($close_comment_days) { + set_pconfig(local_channel(), 'system', 'close_comments', $close_comment_days . ' days'); + } else { + set_pconfig(local_channel(), 'system', 'close_comments', EMPTY_STR); + } + // allow a permission change to over-ride the autoperms setting from the form - if(! isset($autoperms)) { - $autoperms = ((x($_POST,'autoperms')) ? intval($_POST['autoperms']) : 0); - } + if (!isset($autoperms)) { + $autoperms = ((x($_POST, 'autoperms')) ? intval($_POST['autoperms']) : 0); + } - $pageflags = $channel['channel_pageflags']; - $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); - if($adult != $existing_adult) - $pageflags = ($pageflags ^ PAGE_ADULT); - - - $notify = 0; - - if(x($_POST,'notify1')) - $notify += intval($_POST['notify1']); - if(x($_POST,'notify2')) - $notify += intval($_POST['notify2']); - if(x($_POST,'notify3')) - $notify += intval($_POST['notify3']); - if(x($_POST,'notify4')) - $notify += intval($_POST['notify4']); - if(x($_POST,'notify5')) - $notify += intval($_POST['notify5']); - if(x($_POST,'notify6')) - $notify += intval($_POST['notify6']); - if(x($_POST,'notify7')) - $notify += intval($_POST['notify7']); - if(x($_POST,'notify8')) - $notify += intval($_POST['notify8']); - if(x($_POST,'notify10')) - $notify += intval($_POST['notify10']); - - - $vnotify = 0; - - if(x($_POST,'vnotify1')) - $vnotify += intval($_POST['vnotify1']); - if(x($_POST,'vnotify2')) - $vnotify += intval($_POST['vnotify2']); - if(x($_POST,'vnotify3')) - $vnotify += intval($_POST['vnotify3']); - if(x($_POST,'vnotify4')) - $vnotify += intval($_POST['vnotify4']); - if(x($_POST,'vnotify5')) - $vnotify += intval($_POST['vnotify5']); - if(x($_POST,'vnotify6')) - $vnotify += intval($_POST['vnotify6']); - if(x($_POST,'vnotify7')) - $vnotify += intval($_POST['vnotify7']); - if(x($_POST,'vnotify8')) - $vnotify += intval($_POST['vnotify8']); - if(x($_POST,'vnotify9')) - $vnotify += intval($_POST['vnotify9']); - if(x($_POST,'vnotify10')) - $vnotify += intval($_POST['vnotify10']); - if(x($_POST,'vnotify11') && is_site_admin()) - $vnotify += intval($_POST['vnotify11']); - if(x($_POST,'vnotify12')) - $vnotify += intval($_POST['vnotify12']); - if(x($_POST,'vnotify13')) - $vnotify += intval($_POST['vnotify13']); - if(x($_POST,'vnotify14')) - $vnotify += intval($_POST['vnotify14']); - if(x($_POST,'vnotify15')) - $vnotify += intval($_POST['vnotify15']); - if(x($_POST,'vnotify16')) - $vnotify += intval($_POST['vnotify16']); - - $always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0; - - $err = ''; - - $name_change = false; - - if($username != $channel['channel_name']) { - $name_change = true; - require_once('include/channel.php'); - $err = validate_channelname($username); - if($err) { - notice($err); - return; - } - } - - if($timezone != $channel['channel_timezone']) { - if(strlen($timezone)) - date_default_timezone_set($timezone); - } + $pageflags = $channel['channel_pageflags']; + $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); + if ($adult != $existing_adult) + $pageflags = ($pageflags ^ PAGE_ADULT); - $followed_tags = $_POST['followed_tags']; - $ntags = []; - if ($followed_tags) { - $tags = explode(',', $followed_tags); - foreach ($tags as $t) { - $t = trim($t); - if ($t) { - $ntags[] = $t; - } - } - } + $notify = 0; - set_pconfig(local_channel(),'system','followed_tags',($ntags) ? $ntags : EMPTY_STR); - set_pconfig(local_channel(),'system','use_browser_location',$allow_location); - set_pconfig(local_channel(),'system','suggestme', $suggestme); - set_pconfig(local_channel(),'system','post_newfriend', $post_newfriend); - set_pconfig(local_channel(),'system','post_joingroup', $post_joingroup); - set_pconfig(local_channel(),'system','post_profilechange', $post_profilechange); - set_pconfig(local_channel(),'system','blocktags',$blocktags); - set_pconfig(local_channel(),'system','channel_menu',$channel_menu); - set_pconfig(local_channel(),'system','vnotify',$vnotify); - set_pconfig(local_channel(),'system','always_show_in_notices',$always_show_in_notices); - set_pconfig(local_channel(),'system','evdays',$evdays); - set_pconfig(local_channel(),'system','photo_path',$photo_path); - set_pconfig(local_channel(),'system','attach_path',$attach_path); - set_pconfig(local_channel(),'system','cal_first_day',$cal_first_day); - set_pconfig(local_channel(),'system','default_permcat',$defpermcat); - set_pconfig(local_channel(),'system','email_notify_host',$mailhost); - set_pconfig(local_channel(),'system','profile_assign',$profile_assign); + if (x($_POST, 'notify1')) + $notify += intval($_POST['notify1']); + if (x($_POST, 'notify2')) + $notify += intval($_POST['notify2']); + if (x($_POST, 'notify3')) + $notify += intval($_POST['notify3']); + if (x($_POST, 'notify4')) + $notify += intval($_POST['notify4']); + if (x($_POST, 'notify5')) + $notify += intval($_POST['notify5']); + if (x($_POST, 'notify6')) + $notify += intval($_POST['notify6']); + if (x($_POST, 'notify7')) + $notify += intval($_POST['notify7']); + if (x($_POST, 'notify8')) + $notify += intval($_POST['notify8']); + if (x($_POST, 'notify10')) + $notify += intval($_POST['notify10']); + + + $vnotify = 0; + + if (x($_POST, 'vnotify1')) + $vnotify += intval($_POST['vnotify1']); + if (x($_POST, 'vnotify2')) + $vnotify += intval($_POST['vnotify2']); + if (x($_POST, 'vnotify3')) + $vnotify += intval($_POST['vnotify3']); + if (x($_POST, 'vnotify4')) + $vnotify += intval($_POST['vnotify4']); + if (x($_POST, 'vnotify5')) + $vnotify += intval($_POST['vnotify5']); + if (x($_POST, 'vnotify6')) + $vnotify += intval($_POST['vnotify6']); + if (x($_POST, 'vnotify7')) + $vnotify += intval($_POST['vnotify7']); + if (x($_POST, 'vnotify8')) + $vnotify += intval($_POST['vnotify8']); + if (x($_POST, 'vnotify9')) + $vnotify += intval($_POST['vnotify9']); + if (x($_POST, 'vnotify10')) + $vnotify += intval($_POST['vnotify10']); + if (x($_POST, 'vnotify11') && is_site_admin()) + $vnotify += intval($_POST['vnotify11']); + if (x($_POST, 'vnotify12')) + $vnotify += intval($_POST['vnotify12']); + if (x($_POST, 'vnotify13')) + $vnotify += intval($_POST['vnotify13']); + if (x($_POST, 'vnotify14')) + $vnotify += intval($_POST['vnotify14']); + if (x($_POST, 'vnotify15')) + $vnotify += intval($_POST['vnotify15']); + if (x($_POST, 'vnotify16')) + $vnotify += intval($_POST['vnotify16']); + + $always_show_in_notices = x($_POST, 'always_show_in_notices') ? 1 : 0; + + $err = ''; + + $name_change = false; + + if ($username != $channel['channel_name']) { + $name_change = true; + require_once('include/channel.php'); + $err = validate_channelname($username); + if ($err) { + notice($err); + return; + } + } + + if ($timezone != $channel['channel_timezone']) { + if (strlen($timezone)) + date_default_timezone_set($timezone); + } + + + $followed_tags = $_POST['followed_tags']; + $ntags = []; + if ($followed_tags) { + $tags = explode(',', $followed_tags); + foreach ($tags as $t) { + $t = trim($t); + if ($t) { + $ntags[] = $t; + } + } + } + + set_pconfig(local_channel(), 'system', 'followed_tags', ($ntags) ? $ntags : EMPTY_STR); + set_pconfig(local_channel(), 'system', 'use_browser_location', $allow_location); + set_pconfig(local_channel(), 'system', 'suggestme', $suggestme); + set_pconfig(local_channel(), 'system', 'post_newfriend', $post_newfriend); + set_pconfig(local_channel(), 'system', 'post_joingroup', $post_joingroup); + set_pconfig(local_channel(), 'system', 'post_profilechange', $post_profilechange); + set_pconfig(local_channel(), 'system', 'blocktags', $blocktags); + set_pconfig(local_channel(), 'system', 'channel_menu', $channel_menu); + set_pconfig(local_channel(), 'system', 'vnotify', $vnotify); + set_pconfig(local_channel(), 'system', 'always_show_in_notices', $always_show_in_notices); + set_pconfig(local_channel(), 'system', 'evdays', $evdays); + set_pconfig(local_channel(), 'system', 'photo_path', $photo_path); + set_pconfig(local_channel(), 'system', 'attach_path', $attach_path); + set_pconfig(local_channel(), 'system', 'cal_first_day', $cal_first_day); + set_pconfig(local_channel(), 'system', 'default_permcat', $defpermcat); + set_pconfig(local_channel(), 'system', 'email_notify_host', $mailhost); + set_pconfig(local_channel(), 'system', 'profile_assign', $profile_assign); // set_pconfig(local_channel(),'system','anymention',$anymention); - set_pconfig(local_channel(),'system','hyperdrive',$hyperdrive); - set_pconfig(local_channel(),'system','activitypub',$activitypub); - set_pconfig(local_channel(),'system','autoperms',$autoperms); - set_pconfig(local_channel(),'system','tag_username',$tag_username); - set_pconfig(local_channel(),'system','permit_all_mentions',$permit_all_mentions); - set_pconfig(local_channel(),'system','noindex',$noindex); - - - $r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d", - dbesc($username), - intval($pageflags), - dbesc($timezone), - dbesc($defloc), - intval($notify), - intval($unkmail), - intval($maxreq), - intval($expire), - intval(local_channel()) - ); - if($r) - info( t('Settings updated.') . EOL); - - - $r = q("UPDATE profile SET publish = %d, hide_friends = %d WHERE is_default = 1 AND uid = %d", - intval($publish), - intval($hide_friends), - intval(local_channel()) - ); - $r = q("UPDATE xchan SET xchan_hidden = %d WHERE xchan_hash = '%s'", - intval(1 - $publish), - intval($channel['channel_hash']) - ); - - if ($name_change) { - // catch xchans for all protocols by matching the url - $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'", - dbesc($username), - dbesc(datetime_convert()), - dbesc(z_root() . '/channel/' . $channel['channel_address']) - ); - $r = q("update profile set fullname = '%s' where uid = %d and is_default = 1", - dbesc($username), - intval($channel['channel_id']) - ); - if (is_sys_channel($channel['channel_id'])) { - set_config('system','sitename', $username); - } - } - - Run::Summon( [ 'Directory', local_channel() ] ); - - Libsync::build_sync_packet(); - - - if($email_changed && App::$config['system']['register_policy'] == REGISTER_VERIFY) { - - // FIXME - set to un-verified, blocked and redirect to logout - // Q: Why? Are we verifying people or email addresses? - // A: the policy is to verify email addresses - } - - goaway(z_root() . '/settings' ); - return; // NOTREACHED - } - - function get() { - - require_once('include/acl_selectors.php'); - require_once('include/permissions.php'); + set_pconfig(local_channel(), 'system', 'hyperdrive', $hyperdrive); + set_pconfig(local_channel(), 'system', 'activitypub', $activitypub); + set_pconfig(local_channel(), 'system', 'autoperms', $autoperms); + set_pconfig(local_channel(), 'system', 'tag_username', $tag_username); + set_pconfig(local_channel(), 'system', 'permit_all_mentions', $permit_all_mentions); + set_pconfig(local_channel(), 'system', 'noindex', $noindex); - $yes_no = [ t('No'), t('Yes') ]; - - - $p = q("SELECT * FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1", - intval(local_channel()) - ); - if(count($p)) - $profile = $p[0]; - - load_pconfig(local_channel(),'expire'); - - $channel = App::get_channel(); - - $global_perms = Permissions::Perms(); - - $permiss = []; - - $perm_opts = [ - [ t('Restricted - from connections only'), PERMS_SPECIFIC ], - [ t('Semi-public - from anybody that can be identified'), PERMS_AUTHED ], - [ t('Public - from anybody on the internet'), PERMS_PUBLIC ] - ]; - - $limits = PermissionLimits::Get(local_channel()); - $anon_comments = get_config('system','anonymous_comments'); - - foreach($global_perms as $k => $perm) { - $options = []; - $can_be_public = ((strstr($k,'view') || ($k === 'post_comments' && $anon_comments)) ? true : false); - foreach($perm_opts as $opt) { - if($opt[1] == PERMS_PUBLIC && (! $can_be_public)) - continue; - $options[$opt[1]] = $opt[0]; - } - if($k === 'post_comments') { - $comment_perms = [ $k, $perm, $limits[$k],'',$options ]; - } - elseif ($k === 'post_mail') { - $mail_perms = [ $k, $perm, $limits[$k],'',$options ]; - } - else { - $permiss[] = array($k,$perm,$limits[$k],'',$options); - } - } - - // logger('permiss: ' . print_r($permiss,true)); - - $username = $channel['channel_name']; - $nickname = $channel['channel_address']; - $timezone = $channel['channel_timezone']; - $notify = $channel['channel_notifyflags']; - $defloc = $channel['channel_location']; - - $maxreq = $channel['channel_max_friend_req']; - $expire = $channel['channel_expire_days']; - $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); - $sys_expire = get_config('system','default_expire_days'); - - $hide_presence = intval(get_pconfig(local_channel(), 'system','hide_online_status')); - - $expire_items = get_pconfig(local_channel(), 'expire','items'); - $expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1 - - $expire_notes = get_pconfig(local_channel(), 'expire','notes'); - $expire_notes = (($expire_notes===false)? '1' : $expire_notes); // default if not set: 1 - - $expire_starred = get_pconfig(local_channel(), 'expire','starred'); - $expire_starred = (($expire_starred===false)? '1' : $expire_starred); // default if not set: 1 - - - $expire_photos = get_pconfig(local_channel(), 'expire','photos'); - $expire_photos = (($expire_photos===false)? '0' : $expire_photos); // default if not set: 0 - - $expire_network_only = get_pconfig(local_channel(), 'expire','network_only'); - $expire_network_only = (($expire_network_only===false)? '0' : $expire_network_only); // default if not set: 0 - - - $suggestme = get_pconfig(local_channel(), 'system','suggestme'); - $suggestme = (($suggestme===false)? '0': $suggestme); // default if not set: 0 - - $post_newfriend = get_pconfig(local_channel(), 'system','post_newfriend'); - $post_newfriend = (($post_newfriend===false)? '0': $post_newfriend); // default if not set: 0 - - $post_joingroup = get_pconfig(local_channel(), 'system','post_joingroup'); - $post_joingroup = (($post_joingroup===false)? '0': $post_joingroup); // default if not set: 0 - - $post_profilechange = get_pconfig(local_channel(), 'system','post_profilechange'); - $post_profilechange = (($post_profilechange===false)? '0': $post_profilechange); // default if not set: 0 - - $blocktags = get_pconfig(local_channel(),'system','blocktags'); - $blocktags = (($blocktags===false) ? '0' : $blocktags); - - $timezone = date_default_timezone_get(); - - $opt_tpl = get_markup_template("field_checkbox.tpl"); - if(get_config('system','publish_all')) { - $profile_in_dir = ''; - } - else { - $profile_in_dir = replace_macros($opt_tpl,array( - '$field' => array('profile_in_directory', t('Publish your profile in the network directory'), $profile['publish'], '', $yes_no), - )); - } - - $suggestme = replace_macros($opt_tpl,array( - '$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no), - - )); - - $subdir = ((strlen(App::get_path())) ? '
      ' . t('or') . ' ' . z_root() . '/channel/' . $nickname : ''); - - $webbie = $nickname . '@' . App::get_hostname(); - $intl_nickname = unpunify($nickname) . '@' . unpunify(App::get_hostname()); - - $prof_addr = replace_macros(get_markup_template('channel_settings_header.tpl'),array( - '$desc' => t('Your channel address is'), - '$nickname' => (($intl_nickname === $webbie) ? $webbie : $intl_nickname . ' (' . $webbie . ')'), - '$compat' => t('Friends using compatible applications can use this address to connect with you.'), - '$subdir' => $subdir, - '$davdesc' => t('Your files/photos are accessible as a network drive at'), - '$davpath' => z_root() . '/dav/' . $nickname, - '$windows' => t('(Windows)'), - '$other' => t('(other platforms)'), - '$or' => t('or'), - '$davspath' => 'davs://' . App::get_hostname() . '/dav/' . $nickname, - '$basepath' => App::get_hostname() - )); + $r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d", + dbesc($username), + intval($pageflags), + dbesc($timezone), + dbesc($defloc), + intval($notify), + intval($unkmail), + intval($maxreq), + intval($expire), + intval(local_channel()) + ); + if ($r) + info(t('Settings updated.') . EOL); - $pcat = new Permcat(local_channel()); - $pcatlist = $pcat->listing(); - $permcats = []; - if($pcatlist) { - foreach($pcatlist as $pc) { - $permcats[$pc['name']] = $pc['localname']; - } - } + $r = q("UPDATE profile SET publish = %d, hide_friends = %d WHERE is_default = 1 AND uid = %d", + intval($publish), + intval($hide_friends), + intval(local_channel()) + ); + $r = q("UPDATE xchan SET xchan_hidden = %d WHERE xchan_hash = '%s'", + intval(1 - $publish), + intval($channel['channel_hash']) + ); - $default_permcat = get_pconfig(local_channel(),'system','default_permcat','default'); + if ($name_change) { + // catch xchans for all protocols by matching the url + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'", + dbesc($username), + dbesc(datetime_convert()), + dbesc(z_root() . '/channel/' . $channel['channel_address']) + ); + $r = q("update profile set fullname = '%s' where uid = %d and is_default = 1", + dbesc($username), + intval($channel['channel_id']) + ); + if (is_sys_channel($channel['channel_id'])) { + set_config('system', 'sitename', $username); + } + } - - $acl = new AccessControl($channel); - $perm_defaults = $acl->get(); - - $group_select = AccessList::select(local_channel(),$channel['channel_default_group']); - - require_once('include/menu.php'); - $m1 = menu_list(local_channel()); - $menu = false; - if($m1) { - $menu = []; - $current = get_pconfig(local_channel(),'system','channel_menu'); - $menu[] = array('name' => '', 'selected' => ((! $current) ? true : false)); - foreach($m1 as $m) { - $menu[] = array('name' => htmlspecialchars($m['menu_name'],ENT_COMPAT,'UTF-8'), 'selected' => (($m['menu_name'] === $current) ? ' selected="selected" ' : false)); - } - } - - $evdays = get_pconfig(local_channel(),'system','evdays'); - if(! $evdays) - $evdays = 3; - - $permissions_role = get_pconfig(local_channel(),'system','permissions_role'); - if(! $permissions_role) - $permissions_role = 'custom'; + Run::Summon(['Directory', local_channel()]); - if(in_array($permissions_role,['forum','repository'])) { - $autoperms = replace_macros(get_markup_template('field_checkbox.tpl'), [ - '$field' => [ 'autoperms',t('Automatic membership approval'), ((get_pconfig(local_channel(),'system','autoperms',0)) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no ]]); - } - else { - $autoperms = ''; - } - - $hyperdrive = [ 'hyperdrive', t('Friend-of-friend conversations'), ((get_pconfig(local_channel(),'system','hyperdrive',true)) ? 1 : 0), t('Import public third-party conversations in which your connections participate.'), $yes_no ]; - - if (get_config('system','activitypub', ACTIVITYPUB_ENABLED)) { - $apconfig = true; - $activitypub = replace_macros(get_markup_template('field_checkbox.tpl'), [ '$field' => [ 'activitypub', t('Enable ActivityPub protocol'), ((get_pconfig(local_channel(),'system','activitypub', ACTIVITYPUB_ENABLED)) ? 1 : 0), t('ActivityPub is an emerging internet standard for social communications'), $yes_no ]]); - } - else { - $apconfig = false; - $activitypub = '' . EOL; - } - - $permissions_set = (($permissions_role != 'custom') ? true : false); - - $perm_roles = PermissionRoles::roles(); - // Don't permit changing to a collection (@TODO unless there is a mechanism to select the channel_parent) - unset($perm_roles['Collection']); - - - $vnotify = get_pconfig(local_channel(),'system','vnotify'); - $always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices'); - if($vnotify === false) - $vnotify = (-1); - - $plugin = [ 'basic' => '', 'security' => '', 'notify' => '', 'misc' => '' ]; - call_hooks('channel_settings',$plugin); - - $public_stream_mode = intval(get_config('system','public_stream_mode', PUBLIC_STREAM_NONE)); - - $ft = get_pconfig(local_channel(),'system','followed_tags',''); - if ($ft && is_array($ft)) { - $followed = implode(',', $ft); - } - else { - $followed = EMPTY_STR; - } + Libsync::build_sync_packet(); + if ($email_changed && App::$config['system']['register_policy'] == REGISTER_VERIFY) { - $o .= replace_macros(get_markup_template('settings.tpl'), [ - '$ptitle' => t('Channel Settings'), - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$uid' => local_channel(), - '$form_security_token' => get_form_security_token("settings"), - '$nickname_block' => $prof_addr, - '$h_basic' => t('Basic Settings'), - '$username' => array('username', t('Full name'), $username,''), - '$email' => array('email', t('Email Address'), $email, ''), - '$timezone' => array('timezone_select' , t('Your timezone'), $timezone, t('This is important for showing the correct time on shared events'), get_timezones()), - '$defloc' => array('defloc', t('Default post location'), $defloc, t('Optional geographical location to display on your posts')), - '$allowloc' => array('allow_location', t('Obtain post location from your web browser or device'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no), - - '$adult' => array('adult', t('Adult content'), $adult_flag, t('Enable to indicate if this channel frequently or regularly publishes adult content. (Please also tag any adult material and/or nudity with #NSFW)'), $yes_no), - - '$h_prv' => t('Security and Privacy'), - '$permissions_set' => $permissions_set, - '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), - - '$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), - '$hidefriends' => array('hide_friends', t('Allow others to view your friends and connections'), 1 - intval($profile['hide_friends']), '', $yes_no ), - '$permiss_arr' => $permiss, - '$comment_perms' => $comment_perms, - '$mail_perms' => $mail_perms, - '$noindex' => [ 'noindex', t('Forbid indexing of your channel content by search engines'), get_pconfig($channel['channel_id'],'system','noindex'), '', $yes_no], - '$close_comments' => [ 'close_comments', t('Disable acceptance of comments on my posts after this many days'), ((intval(get_pconfig(local_channel(),'system','close_comments'))) ? intval(get_pconfig(local_channel(),'system','close_comments')) : EMPTY_STR), t('Leave unset or enter 0 to allow comments indefinitely') ], - '$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no), - - '$lbl_p2macro' => t('Channel Permission Limits'), - - '$expire' => array('expire',t('Expire conversations you have not participated in after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not provide an expiration policy.')) . ' ' . t('The website limit takes precedence if lower than your limit.')), - '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')), - '$permissions' => t('Default Access List'), - '$permdesc' => t("(click to open/close)"), - '$aclselect' => populate_acl($perm_defaults, false, PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))), - '$profseltxt' => t('Profile to assign new connections'), - '$profselect' => ((feature_enabled(local_channel(),'multi_profiles')) ? contact_profile_assign(get_pconfig(local_channel(),'system','profile_assign','')) : ''), + // FIXME - set to un-verified, blocked and redirect to logout + // Q: Why? Are we verifying people or email addresses? + // A: the policy is to verify email addresses + } - '$allow_cid' => acl2json($perm_defaults['allow_cid']), - '$allow_gid' => acl2json($perm_defaults['allow_gid']), - '$deny_cid' => acl2json($perm_defaults['deny_cid']), - '$deny_gid' => acl2json($perm_defaults['deny_gid']), - '$suggestme' => $suggestme, - '$group_select' => $group_select, - '$can_change_role' => ((in_array($permissions_role, [ 'collection', 'collection_restricted'] )) ? false : true), - '$permissions_role' => $permissions_role, - '$role' => array('permissions_role' , t('Channel type and privacy'), $permissions_role, '', $perm_roles, ' onchange="update_role_text(); return false;"'), - '$defpermcat' => [ 'defpermcat', t('Default Permissions Group'), $default_permcat, '', $permcats ], - '$permcat_enable' => feature_enabled(local_channel(),'permcats'), - '$profile_in_dir' => $profile_in_dir, - '$hide_friends' => $hide_friends, - '$hide_wall' => $hide_wall, - '$unkmail' => $unkmail, - '$cntunkmail' => array('cntunkmail', t('Maximum direct messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming if you allow direct messages from unknown people")), - - '$autoperms' => $autoperms, + goaway(z_root() . '/settings'); + return; // NOTREACHED + } + + public function get() + { + + require_once('include/acl_selectors.php'); + require_once('include/permissions.php'); + + + $yes_no = [t('No'), t('Yes')]; + + + $p = q("SELECT * FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1", + intval(local_channel()) + ); + if (count($p)) + $profile = $p[0]; + + load_pconfig(local_channel(), 'expire'); + + $channel = App::get_channel(); + + $global_perms = Permissions::Perms(); + + $permiss = []; + + $perm_opts = [ + [t('Restricted - from connections only'), PERMS_SPECIFIC], + [t('Semi-public - from anybody that can be identified'), PERMS_AUTHED], + [t('Public - from anybody on the internet'), PERMS_PUBLIC] + ]; + + $limits = PermissionLimits::Get(local_channel()); + $anon_comments = get_config('system', 'anonymous_comments'); + + foreach ($global_perms as $k => $perm) { + $options = []; + $can_be_public = ((strstr($k, 'view') || ($k === 'post_comments' && $anon_comments)) ? true : false); + foreach ($perm_opts as $opt) { + if ($opt[1] == PERMS_PUBLIC && (!$can_be_public)) + continue; + $options[$opt[1]] = $opt[0]; + } + if ($k === 'post_comments') { + $comment_perms = [$k, $perm, $limits[$k], '', $options]; + } elseif ($k === 'post_mail') { + $mail_perms = [$k, $perm, $limits[$k], '', $options]; + } else { + $permiss[] = array($k, $perm, $limits[$k], '', $options); + } + } + + // logger('permiss: ' . print_r($permiss,true)); + + $username = $channel['channel_name']; + $nickname = $channel['channel_address']; + $timezone = $channel['channel_timezone']; + $notify = $channel['channel_notifyflags']; + $defloc = $channel['channel_location']; + + $maxreq = $channel['channel_max_friend_req']; + $expire = $channel['channel_expire_days']; + $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); + $sys_expire = get_config('system', 'default_expire_days'); + + $hide_presence = intval(get_pconfig(local_channel(), 'system', 'hide_online_status')); + + $expire_items = get_pconfig(local_channel(), 'expire', 'items'); + $expire_items = (($expire_items === false) ? '1' : $expire_items); // default if not set: 1 + + $expire_notes = get_pconfig(local_channel(), 'expire', 'notes'); + $expire_notes = (($expire_notes === false) ? '1' : $expire_notes); // default if not set: 1 + + $expire_starred = get_pconfig(local_channel(), 'expire', 'starred'); + $expire_starred = (($expire_starred === false) ? '1' : $expire_starred); // default if not set: 1 + + + $expire_photos = get_pconfig(local_channel(), 'expire', 'photos'); + $expire_photos = (($expire_photos === false) ? '0' : $expire_photos); // default if not set: 0 + + $expire_network_only = get_pconfig(local_channel(), 'expire', 'network_only'); + $expire_network_only = (($expire_network_only === false) ? '0' : $expire_network_only); // default if not set: 0 + + + $suggestme = get_pconfig(local_channel(), 'system', 'suggestme'); + $suggestme = (($suggestme === false) ? '0' : $suggestme); // default if not set: 0 + + $post_newfriend = get_pconfig(local_channel(), 'system', 'post_newfriend'); + $post_newfriend = (($post_newfriend === false) ? '0' : $post_newfriend); // default if not set: 0 + + $post_joingroup = get_pconfig(local_channel(), 'system', 'post_joingroup'); + $post_joingroup = (($post_joingroup === false) ? '0' : $post_joingroup); // default if not set: 0 + + $post_profilechange = get_pconfig(local_channel(), 'system', 'post_profilechange'); + $post_profilechange = (($post_profilechange === false) ? '0' : $post_profilechange); // default if not set: 0 + + $blocktags = get_pconfig(local_channel(), 'system', 'blocktags'); + $blocktags = (($blocktags === false) ? '0' : $blocktags); + + $timezone = date_default_timezone_get(); + + $opt_tpl = get_markup_template("field_checkbox.tpl"); + if (get_config('system', 'publish_all')) { + $profile_in_dir = ''; + } else { + $profile_in_dir = replace_macros($opt_tpl, array( + '$field' => array('profile_in_directory', t('Publish your profile in the network directory'), $profile['publish'], '', $yes_no), + )); + } + + $suggestme = replace_macros($opt_tpl, array( + '$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no), + + )); + + $subdir = ((strlen(App::get_path())) ? '
      ' . t('or') . ' ' . z_root() . '/channel/' . $nickname : ''); + + $webbie = $nickname . '@' . App::get_hostname(); + $intl_nickname = unpunify($nickname) . '@' . unpunify(App::get_hostname()); + + $prof_addr = replace_macros(get_markup_template('channel_settings_header.tpl'), array( + '$desc' => t('Your channel address is'), + '$nickname' => (($intl_nickname === $webbie) ? $webbie : $intl_nickname . ' (' . $webbie . ')'), + '$compat' => t('Friends using compatible applications can use this address to connect with you.'), + '$subdir' => $subdir, + '$davdesc' => t('Your files/photos are accessible as a network drive at'), + '$davpath' => z_root() . '/dav/' . $nickname, + '$windows' => t('(Windows)'), + '$other' => t('(other platforms)'), + '$or' => t('or'), + '$davspath' => 'davs://' . App::get_hostname() . '/dav/' . $nickname, + '$basepath' => App::get_hostname() + )); + + + $pcat = new Permcat(local_channel()); + $pcatlist = $pcat->listing(); + $permcats = []; + if ($pcatlist) { + foreach ($pcatlist as $pc) { + $permcats[$pc['name']] = $pc['localname']; + } + } + + $default_permcat = get_pconfig(local_channel(), 'system', 'default_permcat', 'default'); + + + $acl = new AccessControl($channel); + $perm_defaults = $acl->get(); + + $group_select = AccessList::select(local_channel(), $channel['channel_default_group']); + + require_once('include/menu.php'); + $m1 = menu_list(local_channel()); + $menu = false; + if ($m1) { + $menu = []; + $current = get_pconfig(local_channel(), 'system', 'channel_menu'); + $menu[] = array('name' => '', 'selected' => ((!$current) ? true : false)); + foreach ($m1 as $m) { + $menu[] = array('name' => htmlspecialchars($m['menu_name'], ENT_COMPAT, 'UTF-8'), 'selected' => (($m['menu_name'] === $current) ? ' selected="selected" ' : false)); + } + } + + $evdays = get_pconfig(local_channel(), 'system', 'evdays'); + if (!$evdays) + $evdays = 3; + + $permissions_role = get_pconfig(local_channel(), 'system', 'permissions_role'); + if (!$permissions_role) + $permissions_role = 'custom'; + + if (in_array($permissions_role, ['forum', 'repository'])) { + $autoperms = replace_macros(get_markup_template('field_checkbox.tpl'), [ + '$field' => ['autoperms', t('Automatic membership approval'), ((get_pconfig(local_channel(), 'system', 'autoperms', 0)) ? 1 : 0), t('If enabled, connection requests will be approved without your interaction'), $yes_no]]); + } else { + $autoperms = ''; + } + + $hyperdrive = ['hyperdrive', t('Friend-of-friend conversations'), ((get_pconfig(local_channel(), 'system', 'hyperdrive', true)) ? 1 : 0), t('Import public third-party conversations in which your connections participate.'), $yes_no]; + + if (get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) { + $apconfig = true; + $activitypub = replace_macros(get_markup_template('field_checkbox.tpl'), ['$field' => ['activitypub', t('Enable ActivityPub protocol'), ((get_pconfig(local_channel(), 'system', 'activitypub', ACTIVITYPUB_ENABLED)) ? 1 : 0), t('ActivityPub is an emerging internet standard for social communications'), $yes_no]]); + } else { + $apconfig = false; + $activitypub = '' . EOL; + } + + $permissions_set = (($permissions_role != 'custom') ? true : false); + + $perm_roles = PermissionRoles::roles(); + // Don't permit changing to a collection (@TODO unless there is a mechanism to select the channel_parent) + unset($perm_roles['Collection']); + + + $vnotify = get_pconfig(local_channel(), 'system', 'vnotify'); + $always_show_in_notices = get_pconfig(local_channel(), 'system', 'always_show_in_notices'); + if ($vnotify === false) + $vnotify = (-1); + + $plugin = ['basic' => '', 'security' => '', 'notify' => '', 'misc' => '']; + call_hooks('channel_settings', $plugin); + + $public_stream_mode = intval(get_config('system', 'public_stream_mode', PUBLIC_STREAM_NONE)); + + $ft = get_pconfig(local_channel(), 'system', 'followed_tags', ''); + if ($ft && is_array($ft)) { + $followed = implode(',', $ft); + } else { + $followed = EMPTY_STR; + } + + + $o .= replace_macros(get_markup_template('settings.tpl'), [ + '$ptitle' => t('Channel Settings'), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$uid' => local_channel(), + '$form_security_token' => get_form_security_token("settings"), + '$nickname_block' => $prof_addr, + '$h_basic' => t('Basic Settings'), + '$username' => array('username', t('Full name'), $username, ''), + '$email' => array('email', t('Email Address'), $email, ''), + '$timezone' => array('timezone_select', t('Your timezone'), $timezone, t('This is important for showing the correct time on shared events'), get_timezones()), + '$defloc' => array('defloc', t('Default post location'), $defloc, t('Optional geographical location to display on your posts')), + '$allowloc' => array('allow_location', t('Obtain post location from your web browser or device'), ((get_pconfig(local_channel(), 'system', 'use_browser_location')) ? 1 : ''), '', $yes_no), + + '$adult' => array('adult', t('Adult content'), $adult_flag, t('Enable to indicate if this channel frequently or regularly publishes adult content. (Please also tag any adult material and/or nudity with #NSFW)'), $yes_no), + + '$h_prv' => t('Security and Privacy'), + '$permissions_set' => $permissions_set, + '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), + + '$hide_presence' => array('hide_presence', t('Hide my online presence'), $hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), + '$hidefriends' => array('hide_friends', t('Allow others to view your friends and connections'), 1 - intval($profile['hide_friends']), '', $yes_no), + '$permiss_arr' => $permiss, + '$comment_perms' => $comment_perms, + '$mail_perms' => $mail_perms, + '$noindex' => ['noindex', t('Forbid indexing of your channel content by search engines'), get_pconfig($channel['channel_id'], 'system', 'noindex'), '', $yes_no], + '$close_comments' => ['close_comments', t('Disable acceptance of comments on my posts after this many days'), ((intval(get_pconfig(local_channel(), 'system', 'close_comments'))) ? intval(get_pconfig(local_channel(), 'system', 'close_comments')) : EMPTY_STR), t('Leave unset or enter 0 to allow comments indefinitely')], + '$blocktags' => array('blocktags', t('Allow others to tag your posts'), 1 - $blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no), + + '$lbl_p2macro' => t('Channel Permission Limits'), + + '$expire' => array('expire', t('Expire conversations you have not participated in after this many days'), $expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf(t('This website expires after %d days.'), intval($sys_expire)) : t('This website does not provide an expiration policy.')) . ' ' . t('The website limit takes precedence if lower than your limit.')), + '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']), t('May reduce spam activity')), + '$permissions' => t('Default Access List'), + '$permdesc' => t("(click to open/close)"), + '$aclselect' => populate_acl($perm_defaults, false, PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))), + '$profseltxt' => t('Profile to assign new connections'), + '$profselect' => ((feature_enabled(local_channel(), 'multi_profiles')) ? contact_profile_assign(get_pconfig(local_channel(), 'system', 'profile_assign', '')) : ''), + + '$allow_cid' => acl2json($perm_defaults['allow_cid']), + '$allow_gid' => acl2json($perm_defaults['allow_gid']), + '$deny_cid' => acl2json($perm_defaults['deny_cid']), + '$deny_gid' => acl2json($perm_defaults['deny_gid']), + '$suggestme' => $suggestme, + '$group_select' => $group_select, + '$can_change_role' => ((in_array($permissions_role, ['collection', 'collection_restricted'])) ? false : true), + '$permissions_role' => $permissions_role, + '$role' => array('permissions_role', t('Channel type and privacy'), $permissions_role, '', $perm_roles, ' onchange="update_role_text(); return false;"'), + '$defpermcat' => ['defpermcat', t('Default Permissions Group'), $default_permcat, '', $permcats], + '$permcat_enable' => feature_enabled(local_channel(), 'permcats'), + '$profile_in_dir' => $profile_in_dir, + '$hide_friends' => $hide_friends, + '$hide_wall' => $hide_wall, + '$unkmail' => $unkmail, + '$cntunkmail' => array('cntunkmail', t('Maximum direct messages per day from unknown people:'), intval($channel['channel_max_anon_mail']), t("Useful to reduce spamming if you allow direct messages from unknown people")), + + '$autoperms' => $autoperms, // '$anymention' => $anymention, - '$hyperdrive' => $hyperdrive, - '$activitypub' => $activitypub, - '$apconfig' => $apconfig, - '$close' => t('Close'), - '$h_not' => t('Notifications'), - '$activity_options' => t('By default post a status message when:'), - '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), - '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no), - '$post_profilechange' => array('post_profilechange', t('making an interesting profile change'), $post_profilechange, '', $yes_no), - '$lbl_not' => t('Send a notification email when:'), - '$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no), + '$hyperdrive' => $hyperdrive, + '$activitypub' => $activitypub, + '$apconfig' => $apconfig, + '$close' => t('Close'), + '$h_not' => t('Notifications'), + '$activity_options' => t('By default post a status message when:'), + '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), + '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no), + '$post_profilechange' => array('post_profilechange', t('making an interesting profile change'), $post_profilechange, '', $yes_no), + '$lbl_not' => t('Send a notification email when:'), + '$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no), // '$notify2' => array('notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no), - '$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no), - '$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no), - '$notify10' => array('notify10', t('Someone shares a followed conversation'), ($notify & NOTIFY_RESHARE), NOTIFY_RESHARE, '', $yes_no), - '$notify5' => array('notify5', t('You receive a direct (private) message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no), + '$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no), + '$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no), + '$notify10' => array('notify10', t('Someone shares a followed conversation'), ($notify & NOTIFY_RESHARE), NOTIFY_RESHARE, '', $yes_no), + '$notify5' => array('notify5', t('You receive a direct (private) message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no), // '$notify6' => array('notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no), - '$notify7' => array('notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no), + '$notify7' => array('notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no), // '$notify8' => array('notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no), - - '$notify9' => array('notify9', t('Someone likes your post/comment'), ($notify & NOTIFY_LIKE), NOTIFY_LIKE, '', $yes_no), - - - '$lbl_vnot' => t('Show visual notifications including:'), - - '$vnotify1' => array('vnotify1', t('Unseen stream activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no), - '$vnotify2' => array('vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no), - '$vnotify3' => array('vnotify3', t('Unseen direct messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no), - '$vnotify4' => array('vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no), - '$vnotify5' => array('vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no), - '$vnotify6' => array('vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no), - '$vnotify7' => array('vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no), - '$vnotify8' => array('vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no), - '$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no), - '$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no), - '$vnotify11' => ((is_site_admin()) ? array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no) : []), + + '$notify9' => array('notify9', t('Someone likes your post/comment'), ($notify & NOTIFY_LIKE), NOTIFY_LIKE, '', $yes_no), + + + '$lbl_vnot' => t('Show visual notifications including:'), + + '$vnotify1' => array('vnotify1', t('Unseen stream activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no), + '$vnotify2' => array('vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no), + '$vnotify3' => array('vnotify3', t('Unseen direct messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no), + '$vnotify4' => array('vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no), + '$vnotify5' => array('vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no), + '$vnotify6' => array('vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no), + '$vnotify7' => array('vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no), + '$vnotify8' => array('vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no), + '$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no), + '$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no), + '$vnotify11' => ((is_site_admin()) ? array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no) : []), // '$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no), - '$vnotify13' => (($public_stream_mode) ? [ 'vnotify13', t('Unseen public stream activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no] : []), - '$vnotify14' => array('vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no), - '$vnotify15' => array('vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no), - '$vnotify16' => ((is_site_admin()) ? array('vnotify16', t('Reported content'), ($vnotify & VNOTIFY_REPORTS), VNOTIFY_REPORTS, '', $yes_no) : [] ), - '$desktop_notifications_info' => t('Desktop notifications are unavailable because the required browser permission has not been granted'), - '$desktop_notifications_request' => t('Grant permission'), - '$mailhost' => [ 'mailhost', t('Email notifications sent from (hostname)'), get_pconfig(local_channel(),'system','email_notify_host',App::get_hostname()), sprintf( t('If your channel is mirrored to multiple locations, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'),App::get_hostname()) ], - '$always_show_in_notices' => array('always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no), - '$permit_all_mentions' => [ 'permit_all_mentions', t('Accept messages from strangers which mention me'), get_pconfig(local_channel(),'system','permit_all_mentions'), t('This setting bypasses normal permissions'), $yes_no ], - '$followed_tags' => [ 'followed_tags', t('Accept messages from strangers which include any of the following hashtags'), $followed, t('comma separated, do not include the #') ], - '$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')), - '$basic_addon' => $plugin['basic'], - '$sec_addon' => $plugin['security'], - '$notify_addon' => $plugin['notify'], - '$misc_addon' => $plugin['misc'], - '$lbl_time' => t('Date and time'), - '$miscdoc' => t('This section is reserved for use by optional addons and apps to provide additional settings.'), - '$h_advn' => t('Advanced Account/Page Type Settings'), - '$h_descadvn' => t('Change the behaviour of this account for special situations'), - '$pagetype' => $pagetype, - '$lbl_misc' => t('Miscellaneous'), - '$photo_path' => array('photo_path', t('Default photo upload folder name'), get_pconfig(local_channel(),'system','photo_path'), t('%Y - current year, %m - current month')), - '$attach_path' => array('attach_path', t('Default file upload folder name'), get_pconfig(local_channel(),'system','attach_path'), t('%Y - current year, %m - current month')), - '$menus' => $menu, - '$menu_desc' => t('Personal menu to display in your channel pages'), - '$removeme' => t('Remove Channel'), - '$removechannel' => t('Remove this channel.'), - '$tag_username' => [ 'tag_username', t('Mentions should display'), intval(get_pconfig(local_channel(),'system','tag_username',get_config('system','tag_username',false))), t('Changes to this setting are applied to new posts/comments only. It is not retroactive.'), - [ - 0 => t('the channel display name [example: @Barbara Jenkins]'), - 1 => t('the channel nickname [example: @barbara1976]'), - 2 => t('combined [example: @Barbara Jenkins (barbara1976)]'), - 127 => t('no preference, use the system default'), - ]], - - '$cal_first_day' => array('first_day', t('Calendar week begins on'), intval(get_pconfig(local_channel(),'system','cal_first_day')), t('This varies by country/culture'), - [ 0 => t('Sunday'), - 1 => t('Monday'), - 2 => t('Tuesday'), - 3 => t('Wednesday'), - 4 => t('Thursday'), - 5 => t('Friday'), - 6 => t('Saturday') - ]), - ]); - - call_hooks('settings_form',$o); - return $o; - } + '$vnotify13' => (($public_stream_mode) ? ['vnotify13', t('Unseen public stream activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no] : []), + '$vnotify14' => array('vnotify14', t('Unseen likes and dislikes'), ($vnotify & VNOTIFY_LIKE), VNOTIFY_LIKE, '', $yes_no), + '$vnotify15' => array('vnotify15', t('Unseen forum posts'), ($vnotify & VNOTIFY_FORUMS), VNOTIFY_FORUMS, '', $yes_no), + '$vnotify16' => ((is_site_admin()) ? array('vnotify16', t('Reported content'), ($vnotify & VNOTIFY_REPORTS), VNOTIFY_REPORTS, '', $yes_no) : []), + '$desktop_notifications_info' => t('Desktop notifications are unavailable because the required browser permission has not been granted'), + '$desktop_notifications_request' => t('Grant permission'), + '$mailhost' => ['mailhost', t('Email notifications sent from (hostname)'), get_pconfig(local_channel(), 'system', 'email_notify_host', App::get_hostname()), sprintf(t('If your channel is mirrored to multiple locations, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'), App::get_hostname())], + '$always_show_in_notices' => array('always_show_in_notices', t('Show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no), + '$permit_all_mentions' => ['permit_all_mentions', t('Accept messages from strangers which mention me'), get_pconfig(local_channel(), 'system', 'permit_all_mentions'), t('This setting bypasses normal permissions'), $yes_no], + '$followed_tags' => ['followed_tags', t('Accept messages from strangers which include any of the following hashtags'), $followed, t('comma separated, do not include the #')], + '$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')), + '$basic_addon' => $plugin['basic'], + '$sec_addon' => $plugin['security'], + '$notify_addon' => $plugin['notify'], + '$misc_addon' => $plugin['misc'], + '$lbl_time' => t('Date and time'), + '$miscdoc' => t('This section is reserved for use by optional addons and apps to provide additional settings.'), + '$h_advn' => t('Advanced Account/Page Type Settings'), + '$h_descadvn' => t('Change the behaviour of this account for special situations'), + '$pagetype' => $pagetype, + '$lbl_misc' => t('Miscellaneous'), + '$photo_path' => array('photo_path', t('Default photo upload folder name'), get_pconfig(local_channel(), 'system', 'photo_path'), t('%Y - current year, %m - current month')), + '$attach_path' => array('attach_path', t('Default file upload folder name'), get_pconfig(local_channel(), 'system', 'attach_path'), t('%Y - current year, %m - current month')), + '$menus' => $menu, + '$menu_desc' => t('Personal menu to display in your channel pages'), + '$removeme' => t('Remove Channel'), + '$removechannel' => t('Remove this channel.'), + '$tag_username' => ['tag_username', t('Mentions should display'), intval(get_pconfig(local_channel(), 'system', 'tag_username', get_config('system', 'tag_username', false))), t('Changes to this setting are applied to new posts/comments only. It is not retroactive.'), + [ + 0 => t('the channel display name [example: @Barbara Jenkins]'), + 1 => t('the channel nickname [example: @barbara1976]'), + 2 => t('combined [example: @Barbara Jenkins (barbara1976)]'), + 127 => t('no preference, use the system default'), + ]], + + '$cal_first_day' => array('first_day', t('Calendar week begins on'), intval(get_pconfig(local_channel(), 'system', 'cal_first_day')), t('This varies by country/culture'), + [0 => t('Sunday'), + 1 => t('Monday'), + 2 => t('Tuesday'), + 3 => t('Wednesday'), + 4 => t('Thursday'), + 5 => t('Friday'), + 6 => t('Saturday') + ]), + ]); + + call_hooks('settings_form', $o); + return $o; + } } diff --git a/Zotlabs/Module/Settings/Display.php b/Zotlabs/Module/Settings/Display.php index 47c7f9b4a..f4c15ab08 100644 --- a/Zotlabs/Module/Settings/Display.php +++ b/Zotlabs/Module/Settings/Display.php @@ -6,228 +6,230 @@ use App; use Zotlabs\Lib\Libsync; -class Display { +class Display +{ - /* - * DISPLAY SETTINGS - */ + /* + * DISPLAY SETTINGS + */ - function post() { - check_form_security_token_redirectOnErr('/settings/display', 'settings_display'); + public function post() + { + check_form_security_token_redirectOnErr('/settings/display', 'settings_display'); - $themespec = explode(':', App::$channel['channel_theme']); - $existing_theme = $themespec[0]; - $existing_schema = $themespec[1]; + $themespec = explode(':', App::$channel['channel_theme']); + $existing_theme = $themespec[0]; + $existing_schema = $themespec[1]; - $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : $existing_theme); + $theme = ((x($_POST, 'theme')) ? notags(trim($_POST['theme'])) : $existing_theme); - if(! $theme) - $theme = 'redbasic'; + if (!$theme) + $theme = 'redbasic'; - $preload_images = ((x($_POST,'preload_images')) ? intval($_POST['preload_images']) : 0); - $channel_menu = ((x($_POST,'channel_menu')) ? intval($_POST['channel_menu']) : 0); - $user_scalable = ((x($_POST,'user_scalable')) ? intval($_POST['user_scalable']) : 0); - $nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0); - $indentpx = ((x($_POST,'indentpx')) ? intval($_POST['indentpx']) : 0); + $preload_images = ((x($_POST, 'preload_images')) ? intval($_POST['preload_images']) : 0); + $channel_menu = ((x($_POST, 'channel_menu')) ? intval($_POST['channel_menu']) : 0); + $user_scalable = ((x($_POST, 'user_scalable')) ? intval($_POST['user_scalable']) : 0); + $nosmile = ((x($_POST, 'nosmile')) ? intval($_POST['nosmile']) : 0); + $indentpx = ((x($_POST, 'indentpx')) ? intval($_POST['indentpx']) : 0); - $channel_divmore_height = ((x($_POST,'channel_divmore_height')) ? intval($_POST['channel_divmore_height']) : 400); - if($channel_divmore_height < 50) - $channel_divmore_height = 50; - $stream_divmore_height = ((x($_POST,'stream_divmore_height')) ? intval($_POST['stream_divmore_height']) : 400); - if($stream_divmore_height < 50) - $stream_divmore_height = 50; + $channel_divmore_height = ((x($_POST, 'channel_divmore_height')) ? intval($_POST['channel_divmore_height']) : 400); + if ($channel_divmore_height < 50) + $channel_divmore_height = 50; + $stream_divmore_height = ((x($_POST, 'stream_divmore_height')) ? intval($_POST['stream_divmore_height']) : 400); + if ($stream_divmore_height < 50) + $stream_divmore_height = 50; - $browser_update = ((x($_POST,'browser_update')) ? intval($_POST['browser_update']) : 0); - $browser_update = $browser_update * 1000; - if($browser_update < 15000) - $browser_update = 15000; + $browser_update = ((x($_POST, 'browser_update')) ? intval($_POST['browser_update']) : 0); + $browser_update = $browser_update * 1000; + if ($browser_update < 15000) + $browser_update = 15000; - $itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 20); - if($itemspage > 100) - $itemspage = 100; + $itemspage = ((x($_POST, 'itemspage')) ? intval($_POST['itemspage']) : 20); + if ($itemspage > 100) + $itemspage = 100; - if ($indentpx < 0) { - $indentpx = 0; - } - if ($indentpx > 20) { - $indentpx = 20; - } + if ($indentpx < 0) { + $indentpx = 0; + } + if ($indentpx > 20) { + $indentpx = 20; + } - set_pconfig(local_channel(),'system','preload_images',$preload_images); - set_pconfig(local_channel(),'system','user_scalable',$user_scalable); - set_pconfig(local_channel(),'system','update_interval', $browser_update); - set_pconfig(local_channel(),'system','itemspage', $itemspage); - set_pconfig(local_channel(),'system','no_smilies',1-intval($nosmile)); - set_pconfig(local_channel(),'system','channel_divmore_height', $channel_divmore_height); - set_pconfig(local_channel(),'system','stream_divmore_height', $stream_divmore_height); - set_pconfig(local_channel(),'system','channel_menu', $channel_menu); - set_pconfig(local_channel(),'system','thread_indent_px',$indentpx); + set_pconfig(local_channel(), 'system', 'preload_images', $preload_images); + set_pconfig(local_channel(), 'system', 'user_scalable', $user_scalable); + set_pconfig(local_channel(), 'system', 'update_interval', $browser_update); + set_pconfig(local_channel(), 'system', 'itemspage', $itemspage); + set_pconfig(local_channel(), 'system', 'no_smilies', 1 - intval($nosmile)); + set_pconfig(local_channel(), 'system', 'channel_divmore_height', $channel_divmore_height); + set_pconfig(local_channel(), 'system', 'stream_divmore_height', $stream_divmore_height); + set_pconfig(local_channel(), 'system', 'channel_menu', $channel_menu); + set_pconfig(local_channel(), 'system', 'thread_indent_px', $indentpx); - $newschema = ''; - if($theme){ - // call theme_post only if theme has not been changed - if( ($themeconfigfile = $this->get_theme_config_file($theme)) != null){ - require_once($themeconfigfile); - if(class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { - $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; - $theme_config = new $clsname(); - $schemas = $theme_config->get_schemas(); - if(array_key_exists($_POST['schema'],$schemas)) - $newschema = $_POST['schema']; - if($newschema === '---') - $newschema = ''; - $theme_config->post(); - } - } - } + $newschema = ''; + if ($theme) { + // call theme_post only if theme has not been changed + if (($themeconfigfile = $this->get_theme_config_file($theme)) != null) { + require_once($themeconfigfile); + if (class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { + $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; + $theme_config = new $clsname(); + $schemas = $theme_config->get_schemas(); + if (array_key_exists($_POST['schema'], $schemas)) + $newschema = $_POST['schema']; + if ($newschema === '---') + $newschema = ''; + $theme_config->post(); + } + } + } - logger('theme: ' . $theme . (($newschema) ? ':' . $newschema : '')); + logger('theme: ' . $theme . (($newschema) ? ':' . $newschema : '')); - $_SESSION['theme'] = $theme . (($newschema) ? ':' . $newschema : ''); + $_SESSION['theme'] = $theme . (($newschema) ? ':' . $newschema : ''); - $r = q("UPDATE channel SET channel_theme = '%s' WHERE channel_id = %d", - dbesc($theme . (($newschema) ? ':' . $newschema : '')), - intval(local_channel()) - ); + $r = q("UPDATE channel SET channel_theme = '%s' WHERE channel_id = %d", + dbesc($theme . (($newschema) ? ':' . $newschema : '')), + intval(local_channel()) + ); - call_hooks('display_settings_post', $_POST); - Libsync::build_sync_packet(); - goaway(z_root() . '/settings/display' ); - return; // NOTREACHED - } + call_hooks('display_settings_post', $_POST); + Libsync::build_sync_packet(); + goaway(z_root() . '/settings/display'); + return; // NOTREACHED + } - function get() { + public function get() + { - $yes_no = array(t('No'),t('Yes')); + $yes_no = array(t('No'), t('Yes')); - $default_theme = get_config('system','theme'); - if(! $default_theme) - $default_theme = 'redbasic'; + $default_theme = get_config('system', 'theme'); + if (!$default_theme) + $default_theme = 'redbasic'; - $themespec = explode(':', App::$channel['channel_theme']); - $existing_theme = $themespec[0]; - $existing_schema = $themespec[1]; + $themespec = explode(':', App::$channel['channel_theme']); + $existing_theme = $themespec[0]; + $existing_schema = $themespec[1]; - $theme = (($existing_theme) ? $existing_theme : $default_theme); + $theme = (($existing_theme) ? $existing_theme : $default_theme); - $allowed_themes_str = get_config('system','allowed_themes'); - $allowed_themes_raw = explode(',',$allowed_themes_str); - $allowed_themes = []; - if(count($allowed_themes_raw)) - foreach($allowed_themes_raw as $x) - if(strlen(trim($x)) && is_dir("view/theme/$x")) - $allowed_themes[] = trim($x); + $allowed_themes_str = get_config('system', 'allowed_themes'); + $allowed_themes_raw = explode(',', $allowed_themes_str); + $allowed_themes = []; + if (count($allowed_themes_raw)) + foreach ($allowed_themes_raw as $x) + if (strlen(trim($x)) && is_dir("view/theme/$x")) + $allowed_themes[] = trim($x); - $themes = []; - $files = glob('view/theme/*'); - if($allowed_themes) { - foreach($allowed_themes as $th) { - $f = $th; + $themes = []; + $files = glob('view/theme/*'); + if ($allowed_themes) { + foreach ($allowed_themes as $th) { + $f = $th; - $info = get_theme_info($th); - $compatible = check_plugin_versions($info); - if(! $compatible) { - $themes[$f] = sprintf(t('%s - (Incompatible)'), $f); - continue; - } + $info = get_theme_info($th); + $compatible = check_plugin_versions($info); + if (!$compatible) { + $themes[$f] = sprintf(t('%s - (Incompatible)'), $f); + continue; + } - $is_experimental = file_exists('view/theme/' . $th . '/experimental'); - $unsupported = file_exists('view/theme/' . $th . '/unsupported'); - $is_library = file_exists('view/theme/'. $th . '/library'); + $is_experimental = file_exists('view/theme/' . $th . '/experimental'); + $unsupported = file_exists('view/theme/' . $th . '/unsupported'); + $is_library = file_exists('view/theme/' . $th . '/library'); - if (!$is_experimental or ($is_experimental && (get_config('experimentals','exp_themes')==1 or get_config('experimentals','exp_themes')===false))){ - $theme_name = (($is_experimental) ? sprintf(t('%s - (Experimental)'), $f) : $f); - if (! $is_library) { - $themes[$f] = $theme_name; - } - } - } - } + if (!$is_experimental or ($is_experimental && (get_config('experimentals', 'exp_themes') == 1 or get_config('experimentals', 'exp_themes') === false))) { + $theme_name = (($is_experimental) ? sprintf(t('%s - (Experimental)'), $f) : $f); + if (!$is_library) { + $themes[$f] = $theme_name; + } + } + } + } - $theme_selected = ((array_key_exists('theme',$_SESSION) && $_SESSION['theme']) ? $_SESSION['theme'] : $theme); + $theme_selected = ((array_key_exists('theme', $_SESSION) && $_SESSION['theme']) ? $_SESSION['theme'] : $theme); - if (strpos($theme_selected, ':')) { - $theme_selected = explode(':', $theme_selected)[0]; - } + if (strpos($theme_selected, ':')) { + $theme_selected = explode(':', $theme_selected)[0]; + } - $preload_images = get_pconfig(local_channel(),'system','preload_images'); + $preload_images = get_pconfig(local_channel(), 'system', 'preload_images'); - $user_scalable = get_pconfig(local_channel(),'system','user_scalable', '0'); + $user_scalable = get_pconfig(local_channel(), 'system', 'user_scalable', '0'); - $browser_update = intval(get_pconfig(local_channel(), 'system','update_interval',30000)); // default if not set: 30 seconds - $browser_update = (($browser_update < 15000) ? 15 : $browser_update / 1000); // minimum 15 seconds + $browser_update = intval(get_pconfig(local_channel(), 'system', 'update_interval', 30000)); // default if not set: 30 seconds + $browser_update = (($browser_update < 15000) ? 15 : $browser_update / 1000); // minimum 15 seconds - $itemspage = intval(get_pconfig(local_channel(), 'system','itemspage')); - $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items + $itemspage = intval(get_pconfig(local_channel(), 'system', 'itemspage')); + $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items - $nosmile = get_pconfig(local_channel(),'system','no_smilies'); - $nosmile = (($nosmile===false)? '0': $nosmile); // default if not set: 0 + $nosmile = get_pconfig(local_channel(), 'system', 'no_smilies'); + $nosmile = (($nosmile === false) ? '0' : $nosmile); // default if not set: 0 - $theme_config = ""; - if(($themeconfigfile = $this->get_theme_config_file($theme)) != null){ - require_once($themeconfigfile); - if(class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { - $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; - $thm_config = new $clsname(); - $schemas = $thm_config->get_schemas(); - $theme_config = $thm_config->get(); - } - } + $theme_config = ""; + if (($themeconfigfile = $this->get_theme_config_file($theme)) != null) { + require_once($themeconfigfile); + if (class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { + $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; + $thm_config = new $clsname(); + $schemas = $thm_config->get_schemas(); + $theme_config = $thm_config->get(); + } + } - // logger('schemas: ' . print_r($schemas,true)); + // logger('schemas: ' . print_r($schemas,true)); - $tpl = get_markup_template("settings_display.tpl"); - $o = replace_macros($tpl, array( - '$ptitle' => t('Display Settings'), - '$d_tset' => t('Theme Settings'), - '$d_ctset' => t('Custom Theme Settings'), - '$d_cset' => t('Content Settings'), - '$form_security_token' => get_form_security_token("settings_display"), - '$submit' => t('Submit'), - '$baseurl' => z_root(), - '$uid' => local_channel(), + $tpl = get_markup_template("settings_display.tpl"); + $o = replace_macros($tpl, array( + '$ptitle' => t('Display Settings'), + '$d_tset' => t('Theme Settings'), + '$d_ctset' => t('Custom Theme Settings'), + '$d_cset' => t('Content Settings'), + '$form_security_token' => get_form_security_token("settings_display"), + '$submit' => t('Submit'), + '$baseurl' => z_root(), + '$uid' => local_channel(), - '$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false), - '$schema' => array('schema', t('Select scheme'), $existing_schema, '' , $schemas), + '$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false), + '$schema' => array('schema', t('Select scheme'), $existing_schema, '', $schemas), - '$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no), - '$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no), - '$ajaxint' => array('browser_update', t("Update notifications every xx seconds"), $browser_update, t('Minimum of 15 seconds, no maximum')), - '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 100 items')), - '$nosmile' => array('nosmile', t("Show emoticons (smilies) as images"), 1-intval($nosmile), '', $yes_no), - '$channel_menu' => [ 'channel_menu', t('Provide channel menu in navigation bar'), get_pconfig(local_channel(),'system','channel_menu',get_config('system','channel_menu',0)), t('Default: channel menu located in app menu'),$yes_no ], - '$layout_editor' => t('System Page Layout Editor - (advanced)'), - '$theme_config' => $theme_config, - '$expert' => feature_enabled(local_channel(),'advanced_theming'), - '$channel_divmore_height' => array('channel_divmore_height', t('Channel page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','channel_divmore_height')) ? get_pconfig(local_channel(),'system','channel_divmore_height') : 400), t('click to expand content exceeding this height')), - '$stream_divmore_height' => array('stream_divmore_height', t('Stream page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','stream_divmore_height')) ? get_pconfig(local_channel(),'system','stream_divmore_height') : 400) , t('click to expand content exceeding this height')), - '$indentpx' => [ 'indentpx', t('Indent threaded comments this many pixels from the parent'), intval(get_pconfig(local_channel(),'system','thread_indent_px', get_config('system','thread_indent_px',0))), t('0-20') ], + '$preload_images' => array('preload_images', t("Preload images before rendering the page"), $preload_images, t("The subjective page load time will be longer but the page will be ready when displayed"), $yes_no), + '$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no), + '$ajaxint' => array('browser_update', t("Update notifications every xx seconds"), $browser_update, t('Minimum of 15 seconds, no maximum')), + '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 100 items')), + '$nosmile' => array('nosmile', t("Show emoticons (smilies) as images"), 1 - intval($nosmile), '', $yes_no), + '$channel_menu' => ['channel_menu', t('Provide channel menu in navigation bar'), get_pconfig(local_channel(), 'system', 'channel_menu', get_config('system', 'channel_menu', 0)), t('Default: channel menu located in app menu'), $yes_no], + '$layout_editor' => t('System Page Layout Editor - (advanced)'), + '$theme_config' => $theme_config, + '$expert' => feature_enabled(local_channel(), 'advanced_theming'), + '$channel_divmore_height' => array('channel_divmore_height', t('Channel page max height of content (in pixels)'), ((get_pconfig(local_channel(), 'system', 'channel_divmore_height')) ? get_pconfig(local_channel(), 'system', 'channel_divmore_height') : 400), t('click to expand content exceeding this height')), + '$stream_divmore_height' => array('stream_divmore_height', t('Stream page max height of content (in pixels)'), ((get_pconfig(local_channel(), 'system', 'stream_divmore_height')) ? get_pconfig(local_channel(), 'system', 'stream_divmore_height') : 400), t('click to expand content exceeding this height')), + '$indentpx' => ['indentpx', t('Indent threaded comments this many pixels from the parent'), intval(get_pconfig(local_channel(), 'system', 'thread_indent_px', get_config('system', 'thread_indent_px', 0))), t('0-20')], - )); + )); - call_hooks('display_settings',$o); - return $o; - } + call_hooks('display_settings', $o); + return $o; + } - function get_theme_config_file($theme){ - - $base_theme = App::$theme_info['extends']; - - if (file_exists("view/theme/$theme/php/config.php")){ - return "view/theme/$theme/php/config.php"; - } - if (file_exists("view/theme/$base_theme/php/config.php")){ - return "view/theme/$base_theme/php/config.php"; - } - return null; - } + public function get_theme_config_file($theme) + { + $base_theme = App::$theme_info['extends']; + if (file_exists("view/theme/$theme/php/config.php")) { + return "view/theme/$theme/php/config.php"; + } + if (file_exists("view/theme/$base_theme/php/config.php")) { + return "view/theme/$base_theme/php/config.php"; + } + return null; + } } diff --git a/Zotlabs/Module/Settings/Featured.php b/Zotlabs/Module/Settings/Featured.php index 83148d648..e722a89a5 100644 --- a/Zotlabs/Module/Settings/Featured.php +++ b/Zotlabs/Module/Settings/Featured.php @@ -5,81 +5,85 @@ namespace Zotlabs\Module\Settings; use Zotlabs\Lib\Libsync; -class Featured { - - function post() { - check_form_security_token_redirectOnErr('/settings/featured', 'settings_featured'); - - call_hooks('feature_settings_post', $_POST); - - if($_POST['affinity_slider-submit']) { - $cmax = intval($_POST['affinity_cmax']); - if($cmax < 0 || $cmax > 99) - $cmax = 99; - $cmin = intval($_POST['affinity_cmin']); - if($cmin < 0 || $cmin > 99) - $cmin = 0; - set_pconfig(local_channel(),'affinity','cmin',$cmin); - set_pconfig(local_channel(),'affinity','cmax',$cmax); +class Featured +{ - info( t('Affinity Slider settings updated.') . EOL); + public function post() + { + check_form_security_token_redirectOnErr('/settings/featured', 'settings_featured'); - } - - Libsync::build_sync_packet(); - return; - } + call_hooks('feature_settings_post', $_POST); - function get() { - $settings_addons = ""; - - $o = ''; - - $r = q("SELECT * FROM hook WHERE hook = 'feature_settings' "); - if(! $r) - $settings_addons = t('No feature settings configured'); - - if(feature_enabled(local_channel(),'affinity')) { - - $cmax = intval(get_pconfig(local_channel(),'affinity','cmax')); - $cmax = (($cmax) ? $cmax : 99); - $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array( - '$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, t('0-99 default 99')) - )); - $cmin = intval(get_pconfig(local_channel(),'affinity','cmin')); - $cmin = (($cmin) ? $cmin : 0); - $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array( - '$field' => array('affinity_cmin', t('Default minimum affinity level'), $cmin, t('0-99 - default 0')) - )); + if ($_POST['affinity_slider-submit']) { + $cmax = intval($_POST['affinity_cmax']); + if ($cmax < 0 || $cmax > 99) + $cmax = 99; + $cmin = intval($_POST['affinity_cmin']); + if ($cmin < 0 || $cmin > 99) + $cmin = 0; + set_pconfig(local_channel(), 'affinity', 'cmin', $cmin); + set_pconfig(local_channel(), 'affinity', 'cmax', $cmax); - $settings_addons .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( - '$addon' => array('affinity_slider', '' . t('Affinity Slider Settings'), '', t('Submit')), - '$content' => $setting_fields - )); - } + info(t('Affinity Slider settings updated.') . EOL); - call_hooks('feature_settings', $settings_addons); - - $this->sortpanels($settings_addons); + } - - $tpl = get_markup_template("settings_addons.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_featured"), - '$title' => t('Addon Settings'), - '$descrip' => t('Please save/submit changes to any panel before opening another.'), - '$settings_addons' => $settings_addons - )); - return $o; - } + Libsync::build_sync_packet(); + return; + } - function sortpanels(&$s) { - $a = explode('
      ',$s); - if($a) { - usort($a,'featured_sort'); - $s = implode('
      ',$a); - } - } + public function get() + { + $settings_addons = ""; + + $o = ''; + + $r = q("SELECT * FROM hook WHERE hook = 'feature_settings' "); + if (!$r) + $settings_addons = t('No feature settings configured'); + + if (feature_enabled(local_channel(), 'affinity')) { + + $cmax = intval(get_pconfig(local_channel(), 'affinity', 'cmax')); + $cmax = (($cmax) ? $cmax : 99); + $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('affinity_cmax', t('Default maximum affinity level'), $cmax, t('0-99 default 99')) + )); + $cmin = intval(get_pconfig(local_channel(), 'affinity', 'cmin')); + $cmin = (($cmin) ? $cmin : 0); + $setting_fields .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('affinity_cmin', t('Default minimum affinity level'), $cmin, t('0-99 - default 0')) + )); + + $settings_addons .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( + '$addon' => array('affinity_slider', '' . t('Affinity Slider Settings'), '', t('Submit')), + '$content' => $setting_fields + )); + } + + call_hooks('feature_settings', $settings_addons); + + $this->sortpanels($settings_addons); + + + $tpl = get_markup_template("settings_addons.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_featured"), + '$title' => t('Addon Settings'), + '$descrip' => t('Please save/submit changes to any panel before opening another.'), + '$settings_addons' => $settings_addons + )); + return $o; + } + + public function sortpanels(&$s) + { + $a = explode('
      ', $s); + if ($a) { + usort($a, 'featured_sort'); + $s = implode('
      ', $a); + } + } } diff --git a/Zotlabs/Module/Settings/Features.php b/Zotlabs/Module/Settings/Features.php index aa46e92e4..4797b48e7 100644 --- a/Zotlabs/Module/Settings/Features.php +++ b/Zotlabs/Module/Settings/Features.php @@ -4,62 +4,65 @@ namespace Zotlabs\Module\Settings; use Zotlabs\Lib\Libsync; -class Features { +class Features +{ - function post() { - check_form_security_token_redirectOnErr('/settings/features', 'settings_features'); - - $features = get_features(false); + public function post() + { + check_form_security_token_redirectOnErr('/settings/features', 'settings_features'); - foreach($features as $fname => $fdata) { - foreach(array_slice($fdata,1) as $f) { - $k = $f[0]; - if(array_key_exists("feature_$k",$_POST)) - set_pconfig(local_channel(),'feature',$k, (string) $_POST["feature_$k"]); - else - set_pconfig(local_channel(),'feature', $k, ''); - } - } - Libsync::build_sync_packet(); - return; - } + $features = get_features(false); - function get() { - - $arr = []; - $harr = []; + foreach ($features as $fname => $fdata) { + foreach (array_slice($fdata, 1) as $f) { + $k = $f[0]; + if (array_key_exists("feature_$k", $_POST)) + set_pconfig(local_channel(), 'feature', $k, (string)$_POST["feature_$k"]); + else + set_pconfig(local_channel(), 'feature', $k, ''); + } + } + Libsync::build_sync_packet(); + return; + } + + public function get() + { + + $arr = []; + $harr = []; - $all_features_raw = get_features(false); + $all_features_raw = get_features(false); - foreach($all_features_raw as $fname => $fdata) { - foreach(array_slice($fdata,1) as $f) { - $harr[$f[0]] = ((intval(feature_enabled(local_channel(),$f[0]))) ? "1" : ''); - } - } + foreach ($all_features_raw as $fname => $fdata) { + foreach (array_slice($fdata, 1) as $f) { + $harr[$f[0]] = ((intval(feature_enabled(local_channel(), $f[0]))) ? "1" : ''); + } + } - $features = get_features(true); + $features = get_features(true); - foreach($features as $fname => $fdata) { - $arr[$fname] = []; - $arr[$fname][0] = $fdata[0]; - foreach(array_slice($fdata,1) as $f) { - $arr[$fname][1][] = array('feature_' . $f[0],$f[1],((intval(feature_enabled(local_channel(),$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On'))); - unset($harr[$f[0]]); - } - } - - $tpl = get_markup_template("settings_features.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_features"), - '$title' => t('Additional Features'), - '$features' => $arr, - '$hiddens' => $harr, - '$baseurl' => z_root(), - '$submit' => t('Submit'), - )); - - return $o; - } + foreach ($features as $fname => $fdata) { + $arr[$fname] = []; + $arr[$fname][0] = $fdata[0]; + foreach (array_slice($fdata, 1) as $f) { + $arr[$fname][1][] = array('feature_' . $f[0], $f[1], ((intval(feature_enabled(local_channel(), $f[0]))) ? "1" : ''), $f[2], array(t('Off'), t('On'))); + unset($harr[$f[0]]); + } + } + + $tpl = get_markup_template("settings_features.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_features"), + '$title' => t('Additional Features'), + '$features' => $arr, + '$hiddens' => $harr, + '$baseurl' => z_root(), + '$submit' => t('Submit'), + )); + + return $o; + } } diff --git a/Zotlabs/Module/Settings/Network.php b/Zotlabs/Module/Settings/Network.php index 14a118f2c..34bbe2c3f 100644 --- a/Zotlabs/Module/Settings/Network.php +++ b/Zotlabs/Module/Settings/Network.php @@ -3,126 +3,130 @@ namespace Zotlabs\Module\Settings; -class Network { +class Network +{ - function post() { - check_form_security_token_redirectOnErr('/settings/network', 'settings_network'); - - $features = self::get_features(); + public function post() + { + check_form_security_token_redirectOnErr('/settings/network', 'settings_network'); - foreach($features as $f) { - $k = $f[0]; - if(array_key_exists("feature_$k",$_POST)) - set_pconfig(local_channel(),'feature',$k, (string) $_POST["feature_$k"]); - else - set_pconfig(local_channel(),'feature', $k, ''); - } - - build_sync_packet(); - return; - } + $features = self::get_features(); - function get() { - - $features = self::get_features(); + foreach ($features as $f) { + $k = $f[0]; + if (array_key_exists("feature_$k", $_POST)) + set_pconfig(local_channel(), 'feature', $k, (string)$_POST["feature_$k"]); + else + set_pconfig(local_channel(), 'feature', $k, ''); + } - foreach($features as $f) { - $arr[] = array('feature_' . $f[0],$f[1],((intval(feature_enabled(local_channel(),$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On'))); - } + build_sync_packet(); + return; + } - $tpl = get_markup_template("settings_module.tpl"); + public function get() + { - $o .= replace_macros($tpl, array( - '$action_url' => 'settings/network', - '$form_security_token' => get_form_security_token("settings_network"), - '$title' => t('Activity Settings'), - '$features' => $arr, - '$baseurl' => z_root(), - '$submit' => t('Submit'), - )); - - return $o; - } + $features = self::get_features(); - function get_features() { - $arr = [ + foreach ($features as $f) { + $arr[] = array('feature_' . $f[0], $f[1], ((intval(feature_enabled(local_channel(), $f[0]))) ? "1" : ''), $f[2], array(t('Off'), t('On'))); + } - [ - 'archives', - t('Search by Date'), - t('Ability to select posts by date ranges'), - false, - get_config('feature_lock','archives') - ], + $tpl = get_markup_template("settings_module.tpl"); - [ - 'savedsearch', - t('Saved Searches'), - t('Save search terms for re-use'), - false, - get_config('feature_lock','savedsearch') - ], + $o .= replace_macros($tpl, array( + '$action_url' => 'settings/network', + '$form_security_token' => get_form_security_token("settings_network"), + '$title' => t('Activity Settings'), + '$features' => $arr, + '$baseurl' => z_root(), + '$submit' => t('Submit'), + )); - [ - 'order_tab', - t('Alternate Stream Order'), - t('Ability to order the stream by last post date, last comment date or unthreaded activities'), - false, - get_config('feature_lock','order_tab') - ], + return $o; + } - [ - 'name_tab', - t('Contact Filter'), - t('Ability to display only posts of a selected contact'), - false, - get_config('feature_lock','name_tab') - ], + public function get_features() + { + $arr = [ - [ - 'forums_tab', - t('Forum Filter'), - t('Ability to display only posts of a specific forum'), - false, - get_config('feature_lock','forums_tab') - ], + [ + 'archives', + t('Search by Date'), + t('Ability to select posts by date ranges'), + false, + get_config('feature_lock', 'archives') + ], - [ - 'personal_tab', - t('Personal Posts Filter'), - t('Ability to display only posts that you\'ve interacted on'), - false, - get_config('feature_lock','personal_tab') - ], + [ + 'savedsearch', + t('Saved Searches'), + t('Save search terms for re-use'), + false, + get_config('feature_lock', 'savedsearch') + ], - [ - 'affinity', - t('Affinity Tool'), - t('Filter stream activity by depth of relationships'), - false, - get_config('feature_lock','affinity') - ], + [ + 'order_tab', + t('Alternate Stream Order'), + t('Ability to order the stream by last post date, last comment date or unthreaded activities'), + false, + get_config('feature_lock', 'order_tab') + ], - [ - 'suggest', - t('Suggest Channels'), - t('Show friend and connection suggestions'), - false, - get_config('feature_lock','suggest') - ], + [ + 'name_tab', + t('Contact Filter'), + t('Ability to display only posts of a selected contact'), + false, + get_config('feature_lock', 'name_tab') + ], - [ - 'connfilter', - t('Connection Filtering'), - t('Filter incoming posts from connections based on keywords/content'), - false, - get_config('feature_lock','connfilter') - ] + [ + 'forums_tab', + t('Forum Filter'), + t('Ability to display only posts of a specific forum'), + false, + get_config('feature_lock', 'forums_tab') + ], - ]; + [ + 'personal_tab', + t('Personal Posts Filter'), + t('Ability to display only posts that you\'ve interacted on'), + false, + get_config('feature_lock', 'personal_tab') + ], - return $arr; + [ + 'affinity', + t('Affinity Tool'), + t('Filter stream activity by depth of relationships'), + false, + get_config('feature_lock', 'affinity') + ], - } + [ + 'suggest', + t('Suggest Channels'), + t('Show friend and connection suggestions'), + false, + get_config('feature_lock', 'suggest') + ], + + [ + 'connfilter', + t('Connection Filtering'), + t('Filter incoming posts from connections based on keywords/content'), + false, + get_config('feature_lock', 'connfilter') + ] + + ]; + + return $arr; + + } } diff --git a/Zotlabs/Module/Settings/Oauth.php b/Zotlabs/Module/Settings/Oauth.php index d6576c6de..c1e55d93d 100644 --- a/Zotlabs/Module/Settings/Oauth.php +++ b/Zotlabs/Module/Settings/Oauth.php @@ -3,45 +3,47 @@ namespace Zotlabs\Module\Settings; -class Oauth { +class Oauth +{ - function post() { - - if(x($_POST,'remove')){ - check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); - - $key = $_POST['remove']; - q("DELETE FROM tokens WHERE id='%s' AND uid=%d", - dbesc($key), - local_channel()); - goaway(z_root()."/settings/oauth/"); - return; - } - - if((argc() > 2) && (argv(2) === 'edit' || argv(2) === 'add') && x($_POST,'submit')) { - - check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); - - $name = ((x($_POST,'name')) ? escape_tags($_POST['name']) : ''); - $key = ((x($_POST,'key')) ? escape_tags($_POST['key']) : ''); - $secret = ((x($_POST,'secret')) ? escape_tags($_POST['secret']) : ''); - $redirect = ((x($_POST,'redirect')) ? escape_tags($_POST['redirect']) : ''); - $icon = ((x($_POST,'icon')) ? escape_tags($_POST['icon']) : ''); - $oauth2 = ((x($_POST,'oauth2')) ? intval($_POST['oauth2']) : 0); - $ok = true; - if($name == '') { - $ok = false; - notice( t('Name is required') . EOL); - } - if($key == '' || $secret == '') { - $ok = false; - notice( t('Key and Secret are required') . EOL); - } - - if($ok) { - if ($_POST['submit']==t("Update")){ - $r = q("UPDATE clients SET + public function post() + { + + if (x($_POST, 'remove')) { + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); + + $key = $_POST['remove']; + q("DELETE FROM tokens WHERE id='%s' AND uid=%d", + dbesc($key), + local_channel()); + goaway(z_root() . "/settings/oauth/"); + return; + } + + if ((argc() > 2) && (argv(2) === 'edit' || argv(2) === 'add') && x($_POST, 'submit')) { + + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); + + $name = ((x($_POST, 'name')) ? escape_tags($_POST['name']) : ''); + $key = ((x($_POST, 'key')) ? escape_tags($_POST['key']) : ''); + $secret = ((x($_POST, 'secret')) ? escape_tags($_POST['secret']) : ''); + $redirect = ((x($_POST, 'redirect')) ? escape_tags($_POST['redirect']) : ''); + $icon = ((x($_POST, 'icon')) ? escape_tags($_POST['icon']) : ''); + $oauth2 = ((x($_POST, 'oauth2')) ? intval($_POST['oauth2']) : 0); + $ok = true; + if ($name == '') { + $ok = false; + notice(t('Name is required') . EOL); + } + if ($key == '' || $secret == '') { + $ok = false; + notice(t('Key and Secret are required') . EOL); + } + + if ($ok) { + if ($_POST['submit'] == t("Update")) { + $r = q("UPDATE clients SET client_id='%s', pw='%s', clname='%s', @@ -49,113 +51,114 @@ class Oauth { icon='%s', uid=%d WHERE client_id='%s'", - dbesc($key), - dbesc($secret), - dbesc($name), - dbesc($redirect), - dbesc($icon), - intval(local_channel()), - dbesc($key)); - } else { - $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid) + dbesc($key), + dbesc($secret), + dbesc($name), + dbesc($redirect), + dbesc($icon), + intval(local_channel()), + dbesc($key)); + } else { + $r = q("INSERT INTO clients (client_id, pw, clname, redirect_uri, icon, uid) VALUES ('%s','%s','%s','%s','%s',%d)", - dbesc($key), - dbesc($secret), - dbesc($name), - dbesc($redirect), - dbesc($icon), - intval(local_channel()) - ); - $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", - dbesc($key), - intval(local_channel()), - dbesc('all') - ); - } - } - goaway(z_root()."/settings/oauth/"); - return; - } - } + dbesc($key), + dbesc($secret), + dbesc($name), + dbesc($redirect), + dbesc($icon), + intval(local_channel()) + ); + $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", + dbesc($key), + intval(local_channel()), + dbesc('all') + ); + } + } + goaway(z_root() . "/settings/oauth/"); + return; + } + } - function get() { - - if((argc() > 2) && (argv(2) === 'add')) { - $tpl = get_markup_template("settings_oauth_edit.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth"), - '$title' => t('Add application'), - '$submit' => t('Submit'), - '$cancel' => t('Cancel'), - '$name' => array('name', t('Name'), '', t('Name of application')), - '$key' => array('key', t('Consumer Key'), random_string(16), t('Automatically generated - change if desired. Max length 20')), - '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), - '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), - '$icon' => array('icon', t('Icon url'), '', t('Optional')), - )); - return $o; - } - - if((argc() > 3) && (argv(2) === 'edit')) { - $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d", - dbesc(argv(3)), - local_channel()); - - if (!count($r)){ - notice(t('Application not found.')); - return; - } - $app = $r[0]; - - $tpl = get_markup_template("settings_oauth_edit.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth"), - '$title' => t('Add application'), - '$submit' => t('Update'), - '$cancel' => t('Cancel'), - '$name' => array('name', t('Name'), $app['clname'] , ''), - '$key' => array('key', t('Consumer Key'), $app['client_id'], ''), - '$secret' => array('secret', t('Consumer Secret'), $app['pw'], ''), - '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''), - '$icon' => array('icon', t('Icon url'), $app['icon'], ''), - )); - return $o; - } - - if((argc() > 3) && (argv(2) === 'delete')) { - check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth', 't'); - - $r = q("DELETE FROM clients WHERE client_id='%s' AND uid=%d", - dbesc(argv(3)), - local_channel()); - goaway(z_root()."/settings/oauth/"); - return; - } - - - $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my + public function get() + { + + if ((argc() > 2) && (argv(2) === 'add')) { + $tpl = get_markup_template("settings_oauth_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$title' => t('Add application'), + '$submit' => t('Submit'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), '', t('Name of application')), + '$key' => array('key', t('Consumer Key'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), + '$icon' => array('icon', t('Icon url'), '', t('Optional')), + )); + return $o; + } + + if ((argc() > 3) && (argv(2) === 'edit')) { + $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d", + dbesc(argv(3)), + local_channel()); + + if (!count($r)) { + notice(t('Application not found.')); + return; + } + $app = $r[0]; + + $tpl = get_markup_template("settings_oauth_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$title' => t('Add application'), + '$submit' => t('Update'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), $app['clname'], ''), + '$key' => array('key', t('Consumer Key'), $app['client_id'], ''), + '$secret' => array('secret', t('Consumer Secret'), $app['pw'], ''), + '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''), + '$icon' => array('icon', t('Icon url'), $app['icon'], ''), + )); + return $o; + } + + if ((argc() > 3) && (argv(2) === 'delete')) { + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth', 't'); + + $r = q("DELETE FROM clients WHERE client_id='%s' AND uid=%d", + dbesc(argv(3)), + local_channel()); + goaway(z_root() . "/settings/oauth/"); + return; + } + + + $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my FROM clients LEFT JOIN tokens ON clients.client_id=tokens.client_id WHERE clients.uid IN (%d,0)", - local_channel(), - local_channel()); - - - $tpl = get_markup_template("settings_oauth.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth"), - '$baseurl' => z_root(), - '$title' => t('Connected Apps'), - '$add' => t('Add application'), - '$edit' => t('Edit'), - '$delete' => t('Delete'), - '$consumerkey' => t('Client key starts with'), - '$noname' => t('No name'), - '$remove' => t('Remove authorization'), - '$apps' => $r, - )); - return $o; - - } + local_channel(), + local_channel()); + + + $tpl = get_markup_template("settings_oauth.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$baseurl' => z_root(), + '$title' => t('Connected Apps'), + '$add' => t('Add application'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$consumerkey' => t('Client key starts with'), + '$noname' => t('No name'), + '$remove' => t('Remove authorization'), + '$apps' => $r, + )); + return $o; + + } } \ No newline at end of file diff --git a/Zotlabs/Module/Settings/Oauth2.php b/Zotlabs/Module/Settings/Oauth2.php index 55dd6a548..a3e25ff73 100644 --- a/Zotlabs/Module/Settings/Oauth2.php +++ b/Zotlabs/Module/Settings/Oauth2.php @@ -5,52 +5,54 @@ namespace Zotlabs\Module\Settings; use Zotlabs\Lib\Apps; -class Oauth2 { +class Oauth2 +{ - function post() { - - if(x($_POST,'remove')){ - check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2'); - $name = ((x($_POST,'name')) ? escape_tags(trim($_POST['name'])) : ''); - logger("REMOVE! ".$name." uid: ".local_channel()); - $key = $_POST['remove']; - q("DELETE FROM oauth_authorization_codes WHERE client_id='%s' AND user_id=%d", - dbesc($name), - intval(local_channel()) - ); - q("DELETE FROM oauth_access_tokens WHERE client_id='%s' AND user_id=%d", - dbesc($name), - intval(local_channel()) - ); - q("DELETE FROM oauth_refresh_tokens WHERE client_id='%s' AND user_id=%d", - dbesc($name), - intval(local_channel()) - ); - goaway(z_root()."/settings/oauth2/"); - return; - } - - if((argc() > 2) && (argv(2) === 'edit' || argv(2) === 'add') && x($_POST,'submit')) { - - check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2'); - - $name = ((x($_POST,'name')) ? escape_tags(trim($_POST['name'])) : ''); - $clid = ((x($_POST,'clid')) ? escape_tags(trim($_POST['clid'])) : ''); - $secret = ((x($_POST,'secret')) ? escape_tags(trim($_POST['secret'])) : ''); - $redirect = ((x($_POST,'redirect')) ? escape_tags(trim($_POST['redirect'])) : ''); - $grant = ((x($_POST,'grant')) ? escape_tags(trim($_POST['grant'])) : ''); - $scope = ((x($_POST,'scope')) ? escape_tags(trim($_POST['scope'])) : ''); -logger('redirect: ' . $redirect); - $ok = true; - if($clid == '' || $secret == '') { - $ok = false; - notice( t('ID and Secret are required') . EOL); - } - - if($ok) { - if ($_POST['submit']==t("Update")){ - $r = q("UPDATE oauth_clients SET + public function post() + { + + if (x($_POST, 'remove')) { + check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2'); + $name = ((x($_POST, 'name')) ? escape_tags(trim($_POST['name'])) : ''); + logger("REMOVE! " . $name . " uid: " . local_channel()); + $key = $_POST['remove']; + q("DELETE FROM oauth_authorization_codes WHERE client_id='%s' AND user_id=%d", + dbesc($name), + intval(local_channel()) + ); + q("DELETE FROM oauth_access_tokens WHERE client_id='%s' AND user_id=%d", + dbesc($name), + intval(local_channel()) + ); + q("DELETE FROM oauth_refresh_tokens WHERE client_id='%s' AND user_id=%d", + dbesc($name), + intval(local_channel()) + ); + goaway(z_root() . "/settings/oauth2/"); + return; + } + + if ((argc() > 2) && (argv(2) === 'edit' || argv(2) === 'add') && x($_POST, 'submit')) { + + check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2'); + + $name = ((x($_POST, 'name')) ? escape_tags(trim($_POST['name'])) : ''); + $clid = ((x($_POST, 'clid')) ? escape_tags(trim($_POST['clid'])) : ''); + $secret = ((x($_POST, 'secret')) ? escape_tags(trim($_POST['secret'])) : ''); + $redirect = ((x($_POST, 'redirect')) ? escape_tags(trim($_POST['redirect'])) : ''); + $grant = ((x($_POST, 'grant')) ? escape_tags(trim($_POST['grant'])) : ''); + $scope = ((x($_POST, 'scope')) ? escape_tags(trim($_POST['scope'])) : ''); + logger('redirect: ' . $redirect); + $ok = true; + if ($clid == '' || $secret == '') { + $ok = false; + notice(t('ID and Secret are required') . EOL); + } + + if ($ok) { + if ($_POST['submit'] == t("Update")) { + $r = q("UPDATE oauth_clients SET client_name = '%s', client_id = '%s', client_secret = '%s', @@ -59,149 +61,150 @@ logger('redirect: ' . $redirect); scope = '%s', user_id = %d WHERE client_id='%s' and user_id = %s", - dbesc($name), - dbesc($clid), - dbesc($secret), - dbesc($redirect), - dbesc($grant), - dbesc($scope), - intval(local_channel()), - dbesc($clid), - intval(local_channel())); - } else { - $r = q("INSERT INTO oauth_clients (client_name, client_id, client_secret, redirect_uri, grant_types, scope, user_id) + dbesc($name), + dbesc($clid), + dbesc($secret), + dbesc($redirect), + dbesc($grant), + dbesc($scope), + intval(local_channel()), + dbesc($clid), + intval(local_channel())); + } else { + $r = q("INSERT INTO oauth_clients (client_name, client_id, client_secret, redirect_uri, grant_types, scope, user_id) VALUES ('%s','%s','%s','%s','%s','%s',%d)", - dbesc($name), - dbesc($clid), - dbesc($secret), - dbesc($redirect), - dbesc($grant), - dbesc($scope), - intval(local_channel()) - ); - $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", - dbesc($name), - intval(local_channel()), - dbesc('all') - ); - } - } - goaway(z_root()."/settings/oauth2/"); - return; - } - } + dbesc($name), + dbesc($clid), + dbesc($secret), + dbesc($redirect), + dbesc($grant), + dbesc($scope), + intval(local_channel()) + ); + $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", + dbesc($name), + intval(local_channel()), + dbesc('all') + ); + } + } + goaway(z_root() . "/settings/oauth2/"); + return; + } + } - function get() { + public function get() + { - if(! Apps::system_app_installed(local_channel(),'Clients')) { - return; - } + if (!Apps::system_app_installed(local_channel(), 'Clients')) { + return; + } - if((argc() > 2) && (argv(2) === 'add')) { - $tpl = get_markup_template("settings_oauth2_edit.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth2"), - '$title' => t('Add OAuth2 application'), - '$submit' => t('Submit'), - '$cancel' => t('Cancel'), - '$name' => array('name', t('Name'), '', t('Name of application')), - '$clid' => array('clid', t('Consumer ID'), random_string(16), t('Automatically generated - change if desired. Max length 20')), - '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), - '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), - '$grant' => array('grant', t('Grant Types'), '', t('leave blank unless your application specifically requires this')), - '$scope' => array('scope', t('Authorization scope'), '', t('leave blank unless your application specifically requires this')), - )); - return $o; - } - - if((argc() > 3) && (argv(2) === 'edit')) { - $r = q("SELECT * FROM oauth_clients WHERE client_id='%s' AND user_id= %d", - dbesc(argv(3)), - intval(local_channel()) - ); - - if (! $r){ - notice(t('OAuth2 Application not found.')); - return; - } + if ((argc() > 2) && (argv(2) === 'add')) { + $tpl = get_markup_template("settings_oauth2_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth2"), + '$title' => t('Add OAuth2 application'), + '$submit' => t('Submit'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), '', t('Name of application')), + '$clid' => array('clid', t('Consumer ID'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), + '$grant' => array('grant', t('Grant Types'), '', t('leave blank unless your application specifically requires this')), + '$scope' => array('scope', t('Authorization scope'), '', t('leave blank unless your application specifically requires this')), + )); + return $o; + } - $app = $r[0]; - - $tpl = get_markup_template("settings_oauth2_edit.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth2"), - '$title' => t('Add application'), - '$submit' => t('Update'), - '$cancel' => t('Cancel'), - '$name' => array('name', t('Name'), $app['client_name'], t('Name of application')), - '$clid' => array('clid', t('Consumer ID'), $app['client_id'], t('Automatically generated - change if desired. Max length 20')), - '$secret' => array('secret', t('Consumer Secret'), $app['client_secret'], t('Automatically generated - change if desired. Max length 20')), - '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], t('Redirect URI - leave blank unless your application specifically requires this')), - '$grant' => array('grant', t('Grant Types'), $app['grant_types'], t('leave blank unless your application specifically requires this')), - '$scope' => array('scope', t('Authorization scope'), $app['scope'], t('leave blank unless your application specifically requires this')), - )); - return $o; - } - - if((argc() > 3) && (argv(2) === 'delete')) { - check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2', 't'); - - $r = q("DELETE FROM oauth_clients WHERE client_id = '%s' AND user_id = %d", - dbesc(argv(3)), - intval(local_channel()) - ); - $r = q("DELETE FROM oauth_access_tokens WHERE client_id = '%s' AND user_id = %d", - dbesc(argv(3)), - intval(local_channel()) - ); - $r = q("DELETE FROM oauth_authorization_codes WHERE client_id = '%s' AND user_id = %d", - dbesc(argv(3)), - intval(local_channel()) - ); - $r = q("DELETE FROM oauth_refresh_tokens WHERE client_id = '%s' AND user_id = %d", - dbesc(argv(3)), - intval(local_channel()) - ); - goaway(z_root()."/settings/oauth2/"); - return; - } - + if ((argc() > 3) && (argv(2) === 'edit')) { + $r = q("SELECT * FROM oauth_clients WHERE client_id='%s' AND user_id= %d", + dbesc(argv(3)), + intval(local_channel()) + ); - $r = q("SELECT * FROM oauth_clients WHERE user_id = %d ", - intval(local_channel()) - ); + if (!$r) { + notice(t('OAuth2 Application not found.')); + return; + } - $c = q("select client_id, access_token from oauth_access_tokens where user_id = %d", - intval(local_channel()) - ); - if ($r && $c) { - foreach($c as $cv) { - for($x = 0; $x < count($r); $x ++) { - if($r[$x]['client_id'] === $cv['client_id']) { - if(! array_key_exists('tokens',$r[$x])) { - $r[$x]['tokens'] = []; - } - $r[$x]['tokens'][] = $cv['access_token']; - } - } - } - } + $app = $r[0]; - $tpl = get_markup_template("settings_oauth2.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_oauth2"), - '$baseurl' => z_root(), - '$title' => t('Connected OAuth2 Apps'), - '$add' => t('Add application'), - '$edit' => t('Edit'), - '$delete' => t('Delete'), - '$consumerkey' => t('Client key starts with'), - '$noname' => t('No name'), - '$remove' => t('Remove authorization'), - '$apps' => $r, - )); - return $o; - - } + $tpl = get_markup_template("settings_oauth2_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth2"), + '$title' => t('Add application'), + '$submit' => t('Update'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), $app['client_name'], t('Name of application')), + '$clid' => array('clid', t('Consumer ID'), $app['client_id'], t('Automatically generated - change if desired. Max length 20')), + '$secret' => array('secret', t('Consumer Secret'), $app['client_secret'], t('Automatically generated - change if desired. Max length 20')), + '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], t('Redirect URI - leave blank unless your application specifically requires this')), + '$grant' => array('grant', t('Grant Types'), $app['grant_types'], t('leave blank unless your application specifically requires this')), + '$scope' => array('scope', t('Authorization scope'), $app['scope'], t('leave blank unless your application specifically requires this')), + )); + return $o; + } + + if ((argc() > 3) && (argv(2) === 'delete')) { + check_form_security_token_redirectOnErr('/settings/oauth2', 'settings_oauth2', 't'); + + $r = q("DELETE FROM oauth_clients WHERE client_id = '%s' AND user_id = %d", + dbesc(argv(3)), + intval(local_channel()) + ); + $r = q("DELETE FROM oauth_access_tokens WHERE client_id = '%s' AND user_id = %d", + dbesc(argv(3)), + intval(local_channel()) + ); + $r = q("DELETE FROM oauth_authorization_codes WHERE client_id = '%s' AND user_id = %d", + dbesc(argv(3)), + intval(local_channel()) + ); + $r = q("DELETE FROM oauth_refresh_tokens WHERE client_id = '%s' AND user_id = %d", + dbesc(argv(3)), + intval(local_channel()) + ); + goaway(z_root() . "/settings/oauth2/"); + return; + } + + + $r = q("SELECT * FROM oauth_clients WHERE user_id = %d ", + intval(local_channel()) + ); + + $c = q("select client_id, access_token from oauth_access_tokens where user_id = %d", + intval(local_channel()) + ); + if ($r && $c) { + foreach ($c as $cv) { + for ($x = 0; $x < count($r); $x++) { + if ($r[$x]['client_id'] === $cv['client_id']) { + if (!array_key_exists('tokens', $r[$x])) { + $r[$x]['tokens'] = []; + } + $r[$x]['tokens'][] = $cv['access_token']; + } + } + } + } + + $tpl = get_markup_template("settings_oauth2.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth2"), + '$baseurl' => z_root(), + '$title' => t('Connected OAuth2 Apps'), + '$add' => t('Add application'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$consumerkey' => t('Client key starts with'), + '$noname' => t('No name'), + '$remove' => t('Remove authorization'), + '$apps' => $r, + )); + return $o; + + } } diff --git a/Zotlabs/Module/Settings/Permcats.php b/Zotlabs/Module/Settings/Permcats.php index 76959a1ed..7c6ca6dac 100644 --- a/Zotlabs/Module/Settings/Permcats.php +++ b/Zotlabs/Module/Settings/Permcats.php @@ -9,117 +9,119 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Lib\Permcat; -class Permcats { +class Permcats +{ - function post() { + public function post() + { - if(! local_channel()) - return; + if (!local_channel()) + return; - $channel = App::get_channel(); + $channel = App::get_channel(); - check_form_security_token_redirectOnErr('/settings/permcats', 'settings_permcats'); + check_form_security_token_redirectOnErr('/settings/permcats', 'settings_permcats'); - $all_perms = Permissions::Perms(); + $all_perms = Permissions::Perms(); - $name = escape_tags(trim($_POST['name'])); - if(! $name) { - notice( t('Permission Name is required.') . EOL); - return; - } + $name = escape_tags(trim($_POST['name'])); + if (!$name) { + notice(t('Permission Name is required.') . EOL); + return; + } - $pcarr = []; + $pcarr = []; - if($all_perms) { - foreach($all_perms as $perm => $desc) { - if(array_key_exists('perms_' . $perm, $_POST)) { - $pcarr[] = $perm; - } - } - } - - Permcat::update(local_channel(),$name,$pcarr); + if ($all_perms) { + foreach ($all_perms as $perm => $desc) { + if (array_key_exists('perms_' . $perm, $_POST)) { + $pcarr[] = $perm; + } + } + } - Libsync::build_sync_packet(); + Permcat::update(local_channel(), $name, $pcarr); - info( t('Permission category saved.') . EOL); - - return; - } - + Libsync::build_sync_packet(); - function get() { + info(t('Permission category saved.') . EOL); - if(! local_channel()) - return; - - $channel = App::get_channel(); + return; + } - if(argc() > 2) - $name = hex2bin(argv(2)); + public function get() + { - if(argc() > 3 && argv(3) === 'drop') { - Permcat::delete(local_channel(),$name); - Libsync::build_sync_packet(); - json_return_and_die([ 'success' => true ]); - } + if (!local_channel()) + return; + + $channel = App::get_channel(); - $desc = t('Use this form to create permission rules for various classes of people or connections.'); + if (argc() > 2) + $name = hex2bin(argv(2)); - $existing = []; - - $pcat = new Permcat(local_channel()); - $pcatlist = $pcat->listing(); - $permcats = []; - if($pcatlist) { - foreach($pcatlist as $pc) { - if(($pc['name']) && ($name) && ($pc['name'] == $name)) - $existing = $pc['perms']; - if(! $pc['system']) - $permcats[bin2hex($pc['name'])] = $pc['localname']; - } - } - - $global_perms = Permissions::Perms(); - - foreach($global_perms as $k => $v) { - $thisperm = Permcat::find_permcat($existing,$k); - $checkinherited = PermissionLimits::Get(local_channel(),$k); - - if($existing[$k]) - $thisperm = "1"; - - $perms[] = array('perms_' . $k, $v, '',$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); - } + if (argc() > 3 && argv(3) === 'drop') { + Permcat::delete(local_channel(), $name); + Libsync::build_sync_packet(); + json_return_and_die(['success' => true]); + } + $desc = t('Use this form to create permission rules for various classes of people or connections.'); + + $existing = []; + + $pcat = new Permcat(local_channel()); + $pcatlist = $pcat->listing(); + $permcats = []; + if ($pcatlist) { + foreach ($pcatlist as $pc) { + if (($pc['name']) && ($name) && ($pc['name'] == $name)) + $existing = $pc['perms']; + if (!$pc['system']) + $permcats[bin2hex($pc['name'])] = $pc['localname']; + } + } + + $global_perms = Permissions::Perms(); + + foreach ($global_perms as $k => $v) { + $thisperm = Permcat::find_permcat($existing, $k); + $checkinherited = PermissionLimits::Get(local_channel(), $k); + + if ($existing[$k]) + $thisperm = "1"; + + $perms[] = array('perms_' . $k, $v, '', $thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); + } + + + $tpl = get_markup_template("settings_permcats.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_permcats"), + '$title' => t('Permission Categories'), + '$desc' => $desc, + '$desc2' => $desc2, + '$tokens' => $t, + '$permcats' => $permcats, + '$atoken' => $atoken, + '$url1' => z_root() . '/channel/' . $channel['channel_address'], + '$url2' => z_root() . '/photos/' . $channel['channel_address'], + '$name' => array('name', t('Permission Name') . ' *', (($name) ? $name : ''), ''), + '$me' => t('My Settings'), + '$perms' => $perms, + '$inherited' => t('inherited'), + '$notself' => 0, + '$self' => 1, + '$permlbl' => t('Individual Permissions'), + '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), + '$submit' => t('Submit') + )); + return $o; + } - $tpl = get_markup_template("settings_permcats.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_permcats"), - '$title' => t('Permission Categories'), - '$desc' => $desc, - '$desc2' => $desc2, - '$tokens' => $t, - '$permcats' => $permcats, - '$atoken' => $atoken, - '$url1' => z_root() . '/channel/' . $channel['channel_address'], - '$url2' => z_root() . '/photos/' . $channel['channel_address'], - '$name' => array('name', t('Permission Name') . ' *', (($name) ? $name : ''), ''), - '$me' => t('My Settings'), - '$perms' => $perms, - '$inherited' => t('inherited'), - '$notself' => 0, - '$self' => 1, - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), - '$submit' => t('Submit') - )); - return $o; - } - } diff --git a/Zotlabs/Module/Settings/Tokens.php b/Zotlabs/Module/Settings/Tokens.php index 9ce89c20a..6aea18fe4 100644 --- a/Zotlabs/Module/Settings/Tokens.php +++ b/Zotlabs/Module/Settings/Tokens.php @@ -10,292 +10,294 @@ use Zotlabs\Lib\Libsync; require_once('include/security.php'); -class Tokens { +class Tokens +{ - function post() { + public function post() + { - $channel = App::get_channel(); + $channel = App::get_channel(); - check_form_security_token_redirectOnErr('/settings/tokens', 'settings_tokens'); - $token_errs = 0; - if(array_key_exists('token',$_POST)) { - $atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0); - if (! $atoken_id) { - $atoken_guid = new_uuid(); - } - $name = trim(escape_tags($_POST['name'])); - $token = trim($_POST['token']); - if((! $name) || (! $token)) - $token_errs ++; - if(trim($_POST['expires'])) - $expires = datetime_convert(date_default_timezone_get(),'UTC',$_POST['expires']); - else - $expires = NULL_DATE; - $max_atokens = service_class_fetch(local_channel(),'access_tokens'); - if($max_atokens) { - $r = q("select count(atoken_id) as total where atoken_uid = %d", - intval(local_channel()) - ); - if($r && intval($r[0]['total']) >= $max_tokens) { - notice( sprintf( t('This channel is limited to %d tokens'), $max_tokens) . EOL); - return; - } - } - } - if($token_errs) { - notice( t('Name and Password are required.') . EOL); - return; - } + check_form_security_token_redirectOnErr('/settings/tokens', 'settings_tokens'); + $token_errs = 0; + if (array_key_exists('token', $_POST)) { + $atoken_id = (($_POST['atoken_id']) ? intval($_POST['atoken_id']) : 0); + if (!$atoken_id) { + $atoken_guid = new_uuid(); + } + $name = trim(escape_tags($_POST['name'])); + $token = trim($_POST['token']); + if ((!$name) || (!$token)) + $token_errs++; + if (trim($_POST['expires'])) + $expires = datetime_convert(date_default_timezone_get(), 'UTC', $_POST['expires']); + else + $expires = NULL_DATE; + $max_atokens = service_class_fetch(local_channel(), 'access_tokens'); + if ($max_atokens) { + $r = q("select count(atoken_id) as total where atoken_uid = %d", + intval(local_channel()) + ); + if ($r && intval($r[0]['total']) >= $max_tokens) { + notice(sprintf(t('This channel is limited to %d tokens'), $max_tokens) . EOL); + return; + } + } + } + if ($token_errs) { + notice(t('Name and Password are required.') . EOL); + return; + } - $old_atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'", - intval($channel['channel_id']), - dbesc($name) - ); - if ($old_atok) { - $old_atok = array_shift($old_atok); - $old_xchan = atoken_xchan($old_atok); - } - - if($atoken_id) { - $r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s' + $old_atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'", + intval($channel['channel_id']), + dbesc($name) + ); + if ($old_atok) { + $old_atok = array_shift($old_atok); + $old_xchan = atoken_xchan($old_atok); + } + + if ($atoken_id) { + $r = q("update atoken set atoken_name = '%s', atoken_token = '%s', atoken_expires = '%s' where atoken_id = %d and atoken_uid = %d", - dbesc($name), - dbesc($token), - dbesc($expires), - intval($atoken_id), - intval($channel['channel_id']) - ); - } - else { - $r = q("insert into atoken ( atoken_guid, atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires ) + dbesc($name), + dbesc($token), + dbesc($expires), + intval($atoken_id), + intval($channel['channel_id']) + ); + } else { + $r = q("insert into atoken ( atoken_guid, atoken_aid, atoken_uid, atoken_name, atoken_token, atoken_expires ) values ( '%s', %d, %d, '%s', '%s', '%s' ) ", - dbesc($atoken_guid), - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc($name), - dbesc($token), - dbesc($expires) - ); - } - $atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'", - intval($channel['channel_id']), - dbesc($name) - ); - if ($atok) { - $xchan = atoken_xchan($atok[0]); - atoken_create_xchan($xchan); - $atoken_xchan = $xchan['xchan_hash']; - if ($old_atok && $old_xchan) { - $r = q("update xchan set xchan_name = '%s' where xchan_hash = '%s'", - dbesc($xchan['xchan_name']), - dbesc($old_xchan['xchan_hash']) - ); - } - } + dbesc($atoken_guid), + intval($channel['channel_account_id']), + intval($channel['channel_id']), + dbesc($name), + dbesc($token), + dbesc($expires) + ); + } + $atok = q("select * from atoken where atoken_uid = %d and atoken_name = '%s'", + intval($channel['channel_id']), + dbesc($name) + ); + if ($atok) { + $xchan = atoken_xchan($atok[0]); + atoken_create_xchan($xchan); + $atoken_xchan = $xchan['xchan_hash']; + if ($old_atok && $old_xchan) { + $r = q("update xchan set xchan_name = '%s' where xchan_hash = '%s'", + dbesc($xchan['xchan_name']), + dbesc($old_xchan['xchan_hash']) + ); + } + } - $all_perms = Permissions::Perms(); + $all_perms = Permissions::Perms(); - $p = EMPTY_STR; + $p = EMPTY_STR; - if($all_perms) { - foreach($all_perms as $perm => $desc) { - if(array_key_exists('perms_' . $perm, $_POST)) { - if($p) - $p .= ','; - $p .= $perm; - } - } - set_abconfig(local_channel(),$atoken_xchan,'system','my_perms',$p); - if ($old_atok) { + if ($all_perms) { + foreach ($all_perms as $perm => $desc) { + if (array_key_exists('perms_' . $perm, $_POST)) { + if ($p) + $p .= ','; + $p .= $perm; + } + } + set_abconfig(local_channel(), $atoken_xchan, 'system', 'my_perms', $p); + if ($old_atok) { - } - } - - if (! $atoken_id) { - - // If this is a new token, create a new abook record + } + } - $closeness = get_pconfig($uid,'system','new_abook_closeness',80); - $profile_assign = get_pconfig($uid,'system','profile_assign',''); + if (!$atoken_id) { - $r = abook_store_lowlevel( - [ - 'abook_account' => $channel['channel_account_id'], - 'abook_channel' => $channel['channel_id'], - 'abook_closeness' => intval($closeness), - 'abook_xchan' => $atoken_xchan, - 'abook_profile' => $profile_assign, - 'abook_feed' => 0, - 'abook_created' => datetime_convert(), - 'abook_updated' => datetime_convert(), - 'abook_instance' => z_root() - ] - ); + // If this is a new token, create a new abook record - if (! $r) { - logger('abook creation failed'); - } + $closeness = get_pconfig($uid, 'system', 'new_abook_closeness', 80); + $profile_assign = get_pconfig($uid, 'system', 'profile_assign', ''); - /** If there is a default group for this channel, add this connection to it */ + $r = abook_store_lowlevel( + [ + 'abook_account' => $channel['channel_account_id'], + 'abook_channel' => $channel['channel_id'], + 'abook_closeness' => intval($closeness), + 'abook_xchan' => $atoken_xchan, + 'abook_profile' => $profile_assign, + 'abook_feed' => 0, + 'abook_created' => datetime_convert(), + 'abook_updated' => datetime_convert(), + 'abook_instance' => z_root() + ] + ); - if ($channel['channel_default_group']) { - $g = AccessList::rec_byhash($uid,$channel['channel_default_group']); - if ($g) { - AccessList::member_add($uid,'',$atoken_xchan,$g['id']); - } - } + if (!$r) { + logger('abook creation failed'); + } - $r = q("SELECT abook.*, xchan.* + /** If there is a default group for this channel, add this connection to it */ + + if ($channel['channel_default_group']) { + $g = AccessList::rec_byhash($uid, $channel['channel_default_group']); + if ($g) { + AccessList::member_add($uid, '', $atoken_xchan, $g['id']); + } + } + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1", - intval($channel['channel_id']), - dbesc($atoken_xchan) - ); + intval($channel['channel_id']), + dbesc($atoken_xchan) + ); - if (! $r) { - logger('abook or xchan record not saved correctly'); - return; - } + if (!$r) { + logger('abook or xchan record not saved correctly'); + return; + } - $clone = array_shift($r); - - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); - - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if ($abconfig) { - $clone['abconfig'] = $abconfig; - } - - Libsync::build_sync_packet($channel['channel_id'], - [ 'abook' => [ $clone ], 'atoken' => $atok ], - true); - } + $clone = array_shift($r); - info( t('Token saved.') . EOL); - return; - } - + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); - function get() { + $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + if ($abconfig) { + $clone['abconfig'] = $abconfig; + } - $channel = App::get_channel(); + Libsync::build_sync_packet($channel['channel_id'], + ['abook' => [$clone], 'atoken' => $atok], + true); + } - $atoken = null; - $atoken_xchan = ''; + info(t('Token saved.') . EOL); + return; + } - if(argc() > 2) { - $id = argv(2); - $atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d", - intval($id), - intval(local_channel()) - ); + public function get() + { - if($atoken) { - $atoken = $atoken[0]; - $atoken_xchan = substr($channel['channel_hash'],0,16) . '.' . $atoken['atoken_guid']; - } + $channel = App::get_channel(); - if($atoken && argc() > 3 && argv(3) === 'drop') { - $atoken['deleted'] = true; - - $r = q("SELECT abook.*, xchan.* + $atoken = null; + $atoken_xchan = ''; + + if (argc() > 2) { + $id = argv(2); + + $atoken = q("select * from atoken where atoken_id = %d and atoken_uid = %d", + intval($id), + intval(local_channel()) + ); + + if ($atoken) { + $atoken = $atoken[0]; + $atoken_xchan = substr($channel['channel_hash'], 0, 16) . '.' . $atoken['atoken_guid']; + } + + if ($atoken && argc() > 3 && argv(3) === 'drop') { + $atoken['deleted'] = true; + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1", - intval($channel['channel_id']), - dbesc($atoken_xchan) - ); - if (! $r) { - return; - } + intval($channel['channel_id']), + dbesc($atoken_xchan) + ); + if (!$r) { + return; + } - $clone = array_shift($r); - - unset($clone['abook_id']); - unset($clone['abook_account']); - unset($clone['abook_channel']); + $clone = array_shift($r); - $clone['entry_deleted'] = true; - - $abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']); - if ($abconfig) { - $clone['abconfig'] = $abconfig; - } + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); - atoken_delete($id); - Libsync::build_sync_packet($channel['channel_id'], - [ 'abook' => [ $clone ], 'atoken' => [ $atoken ] ], - true); + $clone['entry_deleted'] = true; - $atoken = null; - $atoken_xchan = ''; - } - } + $abconfig = load_abconfig($channel['channel_id'], $clone['abook_xchan']); + if ($abconfig) { + $clone['abconfig'] = $abconfig; + } - $t = q("select * from atoken where atoken_uid = %d", - intval(local_channel()) - ); + atoken_delete($id); + Libsync::build_sync_packet($channel['channel_id'], + ['abook' => [$clone], 'atoken' => [$atoken]], + true); - $desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'); + $atoken = null; + $atoken_xchan = ''; + } + } - $desc2 = t('You may also provide dropbox style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'); + $t = q("select * from atoken where atoken_uid = %d", + intval(local_channel()) + ); + + $desc = t('Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'); + + $desc2 = t('You may also provide dropbox style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'); - $global_perms = Permissions::Perms(); - $existing = get_all_perms(local_channel(),(($atoken_xchan) ? $atoken_xchan : EMPTY_STR)); + $global_perms = Permissions::Perms(); + $existing = get_all_perms(local_channel(), (($atoken_xchan) ? $atoken_xchan : EMPTY_STR)); - $theirs = get_abconfig(local_channel(),$atoken_xchan,'system','their_perms',EMPTY_STR); + $theirs = get_abconfig(local_channel(), $atoken_xchan, 'system', 'their_perms', EMPTY_STR); - $their_perms = Permissions::FilledPerms(explode(',',$theirs)); - foreach($global_perms as $k => $v) { - if(! array_key_exists($k,$their_perms)) - $their_perms[$k] = 1; - } + $their_perms = Permissions::FilledPerms(explode(',', $theirs)); + foreach ($global_perms as $k => $v) { + if (!array_key_exists($k, $their_perms)) + $their_perms[$k] = 1; + } - $my_perms = explode(',',get_abconfig(local_channel(),$atoken_xchan,'system','my_perms',EMPTY_STR)); + $my_perms = explode(',', get_abconfig(local_channel(), $atoken_xchan, 'system', 'my_perms', EMPTY_STR)); - foreach($global_perms as $k => $v) { - $thisperm = ((in_array($k,$my_perms)) ? 1 : 0); - - $checkinherited = PermissionLimits::Get(local_channel(),$k); - - // For auto permissions (when $self is true) we don't want to look at existing - // permissions because they are enabled for the channel owner - if((! $self) && ($existing[$k])) - $thisperm = "1"; + foreach ($global_perms as $k => $v) { + $thisperm = ((in_array($k, $my_perms)) ? 1 : 0); - $perms[] = array('perms_' . $k, $v, ((array_key_exists($k,$their_perms)) ? intval($their_perms[$k]) : ''),$thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); - } + $checkinherited = PermissionLimits::Get(local_channel(), $k); + + // For auto permissions (when $self is true) we don't want to look at existing + // permissions because they are enabled for the channel owner + if ((!$self) && ($existing[$k])) + $thisperm = "1"; + + $perms[] = array('perms_' . $k, $v, ((array_key_exists($k, $their_perms)) ? intval($their_perms[$k]) : ''), $thisperm, 1, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); + } - $tpl = get_markup_template("settings_tokens.tpl"); - $o .= replace_macros($tpl, array( - '$form_security_token' => get_form_security_token("settings_tokens"), - '$title' => t('Guest Access Tokens'), - '$desc' => $desc, - '$desc2' => $desc2, - '$tokens' => $t, - '$atoken' => $atoken, - '$atoken_xchan' => $atoken_chan, - '$url1' => z_root() . '/channel/' . $channel['channel_address'], - '$url2' => z_root() . '/photos/' . $channel['channel_address'], - '$name' => array('name', t('Login Name') . ' *', (($atoken) ? $atoken['atoken_name'] : ''),''), - '$token'=> array('token', t('Login Password') . ' *',(($atoken) ? $atoken['atoken_token'] : new_token()), ''), - '$expires'=> array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] > NULL_DATE) ? datetime_convert('UTC',date_default_timezone_get(),$atoken['atoken_expires']) : ''), ''), - '$them' => t('Their Settings'), - '$me' => t('My Settings'), - '$perms' => $perms, - '$inherited' => t('inherited'), - '$notself' => 1, - '$self' => 0, - '$permlbl' => t('Individual Permissions'), - '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), - '$submit' => t('Submit') - )); - return $o; - } - + $tpl = get_markup_template("settings_tokens.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_tokens"), + '$title' => t('Guest Access Tokens'), + '$desc' => $desc, + '$desc2' => $desc2, + '$tokens' => $t, + '$atoken' => $atoken, + '$atoken_xchan' => $atoken_chan, + '$url1' => z_root() . '/channel/' . $channel['channel_address'], + '$url2' => z_root() . '/photos/' . $channel['channel_address'], + '$name' => array('name', t('Login Name') . ' *', (($atoken) ? $atoken['atoken_name'] : ''), ''), + '$token' => array('token', t('Login Password') . ' *', (($atoken) ? $atoken['atoken_token'] : new_token()), ''), + '$expires' => array('expires', t('Expires (yyyy-mm-dd)'), (($atoken['atoken_expires'] && $atoken['atoken_expires'] > NULL_DATE) ? datetime_convert('UTC', date_default_timezone_get(), $atoken['atoken_expires']) : ''), ''), + '$them' => t('Their Settings'), + '$me' => t('My Settings'), + '$perms' => $perms, + '$inherited' => t('inherited'), + '$notself' => 1, + '$self' => 0, + '$permlbl' => t('Individual Permissions'), + '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), + '$submit' => t('Submit') + )); + return $o; + } + } diff --git a/Zotlabs/Module/Setup.php b/Zotlabs/Module/Setup.php index a1e9a2819..94d7ba5aa 100644 --- a/Zotlabs/Module/Setup.php +++ b/Zotlabs/Module/Setup.php @@ -20,869 +20,880 @@ use Zotlabs\Web\Controller; * @brief Initialisation for the setup module. * */ +class Setup extends Controller +{ -class Setup extends Controller { + private static $install_wizard_pass = 1; - private static $install_wizard_pass = 1; + /** + * {@inheritDoc} + * @see \\Zotlabs\\Web\\Controller::init() + */ - /** - * {@inheritDoc} - * @see \\Zotlabs\\Web\\Controller::init() - */ + public function init() + { - function init() { + // Ensure that if somebody hasn't read the install documentation and doesn't have all + // the required modules or has a totally borked shared hosting provider and they can't + // figure out what the hell is going on - that we at least spit out an error message which + // we can inquire about when they write to tell us that our software doesn't work. - // Ensure that if somebody hasn't read the install documentation and doesn't have all - // the required modules or has a totally borked shared hosting provider and they can't - // figure out what the hell is going on - that we at least spit out an error message which - // we can inquire about when they write to tell us that our software doesn't work. + // The worst thing we can do at this point is throw a white screen of death and rely on + // them knowing about servers and php modules and logfiles enough so that we can guess + // at the source of the problem. As ugly as it may be, we need to throw a technically worded + // PHP error message in their face. Once installation is complete application errors will + // throw a white screen because these error messages divulge information which can + // potentially be useful to hackers. - // The worst thing we can do at this point is throw a white screen of death and rely on - // them knowing about servers and php modules and logfiles enough so that we can guess - // at the source of the problem. As ugly as it may be, we need to throw a technically worded - // PHP error message in their face. Once installation is complete application errors will - // throw a white screen because these error messages divulge information which can - // potentially be useful to hackers. + // We can only set E_WARNING once the code has been thoroughly cleansed of referencing + // undeclared or unset variables which were once legal or accepted in PHP. - // We can only set E_WARNING once the code has been thoroughly cleansed of referencing - // undeclared or unset variables which were once legal or accepted in PHP. - - error_reporting(E_ERROR | E_PARSE ); - ini_set('log_errors', '0'); - ini_set('display_errors', '1'); + error_reporting(E_ERROR | E_PARSE); + ini_set('log_errors', '0'); + ini_set('display_errors', '1'); - // $baseurl/setup/testrewrite to test if rewrite in .htaccess is working - - if (argc() == 2 && argv(1) == "testrewrite") { - echo 'ok'; - killme(); - } + // $baseurl/setup/testrewrite to test if rewrite in .htaccess is working - if (x($_POST, 'pass')) { - $this->install_wizard_pass = intval($_POST['pass']); - } - else { - $this->install_wizard_pass = 1; - } - } - - /** - * @brief Handle the actions of the different setup steps. - * - */ - function post() { - - switch ($this->install_wizard_pass) { - case 1: - case 2: - return; - // implied break; - case 3: - $urlpath = App::get_path(); - $dbhost = trim($_POST['dbhost']); - $dbport = intval(trim($_POST['dbport'])); - $dbuser = trim($_POST['dbuser']); - $dbpass = trim($_POST['dbpass']); - $dbdata = trim($_POST['dbdata']); - $dbtype = intval(trim($_POST['dbtype'])); - $servertype = intval(trim($_POST['servertype'])); - $phpath = trim($_POST['phpath']); - $adminmail = trim($_POST['adminmail']); - $siteurl = trim($_POST['siteurl']); - - // $siteurl should not have a trailing slash - - $siteurl = rtrim($siteurl,'/'); - - require_once('include/dba/dba_driver.php'); - - $db = DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true); - - if (! DBA::$dba->connected) { - echo 'Database Connect failed: ' . DBA::$dba->error; - killme(); - } - return; - // implied break; - case 4: - $urlpath = App::get_path(); - $dbhost = trim($_POST['dbhost']); - $dbport = intval(trim($_POST['dbport'])); - $dbuser = trim($_POST['dbuser']); - $dbpass = trim($_POST['dbpass']); - $dbdata = trim($_POST['dbdata']); - $dbtype = intval(trim($_POST['dbtype'])); - $servertype = intval(trim($_POST['servertype'])); - $phpath = trim($_POST['phpath']); - $timezone = trim($_POST['timezone']); - $adminmail = trim($_POST['adminmail']); - $siteurl = trim($_POST['siteurl']); - - if ($siteurl != z_root()) { - $test = z_fetch_url($siteurl . '/setup/testrewrite'); - if ((! $test['success']) || ($test['body'] !== 'ok')) { - App::$data['url_fail'] = true; - App::$data['url_error'] = $test['error']; - return; - } - } - - if (! DBA::$dba->connected) { - // connect to db - $db = DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true); - } - - if (! DBA::$dba->connected) { - echo 'CRITICAL: DB not connected.'; - killme(); - } - - $txt = replace_macros(get_intltext_template('htconfig.tpl'), [ - '$dbhost' => $dbhost, - '$dbport' => $dbport, - '$dbuser' => $dbuser, - '$dbpass' => $dbpass, - '$dbdata' => $dbdata, - '$dbtype' => $dbtype, - '$servertype' => '', - '$server_role' => 'pro', - '$timezone' => $timezone, - '$platform' => ucfirst(PLATFORM_NAME), - '$siteurl' => $siteurl, - '$site_id' => random_string(), - '$phpath' => $phpath, - '$adminmail' => $adminmail - ]); - - $result = file_put_contents('.htconfig.php', $txt); - if (! $result) { - App::$data['txt'] = $txt; - } - - $errors = $this->load_database($db); - - if ($errors) { - App::$data['db_failed'] = $errors; - } - else { - App::$data['db_installed'] = true; - } - - return; - // implied break; - default: - break; - } - } - - /** - * @brief Get output for the setup page. - * - * Depending on the state we are currently in it returns different content. - * - * @return string parsed HTML output - */ - - function get() { - - $o = EMPTY_STR; - $wizard_status = EMPTY_STR; - $db_return_text = EMPTY_STR; - $install_title = t('$Projectname Server - Setup'); - - if (x(App::$data, 'db_conn_failed')) { - $this->install_wizard_pass = 2; - $wizard_status = t('Could not connect to database.'); - } - if (x(App::$data, 'url_fail')) { - $this->install_wizard_pass = 3; - $wizard_status = t('Could not connect to specified site URL. Possible SSL certificate or DNS issue.'); - if (App::$data['url_error']) { - $wizard_status .= ' ' . App::$data['url_error']; - } - } - - if (x(App::$data, 'db_create_failed')) { - $this->install_wizard_pass = 2; - $wizard_status = t('Could not create table.'); - } - if (x(App::$data, 'db_installed')) { - $pass = t('Installation succeeded!'); - $icon = 'check'; - $txt = t('Your site database has been installed.') . EOL; - $db_return_text .= $txt; - } - if (x(App::$data, 'db_failed')) { - $pass = t('Database install failed!'); - $icon = 'exclamation-triangle'; - $txt = t('You may need to import the file "install/schema_xxx.sql" manually using a database client.') . EOL; - $txt .= t('Please see the file "install/INSTALL.txt".') . EOL . '
      ' ; - $txt .= '
      ' . App::$data['db_failed'] . '
      ' . EOL ; - $db_return_text .= $txt; - } - if (DBA::$dba && DBA::$dba->connected) { - $r = q("SELECT COUNT(*) as total FROM account"); - if ($r && count($r) && $r[0]['total']) { - return replace_macros(get_markup_template('install.tpl'), [ - '$title' => $install_title, - '$pass' => '', - '$status' => t('Permission denied.'), - '$text' => '', - ]); - } - } - - if (x(App::$data, 'txt') && strlen(App::$data['txt'])) { - $db_return_text .= $this->manual_config($a); - } - - if ($db_return_text !== EMPTY_STR) { - $tpl = get_markup_template('install.tpl'); - return replace_macros(get_markup_template('install.tpl'), [ - '$title' => $install_title, - '$icon' => $icon, - '$pass' => $pass, - '$text' => $db_return_text, - '$what_next' => $this->what_next() - ]); - } - - switch ($this->install_wizard_pass) { - - case 1: { - // System check - - $checks = []; - - $this->check_funcs($checks); - - $this->check_htconfig($checks); - - $this->check_store($checks); - - $this->check_smarty3($checks); - - $this->check_keys($checks); - - if (x($_POST, 'phpath')) { - $phpath = notags(trim($_POST['phpath'])); - } - - $this->check_php($phpath, $checks); - - $this->check_phpconfig($checks); - - $this->check_htaccess($checks); - - $checkspassed = array_reduce($checks, "self::check_passed", true); - - $o .= replace_macros(get_markup_template('install_checks.tpl'), [ - '$title' => $install_title, - '$pass' => t('System check'), - '$checks' => $checks, - '$passed' => $checkspassed, - '$see_install' => t('Please see the file "install/INSTALL.txt".'), - '$next' => t('Next'), - '$reload' => t('Check again'), - '$phpath' => $phpath, - '$baseurl' => z_root(), - ]); - return $o; - break; - } - - case 2: { - // Database config - - $dbhost = ((x($_POST,'dbhost')) ? trim($_POST['dbhost']) : '127.0.0.1'); - $dbuser = ((x($_POST,'dbuser')) ? trim($_POST['dbuser']): EMPTY_STR); - $dbport = ((x($_POST,'dbport')) ? intval(trim($_POST['dbport'])) : 0); - $dbpass = ((x($_POST,'dbpass')) ? trim($_POST['dbpass']): EMPTY_STR); - $dbdata = ((x($_POST,'dbdata')) ? trim($_POST['dbdata']): EMPTY_STR); - $dbtype = ((x($_POST,'dbtype')) ? intval(trim($_POST['dbtype'])) : 0); - $phpath = ((x($_POST,'phpath')) ? trim($_POST['phpath']): EMPTY_STR); - $adminmail = ((x($_POST,'adminmail')) ? trim($_POST['adminmail']): EMPTY_STR); - $siteurl = ((x($_POST,'siteurl')) ? trim($_POST['siteurl']): EMPTY_STR); - - $servertype = EMPTY_STR; - - $o .= replace_macros(get_markup_template('install_db.tpl'), [ - '$title' => $install_title, - '$pass' => t('Database connection'), - '$info_01' => t('In order to install this software we need to know how to connect to your database.'), - '$info_02' => t('Please contact your hosting provider or site administrator if you have questions about these settings.'), - '$info_03' => t('The database you specify below should already exist. If it does not, please create it before continuing.'), - - '$status' => $wizard_status, - - '$dbhost' => array('dbhost', t('Database Server Name'), $dbhost, t('Default is 127.0.0.1')), - '$dbport' => array('dbport', t('Database Port'), $dbport, t('Communication port number - use 0 for default')), - '$dbuser' => array('dbuser', t('Database Login Name'), $dbuser, ''), - '$dbpass' => array('dbpass', t('Database Login Password'), $dbpass, ''), - '$dbdata' => array('dbdata', t('Database Name'), $dbdata, ''), - '$dbtype' => array('dbtype', t('Database Type'), $dbtype, '', array( 0=>'MySQL', 1=>'PostgreSQL' )), - - '$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Required. Your account email address must match this in order to use the web admin panel.')), - '$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Required. Please use SSL (https) URL if available.')), - '$lbl_10' => t('Please select a default timezone for your website'), - '$baseurl' => z_root(), - '$phpath' => $phpath, - '$submit' => t('Submit'), - ]); - - return $o; - break; - } - case 3: { - // Site settings - $dbhost = ((x($_POST,'dbhost')) ? trim($_POST['dbhost']) : '127.0.0.1'); - $dbuser = ((x($_POST,'dbuser')) ? trim($_POST['dbuser']): EMPTY_STR); - $dbport = ((x($_POST,'dbport')) ? intval(trim($_POST['dbport'])) : 0); - $dbpass = ((x($_POST,'dbpass')) ? trim($_POST['dbpass']): EMPTY_STR); - $dbdata = ((x($_POST,'dbdata')) ? trim($_POST['dbdata']): EMPTY_STR); - $dbtype = ((x($_POST,'dbtype')) ? intval(trim($_POST['dbtype'])) : 0); - $phpath = ((x($_POST,'phpath')) ? trim($_POST['phpath']): EMPTY_STR); - - $servertype = EMPTY_STR; - - $adminmail = ((x($_POST,'adminmail')) ? trim($_POST['adminmail']): EMPTY_STR); - $siteurl = ((x($_POST,'siteurl')) ? trim($_POST['siteurl']): EMPTY_STR); - $timezone = ((x($_POST,'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles'); - - $o .= replace_macros(get_markup_template('install_settings.tpl'), [ - '$title' => $install_title, - '$pass' => t('Site settings'), - '$status' => $wizard_status, - - '$dbhost' => $dbhost, - '$dbport' => $dbport, - '$dbuser' => $dbuser, - '$dbpass' => $dbpass, - '$dbdata' => $dbdata, - '$phpath' => $phpath, - '$dbtype' => $dbtype, - '$servertype' => $servertype, - - '$adminmail' => [ 'adminmail', t('Site administrator email address'), $adminmail, t('Required. Your account email address must match this in order to use the web admin panel.') ], - - '$siteurl' => [ 'siteurl', t('Website URL'), z_root(), t('Required. Please use SSL (https) URL if available.')], - - '$timezone' => [ 'timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones() ], - - '$baseurl' => z_root(), - - '$submit' => t('Submit'), - ]); - return $o; - break; - } - } - } - - /** - * @brief Add a check result to the array for output. - * - * @param[in,out] array &$checks array passed to template - * @param string $title a title for the check - * @param boolean $status - * @param boolean $required - * @param string $help optional help string - */ - function check_add(&$checks, $title, $status, $required, $help = '') { - $checks[] = [ - 'title' => $title, - 'status' => $status, - 'required' => $required, - 'help' => $help - ]; - } - - /** - * @brief Checks the PHP environment. - * - * @param[in,out] string &$phpath - * @param[out] array &$checks - */ - function check_php(&$phpath, &$checks) { - $help = ''; - - if (version_compare(PHP_VERSION, '7.1') < 0) { - $help .= t('PHP version 7.1 or greater is required.'); - $this->check_add($checks, t('PHP version'), false, true, $help); - } - - if (strlen($phpath)) { - $passed = file_exists($phpath); - } - elseif (function_exists('shell_exec')) { - if (is_windows()) { - $phpath = trim(shell_exec('where php')); - } - else { - $phpath = trim(shell_exec('which php')); - } - $passed = strlen($phpath); - } - - if (!$passed) { - $help .= t('Could not find a command line version of PHP in the web server PATH.'). EOL; - $help .= t('If you do not have a command line version of PHP installed on server, you will not be able to run background tasks - including message delivery.') . EOL; - $help .= EOL; - - $help .= replace_macros(get_markup_template('field_input.tpl'), [ - '$field' => [ 'phpath', t('PHP executable path'), $phpath, t('Enter full path to php executable. You can leave this blank to continue the installation.')], - ]); - $phpath = ''; - } - - $this->check_add($checks, t('Command line PHP') . ($passed ? " ($phpath)" : EMPTY_STR), $passed, false, $help); - - if ($passed) { - $str = autoname(8); - $cmd = "$phpath install/testargs.php $str"; - $help = ''; - - if (function_exists('shell_exec')) { - $result = trim(shell_exec($cmd)); - } - else { - $help .= t('Unable to check command line PHP, as shell_exec() is disabled. This is required.') . EOL; - } - $passed2 = (($result === $str) ? true : false); - if (!$passed2) { - $help .= t('The command line version of PHP on your system does not have "register_argc_argv" enabled.'). EOL; - $help .= t('This is required for message delivery to work.'); - } - - $this->check_add($checks, t('PHP register_argc_argv'), $passed, true, $help); - } - } - - /** - * @brief Some PHP configuration checks. - * - * @todo Change how we display such informational text. Add more description - * how to change them. - * - * @param[out] array &$checks - */ - function check_phpconfig(&$checks) { - - $help = ''; - $mem_warning = EMPTY_STR; - - $result = self::getPhpiniUploadLimits(); - if($result['post_max_size'] < (2 * 1024 * 1024) || $result['max_upload_filesize'] < (2 * 1024 * 1024)) { - $mem_warning = '' . t('This is not sufficient to upload larger images or files. You should be able to upload at least 2MB (2097152 bytes) at once.') . ''; + if (argc() == 2 && argv(1) == "testrewrite") { + echo 'ok'; + killme(); } - $help = sprintf(t('Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once.'), - userReadableSize($result['post_max_size']), - userReadableSize($result['max_upload_filesize']), - $result['max_file_uploads'] - ); + if (x($_POST, 'pass')) { + $this->install_wizard_pass = intval($_POST['pass']); + } else { + $this->install_wizard_pass = 1; + } + } - $help .= (($mem_warning) ? $mem_warning : EMPTY_STR); - $help .= '

      ' . t('You can adjust these settings in the server php.ini file.'); + /** + * @brief Handle the actions of the different setup steps. + * + */ + public function post() + { - $this->check_add($checks, t('PHP upload limits'), true, false, $help); - } + switch ($this->install_wizard_pass) { + case 1: + case 2: + return; + // implied break; + case 3: + $urlpath = App::get_path(); + $dbhost = trim($_POST['dbhost']); + $dbport = intval(trim($_POST['dbport'])); + $dbuser = trim($_POST['dbuser']); + $dbpass = trim($_POST['dbpass']); + $dbdata = trim($_POST['dbdata']); + $dbtype = intval(trim($_POST['dbtype'])); + $servertype = intval(trim($_POST['servertype'])); + $phpath = trim($_POST['phpath']); + $adminmail = trim($_POST['adminmail']); + $siteurl = trim($_POST['siteurl']); - /** - * @brief Check if the openssl implementation can generate keys. - * - * @param[out] array $checks - */ - function check_keys(&$checks) { - $help = ''; - $res = false; + // $siteurl should not have a trailing slash - if (function_exists('openssl_pkey_new')) { - $res = openssl_pkey_new(array( - 'digest_alg' => 'sha1', - 'private_key_bits' => 4096, - 'encrypt_key' => false) - ); - } + $siteurl = rtrim($siteurl, '/'); - // Get private key + require_once('include/dba/dba_driver.php'); - if (! $res) { - $help .= t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys'). EOL; - $help .= t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".'); - } + $db = DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true); - $this->check_add($checks, t('Generate encryption keys'), $res, true, $help); - } + if (!DBA::$dba->connected) { + echo 'Database Connect failed: ' . DBA::$dba->error; + killme(); + } + return; + // implied break; + case 4: + $urlpath = App::get_path(); + $dbhost = trim($_POST['dbhost']); + $dbport = intval(trim($_POST['dbport'])); + $dbuser = trim($_POST['dbuser']); + $dbpass = trim($_POST['dbpass']); + $dbdata = trim($_POST['dbdata']); + $dbtype = intval(trim($_POST['dbtype'])); + $servertype = intval(trim($_POST['servertype'])); + $phpath = trim($_POST['phpath']); + $timezone = trim($_POST['timezone']); + $adminmail = trim($_POST['adminmail']); + $siteurl = trim($_POST['siteurl']); - /** - * @brief Check for some PHP functions and modules. - * - * @param[in,out] array &$checks - */ - function check_funcs(&$checks) { - $ck_funcs = []; + if ($siteurl != z_root()) { + $test = z_fetch_url($siteurl . '/setup/testrewrite'); + if ((!$test['success']) || ($test['body'] !== 'ok')) { + App::$data['url_fail'] = true; + App::$data['url_error'] = $test['error']; + return; + } + } - $disabled = explode(',',ini_get('disable_functions')); - if ($disabled) { - array_walk($disabled,'array_trim'); - } + if (!DBA::$dba->connected) { + // connect to db + $db = DBA::dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true); + } - // add check metadata, the real check is done bit later and return values set + if (!DBA::$dba->connected) { + echo 'CRITICAL: DB not connected.'; + killme(); + } - $this->check_add($ck_funcs, t('libCurl PHP module'), true, true); - $this->check_add($ck_funcs, t('GD graphics PHP module'), true, true); - $this->check_add($ck_funcs, t('OpenSSL PHP module'), true, true); - $this->check_add($ck_funcs, t('PDO database PHP module'), true, true); - $this->check_add($ck_funcs, t('mb_string PHP module'), true, true); - $this->check_add($ck_funcs, t('xml PHP module'), true, true); - $this->check_add($ck_funcs, t('zip PHP module'), true, true); + $txt = replace_macros(get_intltext_template('htconfig.tpl'), [ + '$dbhost' => $dbhost, + '$dbport' => $dbport, + '$dbuser' => $dbuser, + '$dbpass' => $dbpass, + '$dbdata' => $dbdata, + '$dbtype' => $dbtype, + '$servertype' => '', + '$server_role' => 'pro', + '$timezone' => $timezone, + '$platform' => ucfirst(PLATFORM_NAME), + '$siteurl' => $siteurl, + '$site_id' => random_string(), + '$phpath' => $phpath, + '$adminmail' => $adminmail + ]); - if (function_exists('apache_get_modules')){ - if (! in_array('mod_rewrite', apache_get_modules())) { - $this->check_add($ck_funcs, t('Apache mod_rewrite module'), false, true, t('Error: Apache webserver mod-rewrite module is required but not installed.')); - } - else { - $this->check_add($ck_funcs, t('Apache mod_rewrite module'), true, true); - } - } - if ((! function_exists('exec')) || in_array('exec',$disabled)) { - $this->check_add($ck_funcs, t('exec'), false, true, t('Error: exec is required but is either not installed or has been disabled in php.ini')); - } - else { - $this->check_add($ck_funcs, t('exec'), true, true); - } - if ((! function_exists('shell_exec')) || in_array('shell_exec',$disabled)) { - $this->check_add($ck_funcs, t('shell_exec'), false, true, t('Error: shell_exec is required but is either not installed or has been disabled in php.ini')); - } - else { - $this->check_add($ck_funcs, t('shell_exec'), true, true); - } + $result = file_put_contents('.htconfig.php', $txt); + if (!$result) { + App::$data['txt'] = $txt; + } - if (! function_exists('curl_init')) { - $ck_funcs[0]['status'] = false; - $ck_funcs[0]['help'] = t('Error: libCURL PHP module required but not installed.'); - } - if ((! function_exists('imagecreatefromjpeg')) && (! class_exists('\\Imagick'))) { - $ck_funcs[1]['status'] = false; - $ck_funcs[1]['help'] = t('Error: GD PHP module with JPEG support or ImageMagick graphics library required but not installed.'); - } - if (! function_exists('openssl_public_encrypt')) { - $ck_funcs[2]['status'] = false; - $ck_funcs[2]['help'] = t('Error: openssl PHP module required but not installed.'); - } - if (class_exists('\\PDO')) { - $x = PDO::getAvailableDrivers(); - if ((! in_array('mysql',$x)) && (! in_array('pgsql',$x))) { - $ck_funcs[3]['status'] = false; - $ck_funcs[3]['help'] = t('Error: PDO database PHP module missing a driver for either mysql or pgsql.'); - } - } - if (! class_exists('\\PDO')) { - $ck_funcs[3]['status'] = false; - $ck_funcs[3]['help'] = t('Error: PDO database PHP module required but not installed.'); - } - if (! function_exists('mb_strlen')) { - $ck_funcs[4]['status'] = false; - $ck_funcs[4]['help'] = t('Error: mb_string PHP module required but not installed.'); - } - if (! extension_loaded('xml')) { - $ck_funcs[5]['status'] = false; - $ck_funcs[5]['help'] = t('Error: xml PHP module required for DAV but not installed.'); - } - if (! extension_loaded('zip')) { - $ck_funcs[6]['status'] = false; - $ck_funcs[6]['help'] = t('Error: zip PHP module required but not installed.'); - } + $errors = $this->load_database($db); - $checks = array_merge($checks, $ck_funcs); - } + if ($errors) { + App::$data['db_failed'] = $errors; + } else { + App::$data['db_installed'] = true; + } - /** - * @brief Check for .htconfig requirements. - * - * @param[out] array &$checks - */ - function check_htconfig(&$checks) { - $status = true; - $help = EMPTY_STR; + return; + // implied break; + default: + break; + } + } - $fname = '.htconfig.php'; + /** + * @brief Get output for the setup page. + * + * Depending on the state we are currently in it returns different content. + * + * @return string parsed HTML output + */ - if((file_exists($fname) && is_writable($fname)) || - (! (file_exists($fname) && is_writable('.')))) { - $this->check_add($checks, t('.htconfig.php is writable'), $status, true, $help); - return; - } + public function get() + { - $status = false; - $help .= t('The web installer needs to be able to create a file called ".htconfig.php" in the top folder of your web server and it is unable to do so.') .EOL; - $help .= t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.').EOL; - $help .= t('Please see install/INSTALL.txt for additional information.'); + $o = EMPTY_STR; + $wizard_status = EMPTY_STR; + $db_return_text = EMPTY_STR; + $install_title = t('$Projectname Server - Setup'); - $this->check_add($checks, t('.htconfig.php is writable'), $status, true, $help); - } + if (x(App::$data, 'db_conn_failed')) { + $this->install_wizard_pass = 2; + $wizard_status = t('Could not connect to database.'); + } + if (x(App::$data, 'url_fail')) { + $this->install_wizard_pass = 3; + $wizard_status = t('Could not connect to specified site URL. Possible SSL certificate or DNS issue.'); + if (App::$data['url_error']) { + $wizard_status .= ' ' . App::$data['url_error']; + } + } - /** - * @brief Checks for our templating engine Smarty3 requirements. - * - * @param[out] array &$checks - */ - function check_smarty3(&$checks) { - $status = true; - $help = ''; + if (x(App::$data, 'db_create_failed')) { + $this->install_wizard_pass = 2; + $wizard_status = t('Could not create table.'); + } + if (x(App::$data, 'db_installed')) { + $pass = t('Installation succeeded!'); + $icon = 'check'; + $txt = t('Your site database has been installed.') . EOL; + $db_return_text .= $txt; + } + if (x(App::$data, 'db_failed')) { + $pass = t('Database install failed!'); + $icon = 'exclamation-triangle'; + $txt = t('You may need to import the file "install/schema_xxx.sql" manually using a database client.') . EOL; + $txt .= t('Please see the file "install/INSTALL.txt".') . EOL . '
      '; + $txt .= '
      ' . App::$data['db_failed'] . '
      ' . EOL; + $db_return_text .= $txt; + } + if (DBA::$dba && DBA::$dba->connected) { + $r = q("SELECT COUNT(*) as total FROM account"); + if ($r && count($r) && $r[0]['total']) { + return replace_macros(get_markup_template('install.tpl'), [ + '$title' => $install_title, + '$pass' => '', + '$status' => t('Permission denied.'), + '$text' => '', + ]); + } + } - @os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true); + if (x(App::$data, 'txt') && strlen(App::$data['txt'])) { + $db_return_text .= $this->manual_config($a); + } - if (! is_writable(TEMPLATE_BUILD_PATH) ) { - $status = false; - $help .= t('This software uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') .EOL; - $help .= sprintf( t('In order to store these compiled templates, the web server needs to have write access to the directory %s under the top level web folder.'), TEMPLATE_BUILD_PATH) . EOL; - $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.') . EOL; - } + if ($db_return_text !== EMPTY_STR) { + $tpl = get_markup_template('install.tpl'); + return replace_macros(get_markup_template('install.tpl'), [ + '$title' => $install_title, + '$icon' => $icon, + '$pass' => $pass, + '$text' => $db_return_text, + '$what_next' => $this->what_next() + ]); + } - $this->check_add($checks, sprintf( t('%s is writable'), TEMPLATE_BUILD_PATH), $status, true, $help); - } + switch ($this->install_wizard_pass) { - /** - * @brief Check for store directory. - * - * @param[out] array &$checks - */ - function check_store(&$checks) { - $status = true; - $help = ''; + case 1: + { + // System check - @os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, true); - - if (! is_writable('store')) { - $status = false; - $help = t('This software uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the top level web folder') . EOL; - $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL; - } + $checks = []; - $this->check_add($checks, t('store is writable'), $status, true, $help); - } + $this->check_funcs($checks); - /** - * @brief Check URL rewrite und SSL certificate. - * - * @param[out] array &$checks - */ - function check_htaccess(&$checks) { - $status = true; - $help = ''; - $ssl_error = false; + $this->check_htconfig($checks); - $url = z_root() . '/setup/testrewrite'; + $this->check_store($checks); - if (function_exists('curl_init')) { - $test = z_fetch_url($url); - if (! $test['success']) { - if (strstr($url,'https://')) { - $test = z_fetch_url($url,false,0, [ 'novalidate' => true ]); - if ($test['success']) { - $ssl_error = true; - } - } - else { - $test = z_fetch_url(str_replace('http://','https://',$url),false,0, [ 'novalidate' => true ]); - if ($test['success']) { - $ssl_error = true; - } - } + $this->check_smarty3($checks); - if ($ssl_error) { - $help .= t('SSL certificate cannot be validated. Fix certificate or disable https access to this site.') . EOL; - $help .= t('If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!') . EOL; - $help .= t('This restriction is incorporated because public posts from you may for example contain references to images on your own hub.') . EOL; - $help .= t('If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues.') . EOL; - $help .= t('This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement.') .EOL; - $help .= t('Providers are available that issue free certificates which are browser-valid.'). EOL; + $this->check_keys($checks); - $help .= t('If you are confident that the certificate is valid and signed by a trusted authority, check to see if you have failed to install an intermediate cert. These are not normally required by browsers, but are required for server-to-server communications.') . EOL; + if (x($_POST, 'phpath')) { + $phpath = notags(trim($_POST['phpath'])); + } - $this->check_add($checks, t('SSL certificate validation'), false, true, $help); - } - } + $this->check_php($phpath, $checks); - if ((! $test['success']) || ($test['body'] !== 'ok')) { - $status = false; - $help = t('Url rewrite in .htaccess is not working. Check your server configuration.' . 'Test: ' . var_export($test,true)); - } + $this->check_phpconfig($checks); - $this->check_add($checks, t('Url rewrite is working'), $status, true, $help); - } - else { - // cannot check modrewrite if libcurl is not installed - } - } + $this->check_htaccess($checks); - /** - * @brief - * - * @param App &$a - * @return string with paresed HTML - */ - function manual_config(&$a) { - $data = htmlspecialchars(App::$data['txt'], ENT_COMPAT, 'UTF-8'); - $o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); - $o .= ""; + $checkspassed = array_reduce($checks, "self::check_passed", true); - return $o; - } + $o .= replace_macros(get_markup_template('install_checks.tpl'), [ + '$title' => $install_title, + '$pass' => t('System check'), + '$checks' => $checks, + '$passed' => $checkspassed, + '$see_install' => t('Please see the file "install/INSTALL.txt".'), + '$next' => t('Next'), + '$reload' => t('Check again'), + '$phpath' => $phpath, + '$baseurl' => z_root(), + ]); + return $o; + break; + } - function load_database_rem($v, $i) { - $l = trim($i); - if (strlen($l) > 1 && ($l[0] === '-' || ($l[0] === '/' && $l[1] === '*'))) { - return $v; - } - else { - return $v . "\n" . $i; - } - } + case 2: + { + // Database config + + $dbhost = ((x($_POST, 'dbhost')) ? trim($_POST['dbhost']) : '127.0.0.1'); + $dbuser = ((x($_POST, 'dbuser')) ? trim($_POST['dbuser']) : EMPTY_STR); + $dbport = ((x($_POST, 'dbport')) ? intval(trim($_POST['dbport'])) : 0); + $dbpass = ((x($_POST, 'dbpass')) ? trim($_POST['dbpass']) : EMPTY_STR); + $dbdata = ((x($_POST, 'dbdata')) ? trim($_POST['dbdata']) : EMPTY_STR); + $dbtype = ((x($_POST, 'dbtype')) ? intval(trim($_POST['dbtype'])) : 0); + $phpath = ((x($_POST, 'phpath')) ? trim($_POST['phpath']) : EMPTY_STR); + $adminmail = ((x($_POST, 'adminmail')) ? trim($_POST['adminmail']) : EMPTY_STR); + $siteurl = ((x($_POST, 'siteurl')) ? trim($_POST['siteurl']) : EMPTY_STR); + + $servertype = EMPTY_STR; + + $o .= replace_macros(get_markup_template('install_db.tpl'), [ + '$title' => $install_title, + '$pass' => t('Database connection'), + '$info_01' => t('In order to install this software we need to know how to connect to your database.'), + '$info_02' => t('Please contact your hosting provider or site administrator if you have questions about these settings.'), + '$info_03' => t('The database you specify below should already exist. If it does not, please create it before continuing.'), + + '$status' => $wizard_status, + + '$dbhost' => array('dbhost', t('Database Server Name'), $dbhost, t('Default is 127.0.0.1')), + '$dbport' => array('dbport', t('Database Port'), $dbport, t('Communication port number - use 0 for default')), + '$dbuser' => array('dbuser', t('Database Login Name'), $dbuser, ''), + '$dbpass' => array('dbpass', t('Database Login Password'), $dbpass, ''), + '$dbdata' => array('dbdata', t('Database Name'), $dbdata, ''), + '$dbtype' => array('dbtype', t('Database Type'), $dbtype, '', array(0 => 'MySQL', 1 => 'PostgreSQL')), + + '$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Required. Your account email address must match this in order to use the web admin panel.')), + '$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Required. Please use SSL (https) URL if available.')), + '$lbl_10' => t('Please select a default timezone for your website'), + '$baseurl' => z_root(), + '$phpath' => $phpath, + '$submit' => t('Submit'), + ]); + + return $o; + break; + } + case 3: + { + // Site settings + $dbhost = ((x($_POST, 'dbhost')) ? trim($_POST['dbhost']) : '127.0.0.1'); + $dbuser = ((x($_POST, 'dbuser')) ? trim($_POST['dbuser']) : EMPTY_STR); + $dbport = ((x($_POST, 'dbport')) ? intval(trim($_POST['dbport'])) : 0); + $dbpass = ((x($_POST, 'dbpass')) ? trim($_POST['dbpass']) : EMPTY_STR); + $dbdata = ((x($_POST, 'dbdata')) ? trim($_POST['dbdata']) : EMPTY_STR); + $dbtype = ((x($_POST, 'dbtype')) ? intval(trim($_POST['dbtype'])) : 0); + $phpath = ((x($_POST, 'phpath')) ? trim($_POST['phpath']) : EMPTY_STR); + + $servertype = EMPTY_STR; + + $adminmail = ((x($_POST, 'adminmail')) ? trim($_POST['adminmail']) : EMPTY_STR); + $siteurl = ((x($_POST, 'siteurl')) ? trim($_POST['siteurl']) : EMPTY_STR); + $timezone = ((x($_POST, 'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles'); + + $o .= replace_macros(get_markup_template('install_settings.tpl'), [ + '$title' => $install_title, + '$pass' => t('Site settings'), + '$status' => $wizard_status, + + '$dbhost' => $dbhost, + '$dbport' => $dbport, + '$dbuser' => $dbuser, + '$dbpass' => $dbpass, + '$dbdata' => $dbdata, + '$phpath' => $phpath, + '$dbtype' => $dbtype, + '$servertype' => $servertype, + + '$adminmail' => ['adminmail', t('Site administrator email address'), $adminmail, t('Required. Your account email address must match this in order to use the web admin panel.')], + + '$siteurl' => ['siteurl', t('Website URL'), z_root(), t('Required. Please use SSL (https) URL if available.')], + + '$timezone' => ['timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones()], + + '$baseurl' => z_root(), + + '$submit' => t('Submit'), + ]); + return $o; + break; + } + } + } + + /** + * @brief Add a check result to the array for output. + * + * @param[in,out] array &$checks array passed to template + * @param string $title a title for the check + * @param bool $status + * @param bool $required + * @param string $help optional help string + */ + public function check_add(&$checks, $title, $status, $required, $help = '') + { + $checks[] = [ + 'title' => $title, + 'status' => $status, + 'required' => $required, + 'help' => $help + ]; + } + + /** + * @brief Checks the PHP environment. + * + * @param[in,out] string &$phpath + * @param[out] array &$checks + */ + public function check_php(&$phpath, &$checks) + { + $help = ''; + + if (version_compare(PHP_VERSION, '7.1') < 0) { + $help .= t('PHP version 7.1 or greater is required.'); + $this->check_add($checks, t('PHP version'), false, true, $help); + } + + if (strlen($phpath)) { + $passed = file_exists($phpath); + } elseif (function_exists('shell_exec')) { + if (is_windows()) { + $phpath = trim(shell_exec('where php')); + } else { + $phpath = trim(shell_exec('which php')); + } + $passed = strlen($phpath); + } + + if (!$passed) { + $help .= t('Could not find a command line version of PHP in the web server PATH.') . EOL; + $help .= t('If you do not have a command line version of PHP installed on server, you will not be able to run background tasks - including message delivery.') . EOL; + $help .= EOL; + + $help .= replace_macros(get_markup_template('field_input.tpl'), [ + '$field' => ['phpath', t('PHP executable path'), $phpath, t('Enter full path to php executable. You can leave this blank to continue the installation.')], + ]); + $phpath = ''; + } + + $this->check_add($checks, t('Command line PHP') . ($passed ? " ($phpath)" : EMPTY_STR), $passed, false, $help); + + if ($passed) { + $str = autoname(8); + $cmd = "$phpath install/testargs.php $str"; + $help = ''; + + if (function_exists('shell_exec')) { + $result = trim(shell_exec($cmd)); + } else { + $help .= t('Unable to check command line PHP, as shell_exec() is disabled. This is required.') . EOL; + } + $passed2 = (($result === $str) ? true : false); + if (!$passed2) { + $help .= t('The command line version of PHP on your system does not have "register_argc_argv" enabled.') . EOL; + $help .= t('This is required for message delivery to work.'); + } + + $this->check_add($checks, t('PHP register_argc_argv'), $passed, true, $help); + } + } + + /** + * @brief Some PHP configuration checks. + * + * @param[out] array &$checks + * @todo Change how we display such informational text. Add more description + * how to change them. + * + */ + public function check_phpconfig(&$checks) + { + + $help = ''; + $mem_warning = EMPTY_STR; + + $result = self::getPhpiniUploadLimits(); + if ($result['post_max_size'] < (2 * 1024 * 1024) || $result['max_upload_filesize'] < (2 * 1024 * 1024)) { + $mem_warning = '' . t('This is not sufficient to upload larger images or files. You should be able to upload at least 2MB (2097152 bytes) at once.') . ''; + } + + $help = sprintf(t('Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once.'), + userReadableSize($result['post_max_size']), + userReadableSize($result['max_upload_filesize']), + $result['max_file_uploads'] + ); + + $help .= (($mem_warning) ? $mem_warning : EMPTY_STR); + $help .= '

      ' . t('You can adjust these settings in the server php.ini file.'); + + $this->check_add($checks, t('PHP upload limits'), true, false, $help); + } + + /** + * @brief Check if the openssl implementation can generate keys. + * + * @param[out] array $checks + */ + public function check_keys(&$checks) + { + $help = ''; + $res = false; + + if (function_exists('openssl_pkey_new')) { + $res = openssl_pkey_new(array( + 'digest_alg' => 'sha1', + 'private_key_bits' => 4096, + 'encrypt_key' => false) + ); + } + + // Get private key + + if (!$res) { + $help .= t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys') . EOL; + $help .= t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".'); + } + + $this->check_add($checks, t('Generate encryption keys'), $res, true, $help); + } + + /** + * @brief Check for some PHP functions and modules. + * + * @param[in,out] array &$checks + */ + public function check_funcs(&$checks) + { + $ck_funcs = []; + + $disabled = explode(',', ini_get('disable_functions')); + if ($disabled) { + array_walk($disabled, 'array_trim'); + } + + // add check metadata, the real check is done bit later and return values set + + $this->check_add($ck_funcs, t('libCurl PHP module'), true, true); + $this->check_add($ck_funcs, t('GD graphics PHP module'), true, true); + $this->check_add($ck_funcs, t('OpenSSL PHP module'), true, true); + $this->check_add($ck_funcs, t('PDO database PHP module'), true, true); + $this->check_add($ck_funcs, t('mb_string PHP module'), true, true); + $this->check_add($ck_funcs, t('xml PHP module'), true, true); + $this->check_add($ck_funcs, t('zip PHP module'), true, true); + + if (function_exists('apache_get_modules')) { + if (!in_array('mod_rewrite', apache_get_modules())) { + $this->check_add($ck_funcs, t('Apache mod_rewrite module'), false, true, t('Error: Apache webserver mod-rewrite module is required but not installed.')); + } else { + $this->check_add($ck_funcs, t('Apache mod_rewrite module'), true, true); + } + } + if ((!function_exists('exec')) || in_array('exec', $disabled)) { + $this->check_add($ck_funcs, t('exec'), false, true, t('Error: exec is required but is either not installed or has been disabled in php.ini')); + } else { + $this->check_add($ck_funcs, t('exec'), true, true); + } + if ((!function_exists('shell_exec')) || in_array('shell_exec', $disabled)) { + $this->check_add($ck_funcs, t('shell_exec'), false, true, t('Error: shell_exec is required but is either not installed or has been disabled in php.ini')); + } else { + $this->check_add($ck_funcs, t('shell_exec'), true, true); + } + + if (!function_exists('curl_init')) { + $ck_funcs[0]['status'] = false; + $ck_funcs[0]['help'] = t('Error: libCURL PHP module required but not installed.'); + } + if ((!function_exists('imagecreatefromjpeg')) && (!class_exists('\\Imagick'))) { + $ck_funcs[1]['status'] = false; + $ck_funcs[1]['help'] = t('Error: GD PHP module with JPEG support or ImageMagick graphics library required but not installed.'); + } + if (!function_exists('openssl_public_encrypt')) { + $ck_funcs[2]['status'] = false; + $ck_funcs[2]['help'] = t('Error: openssl PHP module required but not installed.'); + } + if (class_exists('\\PDO')) { + $x = PDO::getAvailableDrivers(); + if ((!in_array('mysql', $x)) && (!in_array('pgsql', $x))) { + $ck_funcs[3]['status'] = false; + $ck_funcs[3]['help'] = t('Error: PDO database PHP module missing a driver for either mysql or pgsql.'); + } + } + if (!class_exists('\\PDO')) { + $ck_funcs[3]['status'] = false; + $ck_funcs[3]['help'] = t('Error: PDO database PHP module required but not installed.'); + } + if (!function_exists('mb_strlen')) { + $ck_funcs[4]['status'] = false; + $ck_funcs[4]['help'] = t('Error: mb_string PHP module required but not installed.'); + } + if (!extension_loaded('xml')) { + $ck_funcs[5]['status'] = false; + $ck_funcs[5]['help'] = t('Error: xml PHP module required for DAV but not installed.'); + } + if (!extension_loaded('zip')) { + $ck_funcs[6]['status'] = false; + $ck_funcs[6]['help'] = t('Error: zip PHP module required but not installed.'); + } + + $checks = array_merge($checks, $ck_funcs); + } + + /** + * @brief Check for .htconfig requirements. + * + * @param[out] array &$checks + */ + public function check_htconfig(&$checks) + { + $status = true; + $help = EMPTY_STR; + + $fname = '.htconfig.php'; + + if ((file_exists($fname) && is_writable($fname)) || + (!(file_exists($fname) && is_writable('.')))) { + $this->check_add($checks, t('.htconfig.php is writable'), $status, true, $help); + return; + } + + $status = false; + $help .= t('The web installer needs to be able to create a file called ".htconfig.php" in the top folder of your web server and it is unable to do so.') . EOL; + $help .= t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.') . EOL; + $help .= t('Please see install/INSTALL.txt for additional information.'); + + $this->check_add($checks, t('.htconfig.php is writable'), $status, true, $help); + } + + /** + * @brief Checks for our templating engine Smarty3 requirements. + * + * @param[out] array &$checks + */ + public function check_smarty3(&$checks) + { + $status = true; + $help = ''; + + @os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true); + + if (!is_writable(TEMPLATE_BUILD_PATH)) { + $status = false; + $help .= t('This software uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') . EOL; + $help .= sprintf(t('In order to store these compiled templates, the web server needs to have write access to the directory %s under the top level web folder.'), TEMPLATE_BUILD_PATH) . EOL; + $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.') . EOL; + } + + $this->check_add($checks, sprintf(t('%s is writable'), TEMPLATE_BUILD_PATH), $status, true, $help); + } + + /** + * @brief Check for store directory. + * + * @param[out] array &$checks + */ + public function check_store(&$checks) + { + $status = true; + $help = ''; + + @os_mkdir('store', STORAGE_DEFAULT_PERMISSIONS, true); + + if (!is_writable('store')) { + $status = false; + $help = t('This software uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the top level web folder') . EOL; + $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.') . EOL; + } + + $this->check_add($checks, t('store is writable'), $status, true, $help); + } + + /** + * @brief Check URL rewrite und SSL certificate. + * + * @param[out] array &$checks + */ + public function check_htaccess(&$checks) + { + $status = true; + $help = ''; + $ssl_error = false; + + $url = z_root() . '/setup/testrewrite'; + + if (function_exists('curl_init')) { + $test = z_fetch_url($url); + if (!$test['success']) { + if (strstr($url, 'https://')) { + $test = z_fetch_url($url, false, 0, ['novalidate' => true]); + if ($test['success']) { + $ssl_error = true; + } + } else { + $test = z_fetch_url(str_replace('http://', 'https://', $url), false, 0, ['novalidate' => true]); + if ($test['success']) { + $ssl_error = true; + } + } + + if ($ssl_error) { + $help .= t('SSL certificate cannot be validated. Fix certificate or disable https access to this site.') . EOL; + $help .= t('If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!') . EOL; + $help .= t('This restriction is incorporated because public posts from you may for example contain references to images on your own hub.') . EOL; + $help .= t('If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues.') . EOL; + $help .= t('This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement.') . EOL; + $help .= t('Providers are available that issue free certificates which are browser-valid.') . EOL; + + $help .= t('If you are confident that the certificate is valid and signed by a trusted authority, check to see if you have failed to install an intermediate cert. These are not normally required by browsers, but are required for server-to-server communications.') . EOL; + + $this->check_add($checks, t('SSL certificate validation'), false, true, $help); + } + } + + if ((!$test['success']) || ($test['body'] !== 'ok')) { + $status = false; + $help = t('Url rewrite in .htaccess is not working. Check your server configuration.' . 'Test: ' . var_export($test, true)); + } + + $this->check_add($checks, t('Url rewrite is working'), $status, true, $help); + } else { + // cannot check modrewrite if libcurl is not installed + } + } + + /** + * @brief + * + * @param App &$a + * @return string with paresed HTML + */ + public function manual_config(&$a) + { + $data = htmlspecialchars(App::$data['txt'], ENT_COMPAT, 'UTF-8'); + $o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); + $o .= ""; + + return $o; + } + + public function load_database_rem($v, $i) + { + $l = trim($i); + if (strlen($l) > 1 && ($l[0] === '-' || ($l[0] === '/' && $l[1] === '*'))) { + return $v; + } else { + return $v . "\n" . $i; + } + } - function load_database($db) { - $str = file_get_contents(DBA::$dba->get_install_script()); - $arr = explode(';', $str); - $errors = false; - foreach ($arr as $a) { - if (strlen(trim($a))) { - $r = dbq(trim($a)); - if (! $r) { - $errors .= t('Errors encountered creating database tables.') . $a . EOL; - } - } - } + public function load_database($db) + { + $str = file_get_contents(DBA::$dba->get_install_script()); + $arr = explode(';', $str); + $errors = false; + foreach ($arr as $a) { + if (strlen(trim($a))) { + $r = dbq(trim($a)); + if (!$r) { + $errors .= t('Errors encountered creating database tables.') . $a . EOL; + } + } + } - return $errors; - } + return $errors; + } - /** - * @brief - * - * @return string with parsed HTML - */ - function what_next() { - // install the standard theme - set_config('system', 'allowed_themes', 'redbasic'); + /** + * @brief + * + * @return string with parsed HTML + */ + public function what_next() + { + // install the standard theme + set_config('system', 'allowed_themes', 'redbasic'); - // if imagick converter is installed, use it - if (@is_executable('/usr/bin/convert')) { - set_config('system','imagick_convert_path','/usr/bin/convert'); - } + // if imagick converter is installed, use it + if (@is_executable('/usr/bin/convert')) { + set_config('system', 'imagick_convert_path', '/usr/bin/convert'); + } - // Set a lenient list of ciphers if using openssl. Other ssl engines - // (e.g. NSS used in RedHat) require different syntax, so hopefully - // the default curl cipher list will work for most sites. If not, - // this can set via config. Many distros are now disabling RC4, - // but many existing sites still use it and are unable to change it. - // We do not use SSL for encryption, only to protect session cookies. - // z_fetch_url() is also used to import shared links and other content - // so in theory most any cipher could show up and we should do our best - // to make the content available rather than tell folks that there's a - // weird SSL error which they can't do anything about. This does not affect - // the SSL server, but is only a client negotiation to find something workable. - // Hence it will not make your system susceptible to POODL or other nasties. + // Set a lenient list of ciphers if using openssl. Other ssl engines + // (e.g. NSS used in RedHat) require different syntax, so hopefully + // the default curl cipher list will work for most sites. If not, + // this can set via config. Many distros are now disabling RC4, + // but many existing sites still use it and are unable to change it. + // We do not use SSL for encryption, only to protect session cookies. + // z_fetch_url() is also used to import shared links and other content + // so in theory most any cipher could show up and we should do our best + // to make the content available rather than tell folks that there's a + // weird SSL error which they can't do anything about. This does not affect + // the SSL server, but is only a client negotiation to find something workable. + // Hence it will not make your system susceptible to POODL or other nasties. - $x = curl_version(); - if(stristr($x['ssl_version'],'openssl')) - set_config('system','curl_ssl_ciphers','ALL:!eNULL'); + $x = curl_version(); + if (stristr($x['ssl_version'], 'openssl')) + set_config('system', 'curl_ssl_ciphers', 'ALL:!eNULL'); - // Create a system channel - - create_sys_channel(); + // Create a system channel - $register_link = '' . t('registration page') . '' ; - - return - t('

      What next?

      ') - . '
      ' - . t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.') - . EOL - . t('Please see the file "install/INSTALL.txt" for more information and instructions.') - . '
      ' - . sprintf( t('Go to your new hub %s and register as new member. Please use the same email address that you entered for the administrator email as this will allow your new account to enter the site admin panel.'), $register_link ) - .'
      '; - } + create_sys_channel(); - /** - * @brief - * - * @param unknown $v - * @param array $c - * @return array - */ - static private function check_passed($v, $c) { - if ($c['required']) { - $v = $v && $c['status']; - } - return $v; - } + $register_link = '' . t('registration page') . ''; - /** - * @brief Get some upload related limits from php.ini. - * - * This function returns values from php.ini like \b post_max_size, - * \b max_file_uploads, \b upload_max_filesize. - * - * @return array associative array - * * \e int \b post_max_size the maximum size of a complete POST in bytes - * * \e int \b upload_max_filesize the maximum size of one file in bytes - * * \e int \b max_file_uploads maximum number of files in one POST - * * \e int \b max_upload_filesize min(post_max_size, upload_max_filesize) - */ + return + t('

      What next?

      ') + . '
      ' + . t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.') + . EOL + . t('Please see the file "install/INSTALL.txt" for more information and instructions.') + . '
      ' + . sprintf(t('Go to your new hub %s and register as new member. Please use the same email address that you entered for the administrator email as this will allow your new account to enter the site admin panel.'), $register_link) + . '
      '; + } - static private function getPhpiniUploadLimits() { - $ret = []; + /** + * @brief + * + * @param unknown $v + * @param array $c + * @return array + */ + private static function check_passed($v, $c) + { + if ($c['required']) { + $v = $v && $c['status']; + } + return $v; + } - // max size of the complete POST - $ret['post_max_size'] = self::phpiniSizeToBytes(ini_get('post_max_size')); - // max size of one file - $ret['upload_max_filesize'] = self::phpiniSizeToBytes(ini_get('upload_max_filesize')); - // catch a configuration error where post_max_size < upload_max_filesize - $ret['max_upload_filesize'] = min( - $ret['post_max_size'], - $ret['upload_max_filesize'] - ); - // maximum number of files in one POST - $ret['max_file_uploads'] = intval(ini_get('max_file_uploads')); + /** + * @brief Get some upload related limits from php.ini. + * + * This function returns values from php.ini like \b post_max_size, + * \b max_file_uploads, \b upload_max_filesize. + * + * @return array associative array + * * \e int \b post_max_size the maximum size of a complete POST in bytes + * * \e int \b upload_max_filesize the maximum size of one file in bytes + * * \e int \b max_file_uploads maximum number of files in one POST + * * \e int \b max_upload_filesize min(post_max_size, upload_max_filesize) + */ - return $ret; - } + private static function getPhpiniUploadLimits() + { + $ret = []; - /** - * @brief Parses php_ini size settings to bytes. - * - * This function parses common size setting from php.ini files to bytes. - * e.g. post_max_size = 8M ==> 8388608 - * - * \note This method does not recognise other human readable formats like - * 8MB, etc. - * - * @todo Make this function more universal useable. MB, T, etc. - * - * @param string $val value from php.ini e.g. 2M, 8M - * @return int size in bytes - */ - static private function phpiniSizeToBytes($val) { - $val = trim($val); - $unit = strtolower($val[strlen($val)-1]); - // strip off any non-numeric portion - $val = intval($val); - switch($unit) { - case 'g': - $val *= 1024; - case 'm': - $val *= 1024; - case 'k': - $val *= 1024; - default: - break; - } + // max size of the complete POST + $ret['post_max_size'] = self::phpiniSizeToBytes(ini_get('post_max_size')); + // max size of one file + $ret['upload_max_filesize'] = self::phpiniSizeToBytes(ini_get('upload_max_filesize')); + // catch a configuration error where post_max_size < upload_max_filesize + $ret['max_upload_filesize'] = min( + $ret['post_max_size'], + $ret['upload_max_filesize'] + ); + // maximum number of files in one POST + $ret['max_file_uploads'] = intval(ini_get('max_file_uploads')); - return (int)$val; - } + return $ret; + } + + /** + * @brief Parses php_ini size settings to bytes. + * + * This function parses common size setting from php.ini files to bytes. + * e.g. post_max_size = 8M ==> 8388608 + * + * \note This method does not recognise other human readable formats like + * 8MB, etc. + * + * @param string $val value from php.ini e.g. 2M, 8M + * @return int size in bytes + * @todo Make this function more universal useable. MB, T, etc. + * + */ + private static function phpiniSizeToBytes($val) + { + $val = trim($val); + $unit = strtolower($val[strlen($val) - 1]); + // strip off any non-numeric portion + $val = intval($val); + switch ($unit) { + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + default: + break; + } + + return (int)$val; + } } diff --git a/Zotlabs/Module/Share.php b/Zotlabs/Module/Share.php index 7500a80d7..0d6c4af3e 100644 --- a/Zotlabs/Module/Share.php +++ b/Zotlabs/Module/Share.php @@ -10,128 +10,130 @@ require_once('include/security.php'); require_once('include/bbcode.php'); -class Share extends Controller { +class Share extends Controller +{ - function init() { - - $post_id = ((argc() > 1) ? intval(argv(1)) : 0); - - if(! $post_id) - killme(); - - if(! local_channel()) { - killme(); - } + public function init() + { - $observer = App::get_observer(); + $post_id = ((argc() > 1) ? intval(argv(1)) : 0); - $channel = App::get_channel(); + if (!$post_id) + killme(); + + if (!local_channel()) { + killme(); + } + + $observer = App::get_observer(); + + $channel = App::get_channel(); - $r = q("SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d LIMIT 1", - intval($post_id) - ); - if(! $r) - killme(); + $r = q("SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d LIMIT 1", + intval($post_id) + ); + if (!$r) + killme(); - if(($r[0]['item_private']) && ($r[0]['xchan_network'] !== 'rss')) - killme(); - - $sql_extra = item_permissions_sql($r[0]['uid']); - - $r = q("select * from item where id = %d $sql_extra", - intval($post_id) - ); - if(! $r) - killme(); - - /** @FIXME we only share bbcode */ - - if (! in_array($r[0]['mimetype'], [ 'text/bbcode', 'text/x-multicode' ])) { - killme(); - } - - - xchan_query($r); - - $arr = []; + if (($r[0]['item_private']) && ($r[0]['xchan_network'] !== 'rss')) + killme(); - $item = $r[0]; + $sql_extra = item_permissions_sql($r[0]['uid']); - $owner_uid = $r[0]['uid']; - $owner_aid = $r[0]['aid']; + $r = q("select * from item where id = %d $sql_extra", + intval($post_id) + ); + if (!$r) + killme(); - $can_comment = false; - if((array_key_exists('owner',$item)) && intval($item['owner']['abook_self'])) - $can_comment = perm_is_allowed($item['uid'],$observer['xchan_hash'],'post_comments'); - else - $can_comment = can_comment_on_post($observer['xchan_hash'],$item); + /** @FIXME we only share bbcode */ - if(! $can_comment) { - notice( t('Permission denied') . EOL); - killme(); - } + if (!in_array($r[0]['mimetype'], ['text/bbcode', 'text/x-multicode'])) { + killme(); + } - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($item['owner_xchan']) - ); - if($r) - $thread_owner = $r[0]; - else - killme(); - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($item['author_xchan']) - ); - if($r) - $item_author = $r[0]; - else - killme(); - + xchan_query($r); - $arr['aid'] = $owner_aid; - $arr['uid'] = $owner_uid; + $arr = []; - $arr['item_origin'] = 1; - $arr['item_wall'] = $item['item_wall']; - $arr['uuid'] = new_uuid(); - $arr['mid'] = z_root() . '/item/' . $arr['uuid']; - $arr['mid'] = str_replace('/item/','/activity/',$arr['mid']); - $arr['parent_mid'] = $item['mid']; + $item = $r[0]; - $mention = '@[zrl=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/zrl]'; - $arr['body'] = sprintf( t('🔁 Repeated %1$s\'s %2$s'), $mention, $item['obj_type']); + $owner_uid = $r[0]['uid']; + $owner_aid = $r[0]['aid']; - $arr['author_xchan'] = $channel['channel_hash']; - $arr['owner_xchan'] = $item['author_xchan']; - $arr['obj'] = $item['obj']; - $arr['obj_type'] = $item['obj_type']; - $arr['verb'] = 'Announce'; + $can_comment = false; + if ((array_key_exists('owner', $item)) && intval($item['owner']['abook_self'])) + $can_comment = perm_is_allowed($item['uid'], $observer['xchan_hash'], 'post_comments'); + else + $can_comment = can_comment_on_post($observer['xchan_hash'], $item); - $post = item_store($arr); + if (!$can_comment) { + notice(t('Permission denied') . EOL); + killme(); + } - $post_id = $post['item_id']; + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['owner_xchan']) + ); - $arr['id'] = $post_id; - - call_hooks('post_local_end', $arr); + if ($r) + $thread_owner = $r[0]; + else + killme(); - info( t('Post repeated') . EOL); + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['author_xchan']) + ); + if ($r) + $item_author = $r[0]; + else + killme(); - $r = q("select * from item where id = %d", - intval($post_id) - ); - if($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]); - } - Run::Summon([ 'Notifier','like',$post_id ]); - - killme(); - - } - + $arr['aid'] = $owner_aid; + $arr['uid'] = $owner_uid; + + $arr['item_origin'] = 1; + $arr['item_wall'] = $item['item_wall']; + $arr['uuid'] = new_uuid(); + $arr['mid'] = z_root() . '/item/' . $arr['uuid']; + $arr['mid'] = str_replace('/item/', '/activity/', $arr['mid']); + $arr['parent_mid'] = $item['mid']; + + $mention = '@[zrl=' . $item['author']['xchan_url'] . ']' . $item['author']['xchan_name'] . '[/zrl]'; + $arr['body'] = sprintf(t('🔁 Repeated %1$s\'s %2$s'), $mention, $item['obj_type']); + + $arr['author_xchan'] = $channel['channel_hash']; + $arr['owner_xchan'] = $item['author_xchan']; + $arr['obj'] = $item['obj']; + $arr['obj_type'] = $item['obj_type']; + $arr['verb'] = 'Announce'; + + $post = item_store($arr); + + $post_id = $post['item_id']; + + $arr['id'] = $post_id; + + call_hooks('post_local_end', $arr); + + info(t('Post repeated') . EOL); + + $r = q("select * from item where id = %d", + intval($post_id) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet($channel['channel_id'], ['item' => [encode_item($sync_item[0], true)]]); + } + + Run::Summon(['Notifier', 'like', $post_id]); + + killme(); + + } + } diff --git a/Zotlabs/Module/Sharedwithme.php b/Zotlabs/Module/Sharedwithme.php index ea996ac7e..17106b70c 100644 --- a/Zotlabs/Module/Sharedwithme.php +++ b/Zotlabs/Module/Sharedwithme.php @@ -13,111 +13,112 @@ require_once('include/text.php'); * @file Zotlabs/Module/Sharedwithme.php * */ +class Sharedwithme extends Controller +{ + + public function get() + { + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + $channel = App::get_channel(); + + $is_owner = (local_channel() && (local_channel() == $channel['channel_id'])); + + //check for updated items and remove them + require_once('include/sharedwithme.php'); + apply_updates(); + + //drop single file - localuser + if ((argc() > 2) && (argv(2) === 'drop')) { + + $id = intval(argv(1)); + + q("DELETE FROM item WHERE id = %d AND uid = %d", + intval($id), + intval(local_channel()) + ); + + goaway(z_root() . '/sharedwithme'); + } + + //drop all files - localuser + if ((argc() > 1) && (argv(1) === 'dropall')) { + + q("DELETE FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d", + dbesc(ACTIVITY_POST), + dbesc(ACTIVITY_OBJ_FILE), + intval(local_channel()) + ); + + goaway(z_root() . '/sharedwithme'); + } + + //list files + $r = q("SELECT id, uid, obj, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'", + dbesc(ACTIVITY_POST), + dbesc(ACTIVITY_OBJ_FILE), + intval(local_channel()), + dbesc($channel['channel_hash']) + ); + + $items = []; + $ids = ''; + + if ($r) { + + foreach ($r as $rr) { + $object = json_decode($rr['obj'], true); + + $item = []; + $item['id'] = $rr['id']; + $item['objfiletype'] = $object['filetype']; + $item['objfiletypeclass'] = getIconFromType($object['filetype']); + $item['objurl'] = rawurldecode(get_rel_link($object['link'], 'alternate')) . '?f=&zid=' . $channel['xchan_addr']; + $item['objfilename'] = $object['filename']; + $item['objfilesize'] = userReadableSize($object['filesize']); + $item['objedited'] = $object['edited']; + $item['unseen'] = $rr['item_unseen']; + + $items[] = $item; + + if ($item['unseen'] > 0) { + $ids .= " '" . $rr['id'] . "',"; + } + + } + + } + + if ($ids) { + + //remove trailing , + $ids = rtrim($ids, ","); + + q("UPDATE item SET item_unseen = 0 WHERE id IN ( $ids ) AND uid = %d", + intval(local_channel()) + ); + + } + + $o = ''; + + $o .= replace_macros(get_markup_template('sharedwithme.tpl'), array( + '$header' => t('Files: shared with me'), + '$name' => t('Name'), + '$label_new' => t('NEW'), + '$size' => t('Size'), + '$lastmod' => t('Last Modified'), + '$dropall' => t('Remove all files'), + '$drop' => t('Remove this file'), + '$items' => $items + )); + + return $o; + + } -class Sharedwithme extends Controller { - function get() { - if(! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } - - $channel = App::get_channel(); - - $is_owner = (local_channel() && (local_channel() == $channel['channel_id'])); - - //check for updated items and remove them - require_once('include/sharedwithme.php'); - apply_updates(); - - //drop single file - localuser - if((argc() > 2) && (argv(2) === 'drop')) { - - $id = intval(argv(1)); - - q("DELETE FROM item WHERE id = %d AND uid = %d", - intval($id), - intval(local_channel()) - ); - - goaway(z_root() . '/sharedwithme'); - } - - //drop all files - localuser - if((argc() > 1) && (argv(1) === 'dropall')) { - - q("DELETE FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d", - dbesc(ACTIVITY_POST), - dbesc(ACTIVITY_OBJ_FILE), - intval(local_channel()) - ); - - goaway(z_root() . '/sharedwithme'); - } - - //list files - $r = q("SELECT id, uid, obj, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'", - dbesc(ACTIVITY_POST), - dbesc(ACTIVITY_OBJ_FILE), - intval(local_channel()), - dbesc($channel['channel_hash']) - ); - - $items =[]; - $ids = ''; - - if($r) { - - foreach($r as $rr) { - $object = json_decode($rr['obj'],true); - - $item = []; - $item['id'] = $rr['id']; - $item['objfiletype'] = $object['filetype']; - $item['objfiletypeclass'] = getIconFromType($object['filetype']); - $item['objurl'] = rawurldecode(get_rel_link($object['link'],'alternate')) . '?f=&zid=' . $channel['xchan_addr']; - $item['objfilename'] = $object['filename']; - $item['objfilesize'] = userReadableSize($object['filesize']); - $item['objedited'] = $object['edited']; - $item['unseen'] = $rr['item_unseen']; - - $items[] = $item; - - if($item['unseen'] > 0) { - $ids .= " '" . $rr['id'] . "',"; - } - - } - - } - - if($ids) { - - //remove trailing , - $ids = rtrim($ids, ","); - - q("UPDATE item SET item_unseen = 0 WHERE id IN ( $ids ) AND uid = %d", - intval(local_channel()) - ); - - } - - $o = ''; - - $o .= replace_macros(get_markup_template('sharedwithme.tpl'), array( - '$header' => t('Files: shared with me'), - '$name' => t('Name'), - '$label_new' => t('NEW'), - '$size' => t('Size'), - '$lastmod' => t('Last Modified'), - '$dropall' => t('Remove all files'), - '$drop' => t('Remove this file'), - '$items' => $items - )); - - return $o; - - } - - } diff --git a/Zotlabs/Module/Siteinfo.php b/Zotlabs/Module/Siteinfo.php index 70d3bfa54..4841b72e3 100644 --- a/Zotlabs/Module/Siteinfo.php +++ b/Zotlabs/Module/Siteinfo.php @@ -5,58 +5,61 @@ use Zotlabs\Lib\System; use Zotlabs\Lib\Config; use Zotlabs\Web\Controller; -class Siteinfo extends Controller { +class Siteinfo extends Controller +{ - function init() { - if (argv(1) === 'json' || $_REQUEST['module_format'] === 'json') { - $data = get_site_info(); - json_return_and_die($data); - } - } - - function get() { + public function init() + { + if (argv(1) === 'json' || $_REQUEST['module_format'] === 'json') { + $data = get_site_info(); + json_return_and_die($data); + } + } - $federated = 'Nomad'; - if (Config::get('system','activitypub',true)) { - $federated .= ', ActivityPub'; - } + public function get() + { + + $federated = 'Nomad'; + if (Config::get('system', 'activitypub', true)) { + $federated .= ', ActivityPub'; + } - call_hooks('federated_transports',$federated); - - $siteinfo = replace_macros(get_markup_template('siteinfo.tpl'), - [ - '$title' => t('About this site'), - '$url' => z_root(), - '$sitenametxt' => t('Site Name'), - '$sitename' => System::get_site_name(), - '$headline' => t('Site Information'), - '$site_about' => bbcode(get_config('system','siteinfo')), - '$admin_headline' => t('Administrator'), - '$admin_about' => bbcode(get_config('system','admininfo')), - '$terms' => t('Terms of Service'), - '$prj_header' => t('Software and Project information'), - '$prj_name' => t('This site is powered by $Projectname'), - '$prj_transport' => t('Federated and decentralised networking and identity services provided by Nomad'), - '$transport_link' => 'https://zotlabs.com', + call_hooks('federated_transports', $federated); - '$ebs' => System::ebs(), - '$additional_text' => t('Protocols:'), - '$additional_fed' => $federated, - '$prj_version' => ((get_config('system','hidden_version_siteinfo')) ? '' : sprintf( t('Version %s'), System::get_project_version())), - '$prj_linktxt' => t('Project homepage'), - '$prj_srctxt' => t('Developer homepage'), - '$prj_link' => System::get_project_link(), - '$prj_src' => System::get_project_srclink(), - '$prj_icon' => System::get_site_icon(), - ] - ); + $siteinfo = replace_macros(get_markup_template('siteinfo.tpl'), + [ + '$title' => t('About this site'), + '$url' => z_root(), + '$sitenametxt' => t('Site Name'), + '$sitename' => System::get_site_name(), + '$headline' => t('Site Information'), + '$site_about' => bbcode(get_config('system', 'siteinfo')), + '$admin_headline' => t('Administrator'), + '$admin_about' => bbcode(get_config('system', 'admininfo')), + '$terms' => t('Terms of Service'), + '$prj_header' => t('Software and Project information'), + '$prj_name' => t('This site is powered by $Projectname'), + '$prj_transport' => t('Federated and decentralised networking and identity services provided by Nomad'), + '$transport_link' => 'https://zotlabs.com', - call_hooks('about_hook', $siteinfo); + '$ebs' => System::ebs(), + '$additional_text' => t('Protocols:'), + '$additional_fed' => $federated, + '$prj_version' => ((get_config('system', 'hidden_version_siteinfo')) ? '' : sprintf(t('Version %s'), System::get_project_version())), + '$prj_linktxt' => t('Project homepage'), + '$prj_srctxt' => t('Developer homepage'), + '$prj_link' => System::get_project_link(), + '$prj_src' => System::get_project_srclink(), + '$prj_icon' => System::get_site_icon(), + ] + ); - return $siteinfo; + call_hooks('about_hook', $siteinfo); + + return $siteinfo; + + } - } - } diff --git a/Zotlabs/Module/Sites.php b/Zotlabs/Module/Sites.php index 4b488f230..fde58775d 100644 --- a/Zotlabs/Module/Sites.php +++ b/Zotlabs/Module/Sites.php @@ -5,142 +5,142 @@ use Zotlabs\Lib\Libzotdir; use Zotlabs\Lib\LibBlock; use Zotlabs\Web\Controller; -class Sites extends Controller { +class Sites extends Controller +{ - function get() { - - $sql_extra = (($_REQUEST['project']) ? " and site_project = '" . escape_tags(protect_sprintf(dbesc($_REQUEST['project']))) . "' " : ""); - - $desc = t('This page provides information about related projects and websites that are currently known to this system. These are a small fraction of the thousands of websites and dozens of projects and providers which make up the fediverse.'); + public function get() + { - $j = []; + $sql_extra = (($_REQUEST['project']) ? " and site_project = '" . escape_tags(protect_sprintf(dbesc($_REQUEST['project']))) . "' " : ""); - $r = q("select * from site where site_flags != 256 and site_dead = 0 $sql_extra order by site_update desc"); + $desc = t('This page provides information about related projects and websites that are currently known to this system. These are a small fraction of the thousands of websites and dozens of projects and providers which make up the fediverse.'); + + $j = []; + + $r = q("select * from site where site_flags != 256 and site_dead = 0 $sql_extra order by site_update desc"); - if ($r) { + if ($r) { - $blocked = LibBlock::fetch($channel['channel_id'],BLOCKTYPE_SERVER); - foreach ($r as $rr) { - $found_block = false; - if ($blocked) { - foreach ($blocked as $b) { - if (strpos($rr['site_url'],$b['block_entity']) !== false) { - $found_block = true; - break; - } - } - if ($found_block) { - continue; - } - } + $blocked = LibBlock::fetch($channel['channel_id'], BLOCKTYPE_SERVER); + foreach ($r as $rr) { + $found_block = false; + if ($blocked) { + foreach ($blocked as $b) { + if (strpos($rr['site_url'], $b['block_entity']) !== false) { + $found_block = true; + break; + } + } + if ($found_block) { + continue; + } + } - if (! check_siteallowed($rr['site_url'])) { - continue; - } + if (!check_siteallowed($rr['site_url'])) { + continue; + } - if ($rr['site_access'] == ACCESS_FREE) - $access = t('free'); - elseif ($rr['site_access'] == ACCESS_PAID) - $access = t('subscription'); - elseif ($rr['site_access'] == ACCESS_TIERED) - $access = t('tiered service plans'); - else - $access = 'private'; - - if ($rr['site_register'] == REGISTER_OPEN) - $register = t('Register'); - elseif ($rr['site_register'] == REGISTER_APPROVE) - $register = t('Register (requires approval)'); - else - $register = 'closed'; + if ($rr['site_access'] == ACCESS_FREE) + $access = t('free'); + elseif ($rr['site_access'] == ACCESS_PAID) + $access = t('subscription'); + elseif ($rr['site_access'] == ACCESS_TIERED) + $access = t('tiered service plans'); + else + $access = 'private'; + + if ($rr['site_register'] == REGISTER_OPEN) + $register = t('Register'); + elseif ($rr['site_register'] == REGISTER_APPROVE) + $register = t('Register (requires approval)'); + else + $register = 'closed'; - $sitename = get_sconfig($rr['site_url'],'system','sitename',$rr['site_url']); - if ($sitename !== $rr['site_url']) { - $sitename .= ' (' . $rr['site_url'] . ')'; - } - $disabled = (($access === 'private' || $register === 'closed') ? true : false); - $logo = get_sconfig($rr['site_url'],'system','logo'); - $about = get_sconfig($rr['site_url'],'system','about'); + $sitename = get_sconfig($rr['site_url'], 'system', 'sitename', $rr['site_url']); + if ($sitename !== $rr['site_url']) { + $sitename .= ' (' . $rr['site_url'] . ')'; + } + $disabled = (($access === 'private' || $register === 'closed') ? true : false); + $logo = get_sconfig($rr['site_url'], 'system', 'logo'); + $about = get_sconfig($rr['site_url'], 'system', 'about'); - if (! $logo && file_exists('images/' . strtolower($rr['site_project']) . '.png')) { - $logo = 'images/' . strtolower($rr['site_project']) . '.png'; - } - if (! $logo) { - if (intval($rr['site_type']) != 0) { - $logo = 'images/activitypub-300.png'; - } - else { - $logo = 'images/default_profile_photos/red_koala_trans/300.png'; - } - } + if (!$logo && file_exists('images/' . strtolower($rr['site_project']) . '.png')) { + $logo = 'images/' . strtolower($rr['site_project']) . '.png'; + } + if (!$logo) { + if (intval($rr['site_type']) != 0) { + $logo = 'images/activitypub-300.png'; + } else { + $logo = 'images/default_profile_photos/red_koala_trans/300.png'; + } + } - if ($rr['site_sellpage']) { - $register_link = $rr['site_sellpage']; - } - else { - $register_link = $rr['site_url'] . '/register'; - } + if ($rr['site_sellpage']) { + $register_link = $rr['site_sellpage']; + } else { + $register_link = $rr['site_url'] . '/register'; + } - $j[] = [ - 'profile_link' => $rr['site_url'], - 'name' => $sitename, - 'access' => $access, - 'register' => $register_link, - 'sellpage' => $rr['site_sellpage'], - 'location_label' => t('Location'), - 'location' => $rr['site_location'], - 'project' => $rr['site_project'], - 'version' => $rr['site_version'], - 'photo' => $logo, - 'about' => bbcode($about), - 'hash' => substr(hash('sha256', $rr['site_url']), 0, 16), - 'network_label' => t('Project'), - 'network' => $rr['site_project'], - 'version_label' => t('Version'), - 'version' => $rr['site_version'], - 'private' => $disabled, - 'connect' => (($disabled) ? '' : $register_link), - 'connect_label' => $register, - 'access' => (($access === 'private') ? '' : $access), - 'access_label' => t('Access type'), - ]; - } - } + $j[] = [ + 'profile_link' => $rr['site_url'], + 'name' => $sitename, + 'access' => $access, + 'register' => $register_link, + 'sellpage' => $rr['site_sellpage'], + 'location_label' => t('Location'), + 'location' => $rr['site_location'], + 'project' => $rr['site_project'], + 'version' => $rr['site_version'], + 'photo' => $logo, + 'about' => bbcode($about), + 'hash' => substr(hash('sha256', $rr['site_url']), 0, 16), + 'network_label' => t('Project'), + 'network' => $rr['site_project'], + 'version_label' => t('Version'), + 'version' => $rr['site_version'], + 'private' => $disabled, + 'connect' => (($disabled) ? '' : $register_link), + 'connect_label' => $register, + 'access' => (($access === 'private') ? '' : $access), + 'access_label' => t('Access type'), + ]; + } + } - $o = replace_macros(get_markup_template('sitentry_header.tpl'), [ - '$dirlbl' => t('Affiliated Sites'), - '$desc' => $desc, - '$entries' => $j, - ]); + $o = replace_macros(get_markup_template('sitentry_header.tpl'), [ + '$dirlbl' => t('Affiliated Sites'), + '$desc' => $desc, + '$entries' => $j, + ]); + return $o; + } + public function sort_sites($a) + { + $ret = []; + if ($a) { + foreach ($a as $e) { + $projectname = explode(' ', $e['project']); + $ret[$projectname[0]][] = $e; + } + } + $projects = array_keys($ret); + rsort($projects); - return $o; - } + $newret = []; + foreach ($projects as $p) { + $newret[$p] = $ret[$p]; + } - function sort_sites($a) { - $ret = []; - if($a) { - foreach($a as $e) { - $projectname = explode(' ',$e['project']); - $ret[$projectname[0]][] = $e; - } - } - $projects = array_keys($ret); - rsort($projects); - - $newret = []; - foreach($projects as $p) { - $newret[$p] = $ret[$p]; - } + return $newret; + } - return $newret; - } - - function sort_versions($a,$b) { - return version_compare($b['version'],$a['version']); - } + public function sort_versions($a, $b) + { + return version_compare($b['version'], $a['version']); + } } diff --git a/Zotlabs/Module/Smilies.php b/Zotlabs/Module/Smilies.php index d82ff297f..0a8148a7e 100644 --- a/Zotlabs/Module/Smilies.php +++ b/Zotlabs/Module/Smilies.php @@ -5,20 +5,21 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Smilies extends Controller { +class Smilies extends Controller +{ + + public function get() + { + if (App::$argv[1] === "json") { + $tmp = list_smilies(); + $results = []; + for ($i = 0; $i < count($tmp['texts']); $i++) { + $results[] = array('text' => $tmp['texts'][$i], 'icon' => $tmp['icons'][$i]); + } + json_return_and_die($results); + } else { + return smilies('', true); + } + } - function get() { - if (App::$argv[1]==="json"){ - $tmp = list_smilies(); - $results = []; - for($i = 0; $i < count($tmp['texts']); $i++) { - $results[] = array('text' => $tmp['texts'][$i], 'icon' => $tmp['icons'][$i]); - } - json_return_and_die($results); - } - else { - return smilies('',true); - } - } - } diff --git a/Zotlabs/Module/Sources.php b/Zotlabs/Module/Sources.php index cae4b0bcd..e22107c77 100644 --- a/Zotlabs/Module/Sources.php +++ b/Zotlabs/Module/Sources.php @@ -4,188 +4,190 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Sources extends Controller { +class Sources extends Controller +{ - function post() { + public function post() + { - if (! local_channel()) { - return; - } + if (!local_channel()) { + return; + } - if (! feature_enabled(local_channel(),'channel_sources')) { - return; - } - - $source = intval($_REQUEST['source']); - $xchan = escape_tags($_REQUEST['xchan']); - $abook = intval($_REQUEST['abook']); - $words = escape_tags($_REQUEST['words']); - $resend = intval($_REQUEST['resend']); - $frequency = $_REQUEST['frequency']; - $name = escape_tags($_REQUEST['name']); - $tags = escape_tags($_REQUEST['tags']); - - $channel = App::get_channel(); - - if ($name == '*') { - $xchan = '*'; - } - - if ($abook) { - $r = q("select abook_xchan from abook where abook_id = %d and abook_channel = %d limit 1", - intval($abook), - intval(local_channel()) - ); - if ($r) { - $xchan = $r[0]['abook_xchan']; - } - } - - if (! $xchan) { - notice ( t('Failed to create source. No channel selected.') . EOL); - return; - } + if (!feature_enabled(local_channel(), 'channel_sources')) { + return; + } - set_abconfig(local_channel(),$xchan, 'system','rself',$resend); + $source = intval($_REQUEST['source']); + $xchan = escape_tags($_REQUEST['xchan']); + $abook = intval($_REQUEST['abook']); + $words = escape_tags($_REQUEST['words']); + $resend = intval($_REQUEST['resend']); + $frequency = $_REQUEST['frequency']; + $name = escape_tags($_REQUEST['name']); + $tags = escape_tags($_REQUEST['tags']); - if (! $source) { - $r = q("insert into source ( src_channel_id, src_channel_xchan, src_xchan, src_patt, src_tag ) + $channel = App::get_channel(); + + if ($name == '*') { + $xchan = '*'; + } + + if ($abook) { + $r = q("select abook_xchan from abook where abook_id = %d and abook_channel = %d limit 1", + intval($abook), + intval(local_channel()) + ); + if ($r) { + $xchan = $r[0]['abook_xchan']; + } + } + + if (!$xchan) { + notice(t('Failed to create source. No channel selected.') . EOL); + return; + } + + set_abconfig(local_channel(), $xchan, 'system', 'rself', $resend); + + if (!$source) { + $r = q("insert into source ( src_channel_id, src_channel_xchan, src_xchan, src_patt, src_tag ) values ( %d, '%s', '%s', '%s', '%s' ) ", - intval(local_channel()), - dbesc($channel['channel_hash']), - dbesc($xchan), - dbesc($words), - dbesc($tags) - ); - if ($r) { - info( t('Source created.') . EOL); - } - goaway(z_root() . '/sources'); - } - else { - $r = q("update source set src_xchan = '%s', src_patt = '%s', src_tag = '%s' where src_channel_id = %d and src_id = %d", - dbesc($xchan), - dbesc($words), - dbesc($tags), - intval(local_channel()), - intval($source) - ); - if ($r) { - info( t('Source updated.') . EOL); - } - } - } - - - function get() { + intval(local_channel()), + dbesc($channel['channel_hash']), + dbesc($xchan), + dbesc($words), + dbesc($tags) + ); + if ($r) { + info(t('Source created.') . EOL); + } + goaway(z_root() . '/sources'); + } else { + $r = q("update source set src_xchan = '%s', src_patt = '%s', src_tag = '%s' where src_channel_id = %d and src_id = %d", + dbesc($xchan), + dbesc($words), + dbesc($tags), + intval(local_channel()), + intval($source) + ); + if ($r) { + info(t('Source updated.') . EOL); + } + } + } - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return EMPTY_STR; - } - - if (! feature_enabled(local_channel(),'channel_sources')) { - return EMPTY_STR; - } - - // list sources - if (argc() == 1) { - $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_channel_id = %d", - intval(local_channel()) - ); - if ($r) { - for ($x = 0; $x < count($r); $x ++) { - if ($r[$x]['src_xchan'] == '*') { - $r[$x]['xchan_name'] = t('*'); - } - $r[$x]['src_patt'] = htmlspecialchars($r[$x]['src_patt'], ENT_COMPAT,'UTF-8'); - } - } - $o = replace_macros(get_markup_template('sources_list.tpl'), [ - '$title' => t('Channel Sources'), - '$desc' => t('Manage remote sources of content for your channel.'), - '$new' => t('New Source'), - '$sources' => $r - ]); - return $o; - } - - if (argc() == 2 && argv(1) === 'new') { - // TODO add the words 'or RSS feed' and corresponding code to manage feeds and frequency - - $o = replace_macros(get_markup_template('sources_new.tpl'), [ - '$title' => t('New Source'), - '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), - '$words' => [ 'words', t('Only import content with these words (one per line)'),'',t('Leave blank to import all public content')], - '$name' => [ 'name', t('Channel Name'), '', '', '', 'autocomplete="off"'], - '$tags' => [ 'tags', t('Add the following categories to posts imported from this source (comma separated)'),'',t('Optional')], - '$resend' => [ 'resend', t('Resend posts with this channel as author'), 0, t('Copyrights may apply'), [ t('No'), t('Yes') ]], - '$submit' => t('Submit') - ]); - return $o; - - } - - if (argc() == 2 && intval(argv(1))) { - // edit source - $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_id = %d and src_channel_id = %d limit 1", - intval(argv(1)), - intval(local_channel()) - ); - if ($r) { - $x = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", - dbesc($r[0]['src_xchan']), - intval(local_channel()) - ); - } - if (! $r) { - notice( t('Source not found.') . EOL); - return ''; - } - - $r[0]['src_patt'] = htmlspecialchars($r[0]['src_patt'], ENT_QUOTES,'UTF-8'); - - $o = replace_macros(get_markup_template('sources_edit.tpl'), array( - '$title' => t('Edit Source'), - '$drop' => t('Delete Source'), - '$id' => $r[0]['src_id'], - '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), - '$words' => array( 'words', t('Only import content with these words (one per line)'),$r[0]['src_patt'],t('Leave blank to import all public content')), - '$xchan' => $r[0]['src_xchan'], - '$abook' => $x[0]['abook_id'], - '$tags' => array('tags', t('Add the following categories to posts imported from this source (comma separated)'),$r[0]['src_tag'],t('Optional')), - '$resend' => [ 'resend', t('Resend posts with this channel as author'), get_abconfig(local_channel(), $r[0]['xchan_hash'],'system','rself'), t('Copyrights may apply'), [ t('No'), t('Yes') ]], - '$name' => array( 'name', t('Channel Name'), $r[0]['xchan_name'], ''), - '$submit' => t('Submit') - )); - return $o; - - } - - if(argc() == 3 && intval(argv(1)) && argv(2) === 'drop') { - $r = q("select * from source where src_id = %d and src_channel_id = %d limit 1", - intval(argv(1)), - intval(local_channel()) - ); - if(! $r) { - notice( t('Source not found.') . EOL); - return ''; - } - $r = q("delete from source where src_id = %d and src_channel_id = %d", - intval(argv(1)), - intval(local_channel()) - ); - if($r) - info( t('Source removed') . EOL); - else - notice( t('Unable to remove source.') . EOL); - - goaway(z_root() . '/sources'); - - } - - // shouldn't get here. - - } + public function get() + { + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return EMPTY_STR; + } + + if (!feature_enabled(local_channel(), 'channel_sources')) { + return EMPTY_STR; + } + + // list sources + if (argc() == 1) { + $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_channel_id = %d", + intval(local_channel()) + ); + if ($r) { + for ($x = 0; $x < count($r); $x++) { + if ($r[$x]['src_xchan'] == '*') { + $r[$x]['xchan_name'] = t('*'); + } + $r[$x]['src_patt'] = htmlspecialchars($r[$x]['src_patt'], ENT_COMPAT, 'UTF-8'); + } + } + $o = replace_macros(get_markup_template('sources_list.tpl'), [ + '$title' => t('Channel Sources'), + '$desc' => t('Manage remote sources of content for your channel.'), + '$new' => t('New Source'), + '$sources' => $r + ]); + return $o; + } + + if (argc() == 2 && argv(1) === 'new') { + // TODO add the words 'or RSS feed' and corresponding code to manage feeds and frequency + + $o = replace_macros(get_markup_template('sources_new.tpl'), [ + '$title' => t('New Source'), + '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), + '$words' => ['words', t('Only import content with these words (one per line)'), '', t('Leave blank to import all public content')], + '$name' => ['name', t('Channel Name'), '', '', '', 'autocomplete="off"'], + '$tags' => ['tags', t('Add the following categories to posts imported from this source (comma separated)'), '', t('Optional')], + '$resend' => ['resend', t('Resend posts with this channel as author'), 0, t('Copyrights may apply'), [t('No'), t('Yes')]], + '$submit' => t('Submit') + ]); + return $o; + + } + + if (argc() == 2 && intval(argv(1))) { + // edit source + $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_id = %d and src_channel_id = %d limit 1", + intval(argv(1)), + intval(local_channel()) + ); + if ($r) { + $x = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($r[0]['src_xchan']), + intval(local_channel()) + ); + } + if (!$r) { + notice(t('Source not found.') . EOL); + return ''; + } + + $r[0]['src_patt'] = htmlspecialchars($r[0]['src_patt'], ENT_QUOTES, 'UTF-8'); + + $o = replace_macros(get_markup_template('sources_edit.tpl'), array( + '$title' => t('Edit Source'), + '$drop' => t('Delete Source'), + '$id' => $r[0]['src_id'], + '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), + '$words' => array('words', t('Only import content with these words (one per line)'), $r[0]['src_patt'], t('Leave blank to import all public content')), + '$xchan' => $r[0]['src_xchan'], + '$abook' => $x[0]['abook_id'], + '$tags' => array('tags', t('Add the following categories to posts imported from this source (comma separated)'), $r[0]['src_tag'], t('Optional')), + '$resend' => ['resend', t('Resend posts with this channel as author'), get_abconfig(local_channel(), $r[0]['xchan_hash'], 'system', 'rself'), t('Copyrights may apply'), [t('No'), t('Yes')]], + + '$name' => array('name', t('Channel Name'), $r[0]['xchan_name'], ''), + '$submit' => t('Submit') + )); + return $o; + + } + + if (argc() == 3 && intval(argv(1)) && argv(2) === 'drop') { + $r = q("select * from source where src_id = %d and src_channel_id = %d limit 1", + intval(argv(1)), + intval(local_channel()) + ); + if (!$r) { + notice(t('Source not found.') . EOL); + return ''; + } + $r = q("delete from source where src_id = %d and src_channel_id = %d", + intval(argv(1)), + intval(local_channel()) + ); + if ($r) + info(t('Source removed') . EOL); + else + notice(t('Unable to remove source.') . EOL); + + goaway(z_root() . '/sources'); + + } + + // shouldn't get here. + + } } diff --git a/Zotlabs/Module/Sslify.php b/Zotlabs/Module/Sslify.php index 0c7b8f171..59f335055 100644 --- a/Zotlabs/Module/Sslify.php +++ b/Zotlabs/Module/Sslify.php @@ -4,24 +4,26 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Sslify extends Controller { +class Sslify extends Controller +{ - function init() { - $x = z_fetch_url($_REQUEST['url']); - if($x['success']) { - $h = explode("\n",$x['header']); - foreach ($h as $l) { - list($k,$v) = array_map("trim", explode(":", trim($l), 2)); - $hdrs[strtolower($k)] = $v; - } - if (array_key_exists('content-type', $hdrs)) { - $type = $hdrs['content-type']; - header('Content-Type: ' . $type); - } + public function init() + { + $x = z_fetch_url($_REQUEST['url']); + if ($x['success']) { + $h = explode("\n", $x['header']); + foreach ($h as $l) { + list($k, $v) = array_map("trim", explode(":", trim($l), 2)); + $hdrs[strtolower($k)] = $v; + } + if (array_key_exists('content-type', $hdrs)) { + $type = $hdrs['content-type']; + header('Content-Type: ' . $type); + } - echo $x['body']; - killme(); - } - killme(); - } + echo $x['body']; + killme(); + } + killme(); + } } diff --git a/Zotlabs/Module/Starred.php b/Zotlabs/Module/Starred.php index b5c5ed1c4..82cdc1e0c 100644 --- a/Zotlabs/Module/Starred.php +++ b/Zotlabs/Module/Starred.php @@ -7,28 +7,28 @@ use Zotlabs\Web\Controller; class Starred extends Controller { - function init() + public function init() { - if (! local_channel()) { + if (!local_channel()) { killme(); } $message_id = ((argc() > 1) ? intval(argv(1)) : 0); - if (! $message_id) { + if (!$message_id) { killme(); } - + $r = q( "SELECT item_starred FROM item WHERE uid = %d AND id = %d LIMIT 1", intval(local_channel()), intval($message_id) ); - if (! count($r)) { + if (!count($r)) { killme(); } - + $item_starred = (intval($r[0]['item_starred']) ? 0 : 1); - + $r = q( "UPDATE item SET item_starred = %d WHERE uid = %d and id = %d", intval($item_starred), diff --git a/Zotlabs/Module/Stream.php b/Zotlabs/Module/Stream.php index 3cb0c38c4..ad9e33ddf 100644 --- a/Zotlabs/Module/Stream.php +++ b/Zotlabs/Module/Stream.php @@ -12,560 +12,549 @@ require_once('include/conversation.php'); require_once('include/acl_selectors.php'); -class Stream extends Controller { +class Stream extends Controller +{ - // State passed in from the Update module. - - public $profile_uid = 0; - public $loading = 0; - public $updating = 0; + // State passed in from the Update module. + + public $profile_uid = 0; + public $loading = 0; + public $updating = 0; + public function init() + { + if (!local_channel()) { + return; + } - function init() { - if (! local_channel()) { - return; - } - - // setup identity information for page - $channel = App::get_channel(); - App::$profile_uid = local_channel(); - App::$data['channel'] = $channel; - head_set_icon($channel['xchan_photo_s']); - } - - - function get() { - - if (! local_channel()) { - $_SESSION['return_url'] = App::$query_string; - return login(false); - } - - $o = ''; - - if ($this->loading) { - $_SESSION['loadtime_stream'] = datetime_convert(); - PConfig::Set(local_channel(),'system','loadtime_stream',$_SESSION['loadtime_stream']); - // stream is a superset of channel when it comes to notifications - $_SESSION['loadtime_channel'] = datetime_convert(); - PConfig::Set(local_channel(),'system','loadtime_channel',$_SESSION['loadtime_channel']); - } - - $arr = [ 'query' => App::$query_string ]; - call_hooks('stream_content_init', $arr); - - $channel = ((isset(App::$data['channel'])) ? App::$data['channel'] : null); - - // if called from liveUpdate() we will not have called Stream->init() on this request and $channel will not be set - - if (! $channel) { - $channel = App::get_channel(); - } + // setup identity information for page + $channel = App::get_channel(); + App::$profile_uid = local_channel(); + App::$data['channel'] = $channel; + head_set_icon($channel['xchan_photo_s']); + } - $item_normal = item_normal(); - $item_normal_update = item_normal_update(); - - $datequery = $datequery2 = ''; - - $group = 0; - - $nouveau = false; - - $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); - $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); - $static = ((x($_GET,'static')) ? intval($_GET['static']) : 0); - $gid = ((x($_GET,'gid')) ? $_REQUEST['gid'] : 0); - $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); - $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : ''); - $verb = ((x($_REQUEST,'verb')) ? $_REQUEST['verb'] : ''); - $dm = ((x($_REQUEST,'dm')) ? $_REQUEST['dm'] : 0); + public function get() + { - $c_order = get_pconfig(local_channel(), 'mod_stream', 'order', 0); - switch ($c_order) { - case 0: - $order = 'comment'; - break; - case 1: - $order = 'post'; - break; - case 2: - $nouveau = true; - break; - } + if (!local_channel()) { + $_SESSION['return_url'] = App::$query_string; + return login(false); + } - $search = (isset($_GET['search']) ? $_GET['search'] : ''); - if ($search) { - $_GET['netsearch'] = escape_tags($search); - if (strpos($search,'@') === 0) { - $r = q("select abook_id from abook left join xchan on abook_xchan = xchan_hash where xchan_name = '%s' and abook_channel = %d limit 1", - dbesc(substr($search,1)), - intval(local_channel()) - ); - if ($r) { - $_GET['cid'] = $r[0]['abook_id']; - $search = $_GET['search'] = ''; - } - } - elseif (strpos($search,'#') === 0) { - $hashtags = substr($search,1); - $search = $_GET['search'] = ''; - } - } - - if ($datequery) { - $order = 'post'; - } - - // filter by collection (e.g. group) + $o = ''; - $vg = false; - - if ($gid) { - if (strpos($gid,':') === 0) { - $g = substr($gid,1); - switch ($g) { - case '1': - $r = [[ 'hash' => 'connections:' . $channel['channel_hash'] ]]; - $vg = t('Connections'); - break; - case '2': - $r = [[ 'hash' => 'zot:' . $channel['channel_hash'] ]]; - $vg = t('Nomad'); - break; - case '3': - $r = [[ 'hash' => 'activitypub:' . $channel['channel_hash'] ]]; - $vg = t('ActivityPub'); - break; - default: - break; - } - } - else { - $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1", - intval($gid), - intval(local_channel()) - ); - if (! $r) { - if ($this->updating) { - killme(); - } - notice( t('Access list not found') . EOL ); - goaway(z_root() . '/stream'); - } - } + if ($this->loading) { + $_SESSION['loadtime_stream'] = datetime_convert(); + PConfig::Set(local_channel(), 'system', 'loadtime_stream', $_SESSION['loadtime_stream']); + // stream is a superset of channel when it comes to notifications + $_SESSION['loadtime_channel'] = datetime_convert(); + PConfig::Set(local_channel(), 'system', 'loadtime_channel', $_SESSION['loadtime_channel']); + } + + $arr = ['query' => App::$query_string]; + call_hooks('stream_content_init', $arr); + + $channel = ((isset(App::$data['channel'])) ? App::$data['channel'] : null); + + // if called from liveUpdate() we will not have called Stream->init() on this request and $channel will not be set + + if (!$channel) { + $channel = App::get_channel(); + } + $item_normal = item_normal(); + $item_normal_update = item_normal_update(); - $group = $gid; - $group_hash = $r[0]['hash']; + $datequery = $datequery2 = ''; - } - - $default_cmin = ((Apps::system_app_installed(local_channel(),'Friend Zoom')) ? get_pconfig(local_channel(),'affinity','cmin',0) : (-1)); - $default_cmax = ((Apps::system_app_installed(local_channel(),'Friend Zoom')) ? get_pconfig(local_channel(),'affinity','cmax',99) : (-1)); + $group = 0; - $cid = ((x($_GET,'cid')) ? intval($_GET['cid']) : 0); - $draft = ((x($_GET,'draft')) ? intval($_GET['draft']) : 0); - $star = ((x($_GET,'star')) ? intval($_GET['star']) : 0); - $liked = ((x($_GET,'liked')) ? intval($_GET['liked']) : 0); - $conv = ((x($_GET,'conv')) ? intval($_GET['conv']) : 0); - $spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0); - $cmin = ((array_key_exists('cmin',$_GET)) ? intval($_GET['cmin']) : $default_cmin); - $cmax = ((array_key_exists('cmax',$_GET)) ? intval($_GET['cmax']) : $default_cmax); - $file = ((x($_GET,'file')) ? $_GET['file'] : ''); - $xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : ''); - $net = ((x($_GET,'net')) ? $_GET['net'] : ''); - $pf = ((x($_GET,'pf')) ? $_GET['pf'] : ''); - - $deftag = ''; - + $nouveau = false; - - if (x($_GET,'search') || $file || (!$pf && $cid)) { - $nouveau = true; - } + $datequery = ((x($_GET, 'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); + $datequery2 = ((x($_GET, 'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); + $static = ((x($_GET, 'static')) ? intval($_GET['static']) : 0); + $gid = ((x($_GET, 'gid')) ? $_REQUEST['gid'] : 0); + $category = ((x($_REQUEST, 'cat')) ? $_REQUEST['cat'] : ''); + $hashtags = ((x($_REQUEST, 'tag')) ? $_REQUEST['tag'] : ''); + $verb = ((x($_REQUEST, 'verb')) ? $_REQUEST['verb'] : ''); + $dm = ((x($_REQUEST, 'dm')) ? $_REQUEST['dm'] : 0); - if ($cid) { - $cid_r = q("SELECT abook.abook_xchan, xchan.xchan_addr, xchan.xchan_name, xchan.xchan_url, xchan.xchan_photo_s, xchan.xchan_type from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1", - intval($cid), - intval(local_channel()) - ); + $c_order = get_pconfig(local_channel(), 'mod_stream', 'order', 0); + switch ($c_order) { + case 0: + $order = 'comment'; + break; + case 1: + $order = 'post'; + break; + case 2: + $nouveau = true; + break; + } - if (! $cid_r) { - if ($this->updating) { - killme(); - } - notice( t('No such channel') . EOL ); - goaway(z_root() . '/stream'); - } - - } - - if (! $this->updating) { - - // search terms header - - // hide the terms we use to search for videos from - // the activity_filter widget because it doesn't look very good - if ($search && $search !== 'video]') { - $o .= replace_macros(get_markup_template("section_title.tpl"), - [ '$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8') ] - ); - } + $search = (isset($_GET['search']) ? $_GET['search'] : ''); + if ($search) { + $_GET['netsearch'] = escape_tags($search); + if (strpos($search, '@') === 0) { + $r = q("select abook_id from abook left join xchan on abook_xchan = xchan_hash where xchan_name = '%s' and abook_channel = %d limit 1", + dbesc(substr($search, 1)), + intval(local_channel()) + ); + if ($r) { + $_GET['cid'] = $r[0]['abook_id']; + $search = $_GET['search'] = ''; + } + } elseif (strpos($search, '#') === 0) { + $hashtags = substr($search, 1); + $search = $_GET['search'] = ''; + } + } - $body = EMPTY_STR; + if ($datequery) { + $order = 'post'; + } - nav_set_selected('Stream'); + // filter by collection (e.g. group) - $channel_acl = [ - 'allow_cid' => $channel['channel_allow_cid'], - 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ]; + $vg = false; - $x = [ - 'is_owner' => true, - 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), - 'default_location' => $channel['channel_location'], - 'nickname' => $channel['channel_address'], - 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), - 'permissions' => $channel_acl, - 'bang' => EMPTY_STR, - 'body' => $body, - 'visitor' => true, - 'profile_uid' => local_channel(), - 'editor_autocomplete' => true, - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true, - 'jotnets' => true, - 'reset' => t('Reset form') - ]; - - if ($deftag) { - $x['pretext'] = $deftag; - } - - $status_editor = status_editor($x); - $o .= $status_editor; - - $static = channel_manual_conv_update(local_channel()); - - } - - - // We don't have to deal with ACL's on this page. You're looking at everything - // that belongs to you, hence you can see all of it. We will filter by group if - // desired. - - - $sql_options = (($star) - ? " and item_starred = 1 " - : ''); - - $sql_nets = ''; - - $item_thread_top = ' AND item_thread_top = 1 '; - - $sql_extra = ''; - - if ($draft) { - $item_normal = item_normal_draft(); - $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE item_unpublished = 1 and item_deleted = 0 ) "; - } - - if ($group) { - $contact_str = ''; - $contacts = AccessList::members(local_channel(),$group); - if ($contacts) { - $contact_str = ids_to_querystr($contacts,'xchan',true); - } - else { - $contact_str = " '0' "; - if (! $this->updating) { - info( t('Access list is empty')); - } - } - $item_thread_top = ''; - - $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) "; - - - if (! $vg) { - $x = AccessList::rec_byhash(local_channel(), $group_hash); - } - - if ($x || $vg) { - $title = replace_macros(get_markup_template("section_title.tpl"),array( - '$title' => sprintf( t('Access list: %s'), (($vg) ? $vg : $x['gname'])) - )); - } - - $o = $title . $status_editor; - - } - elseif (isset($cid_r) && $cid_r) { - $item_thread_top = EMPTY_STR; - - if ($this->loading || $this->updating) { - if (!$pf && $nouveau) { - $sql_extra = " AND author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' "; - } - else { - $ttype = (($pf) ? TERM_FORUM : TERM_MENTION); - - $p1 = q("SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal "); - $p2 = q("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . dbesc($cid_r[0]['xchan_name']) . "'"); - - $p_str = ids_to_querystr(array_merge($p1,$p2),'parent'); - $sql_extra = " AND item.parent IN ( $p_str ) "; - } - } - - $title = replace_macros(get_markup_template('section_title.tpl'), [ - '$title' => '' . urlencode($cid_r[0]['xchan_name']) . ' ' . $cid_r[0]['xchan_name'] . '' - ]); - - $o = $title; - $o .= $status_editor; - } - elseif ($xchan) { - $r = q("select * from xchan where xchan_hash = '%s'", - dbesc($xchan) - ); - if ($r) { - $item_thread_top = ''; - $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($xchan) . "' or owner_xchan = '" . dbesc($xchan) . "' ) $item_normal ) "; - $title = replace_macros(get_markup_template('section_title.tpl'), [ - '$title' => '' . urlencode($r[0]['xchan_name']) . ' ' . $r[0]['xchan_name'] . '' - ]); - - $o = $title; - $o .= $status_editor; - - } - else { - notice( t('Invalid channel.') . EOL); - goaway(z_root() . '/stream'); - } - - } - - if (x($category)) { - $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY)); - } - if (x($hashtags)) { - $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); - } - - if (! $this->updating) { - // The special div is needed for liveUpdate to kick in for this page. - // We only launch liveUpdate if you aren't filtering in some incompatible - // way and also you aren't writing a comment (discovered in javascript). - - $maxheight = get_pconfig(local_channel(),'system','stream_divmore_height'); - if(! $maxheight) - $maxheight = 400; - - - $o .= '
      ' . "\r\n"; - $o .= "\r\n"; - - App::$page['htmlhead'] .= replace_macros(get_markup_template('build_query.tpl'), [ - '$baseurl' => z_root(), - '$pgtype' => 'stream', - '$uid' => ((local_channel()) ? local_channel() : '0'), - '$gid' => (($gid) ? $gid : '0'), - '$cid' => (($cid) ? $cid : '0'), - '$cmin' => (($cmin) ? $cmin : '(-1)'), - '$cmax' => (($cmax) ? $cmax : '(-1)'), - '$star' => (($star) ? $star : '0'), - '$liked' => (($liked) ? $liked : '0'), - '$conv' => (($conv) ? $conv : '0'), - '$spam' => (($spam) ? $spam : '0'), - '$fh' => '0', - '$dm' => (($dm) ? $dm : '0'), - '$nouveau' => (($nouveau) ? $nouveau : '0'), - '$wall' => '0', - '$draft' => (($draft) ? $draft : '0'), - '$static' => $static, - '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), - '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), - '$search' => (($search) ? urlencode($search) : ''), - '$xchan' => (($xchan) ? urlencode($xchan) : ''), - '$order' => (($order) ? urlencode($order) : ''), - '$file' => (($file) ? urlencode($file) : ''), - '$cats' => (($category) ? urlencode($category) : ''), - '$tags' => (($hashtags) ? urlencode($hashtags) : ''), - '$dend' => $datequery, - '$mid' => '', - '$verb' => (($verb) ? urlencode($verb) : ''), - '$net' => (($net) ? urlencode($net) : ''), - '$dbegin' => $datequery2, - '$pf' => (($pf) ? intval($pf) : '0'), - ]); - } - - $sql_extra3 = ''; - - if ($datequery) { - $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery)))); - } - if ($datequery2) { - $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2)))); - } - - $sql_extra2 = (($nouveau) ? '' : " AND item.parent = item.id "); - $sql_extra3 = (($nouveau) ? '' : $sql_extra3); - - if (x($_GET,'search')) { - $search = escape_tags($_GET['search']); - if (strpos($search,'#') === 0) { - $sql_extra .= term_query('item',substr($search,1),TERM_HASHTAG,TERM_COMMUNITYTAG); - } - else { - $sql_extra .= sprintf(" AND (item.body like '%s' OR item.title like '%s') ", - dbesc(protect_sprintf('%' . $search . '%')), - dbesc(protect_sprintf('%' . $search . '%')) - ); - } - } - - if ($verb) { - - // the presence of a leading dot in the verb determines - // whether to match the type of activity or the child object. - // The name 'verb' is a holdover from the earlier XML - // ActivityStreams specification. - - if (substr($verb,0,1) === '.') { - $verb = substr($verb,1); - $sql_extra .= sprintf(" AND item.obj_type like '%s' ", - dbesc(protect_sprintf('%' . $verb . '%')) - ); - } - else { - $sql_extra .= sprintf(" AND item.verb like '%s' ", - dbesc(protect_sprintf('%' . $verb . '%')) - ); - } - } - - if (strlen($file)) { - $sql_extra .= term_query('item',$file,TERM_FILE); - } - - if ($dm) { - $sql_extra .= " and item_private = 2 "; - } - - if ($conv) { - - $item_thread_top = ''; - - if ($nouveau) { - $sql_extra .= " AND author_xchan = '" . dbesc($channel['channel_hash']) . "' "; - } - else { - $sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan = '%s' or item_mentionsme = 1 ) and item_deleted = 0 ) ", - dbesc(protect_sprintf($channel['channel_hash'])) - ); - } - } - - if ($this->updating && ! $this->loading) { - - // only setup pagination on initial page view - $pager_sql = ''; - - } - else { - $itemspage = get_pconfig(local_channel(),'system','itemspage'); - App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); - $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); - } - - // cmin and cmax are both -1 when the affinity tool is disabled - - if (($cmin != (-1)) || ($cmax != (-1))) { - - // Not everybody who shows up in the network stream will be in your address book. - // By default those that aren't are assumed to have closeness = 99; but this isn't - // recorded anywhere. So if cmax is 99, we'll open the search up to anybody in - // the stream with a NULL address book entry. - - $sql_nets .= " AND "; - - if ($cmax == 99) - $sql_nets .= " ( "; - - $sql_nets .= "( abook.abook_closeness >= " . intval($cmin) . " "; - $sql_nets .= " AND abook.abook_closeness <= " . intval($cmax) . " ) "; - - if ($cmax == 99) - $sql_nets .= " OR abook.abook_closeness IS NULL ) "; - - } - - $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : ''); - $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : ''); - - $abook_uids = " and abook.abook_channel = " . local_channel() . " "; - $uids = " and item.uid = " . local_channel() . " "; - - if (get_pconfig(local_channel(),'system','stream_list_mode')) - $page_mode = 'list'; - else - $page_mode = 'client'; - - $simple_update = (($this->updating) ? " and item_changed > = '" . $_SESSION['loadtime_stream'] . "' " : ''); - - $parents_str = ''; - $update_unseen = ''; - $items = []; - - // This fixes a very subtle bug so I'd better explain it. You wake up in the morning or return after a day - // or three and look at your stream page - after opening up your browser. The first page loads just as it - // should. All of a sudden a few seconds later, page 2 will get inserted at the beginning of the page - // (before the page 1 content). The update code is actually doing just what it's supposed - // to, it's fetching posts that have the ITEM_UNSEEN bit set. But the reason that page 2 content is being - // returned in an UPDATE is because you hadn't gotten that far yet - you're still on page 1 and everything - // that we loaded for page 1 is now marked as seen. But the stuff on page 2 hasn't been. So... it's being - // treated as "new fresh" content because it is unseen. We need to distinguish it somehow from content - // which "arrived as you were reading page 1". We're going to do this - // by storing in your session the current UTC time whenever you LOAD a network page, and only UPDATE items - // which are both ITEM_UNSEEN and have "changed" since that time. Cross fingers... - - if ($this->updating && $_SESSION['loadtime_stream']) - $simple_update = " AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime_stream']) . "' "; - if ($this->loading) - $simple_update = ''; - - if ($static && $simple_update) - $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + if ($gid) { + if (strpos($gid, ':') === 0) { + $g = substr($gid, 1); + switch ($g) { + case '1': + $r = [['hash' => 'connections:' . $channel['channel_hash']]]; + $vg = t('Connections'); + break; + case '2': + $r = [['hash' => 'zot:' . $channel['channel_hash']]]; + $vg = t('Nomad'); + break; + case '3': + $r = [['hash' => 'activitypub:' . $channel['channel_hash']]]; + $vg = t('ActivityPub'); + break; + default: + break; + } + } else { + $r = q("SELECT * FROM pgrp WHERE id = %d AND uid = %d LIMIT 1", + intval($gid), + intval(local_channel()) + ); + if (!$r) { + if ($this->updating) { + killme(); + } + notice(t('Access list not found') . EOL); + goaway(z_root() . '/stream'); + } + } - // we are not yet using this in updates because the content may have just been marked seen - // and this might prevent us from loading the update. Will need to test further. - - $seenstr = EMPTY_STR; - if (local_channel()) { - $seen = PConfig::Get(local_channel(),'system','seen_items',[]); - if ($seen) { - $seenstr = " and not item.id in (" . implode(',',$seen) . ") "; - } - } + $group = $gid; + $group_hash = $r[0]['hash']; - if ($nouveau && $this->loading) { - // "New Item View" - show all items unthreaded in reverse created date order - - $items = q("SELECT item.*, item.id AS item_id, created FROM item + } + + $default_cmin = ((Apps::system_app_installed(local_channel(), 'Friend Zoom')) ? get_pconfig(local_channel(), 'affinity', 'cmin', 0) : (-1)); + $default_cmax = ((Apps::system_app_installed(local_channel(), 'Friend Zoom')) ? get_pconfig(local_channel(), 'affinity', 'cmax', 99) : (-1)); + + $cid = ((x($_GET, 'cid')) ? intval($_GET['cid']) : 0); + $draft = ((x($_GET, 'draft')) ? intval($_GET['draft']) : 0); + $star = ((x($_GET, 'star')) ? intval($_GET['star']) : 0); + $liked = ((x($_GET, 'liked')) ? intval($_GET['liked']) : 0); + $conv = ((x($_GET, 'conv')) ? intval($_GET['conv']) : 0); + $spam = ((x($_GET, 'spam')) ? intval($_GET['spam']) : 0); + $cmin = ((array_key_exists('cmin', $_GET)) ? intval($_GET['cmin']) : $default_cmin); + $cmax = ((array_key_exists('cmax', $_GET)) ? intval($_GET['cmax']) : $default_cmax); + $file = ((x($_GET, 'file')) ? $_GET['file'] : ''); + $xchan = ((x($_GET, 'xchan')) ? $_GET['xchan'] : ''); + $net = ((x($_GET, 'net')) ? $_GET['net'] : ''); + $pf = ((x($_GET, 'pf')) ? $_GET['pf'] : ''); + + $deftag = ''; + + + if (x($_GET, 'search') || $file || (!$pf && $cid)) { + $nouveau = true; + } + + if ($cid) { + $cid_r = q("SELECT abook.abook_xchan, xchan.xchan_addr, xchan.xchan_name, xchan.xchan_url, xchan.xchan_photo_s, xchan.xchan_type from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1", + intval($cid), + intval(local_channel()) + ); + + if (!$cid_r) { + if ($this->updating) { + killme(); + } + notice(t('No such channel') . EOL); + goaway(z_root() . '/stream'); + } + + } + + if (!$this->updating) { + + // search terms header + + // hide the terms we use to search for videos from + // the activity_filter widget because it doesn't look very good + if ($search && $search !== 'video]') { + $o .= replace_macros(get_markup_template("section_title.tpl"), + ['$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT, 'UTF-8')] + ); + } + + $body = EMPTY_STR; + + nav_set_selected('Stream'); + + $channel_acl = [ + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ]; + + $x = [ + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'], 'system', 'use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel_acl, true, PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'), + 'permissions' => $channel_acl, + 'bang' => EMPTY_STR, + 'body' => $body, + 'visitor' => true, + 'profile_uid' => local_channel(), + 'editor_autocomplete' => true, + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true, + 'jotnets' => true, + 'reset' => t('Reset form') + ]; + + if ($deftag) { + $x['pretext'] = $deftag; + } + + $status_editor = status_editor($x); + $o .= $status_editor; + + $static = channel_manual_conv_update(local_channel()); + + } + + + // We don't have to deal with ACL's on this page. You're looking at everything + // that belongs to you, hence you can see all of it. We will filter by group if + // desired. + + + $sql_options = (($star) + ? " and item_starred = 1 " + : ''); + + $sql_nets = ''; + + $item_thread_top = ' AND item_thread_top = 1 '; + + $sql_extra = ''; + + if ($draft) { + $item_normal = item_normal_draft(); + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE item_unpublished = 1 and item_deleted = 0 ) "; + } + + if ($group) { + $contact_str = ''; + $contacts = AccessList::members(local_channel(), $group); + if ($contacts) { + $contact_str = ids_to_querystr($contacts, 'xchan', true); + } else { + $contact_str = " '0' "; + if (!$this->updating) { + info(t('Access list is empty')); + } + } + $item_thread_top = ''; + + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) "; + + + if (!$vg) { + $x = AccessList::rec_byhash(local_channel(), $group_hash); + } + + if ($x || $vg) { + $title = replace_macros(get_markup_template("section_title.tpl"), array( + '$title' => sprintf(t('Access list: %s'), (($vg) ? $vg : $x['gname'])) + )); + } + + $o = $title . $status_editor; + + } elseif (isset($cid_r) && $cid_r) { + $item_thread_top = EMPTY_STR; + + if ($this->loading || $this->updating) { + if (!$pf && $nouveau) { + $sql_extra = " AND author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' "; + } else { + $ttype = (($pf) ? TERM_FORUM : TERM_MENTION); + + $p1 = q("SELECT DISTINCT parent FROM item WHERE uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' OR owner_xchan = '" . dbesc($cid_r[0]['abook_xchan']) . "' ) $item_normal "); + $p2 = q("SELECT oid AS parent FROM term WHERE uid = " . intval(local_channel()) . " AND ttype = $ttype AND term = '" . dbesc($cid_r[0]['xchan_name']) . "'"); + + $p_str = ids_to_querystr(array_merge($p1, $p2), 'parent'); + $sql_extra = " AND item.parent IN ( $p_str ) "; + } + } + + $title = replace_macros(get_markup_template('section_title.tpl'), [ + '$title' => '' . urlencode($cid_r[0]['xchan_name']) . ' ' . $cid_r[0]['xchan_name'] . '' + ]); + + $o = $title; + $o .= $status_editor; + } elseif ($xchan) { + $r = q("select * from xchan where xchan_hash = '%s'", + dbesc($xchan) + ); + if ($r) { + $item_thread_top = ''; + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($xchan) . "' or owner_xchan = '" . dbesc($xchan) . "' ) $item_normal ) "; + $title = replace_macros(get_markup_template('section_title.tpl'), [ + '$title' => '' . urlencode($r[0]['xchan_name']) . ' ' . $r[0]['xchan_name'] . '' + ]); + + $o = $title; + $o .= $status_editor; + + } else { + notice(t('Invalid channel.') . EOL); + goaway(z_root() . '/stream'); + } + + } + + if (x($category)) { + $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY)); + } + if (x($hashtags)) { + $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG, TERM_COMMUNITYTAG)); + } + + if (!$this->updating) { + // The special div is needed for liveUpdate to kick in for this page. + // We only launch liveUpdate if you aren't filtering in some incompatible + // way and also you aren't writing a comment (discovered in javascript). + + $maxheight = get_pconfig(local_channel(), 'system', 'stream_divmore_height'); + if (!$maxheight) + $maxheight = 400; + + + $o .= '
      ' . "\r\n"; + $o .= "\r\n"; + + App::$page['htmlhead'] .= replace_macros(get_markup_template('build_query.tpl'), [ + '$baseurl' => z_root(), + '$pgtype' => 'stream', + '$uid' => ((local_channel()) ? local_channel() : '0'), + '$gid' => (($gid) ? $gid : '0'), + '$cid' => (($cid) ? $cid : '0'), + '$cmin' => (($cmin) ? $cmin : '(-1)'), + '$cmax' => (($cmax) ? $cmax : '(-1)'), + '$star' => (($star) ? $star : '0'), + '$liked' => (($liked) ? $liked : '0'), + '$conv' => (($conv) ? $conv : '0'), + '$spam' => (($spam) ? $spam : '0'), + '$fh' => '0', + '$dm' => (($dm) ? $dm : '0'), + '$nouveau' => (($nouveau) ? $nouveau : '0'), + '$wall' => '0', + '$draft' => (($draft) ? $draft : '0'), + '$static' => $static, + '$list' => ((x($_REQUEST, 'list')) ? intval($_REQUEST['list']) : 0), + '$page' => ((App::$pager['page'] != 1) ? App::$pager['page'] : 1), + '$search' => (($search) ? urlencode($search) : ''), + '$xchan' => (($xchan) ? urlencode($xchan) : ''), + '$order' => (($order) ? urlencode($order) : ''), + '$file' => (($file) ? urlencode($file) : ''), + '$cats' => (($category) ? urlencode($category) : ''), + '$tags' => (($hashtags) ? urlencode($hashtags) : ''), + '$dend' => $datequery, + '$mid' => '', + '$verb' => (($verb) ? urlencode($verb) : ''), + '$net' => (($net) ? urlencode($net) : ''), + '$dbegin' => $datequery2, + '$pf' => (($pf) ? intval($pf) : '0'), + ]); + } + + $sql_extra3 = ''; + + if ($datequery) { + $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery)))); + } + if ($datequery2) { + $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(), '', $datequery2)))); + } + + $sql_extra2 = (($nouveau) ? '' : " AND item.parent = item.id "); + $sql_extra3 = (($nouveau) ? '' : $sql_extra3); + + if (x($_GET, 'search')) { + $search = escape_tags($_GET['search']); + if (strpos($search, '#') === 0) { + $sql_extra .= term_query('item', substr($search, 1), TERM_HASHTAG, TERM_COMMUNITYTAG); + } else { + $sql_extra .= sprintf(" AND (item.body like '%s' OR item.title like '%s') ", + dbesc(protect_sprintf('%' . $search . '%')), + dbesc(protect_sprintf('%' . $search . '%')) + ); + } + } + + if ($verb) { + + // the presence of a leading dot in the verb determines + // whether to match the type of activity or the child object. + // The name 'verb' is a holdover from the earlier XML + // ActivityStreams specification. + + if (substr($verb, 0, 1) === '.') { + $verb = substr($verb, 1); + $sql_extra .= sprintf(" AND item.obj_type like '%s' ", + dbesc(protect_sprintf('%' . $verb . '%')) + ); + } else { + $sql_extra .= sprintf(" AND item.verb like '%s' ", + dbesc(protect_sprintf('%' . $verb . '%')) + ); + } + } + + if (strlen($file)) { + $sql_extra .= term_query('item', $file, TERM_FILE); + } + + if ($dm) { + $sql_extra .= " and item_private = 2 "; + } + + if ($conv) { + + $item_thread_top = ''; + + if ($nouveau) { + $sql_extra .= " AND author_xchan = '" . dbesc($channel['channel_hash']) . "' "; + } else { + $sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan = '%s' or item_mentionsme = 1 ) and item_deleted = 0 ) ", + dbesc(protect_sprintf($channel['channel_hash'])) + ); + } + } + + if ($this->updating && !$this->loading) { + + // only setup pagination on initial page view + $pager_sql = ''; + + } else { + $itemspage = get_pconfig(local_channel(), 'system', 'itemspage'); + App::set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); + } + + // cmin and cmax are both -1 when the affinity tool is disabled + + if (($cmin != (-1)) || ($cmax != (-1))) { + + // Not everybody who shows up in the network stream will be in your address book. + // By default those that aren't are assumed to have closeness = 99; but this isn't + // recorded anywhere. So if cmax is 99, we'll open the search up to anybody in + // the stream with a NULL address book entry. + + $sql_nets .= " AND "; + + if ($cmax == 99) + $sql_nets .= " ( "; + + $sql_nets .= "( abook.abook_closeness >= " . intval($cmin) . " "; + $sql_nets .= " AND abook.abook_closeness <= " . intval($cmax) . " ) "; + + if ($cmax == 99) + $sql_nets .= " OR abook.abook_closeness IS NULL ) "; + + } + + $net_query = (($net) ? " left join xchan on xchan_hash = author_xchan " : ''); + $net_query2 = (($net) ? " and xchan_network = '" . protect_sprintf(dbesc($net)) . "' " : ''); + + $abook_uids = " and abook.abook_channel = " . local_channel() . " "; + $uids = " and item.uid = " . local_channel() . " "; + + if (get_pconfig(local_channel(), 'system', 'stream_list_mode')) + $page_mode = 'list'; + else + $page_mode = 'client'; + + $simple_update = (($this->updating) ? " and item_changed > = '" . $_SESSION['loadtime_stream'] . "' " : ''); + + $parents_str = ''; + $update_unseen = ''; + $items = []; + + // This fixes a very subtle bug so I'd better explain it. You wake up in the morning or return after a day + // or three and look at your stream page - after opening up your browser. The first page loads just as it + // should. All of a sudden a few seconds later, page 2 will get inserted at the beginning of the page + // (before the page 1 content). The update code is actually doing just what it's supposed + // to, it's fetching posts that have the ITEM_UNSEEN bit set. But the reason that page 2 content is being + // returned in an UPDATE is because you hadn't gotten that far yet - you're still on page 1 and everything + // that we loaded for page 1 is now marked as seen. But the stuff on page 2 hasn't been. So... it's being + // treated as "new fresh" content because it is unseen. We need to distinguish it somehow from content + // which "arrived as you were reading page 1". We're going to do this + // by storing in your session the current UTC time whenever you LOAD a network page, and only UPDATE items + // which are both ITEM_UNSEEN and have "changed" since that time. Cross fingers... + + if ($this->updating && $_SESSION['loadtime_stream']) + $simple_update = " AND item.changed > '" . datetime_convert('UTC', 'UTC', $_SESSION['loadtime_stream']) . "' "; + if ($this->loading) + $simple_update = ''; + + if ($static && $simple_update) + $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' "; + + + // we are not yet using this in updates because the content may have just been marked seen + // and this might prevent us from loading the update. Will need to test further. + + $seenstr = EMPTY_STR; + if (local_channel()) { + $seen = PConfig::Get(local_channel(), 'system', 'seen_items', []); + if ($seen) { + $seenstr = " and not item.id in (" . implode(',', $seen) . ") "; + } + } + + if ($nouveau && $this->loading) { + // "New Item View" - show all items unthreaded in reverse created date order + + $items = q("SELECT item.*, item.id AS item_id, created FROM item left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) $net_query WHERE true $uids $item_normal @@ -574,24 +563,23 @@ class Stream extends Controller { $sql_extra $sql_options $sql_nets $net_query2 ORDER BY item.created DESC $pager_sql " - ); - - xchan_query($items); - - $items = fetch_post_tags($items,true); - } - elseif ($this->updating) { - - // Normal conversation view + ); - if($order === 'post') - $ordering = "created"; - else - $ordering = "commented"; + xchan_query($items); - if ($this->loading) { - // Fetch a page full of parent items for this page - $r = q("SELECT item.parent AS item_id FROM item + $items = fetch_post_tags($items, true); + } elseif ($this->updating) { + + // Normal conversation view + + if ($order === 'post') + $ordering = "created"; + else + $ordering = "commented"; + + if ($this->loading) { + // Fetch a page full of parent items for this page + $r = q("SELECT item.parent AS item_id FROM item left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) $net_query WHERE true $uids $item_thread_top $item_normal @@ -600,82 +588,80 @@ class Stream extends Controller { $sql_extra3 $sql_extra $sql_options $sql_nets $net_query2 ORDER BY $ordering DESC $pager_sql " - ); - } - else { + ); + } else { - // this is an update + // this is an update - $r = q("SELECT item.parent AS item_id FROM item + $r = q("SELECT item.parent AS item_id FROM item left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) $net_query WHERE true $uids $item_normal_update $simple_update and (abook.abook_blocked = 0 or abook.abook_flags is null) $sql_extra3 $sql_extra $sql_options $sql_nets $net_query2" - ); - } + ); + } - if ($r) { - - $parents_str = ids_to_querystr($r,'item_id'); - - $items = q("SELECT item.*, item.id AS item_id FROM item + if ($r) { + + $parents_str = ids_to_querystr($r, 'item_id'); + + $items = q("SELECT item.*, item.id AS item_id FROM item WHERE true $uids $item_normal AND item.parent IN ( %s ) $sql_extra ", - dbesc($parents_str) - ); - - xchan_query($items,true); - $items = fetch_post_tags($items,true); - $items = conv_sort($items,$ordering); + dbesc($parents_str) + ); - } + xchan_query($items, true); + $items = fetch_post_tags($items, true); + $items = conv_sort($items, $ordering); - if ($page_mode === 'list') { - - /** - * in "list mode", only mark the parent item and any like activities as "seen". - * We won't distinguish between comment likes and post likes. The important thing - * is that the number of unseen comments will be accurate. The SQL to separate the - * comment likes could also get somewhat hairy. - */ - - if ($parents_str) { - $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; - $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; - } - } - else { - if ($parents_str) { - $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; - } - } - } - - if ($update_unseen && (! (isset($_SESSION['sudo']) && $_SESSION['sudo']))) { - $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ]; - call_hooks('update_unseen',$x); - if ($x['update'] === 'unset' || intval($x['update'])) { - $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ", - intval(local_channel()) - ); - } - } - - $mode = (($nouveau) ? 'stream-new' : 'stream'); + } + + if ($page_mode === 'list') { + + /** + * in "list mode", only mark the parent item and any like activities as "seen". + * We won't distinguish between comment likes and post likes. The important thing + * is that the number of unseen comments will be accurate. The SQL to separate the + * comment likes could also get somewhat hairy. + */ + + if ($parents_str) { + $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; + $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; + } + } else { + if ($parents_str) { + $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; + } + } + } + + if ($update_unseen && (!(isset($_SESSION['sudo']) && $_SESSION['sudo']))) { + $x = ['channel_id' => local_channel(), 'update' => 'unset']; + call_hooks('update_unseen', $x); + if ($x['update'] === 'unset' || intval($x['update'])) { + $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ", + intval(local_channel()) + ); + } + } + + $mode = (($nouveau) ? 'stream-new' : 'stream'); + + if ($search) { + $mode = 'search'; + } + + $o .= conversation($items, $mode, $this->updating, $page_mode); + + if (($items) && (!$this->updating)) { + $o .= alt_pager(count($items)); + } + + return $o; + } - if ($search) { - $mode = 'search'; - } - - $o .= conversation($items,$mode,$this->updating,$page_mode); - - if (($items) && (! $this->updating)) { - $o .= alt_pager(count($items)); - } - - return $o; - } - } diff --git a/Zotlabs/Module/Subthread.php b/Zotlabs/Module/Subthread.php index 2761d8103..76e28aebf 100644 --- a/Zotlabs/Module/Subthread.php +++ b/Zotlabs/Module/Subthread.php @@ -9,176 +9,173 @@ require_once('include/security.php'); require_once('include/bbcode.php'); +class Subthread extends Controller +{ -class Subthread extends Controller { + public function get() + { - function get() { - - if (! local_channel()) { - return; - } - - $sys = get_sys_channel(); - $channel = App::get_channel(); + if (!local_channel()) { + return; + } - $item_id = ((argc() > 2) ? notags(trim(argv(2))) : 0); - - if (argv(1) === 'sub') { - $activity = ACTIVITY_FOLLOW; - } - elseif (argv(1) === 'unsub') { - $activity = ACTIVITY_IGNORE; - } - - $i = q("select * from item where id = %d and uid = %d", - intval($item_id), - intval(local_channel()) - ); + $sys = get_sys_channel(); + $channel = App::get_channel(); - if (! $i) { - // try the global public stream - $i = q("select * from item where id = %d and uid = %d", - intval($postid), - intval($sys['channel_id']) - ); - // try the local public stream - if (! $i) { - $i = q("select * from item where id = %d and item_wall = 1 and item_private = 0", - intval($postid) - ); - } + $item_id = ((argc() > 2) ? notags(trim(argv(2))) : 0); - if ($i && local_channel() && (! is_sys_channel(local_channel()))) { - $i = [ copy_of_pubitem($channel, $i[0]['mid']) ]; - $item_id = (($i) ? $i[0]['id'] : 0); - } - } - - if (! $i) { - return; - } + if (argv(1) === 'sub') { + $activity = ACTIVITY_FOLLOW; + } elseif (argv(1) === 'unsub') { + $activity = ACTIVITY_IGNORE; + } - $r = q("select * from item where id = parent and id = %d limit 1", - dbesc($i[0]['parent']) - ); - - if ((! $item_id) || (! $r)) { - logger('subthread: no item ' . $item_id); - return; - } - - $item = $r[0]; - - $owner_uid = $item['uid']; - $observer = App::get_observer(); - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - - if (! perm_is_allowed($owner_uid,$ob_hash,'post_comments')) { - return; - } - - $sys = get_sys_channel(); - - $owner_uid = $item['uid']; - $owner_aid = $item['aid']; - - // if this is a "discover" item, (item['uid'] is the sys channel), - // fallback to the item comment policy, which should've been - // respected when generating the conversation thread. - // Even if the activity is rejected by the item owner, it should still get attached - // to the local discover conversation on this site. - - if (($owner_uid != $sys['channel_id']) && (! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments'))) { - notice( t('Permission denied') . EOL); - killme(); - } - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($item['owner_xchan']) - ); - if ($r) { - $thread_owner = $r[0]; - } - else { - killme(); - } - - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($item['author_xchan']) - ); - if ($r) { - $item_author = $r[0]; - } - else { - killme(); - } - - $uuid = new_uuid(); - $mid = z_root() . '/item/' . $uuid; - - $post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status')); - - $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink'])); - $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); - - $body = $item['body']; + $i = q("select * from item where id = %d and uid = %d", + intval($item_id), + intval(local_channel()) + ); - $obj = Activity::fetch_item( [ 'id' => $item['mid'] ] ); - $objtype = $obj['type']; + if (!$i) { + // try the global public stream + $i = q("select * from item where id = %d and uid = %d", + intval($postid), + intval($sys['channel_id']) + ); + // try the local public stream + if (!$i) { + $i = q("select * from item where id = %d and item_wall = 1 and item_private = 0", + intval($postid) + ); + } - if (! intval($item['item_thread_top'])) - $post_type = 'comment'; - - if ($activity === ACTIVITY_FOLLOW) { - $bodyverb = t('%1$s is following %2$s\'s %3$s'); - } - if ($activity === ACTIVITY_IGNORE) { - $bodyverb = t('%1$s stopped following %2$s\'s %3$s'); - } - - $arr = []; + if ($i && local_channel() && (!is_sys_channel(local_channel()))) { + $i = [copy_of_pubitem($channel, $i[0]['mid'])]; + $item_id = (($i) ? $i[0]['id'] : 0); + } + } - $arr['uuid'] = $uuid; - $arr['mid'] = $mid; - $arr['aid'] = $owner_aid; - $arr['uid'] = $owner_uid; - $arr['parent'] = $item['id']; - $arr['parent_mid'] = $item['mid']; - $arr['thr_parent'] = $item['mid']; - $arr['owner_xchan'] = $thread_owner['xchan_hash']; - $arr['author_xchan'] = $observer['xchan_hash']; - $arr['item_origin'] = 1; - $arr['item_notshown'] = 1; + if (!$i) { + return; + } - if (intval($item['item_wall'])) { - $arr['item_wall'] = 1; - } - else { - $arr['item_wall'] = 0; - } - - $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; - $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; - $plink = '[zrl=' . z_root() . '/display/' . gen_link_id($item['mid']) . ']' . $post_type . '[/zrl]'; - - $arr['body'] = sprintf( $bodyverb, $alink, $ulink, $plink ); - - $arr['verb'] = $activity; - $arr['obj_type'] = $objtype; - $arr['obj'] = json_encode($obj); - - $arr['allow_cid'] = $item['allow_cid']; - $arr['allow_gid'] = $item['allow_gid']; - $arr['deny_cid'] = $item['deny_cid']; - $arr['deny_gid'] = $item['deny_gid']; - - $post = item_store($arr); - $post_id = $post['item_id']; - - $arr['id'] = $post_id; - - call_hooks('post_local_end', $arr); - - killme(); - } + $r = q("select * from item where id = parent and id = %d limit 1", + dbesc($i[0]['parent']) + ); + + if ((!$item_id) || (!$r)) { + logger('subthread: no item ' . $item_id); + return; + } + + $item = $r[0]; + + $owner_uid = $item['uid']; + $observer = App::get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if (!perm_is_allowed($owner_uid, $ob_hash, 'post_comments')) { + return; + } + + $sys = get_sys_channel(); + + $owner_uid = $item['uid']; + $owner_aid = $item['aid']; + + // if this is a "discover" item, (item['uid'] is the sys channel), + // fallback to the item comment policy, which should've been + // respected when generating the conversation thread. + // Even if the activity is rejected by the item owner, it should still get attached + // to the local discover conversation on this site. + + if (($owner_uid != $sys['channel_id']) && (!perm_is_allowed($owner_uid, $observer['xchan_hash'], 'post_comments'))) { + notice(t('Permission denied') . EOL); + killme(); + } + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['owner_xchan']) + ); + if ($r) { + $thread_owner = $r[0]; + } else { + killme(); + } + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['author_xchan']) + ); + if ($r) { + $item_author = $r[0]; + } else { + killme(); + } + + $uuid = new_uuid(); + $mid = z_root() . '/item/' . $uuid; + + $post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status')); + + $links = array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['plink'])); + $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE); + + $body = $item['body']; + + $obj = Activity::fetch_item(['id' => $item['mid']]); + $objtype = $obj['type']; + + if (!intval($item['item_thread_top'])) + $post_type = 'comment'; + + if ($activity === ACTIVITY_FOLLOW) { + $bodyverb = t('%1$s is following %2$s\'s %3$s'); + } + if ($activity === ACTIVITY_IGNORE) { + $bodyverb = t('%1$s stopped following %2$s\'s %3$s'); + } + + $arr = []; + + $arr['uuid'] = $uuid; + $arr['mid'] = $mid; + $arr['aid'] = $owner_aid; + $arr['uid'] = $owner_uid; + $arr['parent'] = $item['id']; + $arr['parent_mid'] = $item['mid']; + $arr['thr_parent'] = $item['mid']; + $arr['owner_xchan'] = $thread_owner['xchan_hash']; + $arr['author_xchan'] = $observer['xchan_hash']; + $arr['item_origin'] = 1; + $arr['item_notshown'] = 1; + + if (intval($item['item_wall'])) { + $arr['item_wall'] = 1; + } else { + $arr['item_wall'] = 0; + } + + $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . z_root() . '/display/' . gen_link_id($item['mid']) . ']' . $post_type . '[/zrl]'; + + $arr['body'] = sprintf($bodyverb, $alink, $ulink, $plink); + + $arr['verb'] = $activity; + $arr['obj_type'] = $objtype; + $arr['obj'] = json_encode($obj); + + $arr['allow_cid'] = $item['allow_cid']; + $arr['allow_gid'] = $item['allow_gid']; + $arr['deny_cid'] = $item['deny_cid']; + $arr['deny_gid'] = $item['deny_gid']; + + $post = item_store($arr); + $post_id = $post['item_id']; + + $arr['id'] = $post_id; + + call_hooks('post_local_end', $arr); + + killme(); + } } diff --git a/Zotlabs/Module/Suggestions.php b/Zotlabs/Module/Suggestions.php index 39cb545c2..5258acab9 100644 --- a/Zotlabs/Module/Suggestions.php +++ b/Zotlabs/Module/Suggestions.php @@ -8,38 +8,41 @@ use Zotlabs\Web\Controller; require_once('include/socgraph.php'); -class Suggestions extends Controller { +class Suggestions extends Controller +{ - function init() { - if (! local_channel()) - return; - - if (x($_GET,'ignore')) { - q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ", - intval(local_channel()), - dbesc($_GET['ignore']) - ); - Libsync::build_sync_packet(local_channel(), [ 'xign' => [ [ 'uid' => local_channel(), 'xchan' => $_GET['ignore'] ]]] ); - } - } - - - function get() { - - $o = ''; - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - return; - } + public function init() + { + if (!local_channel()) + return; - if (Apps::system_app_installed(local_channel(),'Suggest Channels')) { + if (x($_GET, 'ignore')) { + q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ", + intval(local_channel()), + dbesc($_GET['ignore']) + ); + Libsync::build_sync_packet(local_channel(), ['xign' => [['uid' => local_channel(), 'xchan' => $_GET['ignore']]]]); + } + } + + + public function get() + { + + $o = ''; + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + return; + } + + if (Apps::system_app_installed(local_channel(), 'Suggest Channels')) { goaway(z_root() . '/directory?f=&suggest=1'); } - $desc = t('This app (when installed) displays a small number of friend suggestions on selected pages or you can run the app to display a full list of channel suggestions.'); + $desc = t('This app (when installed) displays a small number of friend suggestions on selected pages or you can run the app to display a full list of channel suggestions.'); return ''; - } - + } + } diff --git a/Zotlabs/Module/Superblock.php b/Zotlabs/Module/Superblock.php index 8bb540f72..d71fe7675 100644 --- a/Zotlabs/Module/Superblock.php +++ b/Zotlabs/Module/Superblock.php @@ -9,247 +9,249 @@ use Zotlabs\Lib\Libsync; use Zotlabs\Lib\LibBlock; use Zotlabs\Lib\Libzot; -class Superblock extends Controller { +class Superblock extends Controller +{ - function init() { - - if (! local_channel()) { - return; - } + public function init() + { - $inline = (isset($_REQUEST['manual_block']) ? true : false); + if (!local_channel()) { + return; + } - $type = BLOCKTYPE_CHANNEL; - $blocked = trim($_REQUEST['block']); - if (! $blocked) { - $blocked = trim($_REQUEST['blocksite']); - if ($blocked) { - $type = BLOCKTYPE_SERVER; - } - } + $inline = (isset($_REQUEST['manual_block']) ? true : false); - $m = parse_url($blocked); - if ($m['scheme'] && $m['host'] && (($type === BLOCKTYPE_SERVER) || (! $m['path']))) { - if (strcasecmp($m['host'],App::get_hostname()) === 0) { - notice(t('Blocking this site is not permitted.')); - if ($inline) { - return; - } - killme(); - } - $type = BLOCKTYPE_SERVER; - $blocked = $m['host']; - } + $type = BLOCKTYPE_CHANNEL; + $blocked = trim($_REQUEST['block']); + if (!$blocked) { + $blocked = trim($_REQUEST['blocksite']); + if ($blocked) { + $type = BLOCKTYPE_SERVER; + } + } - $handled = false; - $ignored = []; + $m = parse_url($blocked); + if ($m['scheme'] && $m['host'] && (($type === BLOCKTYPE_SERVER) || (!$m['path']))) { + if (strcasecmp($m['host'], App::get_hostname()) === 0) { + notice(t('Blocking this site is not permitted.')); + if ($inline) { + return; + } + killme(); + } + $type = BLOCKTYPE_SERVER; + $blocked = $m['host']; + } - if ($blocked) { - $handled = true; - if ($type === BLOCKTYPE_CHANNEL) { + $handled = false; + $ignored = []; - $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_addr = '%s' or xchan_url = '%s' )", - dbesc($blocked), - dbesc($blocked), - dbesc($blocked) - ); + if ($blocked) { + $handled = true; + if ($type === BLOCKTYPE_CHANNEL) { - if (! $r) { - // not in cache - try discovery - $wf = discover_by_webbie($blocked,'',false); - - if (! $wf) { - notice( t('Channel not found.') . EOL); - if ($inline) { - return; - } - killme(); - } + $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_addr = '%s' or xchan_url = '%s' )", + dbesc($blocked), + dbesc($blocked), + dbesc($blocked) + ); - if ($wf) { + if (!$r) { + // not in cache - try discovery + $wf = discover_by_webbie($blocked, '', false); - // something was discovered - find the record which was just created. - - $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' )", - dbesc(($wf) ? $wf : $blocked), - dbesc($blocked), - dbesc($blocked) - ); - } - } + if (!$wf) { + notice(t('Channel not found.') . EOL); + if ($inline) { + return; + } + killme(); + } - if ($r) { - $r = Libzot::zot_record_preferred($r,'xchan_network'); - $blocked = $r['xchan_hash']; - } - } + if ($wf) { - $bl = [ - 'block_channel_id' => local_channel(), - 'block_entity' => $blocked, - 'block_type' => $type, - 'block_comment' => t('Added by Superblock') - ]; + // something was discovered - find the record which was just created. - LibBlock::store($bl); + $r = q("select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' )", + dbesc(($wf) ? $wf : $blocked), + dbesc($blocked), + dbesc($blocked) + ); + } + } - $sync = []; - - $sync['block'] = [ LibBlock::fetch_by_entity(local_channel(),$blocked) ]; + if ($r) { + $r = Libzot::zot_record_preferred($r, 'xchan_network'); + $blocked = $r['xchan_hash']; + } + } - if ($type === BLOCKTYPE_CHANNEL) { - $z = q("insert into xign ( uid, xchan ) values ( %d , '%s' ) ", - intval(local_channel()), - dbesc($blocked) - ); - $ab = q("select * from abook where abook_channel = %d and abook_xchan = '%s'", - intval(local_channel()), - dbesc($blocked) - ); - if (($ab) && (! intval($ab['abook_blocked']))) { - q("update abook set abook_blocked = 1 where abook_channel = %d and abook_xchan = '%s'", - intval(local_channel()), - dbesc($blocked) - ); - - $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1", - intval(local_channel()), - dbesc($blocked) - ); - if ($r) { - $r = array_shift($r); - $abconfig = load_abconfig(local_channel(),$blocked); - if ($abconfig) { - $r['abconfig'] = $abconfig; - } - unset($r['abook_id']); - unset($r['abook_account']); - unset($r['abook_channel']); - $sync['abook'] = [ $r ]; - } - } - $sync['xign'] = [[ 'uid' => local_channel(), 'xchan' => $_GET['block'] ]]; - } - Libsync::build_sync_packet(0, $sync); - } + $bl = [ + 'block_channel_id' => local_channel(), + 'block_entity' => $blocked, + 'block_type' => $type, + 'block_comment' => t('Added by Superblock') + ]; - $type = BLOCKTYPE_CHANNEL; - $unblocked = trim($_REQUEST['unblock']); - if (! $unblocked) { - $unblocked = trim($_REQUEST['unblocksite']); - if ($unblocked) { - $type = BLOCKTYPE_SERVER; - } - } - if ($unblocked) { - $handled = true; - if (check_form_security_token('superblock','sectok')) { - $r = LibBlock::fetch_by_entity(local_channel(), $unblocked); - if ($r) { - LibBlock::remove(local_channel(), $unblocked); + LibBlock::store($bl); - $sync = []; - $sync['block'] = [[ - 'block_channel_id' => local_channel(), - 'block_entity' => $unblocked, - 'block_type' => $type, - 'deleted' => true, - ]]; - if ($type === BLOCKTYPE_CHANNEL) { - $ab = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_xchan = '%s'", - intval(local_channel()), - dbesc($unblocked) - ); - if (($ab) && (intval($ab['abook_blocked']))) { - q("update abook set abook_blocked = 1 where abook_channel = %d and abook_xchan = '%s'", - intval(local_channel()), - dbesc($unblocked) - ); - $ab['abook_blocked'] = 0; - $abconfig = load_abconfig(local_channel(),$unblocked); - if ($abconfig) { - $ab['abconfig'] = $abconfig; - } - unset($ab['abook_id']); - unset($ab['abook_account']); - unset($ab['abook_channel']); - $sync['abook'] = [ $ab ]; - } + $sync = []; - $z = q("delete from xign where uid = %d and xchan = '%s' ", - intval(local_channel()), - dbesc($unblocked) - ); - } - Libsync::build_sync_packet(0, $sync ); - } - } - } + $sync['block'] = [LibBlock::fetch_by_entity(local_channel(), $blocked)]; - if ($handled) { + if ($type === BLOCKTYPE_CHANNEL) { + $z = q("insert into xign ( uid, xchan ) values ( %d , '%s' ) ", + intval(local_channel()), + dbesc($blocked) + ); + $ab = q("select * from abook where abook_channel = %d and abook_xchan = '%s'", + intval(local_channel()), + dbesc($blocked) + ); + if (($ab) && (!intval($ab['abook_blocked']))) { + q("update abook set abook_blocked = 1 where abook_channel = %d and abook_xchan = '%s'", + intval(local_channel()), + dbesc($blocked) + ); - info( t('superblock settings updated') . EOL ); + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d and abook_xchan = '%s' LIMIT 1", + intval(local_channel()), + dbesc($blocked) + ); + if ($r) { + $r = array_shift($r); + $abconfig = load_abconfig(local_channel(), $blocked); + if ($abconfig) { + $r['abconfig'] = $abconfig; + } + unset($r['abook_id']); + unset($r['abook_account']); + unset($r['abook_channel']); + $sync['abook'] = [$r]; + } + } + $sync['xign'] = [['uid' => local_channel(), 'xchan' => $_GET['block']]]; + } + Libsync::build_sync_packet(0, $sync); + } - if ($unblocked || $inline) { - return; - } - - killme(); - } + $type = BLOCKTYPE_CHANNEL; + $unblocked = trim($_REQUEST['unblock']); + if (!$unblocked) { + $unblocked = trim($_REQUEST['unblocksite']); + if ($unblocked) { + $type = BLOCKTYPE_SERVER; + } + } + if ($unblocked) { + $handled = true; + if (check_form_security_token('superblock', 'sectok')) { + $r = LibBlock::fetch_by_entity(local_channel(), $unblocked); + if ($r) { + LibBlock::remove(local_channel(), $unblocked); - } + $sync = []; + $sync['block'] = [[ + 'block_channel_id' => local_channel(), + 'block_entity' => $unblocked, + 'block_type' => $type, + 'deleted' => true, + ]]; + if ($type === BLOCKTYPE_CHANNEL) { + $ab = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_xchan = '%s'", + intval(local_channel()), + dbesc($unblocked) + ); + if (($ab) && (intval($ab['abook_blocked']))) { + q("update abook set abook_blocked = 1 where abook_channel = %d and abook_xchan = '%s'", + intval(local_channel()), + dbesc($unblocked) + ); + $ab['abook_blocked'] = 0; + $abconfig = load_abconfig(local_channel(), $unblocked); + if ($abconfig) { + $ab['abconfig'] = $abconfig; + } + unset($ab['abook_id']); + unset($ab['abook_account']); + unset($ab['abook_channel']); + $sync['abook'] = [$ab]; + } - function get() { + $z = q("delete from xign where uid = %d and xchan = '%s' ", + intval(local_channel()), + dbesc($unblocked) + ); + } + Libsync::build_sync_packet(0, $sync); + } + } + } - $l = LibBlock::fetch(local_channel(),BLOCKTYPE_CHANNEL); + if ($handled) { - $list = ids_to_array($l,'block_entity'); + info(t('superblock settings updated') . EOL); - stringify_array_elms($list,true); - $query_str = implode(',',$list); - if ($query_str) { - $r = q("select * from xchan where xchan_hash in ( " . $query_str . " ) "); - } - else { - $r = []; - } - if ($r) { - for ($x = 0; $x < count($r); $x ++) { - $r[$x]['encoded_hash'] = urlencode($r[$x]['xchan_hash']); - } - } + if ($unblocked || $inline) { + return; + } - $sc .= replace_macros(get_markup_template('superblock_list.tpl'), [ - '$blocked' => t('Blocked channels'), - '$entries' => $r, - '$nothing' => (($r) ? '' : t('No channels currently blocked')), - '$token' => get_form_security_token('superblock'), - '$remove' => t('Remove') - ]); + killme(); + } + + } + + public function get() + { + + $l = LibBlock::fetch(local_channel(), BLOCKTYPE_CHANNEL); + + $list = ids_to_array($l, 'block_entity'); + + stringify_array_elms($list, true); + $query_str = implode(',', $list); + if ($query_str) { + $r = q("select * from xchan where xchan_hash in ( " . $query_str . " ) "); + } else { + $r = []; + } + if ($r) { + for ($x = 0; $x < count($r); $x++) { + $r[$x]['encoded_hash'] = urlencode($r[$x]['xchan_hash']); + } + } + + $sc .= replace_macros(get_markup_template('superblock_list.tpl'), [ + '$blocked' => t('Blocked channels'), + '$entries' => $r, + '$nothing' => (($r) ? '' : t('No channels currently blocked')), + '$token' => get_form_security_token('superblock'), + '$remove' => t('Remove') + ]); - $l = LibBlock::fetch(local_channel(),BLOCKTYPE_SERVER); - $list = ids_to_array($l,'block_entity'); - if ($list) { - for ($x = 0; $x < count($list); $x ++ ) { - $list[$x] = [ $list[$x], urlencode($list[$x]) ]; - } - } + $l = LibBlock::fetch(local_channel(), BLOCKTYPE_SERVER); + $list = ids_to_array($l, 'block_entity'); + if ($list) { + for ($x = 0; $x < count($list); $x++) { + $list[$x] = [$list[$x], urlencode($list[$x])]; + } + } - $sc .= replace_macros(get_markup_template('superblock_serverlist.tpl'), [ - '$blocked' => t('Blocked servers'), - '$entries' => $list, - '$nothing' => (($list) ? '' : t('No servers currently blocked')), - '$token' => get_form_security_token('superblock'), - '$remove' => t('Remove') - ]); + $sc .= replace_macros(get_markup_template('superblock_serverlist.tpl'), [ + '$blocked' => t('Blocked servers'), + '$entries' => $list, + '$nothing' => (($list) ? '' : t('No servers currently blocked')), + '$token' => get_form_security_token('superblock'), + '$remove' => t('Remove') + ]); - $s .= replace_macros(get_markup_template('generic_app_settings.tpl'), [ - '$addon' => array('superblock', t('Manage Blocks'), '', t('Submit')), - '$content' => $sc - ]); + $s .= replace_macros(get_markup_template('generic_app_settings.tpl'), [ + '$addon' => array('superblock', t('Manage Blocks'), '', t('Submit')), + '$content' => $sc + ]); - return $s; + return $s; - } + } } \ No newline at end of file diff --git a/Zotlabs/Module/Tagadelic.php b/Zotlabs/Module/Tagadelic.php index d17fdb36a..393826d57 100644 --- a/Zotlabs/Module/Tagadelic.php +++ b/Zotlabs/Module/Tagadelic.php @@ -9,28 +9,31 @@ use Zotlabs\Lib\Libprofile; use Zotlabs\Web\Controller; use Zotlabs\Render\Comanche; -class Tagadelic extends Controller { +class Tagadelic extends Controller +{ - function init() { + public function init() + { - if(local_channel()) { - $channel = App::get_channel(); - if($channel && $channel['channel_address']) { - $which = $channel['channel_address']; - } - Libprofile::load($which,0); - } + if (local_channel()) { + $channel = App::get_channel(); + if ($channel && $channel['channel_address']) { + $which = $channel['channel_address']; + } + Libprofile::load($which, 0); + } - } + } - function get() { + public function get() + { $desc = t('This app displays a hashtag cloud on your channel homepage.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Tagadelic'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Tagadelic'))) { return $text; } @@ -39,10 +42,10 @@ class Tagadelic extends Controller { $text = ''; - $c = new Comanche; - return $text . EOL . EOL . $c->widget('tagcloud_wall',EMPTY_STR); + $c = new Comanche(); + return $text . EOL . EOL . $c->widget('tagcloud_wall', EMPTY_STR); - } + } } diff --git a/Zotlabs/Module/Tagger.php b/Zotlabs/Module/Tagger.php index 48114d905..a782c42aa 100644 --- a/Zotlabs/Module/Tagger.php +++ b/Zotlabs/Module/Tagger.php @@ -9,164 +9,164 @@ require_once('include/security.php'); require_once('include/bbcode.php'); +class Tagger extends Controller +{ + public function get() + { -class Tagger extends Controller { + if (!local_channel()) { + return; + } - function get() { - - if(! local_channel()) { - return; - } - - $sys = get_sys_channel(); + $sys = get_sys_channel(); - $observer_hash = get_observer_hash(); - //strip html-tags - $term = notags(trim($_GET['term'])); - //check if empty - if(! $term) - return; - - $item_id = ((argc() > 1) ? notags(trim(argv(1))) : 0); - - logger('tagger: tag ' . $term . ' item ' . $item_id); - - $r = q("select * from item where id = %d and uid = %d limit 1", - intval($item_id), - intval(local_channel()) - ); + $observer_hash = get_observer_hash(); + //strip html-tags + $term = notags(trim($_GET['term'])); + //check if empty + if (!$term) + return; - if(! $r) { - $r = q("select * from item where id = %d and uid = %d limit 1", - intval($item_id), - intval($sys['channel_id']) - ); - if (! $r) { - $r = q("select * from item where id = %d and item_private = 0 and item_wall = 1", - intval($item_id) - ); - } - if ($r && local_channel() && (! is_sys_channel(local_channel()))) { - $r = [ copy_of_pubitem($channel, $i[0]['mid']) ]; + $item_id = ((argc() > 1) ? notags(trim(argv(1))) : 0); + + logger('tagger: tag ' . $term . ' item ' . $item_id); + + $r = q("select * from item where id = %d and uid = %d limit 1", + intval($item_id), + intval(local_channel()) + ); + + if (!$r) { + $r = q("select * from item where id = %d and uid = %d limit 1", + intval($item_id), + intval($sys['channel_id']) + ); + if (!$r) { + $r = q("select * from item where id = %d and item_private = 0 and item_wall = 1", + intval($item_id) + ); + } + if ($r && local_channel() && (!is_sys_channel(local_channel()))) { + $r = [copy_of_pubitem($channel, $i[0]['mid'])]; $item_id = (($r) ? $r[0]['id'] : 0); - } - } + } + } - if(! $r) { - notice( t('Post not found.') . EOL); - return; - } + if (!$r) { + notice(t('Post not found.') . EOL); + return; + } - $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = %d and uid = %d LIMIT 1", - intval($item_id), - intval(local_channel()) - ); - - if((! $item_id) || (! $r)) { - logger('tagger: no item ' . $item_id); - return; - } - - $item = $r[0]; - - $owner_uid = $item['uid']; - - switch($item['resource_type']) { - case 'photo': - $targettype = ACTIVITY_OBJ_PHOTO; - $post_type = t('photo'); - break; - case 'event': - $targgettype = ACTIVITY_OBJ_EVENT; - $post_type = t('event'); - break; - default: - $targettype = ACTIVITY_OBJ_NOTE; - $post_type = t('post'); - if($item['mid'] != $item['parent_mid']) - $post_type = t('comment'); - break; - } - + $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = %d and uid = %d LIMIT 1", + intval($item_id), + intval(local_channel()) + ); - $clean_term = trim($term,'"\' '); - - $links = array(array('rel' => 'alternate','type' => 'text/html', - 'href' => z_root() . '/display/' . gen_link_id($item['mid']))); - - $target = json_encode(array( - 'type' => $targettype, - 'id' => $item['mid'], - 'link' => $links, - 'title' => $item['title'], - 'content' => $item['body'], - 'created' => $item['created'], - 'edited' => $item['edited'], - 'author' => array( - 'name' => $item['xchan_name'], - 'address' => $item['xchan_addr'], - 'guid' => $item['xchan_guid'], - 'guid_sig' => $item['xchan_guid_sig'], - 'link' => array( - array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['xchan_url']), - array('rel' => 'photo', 'type' => $item['xchan_photo_mimetype'], 'href' => $item['xchan_photo_m'])), - ), - )); - - $tagid = z_root() . '/search?tag=' . $clean_term; - $objtype = ACTIVITY_OBJ_TAGTERM; - - $obj = json_encode(array( - 'type' => $objtype, - 'id' => $tagid, - 'link' => array(array('rel' => 'alternate','type' => 'text/html', 'href' => $tagid)), - 'title' => $clean_term, - 'content' => $clean_term - )); - - $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s'); - - // saving here for reference - // also check out x22d5 and x2317 and x0d6b and x0db8 and x24d0 and xff20 !!! - - $termlink = html_entity_decode('⋕') . '[zrl=' . z_root() . '/search?tag=' . urlencode($clean_term) . ']'. $clean_term . '[/zrl]'; - - $channel = App::get_channel(); - - $arr = []; - - $arr['owner_xchan'] = $item['owner_xchan']; - $arr['author_xchan'] = $channel['channel_hash']; - - $arr['item_origin'] = 1; - $arr['item_wall'] = ((intval($item['item_wall'])) ? 1 : 0); - - $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; - $alink = '[zrl=' . $item['xchan_url'] . ']' . $item['xchan_name'] . '[/zrl]'; - $plink = '[zrl=' . $item['plink'] . ']' . $post_type . '[/zrl]'; - - $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink, $termlink ); - - $arr['verb'] = ACTIVITY_TAG; - $arr['tgt_type'] = $targettype; - $arr['target'] = $target; - $arr['obj_type'] = $objtype; - $arr['obj'] = $obj; - $arr['parent_mid'] = $item['mid']; - store_item_tag($item['uid'],$item['id'],TERM_OBJ_POST,TERM_COMMUNITYTAG,$clean_term,$tagid); - $ret = post_activity_item($arr); + if ((!$item_id) || (!$r)) { + logger('tagger: no item ' . $item_id); + return; + } + + $item = $r[0]; + + $owner_uid = $item['uid']; + + switch ($item['resource_type']) { + case 'photo': + $targettype = ACTIVITY_OBJ_PHOTO; + $post_type = t('photo'); + break; + case 'event': + $targgettype = ACTIVITY_OBJ_EVENT; + $post_type = t('event'); + break; + default: + $targettype = ACTIVITY_OBJ_NOTE; + $post_type = t('post'); + if ($item['mid'] != $item['parent_mid']) + $post_type = t('comment'); + break; + } + + + $clean_term = trim($term, '"\' '); + + $links = array(array('rel' => 'alternate', 'type' => 'text/html', + 'href' => z_root() . '/display/' . gen_link_id($item['mid']))); + + $target = json_encode(array( + 'type' => $targettype, + 'id' => $item['mid'], + 'link' => $links, + 'title' => $item['title'], + 'content' => $item['body'], + 'created' => $item['created'], + 'edited' => $item['edited'], + 'author' => array( + 'name' => $item['xchan_name'], + 'address' => $item['xchan_addr'], + 'guid' => $item['xchan_guid'], + 'guid_sig' => $item['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['xchan_url']), + array('rel' => 'photo', 'type' => $item['xchan_photo_mimetype'], 'href' => $item['xchan_photo_m'])), + ), + )); + + $tagid = z_root() . '/search?tag=' . $clean_term; + $objtype = ACTIVITY_OBJ_TAGTERM; + + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $tagid, + 'link' => array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $tagid)), + 'title' => $clean_term, + 'content' => $clean_term + )); + + $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s'); + + // saving here for reference + // also check out x22d5 and x2317 and x0d6b and x0db8 and x24d0 and xff20 !!! + + $termlink = html_entity_decode('⋕') . '[zrl=' . z_root() . '/search?tag=' . urlencode($clean_term) . ']' . $clean_term . '[/zrl]'; + + $channel = App::get_channel(); + + $arr = []; + + $arr['owner_xchan'] = $item['owner_xchan']; + $arr['author_xchan'] = $channel['channel_hash']; + + $arr['item_origin'] = 1; + $arr['item_wall'] = ((intval($item['item_wall'])) ? 1 : 0); + + $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; + $alink = '[zrl=' . $item['xchan_url'] . ']' . $item['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . $item['plink'] . ']' . $post_type . '[/zrl]'; + + $arr['body'] = sprintf($bodyverb, $ulink, $alink, $plink, $termlink); + + $arr['verb'] = ACTIVITY_TAG; + $arr['tgt_type'] = $targettype; + $arr['target'] = $target; + $arr['obj_type'] = $objtype; + $arr['obj'] = $obj; + $arr['parent_mid'] = $item['mid']; + store_item_tag($item['uid'], $item['id'], TERM_OBJ_POST, TERM_COMMUNITYTAG, $clean_term, $tagid); + $ret = post_activity_item($arr); + + if ($ret['success']) { + Libsync::build_sync_packet(local_channel(), + [ + 'item' => [encode_item($ret['activity'], true)] + ] + ); + } + + killme(); + + } - if($ret['success']) { - Libsync::build_sync_packet(local_channel(), - [ - 'item' => [ encode_item($ret['activity'],true) ] - ] - ); - } - - killme(); - - } - } diff --git a/Zotlabs/Module/Tagrm.php b/Zotlabs/Module/Tagrm.php index 3e34ae7db..0b9fab99a 100644 --- a/Zotlabs/Module/Tagrm.php +++ b/Zotlabs/Module/Tagrm.php @@ -6,144 +6,146 @@ use Zotlabs\Web\Controller; require_once('include/bbcode.php'); -class Tagrm extends Controller { +class Tagrm extends Controller +{ + + public function post() + { + + if (!local_channel()) + goaway(z_root() . '/' . $_SESSION['photo_return']); + + + if ((x($_POST, 'submit')) && ($_POST['submit'] === t('Cancel'))) + goaway(z_root() . '/' . $_SESSION['photo_return']); + + $tag = ((x($_POST, 'tag')) ? trim($_POST['tag']) : ''); + $item = ((x($_POST, 'item')) ? intval($_POST['item']) : 0); + + $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", + intval($item), + intval(local_channel()) + ); + + if (!$r) + goaway(z_root() . '/' . $_SESSION['photo_return']); + + $r = fetch_post_tags($r, true); + + $item = $r[0]; + $new_tags = []; + + if ($item['term']) { + for ($x = 0; $x < count($item['term']); $x++) { + if ($item['term'][$x]['term'] !== hex2bin($tag)) + $new_tags[] = $item['term'][$x]; + } + } + + if ($new_tags) + $item['term'] = $new_tags; + else + unset($item['term']); + + item_store_update($item); + + info(t('Tag removed') . EOL); + goaway(z_root() . '/' . $_SESSION['photo_return']); + + // NOTREACHED + + } + + + public function get() + { + + if (!local_channel()) { + goaway(z_root() . '/' . $_SESSION['photo_return']); + // NOTREACHED + } + + // remove tag on the fly if item and tag are provided + if ((argc() == 4) && (argv(1) === 'drop') && intval(argv(2))) { + + $item = intval(argv(2)); + $tag = argv(3); + + $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", + intval($item), + intval(local_channel()) + ); + + if (!$r) + goaway(z_root() . '/' . $_SESSION['photo_return']); + + $r = fetch_post_tags($r, true); + + $item = $r[0]; + + $new_tags = []; + + if ($item['term']) { + for ($x = 0; $x < count($item['term']); $x++) { + if ($item['term'][$x]['term'] !== hex2bin($tag)) + $new_tags[] = $item['term'][$x]; + } + } + + if ($new_tags) + $item['term'] = $new_tags; + else + unset($item['term']); + + item_store_update($item); + + info(t('Tag removed') . EOL); + goaway(z_root() . '/' . $_SESSION['photo_return']); + + } + + //if we got only the item print a list of tags to select + if ((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { + + $o = ''; + + $item = intval(argv(2)); + + $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", + intval($item), + intval(local_channel()) + ); + + if (!$r) + goaway(z_root() . '/' . $_SESSION['photo_return']); + + $r = fetch_post_tags($r, true); + + if (!count($r[0]['term'])) + goaway(z_root() . '/' . $_SESSION['photo_return']); + + $o .= '

      ' . t('Remove Item Tag') . '

      '; + + $o .= '

      ' . t('Select a tag to remove: ') . '

      '; + + $o .= '
      '; + $o .= ''; + $o .= '
        '; + + + foreach ($r[0]['term'] as $x) { + $o .= '
      • ' . bbcode($x['term']) . '
      • '; + } + + $o .= '
      '; + $o .= ''; + $o .= ''; + $o .= '
      '; + + return $o; + + } + + } - function post() { - - if(! local_channel()) - goaway(z_root() . '/' . $_SESSION['photo_return']); - - - if((x($_POST,'submit')) && ($_POST['submit'] === t('Cancel'))) - goaway(z_root() . '/' . $_SESSION['photo_return']); - - $tag = ((x($_POST,'tag')) ? trim($_POST['tag']) : ''); - $item = ((x($_POST,'item')) ? intval($_POST['item']) : 0 ); - - $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", - intval($item), - intval(local_channel()) - ); - - if(! $r) - goaway(z_root() . '/' . $_SESSION['photo_return']); - - $r = fetch_post_tags($r,true); - - $item = $r[0]; - $new_tags = []; - - if($item['term']) { - for($x = 0; $x < count($item['term']); $x ++) { - if($item['term'][$x]['term'] !== hex2bin($tag)) - $new_tags[] = $item['term'][$x]; - } - } - - if($new_tags) - $item['term'] = $new_tags; - else - unset($item['term']); - - item_store_update($item); - - info( t('Tag removed') . EOL ); - goaway(z_root() . '/' . $_SESSION['photo_return']); - - // NOTREACHED - - } - - - - function get() { - - if(! local_channel()) { - goaway(z_root() . '/' . $_SESSION['photo_return']); - // NOTREACHED - } - - // remove tag on the fly if item and tag are provided - if((argc() == 4) && (argv(1) === 'drop') && intval(argv(2))) { - - $item = intval(argv(2)); - $tag = argv(3); - - $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", - intval($item), - intval(local_channel()) - ); - - if(! $r) - goaway(z_root() . '/' . $_SESSION['photo_return']); - - $r = fetch_post_tags($r,true); - - $item = $r[0]; - - $new_tags = []; - - if($item['term']) { - for($x = 0; $x < count($item['term']); $x ++) { - if($item['term'][$x]['term'] !== hex2bin($tag)) - $new_tags[] = $item['term'][$x]; - } - } - - if($new_tags) - $item['term'] = $new_tags; - else - unset($item['term']); - - item_store_update($item); - - info( t('Tag removed') . EOL ); - goaway(z_root() . '/' . $_SESSION['photo_return']); - - } - - //if we got only the item print a list of tags to select - if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { - - $o = ''; - - $item = intval(argv(2)); - - $r = q("SELECT * FROM item WHERE id = %d AND uid = %d LIMIT 1", - intval($item), - intval(local_channel()) - ); - - if(! $r) - goaway(z_root() . '/' . $_SESSION['photo_return']); - - $r = fetch_post_tags($r,true); - - if(! count($r[0]['term'])) - goaway(z_root() . '/' . $_SESSION['photo_return']); - - $o .= '

      ' . t('Remove Item Tag') . '

      '; - - $o .= '

      ' . t('Select a tag to remove: ') . '

      '; - - $o .= '
      '; - $o .= ''; - $o .= '
        '; - - - foreach($r[0]['term'] as $x) { - $o .= '
      • ' . bbcode($x['term']) . '
      • '; - } - - $o .= '
      '; - $o .= ''; - $o .= ''; - $o .= '
      '; - - return $o; - - } - - } - } diff --git a/Zotlabs/Module/Tasks.php b/Zotlabs/Module/Tasks.php index 776958ab5..3c0b30ebc 100644 --- a/Zotlabs/Module/Tasks.php +++ b/Zotlabs/Module/Tasks.php @@ -8,109 +8,110 @@ use Zotlabs\Widget\Tasklist; require_once('include/event.php'); -class Tasks extends Controller { +class Tasks extends Controller +{ - function init() { - // logger('request: ' . print_r($_REQUEST,true)); - - $arr = []; - - if (argc() > 1 && argv(1) === 'fetch') { - if (argc() > 2 && argv(2) === 'all') - $arr['all'] = 1; - - $x = tasks_fetch($arr); - $x['html'] = ''; - if(isset($x['tasks']) && is_array($x['tasks'])) { - foreach($x['tasks'] as $y) { - $x['html'] .= '
      ' . $y['summary'] . '
      '; - } - } - json_return_and_die($x); - } - - } - - - - function post() { - // logger('post: ' . print_r($_POST,true)); - - - if (! local_channel()) { - return; - } - - $channel = App::get_channel(); - - if ((argc() > 2) && (argv(1) === 'complete') && intval(argv(2))) { - $ret = array('success' => false); - $r = q("select * from event where etype = 'task' and uid = %d and id = %d limit 1", - intval(local_channel()), - intval(argv(2)) - ); - if ($r) { - $event = $r[0]; - if ($event['event_status'] === 'COMPLETED') { - $event['event_status'] = 'IN-PROCESS'; - $event['event_status_date'] = NULL_DATE; - $event['event_percent'] = 0; - $event['event_sequence'] = $event['event_sequence'] + 1; - $event['edited'] = datetime_convert(); - } - else { - $event['event_status'] = 'COMPLETED'; - $event['event_status_date'] = datetime_convert(); - $event['event_percent'] = 100; - $event['event_sequence'] = $event['event_sequence'] + 1; - $event['edited'] = datetime_convert(); - } - $x = event_store_event($event); - if ($x) { - $ret['success'] = true; - } - } - json_return_and_die($ret); - } - - if (argc() == 2 && argv(1) === 'new') { - $text = escape_tags(trim($_REQUEST['summary'])); - if (! $text) { - return [ 'success' => false ]; - } - $event = []; - $event['account'] = $channel['channel_account_id']; - $event['uid'] = $channel['channel_id']; - $event['event_xchan'] = $channel['channel_hash']; - $event['etype'] = 'task'; - $event['nofinish'] = true; - $event['created'] = $event['edited'] = $event['dtstart'] = datetime_convert(); - $event['adjust'] = 1; - $event['allow_cid'] = '<' . $channel['channel_hash'] . '>'; - $event['summary'] = escape_tags($_REQUEST['summary']); - $x = event_store_event($event); - if ($x) { - $x['success'] = true; - } - else { - $x = [ 'success' => false ]; - } - json_return_and_die($x); - } - } + public function init() + { + // logger('request: ' . print_r($_REQUEST,true)); - function get() { + $arr = []; + + if (argc() > 1 && argv(1) === 'fetch') { + if (argc() > 2 && argv(2) === 'all') + $arr['all'] = 1; + + $x = tasks_fetch($arr); + $x['html'] = ''; + if (isset($x['tasks']) && is_array($x['tasks'])) { + foreach ($x['tasks'] as $y) { + $x['html'] .= '
      ' . $y['summary'] . '
      '; + } + } + json_return_and_die($x); + } + + } + + + public function post() + { + // logger('post: ' . print_r($_POST,true)); + + + if (!local_channel()) { + return; + } + + $channel = App::get_channel(); + + if ((argc() > 2) && (argv(1) === 'complete') && intval(argv(2))) { + $ret = array('success' => false); + $r = q("select * from event where etype = 'task' and uid = %d and id = %d limit 1", + intval(local_channel()), + intval(argv(2)) + ); + if ($r) { + $event = $r[0]; + if ($event['event_status'] === 'COMPLETED') { + $event['event_status'] = 'IN-PROCESS'; + $event['event_status_date'] = NULL_DATE; + $event['event_percent'] = 0; + $event['event_sequence'] = $event['event_sequence'] + 1; + $event['edited'] = datetime_convert(); + } else { + $event['event_status'] = 'COMPLETED'; + $event['event_status_date'] = datetime_convert(); + $event['event_percent'] = 100; + $event['event_sequence'] = $event['event_sequence'] + 1; + $event['edited'] = datetime_convert(); + } + $x = event_store_event($event); + if ($x) { + $ret['success'] = true; + } + } + json_return_and_die($ret); + } + + if (argc() == 2 && argv(1) === 'new') { + $text = escape_tags(trim($_REQUEST['summary'])); + if (!$text) { + return ['success' => false]; + } + $event = []; + $event['account'] = $channel['channel_account_id']; + $event['uid'] = $channel['channel_id']; + $event['event_xchan'] = $channel['channel_hash']; + $event['etype'] = 'task'; + $event['nofinish'] = true; + $event['created'] = $event['edited'] = $event['dtstart'] = datetime_convert(); + $event['adjust'] = 1; + $event['allow_cid'] = '<' . $channel['channel_hash'] . '>'; + $event['summary'] = escape_tags($_REQUEST['summary']); + $x = event_store_event($event); + if ($x) { + $x['success'] = true; + } else { + $x = ['success' => false]; + } + json_return_and_die($x); + } + } + + public function get() + { $desc = t('This app provides a simple personal and task list.'); $text = ''; - if(! ( local_channel() && Apps::system_app_installed(local_channel(),'Tasks'))) { + if (!(local_channel() && Apps::system_app_installed(local_channel(), 'Tasks'))) { return $text; } - $obj = new Tasklist; - return $obj->widget([]); - } + $obj = new Tasklist(); + return $obj->widget([]); + } } diff --git a/Zotlabs/Module/Theme_info.php b/Zotlabs/Module/Theme_info.php index 32207b234..2dace56d2 100644 --- a/Zotlabs/Module/Theme_info.php +++ b/Zotlabs/Module/Theme_info.php @@ -6,69 +6,71 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Theme_info extends Controller { +class Theme_info extends Controller +{ - function get() { - $theme = argv(1); - if(! $theme) - killme(); - - $schemalist = []; + public function get() + { + $theme = argv(1); + if (!$theme) + killme(); - $theme_config = ""; - if(($themeconfigfile = $this->get_theme_config_file($theme)) != null){ - require_once($themeconfigfile); - if(class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { - $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; - $th_config = new $clsname(); - $schemas = $th_config->get_schemas(); - if($schemas) { - foreach($schemas as $k => $v) { - $schemalist[] = [ 'key' => $k, 'val' => $v ]; - } - } - $theme_config = $th_config->get(); - } - } - $info = get_theme_info($theme); - if($info) { - // unfortunately there will be no translation for this string - $desc = $info['description']; - $version = $info['version']; - $credits = $info['credits']; - } - else { - $desc = ''; - $version = ''; - $credits = ''; - } + $schemalist = []; - $ret = [ - 'theme' => $theme, - 'img' => get_theme_screenshot($theme), - 'desc' => $desc, - 'version' => $version, - 'credits' => $credits, - 'schemas' => $schemalist, - 'config' => $theme_config - ]; - json_return_and_die($ret); - - } + $theme_config = ""; + if (($themeconfigfile = $this->get_theme_config_file($theme)) != null) { + require_once($themeconfigfile); + if (class_exists('\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config')) { + $clsname = '\\Zotlabs\\Theme\\' . ucfirst($theme) . 'Config'; + $th_config = new $clsname(); + $schemas = $th_config->get_schemas(); + if ($schemas) { + foreach ($schemas as $k => $v) { + $schemalist[] = ['key' => $k, 'val' => $v]; + } + } + $theme_config = $th_config->get(); + } + } + $info = get_theme_info($theme); + if ($info) { + // unfortunately there will be no translation for this string + $desc = $info['description']; + $version = $info['version']; + $credits = $info['credits']; + } else { + $desc = ''; + $version = ''; + $credits = ''; + } + + $ret = [ + 'theme' => $theme, + 'img' => get_theme_screenshot($theme), + 'desc' => $desc, + 'version' => $version, + 'credits' => $credits, + 'schemas' => $schemalist, + 'config' => $theme_config + ]; + json_return_and_die($ret); + + } - function get_theme_config_file($theme){ + public function get_theme_config_file($theme) + { - $base_theme = App::$theme_info['extends']; - - if (file_exists("view/theme/$theme/php/config.php")){ - return "view/theme/$theme/php/config.php"; - } - if (file_exists("view/theme/$base_theme/php/config.php")){ - return "view/theme/$base_theme/php/config.php"; - } - return null; - } + $base_theme = App::$theme_info['extends']; + + if (file_exists("view/theme/$theme/php/config.php")) { + return "view/theme/$theme/php/config.php"; + } + if (file_exists("view/theme/$base_theme/php/config.php")) { + return "view/theme/$base_theme/php/config.php"; + } + return null; + } } \ No newline at end of file diff --git a/Zotlabs/Module/Thing.php b/Zotlabs/Module/Thing.php index a49e0c13c..9f3310875 100644 --- a/Zotlabs/Module/Thing.php +++ b/Zotlabs/Module/Thing.php @@ -19,387 +19,385 @@ require_once('include/security.php'); require_once('include/acl_selectors.php'); -class Thing extends Controller { - - function init() { - - if(! local_channel()) - return; - - $channel = App::get_channel(); - - if($_SERVER['REQUEST_METHOD'] === 'GET' && argc() < 2) { - Libprofile::load($channel['channel_address']); - } - - - $term_hash = (($_REQUEST['term_hash']) ? $_REQUEST['term_hash'] : ''); - - $name = escape_tags($_REQUEST['term']); - $verb = escape_tags($_REQUEST['verb']); - $activity = intval($_REQUEST['activity']); - $profile_guid = escape_tags($_REQUEST['profile_assign']); - $url = $_REQUEST['url']; - $photo = $_REQUEST['img']; - - $hash = random_string(); - - $verbs = obj_verbs(); - - /** - * verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person singular, e.g. "Bill wants" - * We use the first person form when creating an activity, but the third person for use in activities - * @FIXME There is no accounting for verb gender for languages where this is significant. We may eventually - * require obj_verbs() to provide full conjugations and specify which form to use in the $_REQUEST params to this module. - */ - - $translated_verb = $verbs[$verb][1]; - - /* - * The site administrator can do things that normals cannot. - * This is restricted because it will likely cause - * an activitystreams protocol violation and the activity might - * choke in some other network and result in unnecessary - * support requests. It isn't because we're trying to be heavy-handed - * about what you can and can't do. - */ - - if(! $translated_verb) { - if(is_site_admin()) - $translated_verb = $verb; - } - - /* - * Things, objects: We do not provide definite (a, an) or indefinite (the) articles or singular/plural designators - * That needs to be specified in your thing. e.g. Mike has "a carrot", Greg wants "balls", Bob likes "the Boston Red Sox". - */ - - /* - * Future work on this module might produce more complex activities with targets, e.g. Phillip likes Karen's moustache - * and to describe other non-thing objects like channels, such as Karl wants Susan - where Susan represents a channel profile. - */ - - if((! $name) || (! $translated_verb)) - return; - - $acl = new AccessControl($channel); - - if(array_key_exists('contact_allow',$_REQUEST) - || array_key_exists('group_allow',$_REQUEST) - || array_key_exists('contact_deny',$_REQUEST) - || array_key_exists('group_deny',$_REQUEST)) { - $acl->set_from_array($_REQUEST); - } - - $x = $acl->get(); - - if($term_hash) { - $t = q("select * from obj where obj_obj = '%s' and obj_channel = %d limit 1", - dbesc($term_hash), - intval(local_channel()) - ); - if(! $t) { - notice( t('Item not found.') . EOL); - return; - } - $orig_record = $t[0]; - if($photo != $orig_record['obj_imgurl']) { - delete_thing_photo($orig_record['obj_imgurl'],get_observer_hash()); - $arr = import_remote_xchan_photo($photo,get_observer_hash(),true); - if ($arr) { - $local_photo = $arr[0]; - $local_photo_type = $arr[3]; - } - else { - $local_photo = $orig_record['obj_imgurl']; - } - } - else { - $local_photo = $orig_record['obj_imgurl']; - } - if ($local_photo) { - $r = q("update obj set obj_term = '%s', obj_url = '%s', obj_imgurl = '%s', obj_edited = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where obj_obj = '%s' and obj_channel = %d ", - dbesc($name), - dbesc(($url) ? $url : z_root() . '/thing/' . $term_hash), - dbesc($local_photo), - dbesc(datetime_convert()), - dbesc($x['allow_cid']), - dbesc($x['allow_gid']), - dbesc($x['deny_cid']), - dbesc($x['deny_gid']), - dbesc($term_hash), - intval(local_channel()) - ); - } - info( t('Thing updated') . EOL); - - $r = q("select * from obj where obj_channel = %d and obj_obj = '%s' limit 1", - intval(local_channel()), - dbesc($term_hash) - ); - if($r) { - Libsync::build_sync_packet(0, array('obj' => $r)); - } - - return; - } - - $sql = (($profile_guid) ? " and profile_guid = '" . dbesc($profile_guid) . "' " : " and is_default = 1 "); - $p = q("select profile_guid, is_default from profile where uid = %d $sql limit 1", - intval(local_channel()) - ); - - if($p) - $profile = $p[0]; - else - return; - - $local_photo = null; - - if($photo) { - $arr = import_remote_xchan_photo($photo,get_observer_hash(),true); - if ($arr) { - $local_photo = $arr[0]; - $local_photo_type = $arr[3]; - } - else { - $local_photo = $photo; - } - } - - - $created = datetime_convert(); - $url = (($url) ? $url : z_root() . '/thing/' . $hash); - - $r = q("insert into obj ( obj_page, obj_verb, obj_type, obj_channel, obj_obj, obj_term, obj_url, obj_imgurl, obj_created, obj_edited, allow_cid, allow_gid, deny_cid, deny_gid ) values ('%s','%s', %d, %d, '%s','%s','%s','%s','%s','%s','%s','%s','%s','%s') ", - dbesc($profile['profile_guid']), - dbesc($verb), - intval(TERM_OBJ_THING), - intval(local_channel()), - dbesc($hash), - dbesc($name), - dbesc($url), - dbesc(($photo) ? $local_photo : ''), - dbesc($created), - dbesc($created), - dbesc($x['allow_cid']), - dbesc($x['allow_gid']), - dbesc($x['deny_cid']), - dbesc($x['deny_gid']) - ); - - if(! $r) { - notice( t('Object store: failed')); - return; - } - - info( t('Thing added')); - - $r = q("select * from obj where obj_channel = %d and obj_obj = '%s' limit 1", - intval(local_channel()), - dbesc($hash) - ); - if($r) { - Libsync::build_sync_packet(0, array('obj' => $r)); - } - - if($activity) { - $arr = []; - $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $url)); - if($local_photo) - $links[] = array('rel' => 'photo', 'type' => $local_photo_type, 'href' => $local_photo); - - $objtype = ACTIVITY_OBJ_THING; - - $obj = json_encode(array( - 'type' => $objtype, - 'id' => $url, - 'link' => $links, - 'title' => $name, - 'content' => $name - )); - - $bodyverb = str_replace('OBJ: ', '',t('OBJ: %1$s %2$s %3$s')); - - $arr['owner_xchan'] = $channel['channel_hash']; - $arr['author_xchan'] = $channel['channel_hash']; - - $arr['item_origin'] = 1; - $arr['item_wall'] = 1; - $arr['item_thread_top'] = 1; - - $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; - $plink = '[zrl=' . $url . ']' . $name . '[/zrl]'; - - $arr['body'] = sprintf( $bodyverb, $ulink, $translated_verb, $plink ); - - if($local_photo) - $arr['body'] .= "\n\n[zmg]" . $local_photo . "[/zmg]"; - - $arr['verb'] = $verb; - $arr['obj_type'] = $objtype; - $arr['obj'] = $obj; - - if(! $profile['is_default']) { - $arr['item_private'] = true; - $str = ''; - $r = q("select abook_xchan from abook where abook_channel = %d and abook_profile = '%s'", - intval(local_channel()), - dbesc($profile_guid) - ); - if($r) { - $arr['allow_cid'] = ''; - foreach($r as $rr) - $arr['allow_cid'] .= '<' . $rr['abook_xchan'] . '>'; - } - else - $arr['allow_cid'] = '<' . get_observer_hash() . '>'; - } - - $ret = post_activity_item($arr); - } - } - - - function get() { - - // @FIXME one problem with things is we can't share them unless we provide the channel in the url - // so we can definitively lookup the owner. - - if(argc() == 2) { - - $r = q("select obj_channel from obj where obj_type = %d and obj_obj = '%s' limit 1", - intval(TERM_OBJ_THING), - dbesc(argv(1)) - ); - if($r) - $sql_extra = permissions_sql($r[0]['obj_channel']); - - $r = q("select * from obj where obj_type = %d and obj_obj = '%s' $sql_extra limit 1", - intval(TERM_OBJ_THING), - dbesc(argv(1)) - ); - - if($r) { - return replace_macros(get_markup_template('show_thing.tpl'), array( - '$header' => t('Show Thing'), - '$edit' => t('Edit'), - '$delete' => t('Delete'), - '$canedit' => ((local_channel() && local_channel() == $r[0]['obj_channel']) ? true : false), - '$thing' => $r[0] )); - } - else { - notice( t('item not found.') . EOL); - return; - } - } - - $channel = App::get_channel(); - - if(! (local_channel() && $channel)) { - notice( t('Permission denied.') . EOL); - return; - } - - $acl = new AccessControl($channel); - $channel_acl = $acl->get(); - - $lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); - - $thing_hash = ''; - - if(argc() == 3 && argv(1) === 'edit') { - $thing_hash = argv(2); - - $r = q("select * from obj where obj_type = %d and obj_obj = '%s' limit 1", - intval(TERM_OBJ_THING), - dbesc($thing_hash) - ); - - if((! $r) || ($r[0]['obj_channel'] != local_channel())) { - notice( t('Permission denied.') . EOL); - return ''; - } - - $o .= replace_macros(get_markup_template('thing_edit.tpl'),array( - '$thing_hdr' => t('Edit Thing'), - '$multiprof' => feature_enabled(local_channel(),'multi_profiles'), - '$profile_lbl' => t('Select a profile'), - '$profile_select' => contact_profile_assign($r[0]['obj_page']), - '$verb_lbl' => $channel['channel_name'], - '$verb_select' => obj_verb_selector($r[0]['obj_verb']), - '$activity' => array('activity',t('Post an activity'),true,t('Only sends to viewers of the applicable profile')), - '$thing_hash' => $thing_hash, - '$thing_lbl' => t('Name of thing e.g. something'), - '$thething' => $r[0]['obj_term'], - '$url_lbl' => t('URL of thing (optional)'), - '$theurl' => $r[0]['obj_url'], - '$img_lbl' => t('URL for photo of thing (optional)'), - '$imgurl' => $r[0]['obj_imgurl'], - '$permissions' => t('Permissions'), - '$aclselect' => populate_acl($channel_acl,false), - '$allow_cid' => acl2json($channel_acl['allow_cid']), - '$allow_gid' => acl2json($channel_acl['allow_gid']), - '$deny_cid' => acl2json($channel_acl['deny_cid']), - '$deny_gid' => acl2json($channel_acl['deny_gid']), - '$lockstate' => $lockstate, - '$submit' => t('Submit') - )); - - return $o; - } - - if(argc() == 3 && argv(1) === 'drop') { - $thing_hash = argv(2); - - $r = q("select * from obj where obj_type = %d and obj_obj = '%s' limit 1", - intval(TERM_OBJ_THING), - dbesc($thing_hash) - ); - - if((! $r) || ($r[0]['obj_channel'] != local_channel())) { - notice( t('Permission denied.') . EOL); - return ''; - } - - - delete_thing_photo($r[0]['obj_imgurl'],get_observer_hash()); - - $x = q("delete from obj where obj_obj = '%s' and obj_type = %d and obj_channel = %d", - dbesc($thing_hash), - intval(TERM_OBJ_THING), - intval(local_channel()) - ); - - $r[0]['obj_deleted'] = 1; - - Libsync::build_sync_packet(0,array('obj' => $r)); - - return $o; - } - - $o .= replace_macros(get_markup_template('thing_input.tpl'),array( - '$thing_hdr' => t('Add Thing to your Profile'), - '$multiprof' => feature_enabled(local_channel(),'multi_profiles'), - '$profile_lbl' => t('Select a profile'), - '$profile_select' => contact_profile_assign(''), - '$verb_lbl' => $channel['channel_name'], - '$activity' => array('activity',t('Post an activity'),((array_key_exists('activity',$_REQUEST)) ? $_REQUEST['activity'] : true),t('Only sends to viewers of the applicable profile')), - '$verb_select' => obj_verb_selector(), - '$thing_lbl' => t('Name of thing e.g. something'), - '$url_lbl' => t('URL of thing (optional)'), - '$img_lbl' => t('URL for photo of thing (optional)'), - '$permissions' => t('Permissions'), - '$aclselect' => populate_acl($channel_acl,false), - '$allow_cid' => acl2json($channel_acl['allow_cid']), - '$allow_gid' => acl2json($channel_acl['allow_gid']), - '$deny_cid' => acl2json($channel_acl['deny_cid']), - '$deny_gid' => acl2json($channel_acl['deny_gid']), - '$lockstate' => $lockstate, - '$submit' => t('Submit') - )); - - return $o; - } +class Thing extends Controller +{ + + public function init() + { + + if (!local_channel()) + return; + + $channel = App::get_channel(); + + if ($_SERVER['REQUEST_METHOD'] === 'GET' && argc() < 2) { + Libprofile::load($channel['channel_address']); + } + + + $term_hash = (($_REQUEST['term_hash']) ? $_REQUEST['term_hash'] : ''); + + $name = escape_tags($_REQUEST['term']); + $verb = escape_tags($_REQUEST['verb']); + $activity = intval($_REQUEST['activity']); + $profile_guid = escape_tags($_REQUEST['profile_assign']); + $url = $_REQUEST['url']; + $photo = $_REQUEST['img']; + + $hash = random_string(); + + $verbs = obj_verbs(); + + /** + * verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person singular, e.g. "Bill wants" + * We use the first person form when creating an activity, but the third person for use in activities + * @FIXME There is no accounting for verb gender for languages where this is significant. We may eventually + * require obj_verbs() to provide full conjugations and specify which form to use in the $_REQUEST params to this module. + */ + + $translated_verb = $verbs[$verb][1]; + + /* + * The site administrator can do things that normals cannot. + * This is restricted because it will likely cause + * an activitystreams protocol violation and the activity might + * choke in some other network and result in unnecessary + * support requests. It isn't because we're trying to be heavy-handed + * about what you can and can't do. + */ + + if (!$translated_verb) { + if (is_site_admin()) + $translated_verb = $verb; + } + + /* + * Things, objects: We do not provide definite (a, an) or indefinite (the) articles or singular/plural designators + * That needs to be specified in your thing. e.g. Mike has "a carrot", Greg wants "balls", Bob likes "the Boston Red Sox". + */ + + /* + * Future work on this module might produce more complex activities with targets, e.g. Phillip likes Karen's moustache + * and to describe other non-thing objects like channels, such as Karl wants Susan - where Susan represents a channel profile. + */ + + if ((!$name) || (!$translated_verb)) + return; + + $acl = new AccessControl($channel); + + if (array_key_exists('contact_allow', $_REQUEST) + || array_key_exists('group_allow', $_REQUEST) + || array_key_exists('contact_deny', $_REQUEST) + || array_key_exists('group_deny', $_REQUEST)) { + $acl->set_from_array($_REQUEST); + } + + $x = $acl->get(); + + if ($term_hash) { + $t = q("select * from obj where obj_obj = '%s' and obj_channel = %d limit 1", + dbesc($term_hash), + intval(local_channel()) + ); + if (!$t) { + notice(t('Item not found.') . EOL); + return; + } + $orig_record = $t[0]; + if ($photo != $orig_record['obj_imgurl']) { + delete_thing_photo($orig_record['obj_imgurl'], get_observer_hash()); + $arr = import_remote_xchan_photo($photo, get_observer_hash(), true); + if ($arr) { + $local_photo = $arr[0]; + $local_photo_type = $arr[3]; + } else { + $local_photo = $orig_record['obj_imgurl']; + } + } else { + $local_photo = $orig_record['obj_imgurl']; + } + if ($local_photo) { + $r = q("update obj set obj_term = '%s', obj_url = '%s', obj_imgurl = '%s', obj_edited = '%s', allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where obj_obj = '%s' and obj_channel = %d ", + dbesc($name), + dbesc(($url) ? $url : z_root() . '/thing/' . $term_hash), + dbesc($local_photo), + dbesc(datetime_convert()), + dbesc($x['allow_cid']), + dbesc($x['allow_gid']), + dbesc($x['deny_cid']), + dbesc($x['deny_gid']), + dbesc($term_hash), + intval(local_channel()) + ); + } + info(t('Thing updated') . EOL); + + $r = q("select * from obj where obj_channel = %d and obj_obj = '%s' limit 1", + intval(local_channel()), + dbesc($term_hash) + ); + if ($r) { + Libsync::build_sync_packet(0, array('obj' => $r)); + } + + return; + } + + $sql = (($profile_guid) ? " and profile_guid = '" . dbesc($profile_guid) . "' " : " and is_default = 1 "); + $p = q("select profile_guid, is_default from profile where uid = %d $sql limit 1", + intval(local_channel()) + ); + + if ($p) + $profile = $p[0]; + else + return; + + $local_photo = null; + + if ($photo) { + $arr = import_remote_xchan_photo($photo, get_observer_hash(), true); + if ($arr) { + $local_photo = $arr[0]; + $local_photo_type = $arr[3]; + } else { + $local_photo = $photo; + } + } + + + $created = datetime_convert(); + $url = (($url) ? $url : z_root() . '/thing/' . $hash); + + $r = q("insert into obj ( obj_page, obj_verb, obj_type, obj_channel, obj_obj, obj_term, obj_url, obj_imgurl, obj_created, obj_edited, allow_cid, allow_gid, deny_cid, deny_gid ) values ('%s','%s', %d, %d, '%s','%s','%s','%s','%s','%s','%s','%s','%s','%s') ", + dbesc($profile['profile_guid']), + dbesc($verb), + intval(TERM_OBJ_THING), + intval(local_channel()), + dbesc($hash), + dbesc($name), + dbesc($url), + dbesc(($photo) ? $local_photo : ''), + dbesc($created), + dbesc($created), + dbesc($x['allow_cid']), + dbesc($x['allow_gid']), + dbesc($x['deny_cid']), + dbesc($x['deny_gid']) + ); + + if (!$r) { + notice(t('Object store: failed')); + return; + } + + info(t('Thing added')); + + $r = q("select * from obj where obj_channel = %d and obj_obj = '%s' limit 1", + intval(local_channel()), + dbesc($hash) + ); + if ($r) { + Libsync::build_sync_packet(0, array('obj' => $r)); + } + + if ($activity) { + $arr = []; + $links = array(array('rel' => 'alternate', 'type' => 'text/html', 'href' => $url)); + if ($local_photo) + $links[] = array('rel' => 'photo', 'type' => $local_photo_type, 'href' => $local_photo); + + $objtype = ACTIVITY_OBJ_THING; + + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $url, + 'link' => $links, + 'title' => $name, + 'content' => $name + )); + + $bodyverb = str_replace('OBJ: ', '', t('OBJ: %1$s %2$s %3$s')); + + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $channel['channel_hash']; + + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['item_thread_top'] = 1; + + $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; + $plink = '[zrl=' . $url . ']' . $name . '[/zrl]'; + + $arr['body'] = sprintf($bodyverb, $ulink, $translated_verb, $plink); + + if ($local_photo) + $arr['body'] .= "\n\n[zmg]" . $local_photo . "[/zmg]"; + + $arr['verb'] = $verb; + $arr['obj_type'] = $objtype; + $arr['obj'] = $obj; + + if (!$profile['is_default']) { + $arr['item_private'] = true; + $str = ''; + $r = q("select abook_xchan from abook where abook_channel = %d and abook_profile = '%s'", + intval(local_channel()), + dbesc($profile_guid) + ); + if ($r) { + $arr['allow_cid'] = ''; + foreach ($r as $rr) + $arr['allow_cid'] .= '<' . $rr['abook_xchan'] . '>'; + } else + $arr['allow_cid'] = '<' . get_observer_hash() . '>'; + } + + $ret = post_activity_item($arr); + } + } + + + public function get() + { + + // @FIXME one problem with things is we can't share them unless we provide the channel in the url + // so we can definitively lookup the owner. + + if (argc() == 2) { + + $r = q("select obj_channel from obj where obj_type = %d and obj_obj = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc(argv(1)) + ); + if ($r) + $sql_extra = permissions_sql($r[0]['obj_channel']); + + $r = q("select * from obj where obj_type = %d and obj_obj = '%s' $sql_extra limit 1", + intval(TERM_OBJ_THING), + dbesc(argv(1)) + ); + + if ($r) { + return replace_macros(get_markup_template('show_thing.tpl'), array( + '$header' => t('Show Thing'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$canedit' => ((local_channel() && local_channel() == $r[0]['obj_channel']) ? true : false), + '$thing' => $r[0])); + } else { + notice(t('item not found.') . EOL); + return; + } + } + + $channel = App::get_channel(); + + if (!(local_channel() && $channel)) { + notice(t('Permission denied.') . EOL); + return; + } + + $acl = new AccessControl($channel); + $channel_acl = $acl->get(); + + $lockstate = (($acl->is_private()) ? 'lock' : 'unlock'); + + $thing_hash = ''; + + if (argc() == 3 && argv(1) === 'edit') { + $thing_hash = argv(2); + + $r = q("select * from obj where obj_type = %d and obj_obj = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($thing_hash) + ); + + if ((!$r) || ($r[0]['obj_channel'] != local_channel())) { + notice(t('Permission denied.') . EOL); + return ''; + } + + $o .= replace_macros(get_markup_template('thing_edit.tpl'), array( + '$thing_hdr' => t('Edit Thing'), + '$multiprof' => feature_enabled(local_channel(), 'multi_profiles'), + '$profile_lbl' => t('Select a profile'), + '$profile_select' => contact_profile_assign($r[0]['obj_page']), + '$verb_lbl' => $channel['channel_name'], + '$verb_select' => obj_verb_selector($r[0]['obj_verb']), + '$activity' => array('activity', t('Post an activity'), true, t('Only sends to viewers of the applicable profile')), + '$thing_hash' => $thing_hash, + '$thing_lbl' => t('Name of thing e.g. something'), + '$thething' => $r[0]['obj_term'], + '$url_lbl' => t('URL of thing (optional)'), + '$theurl' => $r[0]['obj_url'], + '$img_lbl' => t('URL for photo of thing (optional)'), + '$imgurl' => $r[0]['obj_imgurl'], + '$permissions' => t('Permissions'), + '$aclselect' => populate_acl($channel_acl, false), + '$allow_cid' => acl2json($channel_acl['allow_cid']), + '$allow_gid' => acl2json($channel_acl['allow_gid']), + '$deny_cid' => acl2json($channel_acl['deny_cid']), + '$deny_gid' => acl2json($channel_acl['deny_gid']), + '$lockstate' => $lockstate, + '$submit' => t('Submit') + )); + + return $o; + } + + if (argc() == 3 && argv(1) === 'drop') { + $thing_hash = argv(2); + + $r = q("select * from obj where obj_type = %d and obj_obj = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($thing_hash) + ); + + if ((!$r) || ($r[0]['obj_channel'] != local_channel())) { + notice(t('Permission denied.') . EOL); + return ''; + } + + + delete_thing_photo($r[0]['obj_imgurl'], get_observer_hash()); + + $x = q("delete from obj where obj_obj = '%s' and obj_type = %d and obj_channel = %d", + dbesc($thing_hash), + intval(TERM_OBJ_THING), + intval(local_channel()) + ); + + $r[0]['obj_deleted'] = 1; + + Libsync::build_sync_packet(0, array('obj' => $r)); + + return $o; + } + + $o .= replace_macros(get_markup_template('thing_input.tpl'), array( + '$thing_hdr' => t('Add Thing to your Profile'), + '$multiprof' => feature_enabled(local_channel(), 'multi_profiles'), + '$profile_lbl' => t('Select a profile'), + '$profile_select' => contact_profile_assign(''), + '$verb_lbl' => $channel['channel_name'], + '$activity' => array('activity', t('Post an activity'), ((array_key_exists('activity', $_REQUEST)) ? $_REQUEST['activity'] : true), t('Only sends to viewers of the applicable profile')), + '$verb_select' => obj_verb_selector(), + '$thing_lbl' => t('Name of thing e.g. something'), + '$url_lbl' => t('URL of thing (optional)'), + '$img_lbl' => t('URL for photo of thing (optional)'), + '$permissions' => t('Permissions'), + '$aclselect' => populate_acl($channel_acl, false), + '$allow_cid' => acl2json($channel_acl['allow_cid']), + '$allow_gid' => acl2json($channel_acl['allow_gid']), + '$deny_cid' => acl2json($channel_acl['deny_cid']), + '$deny_gid' => acl2json($channel_acl['deny_gid']), + '$lockstate' => $lockstate, + '$submit' => t('Submit') + )); + + return $o; + } } diff --git a/Zotlabs/Module/Toggle_safesearch.php b/Zotlabs/Module/Toggle_safesearch.php index 3368f6542..9b8e7d5da 100644 --- a/Zotlabs/Module/Toggle_safesearch.php +++ b/Zotlabs/Module/Toggle_safesearch.php @@ -4,30 +4,32 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Toggle_safesearch extends Controller { +class Toggle_safesearch extends Controller +{ + + public function init() + { + + $observer = get_observer_hash(); + if (!$observer) + return; + + if ($observer) + $safe_mode = get_xconfig($observer, 'directory', 'safe_mode'); + if ($safe_mode == '') + set_xconfig($observer, 'directory', 'safe_mode', '0'); + elseif ($safe_mode == '0') + set_xconfig($observer, 'directory', 'safe_mode', '1'); + elseif ($safe_mode == '1') + set_xconfig($observer, 'directory', 'safe_mode', '0'); + + if (isset($_GET['address'])) + $address = $_GET['address']; + else + $address = z_root() . '/directory'; + + goaway($address); + } + - function init() { - - $observer = get_observer_hash(); - if (! $observer) - return; - - if($observer) - $safe_mode = get_xconfig($observer,'directory','safe_mode'); - if ($safe_mode == '') - set_xconfig($observer,'directory','safe_mode', '0'); - elseif($safe_mode == '0') - set_xconfig($observer,'directory','safe_mode', '1'); - elseif($safe_mode == '1') - set_xconfig($observer,'directory','safe_mode', '0'); - - if(isset($_GET['address'])) - $address = $_GET['address']; - else - $address = z_root() . '/directory'; - - goaway($address); - } - - } diff --git a/Zotlabs/Module/Token.php b/Zotlabs/Module/Token.php index 62c2b8a33..e7833c847 100644 --- a/Zotlabs/Module/Token.php +++ b/Zotlabs/Module/Token.php @@ -11,37 +11,39 @@ use OAuth2\Request; use OAuth2\Response; -class Token extends Controller { +class Token extends Controller +{ - function init() { + public function init() + { - logger('args: ' . print_r($_REQUEST,true)); + logger('args: ' . print_r($_REQUEST, true)); - // workaround for HTTP-auth in CGI mode - if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { - $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ; - if(strlen($userpass)) { - list($name, $password) = explode(':', $userpass); - $_SERVER['PHP_AUTH_USER'] = $name; - $_SERVER['PHP_AUTH_PW'] = $password; - } - } + // workaround for HTTP-auth in CGI mode + if (x($_SERVER, 'REDIRECT_REMOTE_USER')) { + $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)); + if (strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } - if (x($_SERVER, 'HTTP_AUTHORIZATION')) { - $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ; - if(strlen($userpass)) { - list($name, $password) = explode(':', $userpass); - $_SERVER['PHP_AUTH_USER'] = $name; - $_SERVER['PHP_AUTH_PW'] = $password; - } - } - - $storage = new OAuth2Storage(DBA::$dba->db); - $s = new OAuth2Server($storage); - $request = Request::createFromGlobals(); - $response = $s->handleTokenRequest($request); - $response->send(); - killme(); - } + if (x($_SERVER, 'HTTP_AUTHORIZATION')) { + $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)); + if (strlen($userpass)) { + list($name, $password) = explode(':', $userpass); + $_SERVER['PHP_AUTH_USER'] = $name; + $_SERVER['PHP_AUTH_PW'] = $password; + } + } + + $storage = new OAuth2Storage(DBA::$dba->db); + $s = new OAuth2Server($storage); + $request = Request::createFromGlobals(); + $response = $s->handleTokenRequest($request); + $response->send(); + killme(); + } } diff --git a/Zotlabs/Module/Uexport.php b/Zotlabs/Module/Uexport.php index 7bea295a1..3df9b3537 100644 --- a/Zotlabs/Module/Uexport.php +++ b/Zotlabs/Module/Uexport.php @@ -4,75 +4,78 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Uexport extends Controller { +class Uexport extends Controller +{ - function init() { - if (! local_channel()) { - return; - } + public function init() + { + if (!local_channel()) { + return; + } - $sections = (($_REQUEST['sections']) ? explode(',',$_REQUEST['sections']) : get_default_export_sections()); + $sections = (($_REQUEST['sections']) ? explode(',', $_REQUEST['sections']) : get_default_export_sections()); - if (argc() > 1) { + if (argc() > 1) { - $channel = App::get_channel(); + $channel = App::get_channel(); - if (argc() > 1 && intval(argv(1)) > 1900) { - $year = intval(argv(1)); - } - - if (argc() > 2 && intval(argv(2)) > 0 && intval(argv(2)) <= 12) { - $month = intval(argv(2)); - } - - header('content-type: application/json'); - header('Content-Disposition: attachment; filename="' . $channel['channel_address'] . (($year) ? '-' . $year : '') . (($month) ? '-' . $month : '') . (($_REQUEST['sections']) ? '-' . $_REQUEST['sections'] : '') . '.json"' ); - - $flags = ((version_compare(PHP_VERSION,'7.2.0') >= 0) ? JSON_INVALID_UTF8_SUBSTITUTE : 0); + if (argc() > 1 && intval(argv(1)) > 1900) { + $year = intval(argv(1)); + } - if ($year) { - echo json_encode(identity_export_year(local_channel(),$year,$month), $flags); - killme(); - } - - if (argc() > 1 && argv(1) === 'basic') { - echo json_encode(identity_basic_export(local_channel(),$sections), $flags); - killme(); - } - - // Warning: this option may consume a lot of memory - - if(argc() > 1 && argv(1) === 'complete') { - $sections[] = 'items'; - echo json_encode(identity_basic_export(local_channel(),$sections)); - killme(); - } - } - } - - function get() { - - $y = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); - - $yearurl = z_root() . '/uexport/' . $y; - $janurl = z_root() . '/uexport/' . $y . '/1'; - $impurl = '/import_items'; - $o = replace_macros(get_markup_template('uexport.tpl'), array( - '$title' => t('Export Channel'), - '$basictitle' => t('Export Channel'), - '$basic' => t('Export your basic channel information to a file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new server hub, but does not contain your content.'), - '$fulltitle' => t('Export Content'), - '$full' => t('Export your channel information and recent content to a JSON backup that can be restored or imported to another server hub. This backs up all of your connections, permissions, profile data and several months of posts. This file may be VERY large. Please be patient - it may take several minutes for this download to begin.'), + if (argc() > 2 && intval(argv(2)) > 0 && intval(argv(2)) <= 12) { + $month = intval(argv(2)); + } + + header('content-type: application/json'); + header('Content-Disposition: attachment; filename="' . $channel['channel_address'] . (($year) ? '-' . $year : '') . (($month) ? '-' . $month : '') . (($_REQUEST['sections']) ? '-' . $_REQUEST['sections'] : '') . '.json"'); + + $flags = ((version_compare(PHP_VERSION, '7.2.0') >= 0) ? JSON_INVALID_UTF8_SUBSTITUTE : 0); + + if ($year) { + echo json_encode(identity_export_year(local_channel(), $year, $month), $flags); + killme(); + } + + if (argc() > 1 && argv(1) === 'basic') { + echo json_encode(identity_basic_export(local_channel(), $sections), $flags); + killme(); + } + + // Warning: this option may consume a lot of memory + + if (argc() > 1 && argv(1) === 'complete') { + $sections[] = 'items'; + echo json_encode(identity_basic_export(local_channel(), $sections)); + killme(); + } + } + } + + public function get() + { + + $y = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y'); + + $yearurl = z_root() . '/uexport/' . $y; + $janurl = z_root() . '/uexport/' . $y . '/1'; + $impurl = '/import_items'; + $o = replace_macros(get_markup_template('uexport.tpl'), array( + '$title' => t('Export Channel'), + '$basictitle' => t('Export Channel'), + '$basic' => t('Export your basic channel information to a file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new server hub, but does not contain your content.'), + '$fulltitle' => t('Export Content'), + '$full' => t('Export your channel information and recent content to a JSON backup that can be restored or imported to another server hub. This backs up all of your connections, permissions, profile data and several months of posts. This file may be VERY large. Please be patient - it may take several minutes for this download to begin.'), + + '$by_year' => t('Export your posts from a given year.'), + + '$extra' => t('You may also export your posts and conversations for a particular year or month. Adjust the date in your browser location bar to select other dates. If the export fails (possibly due to memory exhaustion on your server hub), please try again selecting a more limited date range.'), + '$extra2' => sprintf(t('To select all posts for a given year, such as this year, visit %2$s'), $yearurl, $yearurl), + '$extra3' => sprintf(t('To select all posts for a given month, such as January of this year, visit %2$s'), $janurl, $janurl), + '$extra4' => sprintf(t('These content files may be imported or restored by visiting %2$s on any site containing your channel. For best results please import or restore these in date order (oldest first).'), $impurl, $impurl) + + )); + return $o; + } - '$by_year' => t('Export your posts from a given year.'), - - '$extra' => t('You may also export your posts and conversations for a particular year or month. Adjust the date in your browser location bar to select other dates. If the export fails (possibly due to memory exhaustion on your server hub), please try again selecting a more limited date range.'), - '$extra2' => sprintf( t('To select all posts for a given year, such as this year, visit %2$s'),$yearurl,$yearurl), - '$extra3' => sprintf( t('To select all posts for a given month, such as January of this year, visit %2$s'),$janurl,$janurl), - '$extra4' => sprintf( t('These content files may be imported or restored by visiting %2$s on any site containing your channel. For best results please import or restore these in date order (oldest first).'),$impurl,$impurl) - - )); - return $o; - } - } diff --git a/Zotlabs/Module/Update.php b/Zotlabs/Module/Update.php index c83fc6b18..b71113504 100644 --- a/Zotlabs/Module/Update.php +++ b/Zotlabs/Module/Update.php @@ -23,59 +23,61 @@ namespace Zotlabs\Module; use App; use Zotlabs\Web\Controller; -class Update extends Controller { +class Update extends Controller +{ - function get() { + public function get() + { - $profile_uid = intval($_GET['p']); + $profile_uid = intval($_GET['p']); - // Change a profile_uid of 0 (not logged in) to (-1) for selected controllers - // as they only respond to liveUpdate with non-zero values - - if ((! $profile_uid) && in_array(argv(1),[ 'display', 'search', 'pubstream', 'home' ])) { - $profile_uid = (-1); - } + // Change a profile_uid of 0 (not logged in) to (-1) for selected controllers + // as they only respond to liveUpdate with non-zero values - if (argc() < 2) { - killme(); - } + if ((!$profile_uid) && in_array(argv(1), ['display', 'search', 'pubstream', 'home'])) { + $profile_uid = (-1); + } - // These modules don't have a completely working liveUpdate implementation currently + if (argc() < 2) { + killme(); + } - if (in_array(strtolower(argv(1)),[ 'articles', 'cards' ])) { - killme(); - } + // These modules don't have a completely working liveUpdate implementation currently - $module = "\\Zotlabs\\Module\\" . ucfirst(argv(1)); - $load = (((argc() > 2) && (argv(2) == 'load')) ? 1 : 0); + if (in_array(strtolower(argv(1)), ['articles', 'cards'])) { + killme(); + } - $mod = new $module; + $module = "\\Zotlabs\\Module\\" . ucfirst(argv(1)); + $load = (((argc() > 2) && (argv(2) == 'load')) ? 1 : 0); - // Set the state flags of the relevant module (only conversational - // modules support state flags - - if (isset($mod->profile_uid)) { - $mod->profile_uid = $profile_uid; - } - if (isset($mod->updating)) { - $mod->updating = 1; - } - if (isset($mod->loading) && $load) { - $mod->loading = 1; - } + $mod = new $module(); - header("Content-type: text/html"); + // Set the state flags of the relevant module (only conversational + // modules support state flags - // Modify the argument parameters to match what the new controller - // expects. They are currently set to what this controller expects. + if (isset($mod->profile_uid)) { + $mod->profile_uid = $profile_uid; + } + if (isset($mod->updating)) { + $mod->updating = 1; + } + if (isset($mod->loading) && $load) { + $mod->loading = 1; + } - App::$argv = [ argv(1) ]; - App::$argc = 1; + header("Content-type: text/html"); - echo "
      \r\n"; - echo $mod->get(); - echo "
      \r\n"; + // Modify the argument parameters to match what the new controller + // expects. They are currently set to what this controller expects. - killme(); - } + App::$argv = [argv(1)]; + App::$argc = 1; + + echo "
      \r\n"; + echo $mod->get(); + echo "
      \r\n"; + + killme(); + } } diff --git a/Zotlabs/Module/Userinfo.php b/Zotlabs/Module/Userinfo.php index 06c9ee81b..e3a83da23 100644 --- a/Zotlabs/Module/Userinfo.php +++ b/Zotlabs/Module/Userinfo.php @@ -8,13 +8,15 @@ use Zotlabs\Identity\OAuth2Storage; use Zotlabs\Identity\OAuth2Server; use OAuth2\Request; -class Userinfo extends Controller { +class Userinfo extends Controller +{ - function init() { - $s = new OAuth2Server(new OAuth2Storage(DBA::$dba->db)); - $request = Request::createFromGlobals(); - $s->handleUserInfoRequest($request)->send(); - killme(); - } + public function init() + { + $s = new OAuth2Server(new OAuth2Storage(DBA::$dba->db)); + $request = Request::createFromGlobals(); + $s->handleUserInfoRequest($request)->send(); + killme(); + } } diff --git a/Zotlabs/Module/View.php b/Zotlabs/Module/View.php index ee9e638fa..6cca0858d 100644 --- a/Zotlabs/Module/View.php +++ b/Zotlabs/Module/View.php @@ -5,18 +5,18 @@ use Zotlabs\Web\Controller; /** * load view/theme/$current_theme/style.php with Hubzilla context */ - +class View extends Controller +{ -class View extends Controller { + public function init() + { + header("Content-Type: text/css"); + + $theme = argv(2); + $THEMEPATH = "view/theme/$theme"; + if (file_exists("view/theme/$theme/php/style.php")) + require_once("view/theme/$theme/php/style.php"); + killme(); + } - function init() { - header("Content-Type: text/css"); - - $theme = argv(2); - $THEMEPATH = "view/theme/$theme"; - if(file_exists("view/theme/$theme/php/style.php")) - require_once("view/theme/$theme/php/style.php"); - killme(); - } - } diff --git a/Zotlabs/Module/Viewconnections.php b/Zotlabs/Module/Viewconnections.php index 194d260da..98b6ac693 100644 --- a/Zotlabs/Module/Viewconnections.php +++ b/Zotlabs/Module/Viewconnections.php @@ -6,115 +6,116 @@ use Zotlabs\Web\Controller; use Zotlabs\Lib\Libprofile; -class Viewconnections extends Controller { +class Viewconnections extends Controller +{ - function init() { - - if (observer_prohibited()) { - return; - } + public function init() + { - if (argc() > 1) { - Libprofile::load(argv(1)); - } - } - - function get() { + if (observer_prohibited()) { + return; + } - // logger('request: ' . print_r($_REQUEST,true)); + if (argc() > 1) { + Libprofile::load(argv(1)); + } + } - if (observer_prohibited()) { - notice( t('Public access denied.') . EOL); - return; - } + public function get() + { - if (((! (is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) { - notice( t('Permission denied.') . EOL); - return; - } - - if (! perm_is_allowed(App::$profile['uid'], get_observer_hash(),'view_contacts')) { - notice( t('Permission denied.') . EOL); - return; - } - - if (! $_REQUEST['aj']) { - $_SESSION['return_url'] = App::$query_string; - } - - $is_owner = ((local_channel() && local_channel() == App::$profile['uid']) ? true : false); - - $abook_flags = " and abook_pending = 0 and abook_self = 0 "; - $sql_extra = ''; - - if (! $is_owner) { - $abook_flags .= " and abook_hidden = 0 "; - $sql_extra = " and xchan_hidden = 0 "; - } - - $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra order by xchan_name LIMIT %d OFFSET %d ", - intval(App::$profile['uid']), - intval(App::$pager['itemspage']), - intval(App::$pager['start']) - ); - - if ((! $r) && (! $_REQUEST['aj'])) { - info( t('No connections.') . EOL ); - return $o; - } - - $contacts = []; - - foreach ($r as $rr) { + // logger('request: ' . print_r($_REQUEST,true)); + + if (observer_prohibited()) { + notice(t('Public access denied.') . EOL); + return; + } + + if (((!(is_array(App::$profile) && count(App::$profile))) || (App::$profile['hide_friends']))) { + notice(t('Permission denied.') . EOL); + return; + } + + if (!perm_is_allowed(App::$profile['uid'], get_observer_hash(), 'view_contacts')) { + notice(t('Permission denied.') . EOL); + return; + } + + if (!$_REQUEST['aj']) { + $_SESSION['return_url'] = App::$query_string; + } + + $is_owner = ((local_channel() && local_channel() == App::$profile['uid']) ? true : false); + + $abook_flags = " and abook_pending = 0 and abook_self = 0 "; + $sql_extra = ''; + + if (!$is_owner) { + $abook_flags .= " and abook_hidden = 0 "; + $sql_extra = " and xchan_hidden = 0 "; + } + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra order by xchan_name LIMIT %d OFFSET %d ", + intval(App::$profile['uid']), + intval(App::$pager['itemspage']), + intval(App::$pager['start']) + ); + + if ((!$r) && (!$_REQUEST['aj'])) { + info(t('No connections.') . EOL); + return $o; + } + + $contacts = []; + + foreach ($r as $rr) { + + $oneway = false; + if (!their_perms_contains(App::$profile['uid'], $rr['xchan_hash'], 'post_comments')) { + $oneway = true; + } + + $url = chanlink_hash($rr['xchan_hash']); + if ($url) { + $contacts[] = [ + 'id' => $rr['abook_id'], + 'archived' => (intval($rr['abook_archived']) ? true : false), + 'img_hover' => sprintf(t('Visit %1$s\'s profile [%2$s]'), $rr['xchan_name'], $rr['xchan_url']), + 'thumb' => $rr['xchan_photo_m'], + 'name' => substr($rr['xchan_name'], 0, 20), + 'username' => $rr['xchan_addr'], + 'link' => $url, + 'sparkle' => '', + 'itemurl' => $rr['url'], + 'network' => '', + 'oneway' => $oneway + ]; + } + } + + + if ($_REQUEST['aj']) { + if ($contacts) { + $o = replace_macros(get_markup_template('viewcontactsajax.tpl'), [ + '$contacts' => $contacts + ]); + } else { + $o = '
      '; + } + echo $o; + killme(); + } else { + $o .= ""; + $o .= replace_macros(get_markup_template('viewcontact_template.tpl'), [ + '$title' => t('View Connections'), + '$contacts' => $contacts, + ]); + } + + if (!$contacts) { + $o .= '
      '; + } + return $o; + } - $oneway = false; - if (! their_perms_contains(App::$profile['uid'],$rr['xchan_hash'],'post_comments')) { - $oneway = true; - } - - $url = chanlink_hash($rr['xchan_hash']); - if ($url) { - $contacts[] = [ - 'id' => $rr['abook_id'], - 'archived' => (intval($rr['abook_archived']) ? true : false), - 'img_hover' => sprintf( t('Visit %1$s\'s profile [%2$s]'), $rr['xchan_name'], $rr['xchan_url']), - 'thumb' => $rr['xchan_photo_m'], - 'name' => substr($rr['xchan_name'],0,20), - 'username' => $rr['xchan_addr'], - 'link' => $url, - 'sparkle' => '', - 'itemurl' => $rr['url'], - 'network' => '', - 'oneway' => $oneway - ]; - } - } - - - if ($_REQUEST['aj']) { - if ($contacts) { - $o = replace_macros(get_markup_template('viewcontactsajax.tpl'), [ - '$contacts' => $contacts - ]); - } - else { - $o = '
      '; - } - echo $o; - killme(); - } - else { - $o .= ""; - $o .= replace_macros(get_markup_template('viewcontact_template.tpl'), [ - '$title' => t('View Connections'), - '$contacts' => $contacts, - ]); - } - - if (! $contacts) { - $o .= '
      '; - } - return $o; - } - } diff --git a/Zotlabs/Module/Viewsrc.php b/Zotlabs/Module/Viewsrc.php index 91d11dcdb..c240c8e8d 100644 --- a/Zotlabs/Module/Viewsrc.php +++ b/Zotlabs/Module/Viewsrc.php @@ -5,67 +5,68 @@ use App; use Zotlabs\Web\Controller; +class Viewsrc extends Controller +{ -class Viewsrc extends Controller { + public function get() + { - function get() { - - $o = ''; - - $sys = get_sys_channel(); - - $item_id = ((argc() > 1) ? intval(argv(1)) : 0); - $json = ((argc() > 2 && argv(2) === 'json') ? true : false); - $dload = ((argc() > 2 && argv(2) === 'download') ? true : false); - - if (! local_channel()) { - notice( t('Permission denied.') . EOL); - } - - if (! $item_id) { - App::$error = 404; - notice( t('Item not found.') . EOL); - } - - $item_normal = item_normal_search(); - - if (local_channel() && $item_id) { - $r = q("select id, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1", - intval(local_channel()), - intval($sys['channel_id']), - intval($item_id) - ); - - if ($r) { - if (intval($r[0]['item_obscured'])) - $dload = true; + $o = ''; - if ($dload) { - header('Content-type: ' . $r[0]['mimetype']); - header('Content-Disposition: attachment; filename="' . t('item') . '-' . $item_id . '"' ); - echo $r[0]['body']; - killme(); - } + $sys = get_sys_channel(); - $content = escape_tags($r[0]['body']); - $o = (($json) ? json_encode($content) : str_replace("\n",'
      ',$content)); - } - } + $item_id = ((argc() > 1) ? intval(argv(1)) : 0); + $json = ((argc() > 2 && argv(2) === 'json') ? true : false); + $dload = ((argc() > 2 && argv(2) === 'download') ? true : false); + + if (!local_channel()) { + notice(t('Permission denied.') . EOL); + } + + if (!$item_id) { + App::$error = 404; + notice(t('Item not found.') . EOL); + } + + $item_normal = item_normal_search(); + + if (local_channel() && $item_id) { + $r = q("select id, item_flags, mimetype, item_obscured, body, llink, plink from item where uid in (%d , %d) and id = %d $item_normal limit 1", + intval(local_channel()), + intval($sys['channel_id']), + intval($item_id) + ); + + if ($r) { + if (intval($r[0]['item_obscured'])) + $dload = true; + + if ($dload) { + header('Content-type: ' . $r[0]['mimetype']); + header('Content-Disposition: attachment; filename="' . t('item') . '-' . $item_id . '"'); + echo $r[0]['body']; + killme(); + } + + $content = escape_tags($r[0]['body']); + $o = (($json) ? json_encode($content) : str_replace("\n", '
      ', $content)); + } + } + + $inspect = ((is_site_admin()) ? '| ' . t('inspect') . '' : EMPTY_STR); + + + if (is_ajax()) { + echo '
      '; + echo '
      id: ' . $r[0]['id'] . ' | plink | llink' . $inspect . '
      '; + echo '
      '; + echo '
      ' . $o . '
      '; + echo '
      '; + killme(); + } + + return $o; + } - $inspect = ((is_site_admin()) ? '| ' . t('inspect') . '' : EMPTY_STR); - - if (is_ajax()) { - echo '
      '; - echo '
      id: ' . $r[0]['id'] . ' | plink | llink' . $inspect . '
      '; - echo '
      '; - echo '
      ' . $o . '
      '; - echo '
      '; - killme(); - } - - return $o; - } - - } diff --git a/Zotlabs/Module/Vlists.php b/Zotlabs/Module/Vlists.php index a63ccd405..4f36d7df7 100644 --- a/Zotlabs/Module/Vlists.php +++ b/Zotlabs/Module/Vlists.php @@ -6,10 +6,12 @@ use Zotlabs\Lib\Apps; use Zotlabs\Lib\Libsync; use Zotlabs\Web\Controller; -class Vlists extends Controller { +class Vlists extends Controller +{ - function get() { + public function get() + { $desc = t('This app creates dynamic access lists corresponding to [1] all connections, [2] all ActivityPub protocol connections, and [3] all Nomad or Zot/6 protocol connections. These additional selections will be found within the Permissions setting tool.'); @@ -20,10 +22,10 @@ class Vlists extends Controller { $text2 = ''; - if (local_channel() && Apps::system_app_installed(local_channel(),'Virtual Lists')) { - $o .= $text2; + if (local_channel() && Apps::system_app_installed(local_channel(), 'Virtual Lists')) { + $o .= $text2; } - return $o; - } + return $o; + } } diff --git a/Zotlabs/Module/Vote.php b/Zotlabs/Module/Vote.php index e614b3f73..f0bff6aaa 100644 --- a/Zotlabs/Module/Vote.php +++ b/Zotlabs/Module/Vote.php @@ -7,128 +7,129 @@ use Zotlabs\Lib\Activity; use Zotlabs\Daemon\Run; use Zotlabs\Lib\Libsync; -class Vote extends Controller { +class Vote extends Controller +{ - function init() { + public function init() + { - $ret = [ 'success' => false, 'message' => EMPTY_STR ]; + $ret = ['success' => false, 'message' => EMPTY_STR]; - $channel = App::get_channel(); + $channel = App::get_channel(); - if (! $channel) { - $ret['message'] = t('Permission denied.'); - json_return_and_die($ret); - } + if (!$channel) { + $ret['message'] = t('Permission denied.'); + json_return_and_die($ret); + } - $fetch = null; - $id = argv(1); - $response = $_REQUEST['answer']; - - if ($id) { - $fetch = q("select * from item where id = %d limit 1", - intval($id) - ); - } + $fetch = null; + $id = argv(1); + $response = $_REQUEST['answer']; - if ($fetch && $fetch[0]['obj_type'] === 'Question') { - $obj = json_decode($fetch[0]['obj'],true); + if ($id) { + $fetch = q("select * from item where id = %d limit 1", + intval($id) + ); + } - } - else { - $ret['message'] = t('Poll not found.'); - json_return_and_die($ret); - } + if ($fetch && $fetch[0]['obj_type'] === 'Question') { + $obj = json_decode($fetch[0]['obj'], true); - $valid = false; - - if ($obj['oneOf']) { - foreach($obj['oneOf'] as $selection) { - // logger('selection: ' . $selection); - // logger('response: ' . $response); - if($selection['name'] && $selection['name'] === $response) { - $valid = true; - } - } - } + } else { + $ret['message'] = t('Poll not found.'); + json_return_and_die($ret); + } - $choices = []; - if ($obj['anyOf']) { - foreach ($obj['anyOf'] as $selection) { - $choices[] = $selection['name']; - } - foreach ($response as $res) { - if (! in_array($res,$choices)) { - $valid = false; - break; - } - $valid = true; - } - } + $valid = false; - if (! $valid) { - $ret['message'] = t('Invalid response.'); - json_return_and_die($ret); - } + if ($obj['oneOf']) { + foreach ($obj['oneOf'] as $selection) { + // logger('selection: ' . $selection); + // logger('response: ' . $response); + if ($selection['name'] && $selection['name'] === $response) { + $valid = true; + } + } + } - if (! is_array($response)) { - $response = [ $response ]; - } + $choices = []; + if ($obj['anyOf']) { + foreach ($obj['anyOf'] as $selection) { + $choices[] = $selection['name']; + } + foreach ($response as $res) { + if (!in_array($res, $choices)) { + $valid = false; + break; + } + $valid = true; + } + } - foreach ($response as $res) { + if (!$valid) { + $ret['message'] = t('Invalid response.'); + json_return_and_die($ret); + } - $item = []; + if (!is_array($response)) { + $response = [$response]; + } - $item['aid'] = $channel['channel_account_id']; - $item['uid'] = $channel['channel_id']; - $item['item_origin'] = true; - $item['parent'] = $fetch[0]['id']; - $item['parent_mid'] = $fetch[0]['mid']; - $item['thr_parent'] = $fetch[0]['mid']; - $item['uuid'] = new_uuid(); - $item['mid'] = z_root() . '/item/' . $item['uuid']; - $item['verb'] = 'Create'; - $item['title'] = $res; - $item['author_xchan'] = $channel['channel_hash']; - $item['owner_xchan'] = $fetch[0]['author_xchan']; + foreach ($response as $res) { + + $item = []; + + $item['aid'] = $channel['channel_account_id']; + $item['uid'] = $channel['channel_id']; + $item['item_origin'] = true; + $item['parent'] = $fetch[0]['id']; + $item['parent_mid'] = $fetch[0]['mid']; + $item['thr_parent'] = $fetch[0]['mid']; + $item['uuid'] = new_uuid(); + $item['mid'] = z_root() . '/item/' . $item['uuid']; + $item['verb'] = 'Create'; + $item['title'] = $res; + $item['author_xchan'] = $channel['channel_hash']; + $item['owner_xchan'] = $fetch[0]['author_xchan']; // $item['allow_cid'] = '<' . $fetch[0]['author_xchan'] . '>'; // $item['item_private'] = 1; - - // These two are placeholder values that will be reset after - // we encode the item - - $item['obj_type'] = 'Note'; - $item['author'] = channelx_by_n($channel['channel_id']); - $item['obj'] = Activity::encode_item($item,((get_config('system','activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); + // These two are placeholder values that will be reset after + // we encode the item - // now reset the placeholders + $item['obj_type'] = 'Note'; + $item['author'] = channelx_by_n($channel['channel_id']); - $item['obj_type'] = 'Answer'; - unset($item['author']); - - $x = item_store($item); + $item['obj'] = Activity::encode_item($item, ((get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) ? true : false)); - retain_item($fetch[0]['id']); + // now reset the placeholders - if($x['success']) { - $itemid = $x['item_id']; - Run::Summon( [ 'Notifier', 'like', $itemid ] ); - } - - $r = q("select * from item where id = %d", - intval($itemid) - ); - if ($r) { - xchan_query($r); - $sync_item = fetch_post_tags($r); - Libsync::build_sync_packet($channel['channel_id'], [ 'item' => [ encode_item($sync_item[0],true) ] ]); - } - } - $ret['success'] = true; - $ret['message'] = t('Response submitted. Updates may not appear instantly.'); - json_return_and_die($ret); - } + $item['obj_type'] = 'Answer'; + unset($item['author']); + + $x = item_store($item); + + retain_item($fetch[0]['id']); + + if ($x['success']) { + $itemid = $x['item_id']; + Run::Summon(['Notifier', 'like', $itemid]); + } + + $r = q("select * from item where id = %d", + intval($itemid) + ); + if ($r) { + xchan_query($r); + $sync_item = fetch_post_tags($r); + Libsync::build_sync_packet($channel['channel_id'], ['item' => [encode_item($sync_item[0], true)]]); + } + } + $ret['success'] = true; + $ret['message'] = t('Response submitted. Updates may not appear instantly.'); + json_return_and_die($ret); + } } diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php index 1039e29d7..d8510b2dd 100644 --- a/Zotlabs/Module/Wall_attach.php +++ b/Zotlabs/Module/Wall_attach.php @@ -8,172 +8,168 @@ use Zotlabs\Lib\Libsync; require_once('include/attach.php'); require_once('include/photos.php'); -class Wall_attach extends Controller { +class Wall_attach extends Controller +{ - function init() { + public function init() + { // logger('request_method: ' . $_SERVER['REQUEST_METHOD'],LOGGER_DATA,LOG_INFO); // logger('wall_attach: ' . print_r($_REQUEST,true),LOGGER_DEBUG,LOG_INFO); // logger('wall_attach files: ' . print_r($_FILES,true),LOGGER_DEBUG,LOG_INFO); - // for testing without actually storing anything - // http_status_exit(200,'OK'); - } + // for testing without actually storing anything + // http_status_exit(200,'OK'); + } - function post() { - - $using_api = false; + public function post() + { - $result = []; + $using_api = false; - if ($_REQUEST['api_source'] && array_key_exists('media',$_FILES)) { - $using_api = true; - } + $result = []; - if ($using_api) { - require_once('include/api.php'); - if (api_user()) { - $channel = channelx_by_n(api_user()); - } - } - else { - if (argc() > 1) - $channel = channelx_by_nick(argv(1)); - } + if ($_REQUEST['api_source'] && array_key_exists('media', $_FILES)) { + $using_api = true; + } - if (! $channel) - killme(); + if ($using_api) { + require_once('include/api.php'); + if (api_user()) { + $channel = channelx_by_n(api_user()); + } + } else { + if (argc() > 1) + $channel = channelx_by_nick(argv(1)); + } - $matches = []; - $partial = false; + if (!$channel) + killme(); - if (array_key_exists('HTTP_CONTENT_RANGE',$_SERVER)) { - $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/',$_SERVER['HTTP_CONTENT_RANGE'],$matches); - if ($pm) { - // logger('Content-Range: ' . print_r($matches,true)); - $partial = true; - } - } + $matches = []; + $partial = false; - if ($partial) { - $x = save_chunk($channel,$matches[1],$matches[2],$matches[3]); - if ($x['partial']) { - header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); - json_return_and_die($x); - } - else { - header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); + if (array_key_exists('HTTP_CONTENT_RANGE', $_SERVER)) { + $pm = preg_match('/bytes (\d*)\-(\d*)\/(\d*)/', $_SERVER['HTTP_CONTENT_RANGE'], $matches); + if ($pm) { + // logger('Content-Range: ' . print_r($matches,true)); + $partial = true; + } + } - $_FILES['userfile'] = [ - 'name' => $x['name'], - 'type' => $x['type'], - 'tmp_name' => $x['tmp_name'], - 'error' => $x['error'], - 'size' => $x['size'] - ]; - } - } - else { - if (! array_key_exists('userfile',$_FILES)) { - $_FILES['userfile'] = [ - 'name' => $_FILES['files']['name'], - 'type' => $_FILES['files']['type'], - 'tmp_name' => $_FILES['files']['tmp_name'], - 'error' => $_FILES['files']['error'], - 'size' => $_FILES['files']['size'] - ]; - } - } + if ($partial) { + $x = save_chunk($channel, $matches[1], $matches[2], $matches[3]); + if ($x['partial']) { + header('Range: bytes=0-' . (($x['length']) ? $x['length'] - 1 : 0)); + json_return_and_die($x); + } else { + header('Range: bytes=0-' . (($x['size']) ? $x['size'] - 1 : 0)); - $observer = App::get_observer(); - - - $def_album = get_pconfig($channel['channel_id'],'system','photo_path'); - $def_attach = get_pconfig($channel['channel_id'],'system','attach_path'); - - $r = attach_store($channel, (($observer) ? $observer['xchan_hash'] : ''), '', [ - 'source' => 'editor', - 'visible' => 0, - 'album' => $def_album, - 'directory' => $def_attach, - 'flags' => 1, // indicates temporary permissions are created - 'allow_cid' => '<' . $channel['channel_hash'] . '>' - ]); - - if (! $r['success']) { - notice( $r['message'] . EOL); - killme(); - } + $_FILES['userfile'] = [ + 'name' => $x['name'], + 'type' => $x['type'], + 'tmp_name' => $x['tmp_name'], + 'error' => $x['error'], + 'size' => $x['size'] + ]; + } + } else { + if (!array_key_exists('userfile', $_FILES)) { + $_FILES['userfile'] = [ + 'name' => $_FILES['files']['name'], + 'type' => $_FILES['files']['type'], + 'tmp_name' => $_FILES['files']['tmp_name'], + 'error' => $_FILES['files']['error'], + 'size' => $_FILES['files']['size'] + ]; + } + } - $s = EMPTY_STR; - - if (intval($r['data']['is_photo'])) { - $s .= "\n\n" . $r['body'] . "\n\n"; - } + $observer = App::get_observer(); - $url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']; - if (strpos($r['data']['filetype'],'video') === 0) { - for ($n = 0; $n < 15; $n ++) { - $thumb = Linkinfo::get_video_poster($url); - if ($thumb) { - break; - } - sleep(1); - continue; - } + $def_album = get_pconfig($channel['channel_id'], 'system', 'photo_path'); + $def_attach = get_pconfig($channel['channel_id'], 'system', 'attach_path'); - if ($thumb) { - $s .= "\n\n" . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . "\n\n"; - } - else { - $s .= "\n\n" . '[zvideo]' . $url . '[/zvideo]' . "\n\n"; - } - } - if (strpos($r['data']['filetype'],'audio') === 0) { - $s .= "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n"; - } - if ($r['data']['filetype'] === 'image/svg+xml') { - $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - if ($x) { - $bb = svg2bb($x); - if ($bb) { - $s .= "\n\n" . $bb; - } - else { - logger('empty return from svgbb'); - } - } - else { - logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - } - } - if ($r['data']['filetype'] === 'text/vnd.abc' && addon_is_installed('abc')) { - $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - if ($x) { - $s .= "\n\n" . '[abc]' . $x . '[/abc]'; - } - else { - logger('unable to read ABC data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - } - } - if ($r['data']['filetype'] === 'text/calendar') { - $content = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); - if ($content) { - $ev = ical_to_ev($content); - if ($ev) { - $s .= "\n\n" . format_event_bbcode($ev[0]) . "\n\n"; - } - } - } + $r = attach_store($channel, (($observer) ? $observer['xchan_hash'] : ''), '', [ + 'source' => 'editor', + 'visible' => 0, + 'album' => $def_album, + 'directory' => $def_attach, + 'flags' => 1, // indicates temporary permissions are created + 'allow_cid' => '<' . $channel['channel_hash'] . '>' + ]); - $s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; + if (!$r['success']) { + notice($r['message'] . EOL); + killme(); + } - - if ($using_api) { - return $s; - } + $s = EMPTY_STR; - $result['message'] = $s; - json_return_and_die($result); - } + if (intval($r['data']['is_photo'])) { + $s .= "\n\n" . $r['body'] . "\n\n"; + } + + $url = z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']; + + if (strpos($r['data']['filetype'], 'video') === 0) { + for ($n = 0; $n < 15; $n++) { + $thumb = Linkinfo::get_video_poster($url); + if ($thumb) { + break; + } + sleep(1); + continue; + } + + if ($thumb) { + $s .= "\n\n" . '[zvideo poster=\'' . $thumb . '\']' . $url . '[/zvideo]' . "\n\n"; + } else { + $s .= "\n\n" . '[zvideo]' . $url . '[/zvideo]' . "\n\n"; + } + } + if (strpos($r['data']['filetype'], 'audio') === 0) { + $s .= "\n\n" . '[zaudio]' . $url . '[/zaudio]' . "\n\n"; + } + if ($r['data']['filetype'] === 'image/svg+xml') { + $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + if ($x) { + $bb = svg2bb($x); + if ($bb) { + $s .= "\n\n" . $bb; + } else { + logger('empty return from svgbb'); + } + } else { + logger('unable to read svg data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + } + } + if ($r['data']['filetype'] === 'text/vnd.abc' && addon_is_installed('abc')) { + $x = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + if ($x) { + $s .= "\n\n" . '[abc]' . $x . '[/abc]'; + } else { + logger('unable to read ABC data file: ' . 'store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + } + } + if ($r['data']['filetype'] === 'text/calendar') { + $content = @file_get_contents('store/' . $channel['channel_address'] . '/' . $r['data']['os_path']); + if ($content) { + $ev = ical_to_ev($content); + if ($ev) { + $s .= "\n\n" . format_event_bbcode($ev[0]) . "\n\n"; + } + } + } + + $s .= "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; + + + if ($using_api) { + return $s; + } + + $result['message'] = $s; + json_return_and_die($result); + } } diff --git a/Zotlabs/Module/Wall_upload.php b/Zotlabs/Module/Wall_upload.php index 3f5973816..f0ec14c82 100644 --- a/Zotlabs/Module/Wall_upload.php +++ b/Zotlabs/Module/Wall_upload.php @@ -9,50 +9,49 @@ require_once('include/channel.php'); require_once('include/photos.php'); +class Wall_upload extends Controller +{ + + public function post() + { -class Wall_upload extends Controller { + $using_api = ((x($_FILES, 'media')) ? true : false); + + if ($using_api) { + require_once('include/api.php'); + if (api_user()) + $channel = channelx_by_n(api_user()); + } else { + if (argc() > 1) + $channel = channelx_by_nick(argv(1)); + } + + if (!$channel) { + if ($using_api) + return; + notice(t('Channel not found.') . EOL); + killme(); + } + + $observer = App::get_observer(); + + $args = array('source' => 'editor', 'visible' => 0, 'contact_allow' => array($channel['channel_hash'])); + + $ret = photo_upload($channel, $observer, $args); + + if (!$ret['success']) { + if ($using_api) + return; + notice($ret['message']); + killme(); + } + + if ($using_api) + return ("\n\n" . $ret['body'] . "\n\n"); + else + echo "\n\n" . $ret['body'] . "\n\n"; + killme(); + } - function post() { - - - $using_api = ((x($_FILES,'media')) ? true : false); - - if($using_api) { - require_once('include/api.php'); - if(api_user()) - $channel = channelx_by_n(api_user()); - } - else { - if(argc() > 1) - $channel = channelx_by_nick(argv(1)); - } - - if(! $channel) { - if($using_api) - return; - notice( t('Channel not found.') . EOL); - killme(); - } - - $observer = App::get_observer(); - - $args = array( 'source' => 'editor', 'visible' => 0, 'contact_allow' => array($channel['channel_hash'])); - - $ret = photo_upload($channel,$observer,$args); - - if(! $ret['success']) { - if($using_api) - return; - notice($ret['message']); - killme(); - } - - if($using_api) - return("\n\n" . $ret['body'] . "\n\n"); - else - echo "\n\n" . $ret['body'] . "\n\n"; - killme(); - } - } diff --git a/Zotlabs/Module/Webfinger.php b/Zotlabs/Module/Webfinger.php index 42b718e8c..46aef0a9e 100644 --- a/Zotlabs/Module/Webfinger.php +++ b/Zotlabs/Module/Webfinger.php @@ -5,172 +5,174 @@ use Zotlabs\Web\Controller; use Zotlabs\Lib\System; use App; -class Webfinger extends Controller { +class Webfinger extends Controller +{ - function init() { + public function init() + { - logger('webfinger from ' . $_SERVER['REMOTE_ADDR']); + logger('webfinger from ' . $_SERVER['REMOTE_ADDR']); - // This is a public resource with relaxed CORS policy. Close the current login session. - session_write_close(); - - header('Access-Control-Allow-Origin: *'); + // This is a public resource with relaxed CORS policy. Close the current login session. + session_write_close(); - $result = []; - - if (! is_https_request()) { - header($_SERVER['SERVER_PROTOCOL'] . ' ' . 500 . ' ' . 'Webfinger requires HTTPS'); - killme(); - } - - $resource = $_REQUEST['resource']; + header('Access-Control-Allow-Origin: *'); - if (! $resource) { - http_status_exit(404,'Not found'); - } + $result = []; - logger('webfinger: ' . $resource, LOGGER_DEBUG); - - // Determine whether to respond as a site actor - // or a normal channel + if (!is_https_request()) { + header($_SERVER['SERVER_PROTOCOL'] . ' ' . 500 . ' ' . 'Webfinger requires HTTPS'); + killme(); + } - $site_query = false; - if (strcasecmp(rtrim($resource,'/'),z_root()) === 0 - || strcasecmp($resource,'acct:sys@' . App::get_hostname()) === 0 - || $resource === z_root() . '/channel/sys') { - $site_query = true; - $result['subject'] = $resource; - $resource = z_root() . '/channel/sys'; - } + $resource = $_REQUEST['resource']; - if (strpos($resource,'tag:' === 0)) { - $arr = explode(':',$resource); - if (count($arr) > 3 && $arr[2] === 'zotid') { - $hash = $arr[3]; - $channel_target = channelx_by_hash($hash); - } - } - - if (strpos($resource,'acct:') === 0) { - $channel_nickname = punify(str_replace('acct:','',$resource)); - if (strrpos($channel_nickname,'@') !== false) { - $host = punify(substr($channel_nickname,strrpos($channel_nickname,'@')+1)); + if (!$resource) { + http_status_exit(404, 'Not found'); + } - // If the webfinger address points off site, redirect to the correct site + logger('webfinger: ' . $resource, LOGGER_DEBUG); - if (strcasecmp($host, App::get_hostname())) { - goaway('https://' . $host . '/.well-known/webfinger?f=&resource=' . $resource); - } - $channel_nickname = substr($channel_nickname,0,strrpos($channel_nickname,'@')); - } - } - if (strpos($resource,'http') === 0) { - $channel_nickname = str_replace( ['~','@'],['',''],basename($resource)); - } + // Determine whether to respond as a site actor + // or a normal channel - if ($channel_nickname) { - $channel_target = channelx_by_nick($channel_nickname); - } - - if ($channel_target || $site_query) { - - $h = get_hubloc_addrs_by_hash($channel_target['channel_hash']); + $site_query = false; + if (strcasecmp(rtrim($resource, '/'), z_root()) === 0 + || strcasecmp($resource, 'acct:sys@' . App::get_hostname()) === 0 + || $resource === z_root() . '/channel/sys') { + $site_query = true; + $result['subject'] = $resource; + $resource = z_root() . '/channel/sys'; + } - if (! isset($result['subject'])) { - $result['subject'] = $resource; - } + if (strpos($resource, 'tag:' === 0)) { + $arr = explode(':', $resource); + if (count($arr) > 3 && $arr[2] === 'zotid') { + $hash = $arr[3]; + $channel_target = channelx_by_hash($hash); + } + } - $aliases = [ - z_root() . '/channel/' . $channel_target['channel_address'], - z_root() . '/~' . $channel_target['channel_address'], - z_root() . '/@' . $channel_target['channel_address'] + if (strpos($resource, 'acct:') === 0) { + $channel_nickname = punify(str_replace('acct:', '', $resource)); + if (strrpos($channel_nickname, '@') !== false) { + $host = punify(substr($channel_nickname, strrpos($channel_nickname, '@') + 1)); - ]; - - if ($h) { - foreach ($h as $hh) { - $aliases[] = 'acct:' . $hh['hubloc_addr']; - } - } - - $result['aliases'] = []; - - $result['properties'] = [ - 'http://webfinger.net/ns/name' => $site_query ? System::get_site_name() : $channel_target['channel_name'], - 'http://xmlns.com/foaf/0.1/name' => $site_query ? System::get_site_name() : $channel_target['channel_name'], - 'https://w3id.org/security/v1#publicKeyPem' => (($site_query) ? get_config('system','pubkey') : $channel_target['xchan_pubkey']), - 'http://purl.org/zot/federation' => ((get_config('system','activitypub', ACTIVITYPUB_ENABLED)) ? 'zot6,activitypub' : 'zot6') - ]; + // If the webfinger address points off site, redirect to the correct site - if ($site_query) { - $aliases[] = z_root(); - $aliases[] = 'acct:sys@' . App::get_hostname(); - } - - foreach ($aliases as $alias) { - if ($alias !== $result['subject']) { - $result['aliases'][] = $alias; - } - } - - $result['links'] = [ + if (strcasecmp($host, App::get_hostname())) { + goaway('https://' . $host . '/.well-known/webfinger?f=&resource=' . $resource); + } + $channel_nickname = substr($channel_nickname, 0, strrpos($channel_nickname, '@')); + } + } + if (strpos($resource, 'http') === 0) { + $channel_nickname = str_replace(['~', '@'], ['', ''], basename($resource)); + } - [ - 'rel' => 'http://webfinger.net/rel/avatar', - 'type' => $channel_target['xchan_photo_mimetype'], - 'href' => $channel_target['xchan_photo_l'] - ], + if ($channel_nickname) { + $channel_target = channelx_by_nick($channel_nickname); + } - [ - 'rel' => 'http://webfinger.net/rel/blog', - 'href' => z_root() . '/channel/' . $channel_target['channel_address'], - ], - - [ - 'rel' => 'http://openid.net/specs/connect/1.0/issuer', - 'href' => z_root() - ], + if ($channel_target || $site_query) { - [ - 'rel' => 'http://purl.org/zot/protocol/6.0', - 'type' => 'application/x-zot+json', - 'href' => (($site_query) ? z_root() : z_root() . '/channel/' . $channel_target['channel_address']), - ], + $h = get_hubloc_addrs_by_hash($channel_target['channel_hash']); - [ - 'rel' => 'http://purl.org/openwebauth/v1', - 'type' => 'application/x-zot+json', - 'href' => z_root() . '/owa' - ], + if (!isset($result['subject'])) { + $result['subject'] = $resource; + } - [ - 'rel' => 'self', - 'type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', - 'href' => (($site_query) ? z_root() : z_root() . '/channel/' . $channel_target['channel_address']) - ], - - [ - 'rel' => 'self', - 'type' => 'application/activity+json', - 'href' => (($site_query) ? z_root() : z_root() . '/channel/' . $channel_target['channel_address']) - ], + $aliases = [ + z_root() . '/channel/' . $channel_target['channel_address'], + z_root() . '/~' . $channel_target['channel_address'], + z_root() . '/@' . $channel_target['channel_address'] - [ - 'rel' => 'http://ostatus.org/schema/1.0/subscribe', - 'template' => z_root() . '/follow?url={uri}' - ], - ]; - } + ]; - if (! $result) { - header($_SERVER['SERVER_PROTOCOL'] . ' ' . 400 . ' ' . 'Bad Request'); - killme(); - } - - $arr = [ 'channel' => $channel_target, 'request' => $_REQUEST, 'result' => $result ]; - call_hooks('webfinger',$arr); + if ($h) { + foreach ($h as $hh) { + $aliases[] = 'acct:' . $hh['hubloc_addr']; + } + } + + $result['aliases'] = []; + + $result['properties'] = [ + 'http://webfinger.net/ns/name' => $site_query ? System::get_site_name() : $channel_target['channel_name'], + 'http://xmlns.com/foaf/0.1/name' => $site_query ? System::get_site_name() : $channel_target['channel_name'], + 'https://w3id.org/security/v1#publicKeyPem' => (($site_query) ? get_config('system', 'pubkey') : $channel_target['xchan_pubkey']), + 'http://purl.org/zot/federation' => ((get_config('system', 'activitypub', ACTIVITYPUB_ENABLED)) ? 'zot6,activitypub' : 'zot6') + ]; + + if ($site_query) { + $aliases[] = z_root(); + $aliases[] = 'acct:sys@' . App::get_hostname(); + } + + foreach ($aliases as $alias) { + if ($alias !== $result['subject']) { + $result['aliases'][] = $alias; + } + } + + $result['links'] = [ + + [ + 'rel' => 'http://webfinger.net/rel/avatar', + 'type' => $channel_target['xchan_photo_mimetype'], + 'href' => $channel_target['xchan_photo_l'] + ], + + [ + 'rel' => 'http://webfinger.net/rel/blog', + 'href' => z_root() . '/channel/' . $channel_target['channel_address'], + ], + + [ + 'rel' => 'http://openid.net/specs/connect/1.0/issuer', + 'href' => z_root() + ], + + [ + 'rel' => 'http://purl.org/zot/protocol/6.0', + 'type' => 'application/x-zot+json', + 'href' => (($site_query) ? z_root() : z_root() . '/channel/' . $channel_target['channel_address']), + ], + + [ + 'rel' => 'http://purl.org/openwebauth/v1', + 'type' => 'application/x-zot+json', + 'href' => z_root() . '/owa' + ], + + [ + 'rel' => 'self', + 'type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"', + 'href' => (($site_query) ? z_root() : z_root() . '/channel/' . $channel_target['channel_address']) + ], + + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => (($site_query) ? z_root() : z_root() . '/channel/' . $channel_target['channel_address']) + ], + + [ + 'rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => z_root() . '/follow?url={uri}' + ], + ]; + } + + if (!$result) { + header($_SERVER['SERVER_PROTOCOL'] . ' ' . 400 . ' ' . 'Bad Request'); + killme(); + } + + $arr = ['channel' => $channel_target, 'request' => $_REQUEST, 'result' => $result]; + call_hooks('webfinger', $arr); - json_return_and_die($arr['result'],'application/jrd+json',true); - } + json_return_and_die($arr['result'], 'application/jrd+json', true); + } } diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php index bcb460096..e5875d13f 100644 --- a/Zotlabs/Module/Webpages.php +++ b/Zotlabs/Module/Webpages.php @@ -13,707 +13,711 @@ require_once('include/channel.php'); require_once('include/conversation.php'); require_once('include/acl_selectors.php'); -class Webpages extends Controller { +class Webpages extends Controller +{ - function init() { - - if(argc() > 1 && argv(1) === 'sys' && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - App::$is_sys = true; - } - } - - if(argc() > 1) - $which = argv(1); - else - return; - - Libprofile::load($which); - - } - - - function get() { - - if(! App::$profile) { - notice( t('Requested profile is not available.') . EOL ); - App::$error = 404; - return; - } + public function init() + { - if(! Apps::system_app_installed(App::$profile_uid, 'Webpages')) { - //Do not display any associated widgets at this point - App::$pdl = ''; + if (argc() > 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + App::$is_sys = true; + } + } - $o = 'Webpages App (Not Installed):
      '; - $o .= t('Provide managed web pages on your channel'); - return $o; - } + if (argc() > 1) + $which = argv(1); + else + return; - nav_set_selected('Webpages'); + Libprofile::load($which); - $which = argv(1); - - $_SESSION['return_url'] = App::$query_string; - - $uid = local_channel(); - $owner = 0; - $observer = App::get_observer(); - - $channel = App::get_channel(); + } - switch ($_SESSION['action']) { - case 'import': - $_SESSION['action'] = null; - $o .= replace_macros(get_markup_template('webpage_import.tpl'), array( - '$title' => t('Import Webpage Elements'), - '$importbtn' => t('Import selected'), - '$action' => 'import', - '$pages' => $_SESSION['pages'], - '$layouts' => $_SESSION['layouts'], - '$blocks' => $_SESSION['blocks'], - )); - return $o; - - case 'importselected': - $_SESSION['action'] = null; - break; - case 'export_select_list': - $_SESSION['action'] = null; - if(!$uid) { - $_SESSION['export'] = null; - break; - } - require_once('include/import.php'); - - $pages = get_webpage_elements($channel, 'pages'); - $layouts = get_webpage_elements($channel, 'layouts'); - $blocks = get_webpage_elements($channel, 'blocks'); - $o .= replace_macros(get_markup_template('webpage_export_list.tpl'), array( - '$title' => t('Export Webpage Elements'), - '$exportbtn' => t('Export selected'), - '$action' => $_SESSION['export'], // value should be 'zipfile' or 'cloud' - '$pages' => $pages['pages'], - '$layouts' => $layouts['layouts'], - '$blocks' => $blocks['blocks'], - )); - $_SESSION['export'] = null; - return $o; - - default : - $_SESSION['action'] = null; - break; - } - - - if(App::$is_sys && is_site_admin()) { - $sys = get_sys_channel(); - if($sys && intval($sys['channel_id'])) { - $uid = $owner = intval($sys['channel_id']); - $channel = $sys; - $observer = $sys; - } - } - - if(! $owner) { - // Figure out who the page owner is. - $r = q("select channel_id from channel where channel_address = '%s'", - dbesc($which) - ); - if($r) { - $owner = intval($r[0]['channel_id']); - } - } - - $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); - - $perms = get_all_perms($owner,$ob_hash); - - if(! $perms['write_pages']) { - notice( t('Permission denied.') . EOL); - return; - } - - $mimetype = (($_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner,'system','page_mimetype')); - - $layout = (($_REQUEST['layout']) ? $_REQUEST['layout'] : get_pconfig($owner,'system','page_layout')); - - // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages - // Nickname is set to the observers xchan, and profile_uid to the owner's. - // This lets you post pages at other people's channels. - - if((! $channel) && ($uid) && ($uid == App::$profile_uid)) { - $channel = App::get_channel(); - } - if($channel) { - $channel_acl = array( - 'allow_cid' => $channel['channel_allow_cid'], - 'allow_gid' => $channel['channel_allow_gid'], - 'deny_cid' => $channel['channel_deny_cid'], - 'deny_gid' => $channel['channel_deny_gid'] - ); - } - else { - $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ]; - } - - $is_owner = ($uid && $uid == $owner); + public function get() + { - $o = ''; - - $x = array( - 'webpage' => ITEM_TYPE_WEBPAGE, - 'is_owner' => true, - 'nickname' => App::$profile['channel_address'], - 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), - 'acl' => (($is_owner) ? populate_acl($channel_acl,false, PermissionDescription::fromGlobalPermission('view_pages')) : ''), - 'permissions' => $channel_acl, - 'showacl' => (($is_owner) ? true : false), - 'visitor' => true, - 'hide_location' => true, - 'hide_voting' => true, - 'profile_uid' => intval($owner), - 'mimetype' => $mimetype, - 'mimeselect' => true, - 'layout' => $layout, - 'layoutselect' => true, - 'expanded' => true, - 'novoting'=> true, - 'bbco_autocomplete' => 'bbcode', - 'bbcode' => true - ); - - if($_REQUEST['title']) - $x['title'] = $_REQUEST['title']; - if($_REQUEST['body']) - $x['body'] = $_REQUEST['body']; - if($_REQUEST['pagetitle']) - $x['pagetitle'] = $_REQUEST['pagetitle']; - - - // Get a list of webpages. We can't display all them because endless scroll makes that unusable, - // so just list titles and an edit link. - - - $sql_extra = item_permissions_sql($owner); - - $r = q("select * from iconfig left join item on iconfig.iid = item.id + if (!App::$profile) { + notice(t('Requested profile is not available.') . EOL); + App::$error = 404; + return; + } + + if (!Apps::system_app_installed(App::$profile_uid, 'Webpages')) { + //Do not display any associated widgets at this point + App::$pdl = ''; + + $o = 'Webpages App (Not Installed):
      '; + $o .= t('Provide managed web pages on your channel'); + return $o; + } + + nav_set_selected('Webpages'); + + $which = argv(1); + + $_SESSION['return_url'] = App::$query_string; + + $uid = local_channel(); + $owner = 0; + $observer = App::get_observer(); + + $channel = App::get_channel(); + + switch ($_SESSION['action']) { + case 'import': + $_SESSION['action'] = null; + $o .= replace_macros(get_markup_template('webpage_import.tpl'), array( + '$title' => t('Import Webpage Elements'), + '$importbtn' => t('Import selected'), + '$action' => 'import', + '$pages' => $_SESSION['pages'], + '$layouts' => $_SESSION['layouts'], + '$blocks' => $_SESSION['blocks'], + )); + return $o; + + case 'importselected': + $_SESSION['action'] = null; + break; + case 'export_select_list': + $_SESSION['action'] = null; + if (!$uid) { + $_SESSION['export'] = null; + break; + } + require_once('include/import.php'); + + $pages = get_webpage_elements($channel, 'pages'); + $layouts = get_webpage_elements($channel, 'layouts'); + $blocks = get_webpage_elements($channel, 'blocks'); + $o .= replace_macros(get_markup_template('webpage_export_list.tpl'), array( + '$title' => t('Export Webpage Elements'), + '$exportbtn' => t('Export selected'), + '$action' => $_SESSION['export'], // value should be 'zipfile' or 'cloud' + '$pages' => $pages['pages'], + '$layouts' => $layouts['layouts'], + '$blocks' => $blocks['blocks'], + )); + $_SESSION['export'] = null; + return $o; + + default : + $_SESSION['action'] = null; + break; + } + + + if (App::$is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if ($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } + + if (!$owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if ($r) { + $owner = intval($r[0]['channel_id']); + } + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner, $ob_hash); + + if (!$perms['write_pages']) { + notice(t('Permission denied.') . EOL); + return; + } + + $mimetype = (($_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner, 'system', 'page_mimetype')); + + $layout = (($_REQUEST['layout']) ? $_REQUEST['layout'] : get_pconfig($owner, 'system', 'page_layout')); + + // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages + // Nickname is set to the observers xchan, and profile_uid to the owner's. + // This lets you post pages at other people's channels. + + if ((!$channel) && ($uid) && ($uid == App::$profile_uid)) { + $channel = App::get_channel(); + } + if ($channel) { + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + } else { + $channel_acl = ['allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '']; + } + + + $is_owner = ($uid && $uid == $owner); + + $o = ''; + + $x = array( + 'webpage' => ITEM_TYPE_WEBPAGE, + 'is_owner' => true, + 'nickname' => App::$profile['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => (($is_owner) ? populate_acl($channel_acl, false, PermissionDescription::fromGlobalPermission('view_pages')) : ''), + 'permissions' => $channel_acl, + 'showacl' => (($is_owner) ? true : false), + 'visitor' => true, + 'hide_location' => true, + 'hide_voting' => true, + 'profile_uid' => intval($owner), + 'mimetype' => $mimetype, + 'mimeselect' => true, + 'layout' => $layout, + 'layoutselect' => true, + 'expanded' => true, + 'novoting' => true, + 'bbco_autocomplete' => 'bbcode', + 'bbcode' => true + ); + + if ($_REQUEST['title']) + $x['title'] = $_REQUEST['title']; + if ($_REQUEST['body']) + $x['body'] = $_REQUEST['body']; + if ($_REQUEST['pagetitle']) + $x['pagetitle'] = $_REQUEST['pagetitle']; + + + // Get a list of webpages. We can't display all them because endless scroll makes that unusable, + // so just list titles and an edit link. + + + $sql_extra = item_permissions_sql($owner); + + $r = q("select * from iconfig left join item on iconfig.iid = item.id where item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc", - intval($owner), - intval(ITEM_TYPE_WEBPAGE) - ); + intval($owner), + intval(ITEM_TYPE_WEBPAGE) + ); - if(! $r) - $x['pagetitle'] = 'home'; + if (!$r) + $x['pagetitle'] = 'home'; - $editor = status_editor($x); + $editor = status_editor($x); - $pages = null; - - if($r) { - $pages = []; - foreach($r as $rr) { - unobscure($rr); - - $lockstate = (($rr['allow_cid'] || $rr['allow_gid'] || $rr['deny_cid'] || $rr['deny_gid']) ? 'lock' : 'unlock'); - - $element_arr = array( - 'type' => 'webpage', - 'title' => $rr['title'], - 'body' => $rr['body'], - 'created' => $rr['created'], - 'edited' => $rr['edited'], - 'mimetype' => $rr['mimetype'], - 'pageurl' => str_replace('%2f','/',$rr['v']), - 'pagetitle' => urldecode($rr['v']), - 'mid' => $rr['mid'], - 'layout_mid' => $rr['layout_mid'] - ); - $pages[$rr['iid']][] = array( - 'url' => $rr['iid'], - 'pageurl' => str_replace('%2f','/',$rr['v']), - 'pagetitle' => urldecode($rr['v']), - 'title' => $rr['title'], - 'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']), - 'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']), - 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]', - 'lockstate' => $lockstate - ); - } - } - - - //Build the base URL for edit links - $url = z_root() . '/editwebpage/' . $which; - - $o .= replace_macros(get_markup_template('webpagelist.tpl'), array( - '$listtitle' => t('Webpages'), - '$baseurl' => $url, - '$create' => t('Create'), - '$edit' => t('Edit'), - '$share' => t('Share'), - '$delete' => t('Delete'), - '$pages' => $pages, - '$channel' => $which, - '$editor' => $editor, - '$view' => t('View'), - '$preview' => t('Preview'), - '$actions_txt' => t('Actions'), - '$pagelink_txt' => t('Page Link'), - '$title_txt' => t('Page Title'), - '$created_txt' => t('Created'), - '$edited_txt' => t('Edited') - )); - - return $o; - } - - function post() { - $action = $_REQUEST['action']; - if( $action ){ - switch ($action) { - case 'scan': - - // the state of this variable tracks whether website files have been scanned (null, true, false) - $cloud = null; - - // Website files are to be imported from an uploaded zip file - if(($_FILES) && array_key_exists('zip_file',$_FILES) && isset($_POST['w_upload'])) { - $source = $_FILES["zip_file"]["tmp_name"]; - $type = $_FILES["zip_file"]["type"]; - $okay = false; - $accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed'); - foreach ($accepted_types as $mime_type) { - if ($mime_type == $type) { - $okay = true; - break; - } - } - if(!$okay) { - notice( t('Invalid file type.') . EOL); - return; - } - $zip = new ZipArchive(); - if ($zip->open($source) === true) { - $tmp_folder_name = random_string(5); - $website = dirname($source) . '/' . $tmp_folder_name; - $zip->extractTo($website); // change this to the correct site path - $zip->close(); - @unlink($source); // delete the compressed file now that the content has been extracted - $cloud = false; - } else { - notice( t('Error opening zip file') . EOL); - return null; - } - } + $pages = null; - // Website files are to be imported from the channel cloud files - if (($_POST) && array_key_exists('path',$_POST) && isset($_POST['cloudsubmit'])) { - - $channel = App::get_channel(); - $dirpath = get_dirpath_by_cloudpath($channel, $_POST['path']); - if(!$dirpath) { - notice( t('Invalid folder path.') . EOL); - return null; - } - $cloud = true; - - } - - // If the website files were uploaded or specified in the cloud files, then $cloud - // should be either true or false - if ($cloud !== null) { - require_once('include/import.php'); - $elements = []; - if($cloud) { - $path = $_POST['path']; - } else { - $path = $website; - } - $elements['pages'] = scan_webpage_elements($path, 'page', $cloud); - $elements['layouts'] = scan_webpage_elements($path, 'layout', $cloud); - $elements['blocks'] = scan_webpage_elements($path, 'block', $cloud); - $_SESSION['blocks'] = $elements['blocks']; - $_SESSION['layouts'] = $elements['layouts']; - $_SESSION['pages'] = $elements['pages']; - if(!(empty($elements['pages']) && empty($elements['blocks']) && empty($elements['layouts']))) { - //info( t('Webpages elements detected.') . EOL); - $_SESSION['action'] = 'import'; - } else { - notice( t('No webpage elements detected.') . EOL); - $_SESSION['action'] = null; - } - - } - - // If the website elements were imported from a zip file, delete the temporary decompressed files - if ($cloud === false && $website && $elements) { - $_SESSION['tempimportpath'] = $website; - //rrmdir($website); // Delete the temporary decompressed files - } - - break; - - case 'importselected': - require_once('include/import.php'); - $channel = App::get_channel(); - - // Import layout first so that pages that reference new layouts will find - // the mid of layout items in the database - - // Obtain the user-selected layouts to import and import them - $checkedlayouts = $_POST['layout']; - $layouts = []; - if (!empty($checkedlayouts)) { - foreach ($checkedlayouts as $name) { - foreach ($_SESSION['layouts'] as &$layout) { - if ($layout['name'] === $name) { - $layout['import'] = 1; - $layoutstoimport[] = $layout; - } - } - } - foreach ($layoutstoimport as $elementtoimport) { - $layouts[] = import_webpage_element($elementtoimport, $channel, 'layout'); - } - } - $_SESSION['import_layouts'] = $layouts; - - // Obtain the user-selected blocks to import and import them - $checkedblocks = $_POST['block']; - $blocks = []; - if (!empty($checkedblocks)) { - foreach ($checkedblocks as $name) { - foreach ($_SESSION['blocks'] as &$block) { - if ($block['name'] === $name) { - $block['import'] = 1; - $blockstoimport[] = $block; - } - } - } - foreach ($blockstoimport as $elementtoimport) { - $blocks[] = import_webpage_element($elementtoimport, $channel, 'block'); - } - } - $_SESSION['import_blocks'] = $blocks; - - // Obtain the user-selected pages to import and import them - $checkedpages = $_POST['page']; + if ($r) { $pages = []; - if (!empty($checkedpages)) { - foreach ($checkedpages as $pagelink) { - foreach ($_SESSION['pages'] as &$page) { - if ($page['pagelink'] === $pagelink) { - $page['import'] = 1; - $pagestoimport[] = $page; + foreach ($r as $rr) { + unobscure($rr); + + $lockstate = (($rr['allow_cid'] || $rr['allow_gid'] || $rr['deny_cid'] || $rr['deny_gid']) ? 'lock' : 'unlock'); + + $element_arr = array( + 'type' => 'webpage', + 'title' => $rr['title'], + 'body' => $rr['body'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'mimetype' => $rr['mimetype'], + 'pageurl' => str_replace('%2f', '/', $rr['v']), + 'pagetitle' => urldecode($rr['v']), + 'mid' => $rr['mid'], + 'layout_mid' => $rr['layout_mid'] + ); + $pages[$rr['iid']][] = array( + 'url' => $rr['iid'], + 'pageurl' => str_replace('%2f', '/', $rr['v']), + 'pagetitle' => urldecode($rr['v']), + 'title' => $rr['title'], + 'created' => datetime_convert('UTC', date_default_timezone_get(), $rr['created']), + 'edited' => datetime_convert('UTC', date_default_timezone_get(), $rr['edited']), + 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]', + 'lockstate' => $lockstate + ); + } + } + + + //Build the base URL for edit links + $url = z_root() . '/editwebpage/' . $which; + + $o .= replace_macros(get_markup_template('webpagelist.tpl'), array( + '$listtitle' => t('Webpages'), + '$baseurl' => $url, + '$create' => t('Create'), + '$edit' => t('Edit'), + '$share' => t('Share'), + '$delete' => t('Delete'), + '$pages' => $pages, + '$channel' => $which, + '$editor' => $editor, + '$view' => t('View'), + '$preview' => t('Preview'), + '$actions_txt' => t('Actions'), + '$pagelink_txt' => t('Page Link'), + '$title_txt' => t('Page Title'), + '$created_txt' => t('Created'), + '$edited_txt' => t('Edited') + )); + + return $o; + } + + public function post() + { + $action = $_REQUEST['action']; + if ($action) { + switch ($action) { + case 'scan': + + // the state of this variable tracks whether website files have been scanned (null, true, false) + $cloud = null; + + // Website files are to be imported from an uploaded zip file + if (($_FILES) && array_key_exists('zip_file', $_FILES) && isset($_POST['w_upload'])) { + $source = $_FILES["zip_file"]["tmp_name"]; + $type = $_FILES["zip_file"]["type"]; + $okay = false; + $accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed'); + foreach ($accepted_types as $mime_type) { + if ($mime_type == $type) { + $okay = true; + break; + } + } + if (!$okay) { + notice(t('Invalid file type.') . EOL); + return; + } + $zip = new ZipArchive(); + if ($zip->open($source) === true) { + $tmp_folder_name = random_string(5); + $website = dirname($source) . '/' . $tmp_folder_name; + $zip->extractTo($website); // change this to the correct site path + $zip->close(); + @unlink($source); // delete the compressed file now that the content has been extracted + $cloud = false; + } else { + notice(t('Error opening zip file') . EOL); + return null; } } - } - foreach ($pagestoimport as $elementtoimport) { - $pages[] = import_webpage_element($elementtoimport, $channel, 'page'); - } - } - $_SESSION['import_pages'] = $pages; - if(!(empty($_SESSION['import_pages']) && empty($_SESSION['import_blocks']) && empty($_SESSION['import_layouts']))) { - info( t('Import complete.') . EOL); - } - if(isset($_SESSION['tempimportpath'])) { - rrmdir($_SESSION['tempimportpath']); // Delete the temporary decompressed files - unset($_SESSION['tempimportpath']); - } - break; - - case 'exportzipfile': - - if(isset($_POST['w_download'])) { - $_SESSION['action'] = 'export_select_list'; - $_SESSION['export'] = 'zipfile'; - if(isset($_POST['zipfilename']) && $_POST['zipfilename'] !== '') { - $filename = filter_var($_POST['zipfilename'], FILTER_SANITIZE_ENCODED); - } else { - $filename = 'website.zip'; - } - $_SESSION['zipfilename'] = $filename; - - } - - break; - - case 'exportcloud': - if(isset($_POST['exportcloudpath']) && $_POST['exportcloudpath'] !== '') { - $_SESSION['action'] = 'export_select_list'; - $_SESSION['export'] = 'cloud'; - $_SESSION['exportcloudpath'] = filter_var($_POST['exportcloudpath'], FILTER_SANITIZE_ENCODED); - } - - break; - - case 'cloud': - case 'zipfile': - - $channel = App::get_channel(); - - $tmp_folder_name = random_string(10); - $zip_folder_name = random_string(10); - $zip_filename = $_SESSION['zipfilename']; - $tmp_folderpath = '/tmp/' . $tmp_folder_name; - $zip_folderpath = '/tmp/' . $zip_folder_name; - if (!mkdir($zip_folderpath, 0770, false)) { - logger('Error creating zip file export folder: ' . $zip_folderpath, LOGGER_NORMAL); - json_return_and_die(array('message' => 'Error creating zip file export folder')); - } - $zip_filepath = '/tmp/' . $zip_folder_name . '/' . $zip_filename; - - $checkedblocks = $_POST['block']; - $blocks = []; - if (!empty($checkedblocks)) { - foreach ($checkedblocks as $mid) { - $b = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + + // Website files are to be imported from the channel cloud files + if (($_POST) && array_key_exists('path', $_POST) && isset($_POST['cloudsubmit'])) { + + $channel = App::get_channel(); + $dirpath = get_dirpath_by_cloudpath($channel, $_POST['path']); + if (!$dirpath) { + notice(t('Invalid folder path.') . EOL); + return null; + } + $cloud = true; + + } + + // If the website files were uploaded or specified in the cloud files, then $cloud + // should be either true or false + if ($cloud !== null) { + require_once('include/import.php'); + $elements = []; + if ($cloud) { + $path = $_POST['path']; + } else { + $path = $website; + } + $elements['pages'] = scan_webpage_elements($path, 'page', $cloud); + $elements['layouts'] = scan_webpage_elements($path, 'layout', $cloud); + $elements['blocks'] = scan_webpage_elements($path, 'block', $cloud); + $_SESSION['blocks'] = $elements['blocks']; + $_SESSION['layouts'] = $elements['layouts']; + $_SESSION['pages'] = $elements['pages']; + if (!(empty($elements['pages']) && empty($elements['blocks']) && empty($elements['layouts']))) { + //info( t('Webpages elements detected.') . EOL); + $_SESSION['action'] = 'import'; + } else { + notice(t('No webpage elements detected.') . EOL); + $_SESSION['action'] = null; + } + + } + + // If the website elements were imported from a zip file, delete the temporary decompressed files + if ($cloud === false && $website && $elements) { + $_SESSION['tempimportpath'] = $website; + //rrmdir($website); // Delete the temporary decompressed files + } + + break; + + case 'importselected': + require_once('include/import.php'); + $channel = App::get_channel(); + + // Import layout first so that pages that reference new layouts will find + // the mid of layout items in the database + + // Obtain the user-selected layouts to import and import them + $checkedlayouts = $_POST['layout']; + $layouts = []; + if (!empty($checkedlayouts)) { + foreach ($checkedlayouts as $name) { + foreach ($_SESSION['layouts'] as &$layout) { + if ($layout['name'] === $name) { + $layout['import'] = 1; + $layoutstoimport[] = $layout; + } + } + } + foreach ($layoutstoimport as $elementtoimport) { + $layouts[] = import_webpage_element($elementtoimport, $channel, 'layout'); + } + } + $_SESSION['import_layouts'] = $layouts; + + // Obtain the user-selected blocks to import and import them + $checkedblocks = $_POST['block']; + $blocks = []; + if (!empty($checkedblocks)) { + foreach ($checkedblocks as $name) { + foreach ($_SESSION['blocks'] as &$block) { + if ($block['name'] === $name) { + $block['import'] = 1; + $blockstoimport[] = $block; + } + } + } + foreach ($blockstoimport as $elementtoimport) { + $blocks[] = import_webpage_element($elementtoimport, $channel, 'block'); + } + } + $_SESSION['import_blocks'] = $blocks; + + // Obtain the user-selected pages to import and import them + $checkedpages = $_POST['page']; + $pages = []; + if (!empty($checkedpages)) { + foreach ($checkedpages as $pagelink) { + foreach ($_SESSION['pages'] as &$page) { + if ($page['pagelink'] === $pagelink) { + $page['import'] = 1; + $pagestoimport[] = $page; + } + } + } + foreach ($pagestoimport as $elementtoimport) { + $pages[] = import_webpage_element($elementtoimport, $channel, 'page'); + } + } + $_SESSION['import_pages'] = $pages; + if (!(empty($_SESSION['import_pages']) && empty($_SESSION['import_blocks']) && empty($_SESSION['import_layouts']))) { + info(t('Import complete.') . EOL); + } + if (isset($_SESSION['tempimportpath'])) { + rrmdir($_SESSION['tempimportpath']); // Delete the temporary decompressed files + unset($_SESSION['tempimportpath']); + } + break; + + case 'exportzipfile': + + if (isset($_POST['w_download'])) { + $_SESSION['action'] = 'export_select_list'; + $_SESSION['export'] = 'zipfile'; + if (isset($_POST['zipfilename']) && $_POST['zipfilename'] !== '') { + $filename = filter_var($_POST['zipfilename'], FILTER_SANITIZE_ENCODED); + } else { + $filename = 'website.zip'; + } + $_SESSION['zipfilename'] = $filename; + + } + + break; + + case 'exportcloud': + if (isset($_POST['exportcloudpath']) && $_POST['exportcloudpath'] !== '') { + $_SESSION['action'] = 'export_select_list'; + $_SESSION['export'] = 'cloud'; + $_SESSION['exportcloudpath'] = filter_var($_POST['exportcloudpath'], FILTER_SANITIZE_ENCODED); + } + + break; + + case 'cloud': + case 'zipfile': + + $channel = App::get_channel(); + + $tmp_folder_name = random_string(10); + $zip_folder_name = random_string(10); + $zip_filename = $_SESSION['zipfilename']; + $tmp_folderpath = '/tmp/' . $tmp_folder_name; + $zip_folderpath = '/tmp/' . $zip_folder_name; + if (!mkdir($zip_folderpath, 0770, false)) { + logger('Error creating zip file export folder: ' . $zip_folderpath, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating zip file export folder')); + } + $zip_filepath = '/tmp/' . $zip_folder_name . '/' . $zip_filename; + + $checkedblocks = $_POST['block']; + $blocks = []; + if (!empty($checkedblocks)) { + foreach ($checkedblocks as $mid) { + $b = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig left join item on item.id = iconfig.iid where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' order by iconfig.v asc limit 1", - dbesc($mid), - intval($channel['channel_id']) - ); - if($b) { - $b = $b[0]; - $blockinfo = array( - 'body' => $b['body'], - 'mimetype' => $b['mimetype'], - 'title' => $b['title'], - 'name' => $b['v'], - 'json' => array( - 'title' => $b['title'], - 'name' => $b['v'], - 'mimetype' => $b['mimetype'], - ) - ); - switch ($blockinfo['mimetype']) { - case 'text/html': - $block_ext = 'html'; - break; - case 'text/bbcode': - $block_ext = 'bbcode'; - break; - case 'text/markdown': - $block_ext = 'md'; - break; - case 'application/x-pdl': - $block_ext = 'pdl'; - break; - case 'application/x-php': - $block_ext = 'php'; - break; - default: - $block_ext = 'bbcode'; - break; - } - $block_filename = $blockinfo['name'] . '.' . $block_ext; - $tmp_blockfolder = $tmp_folderpath . '/blocks/' . $blockinfo['name']; - $block_filepath = $tmp_blockfolder . '/' . $block_filename; - $blockinfo['json']['contentfile'] = $block_filename; - $block_jsonpath = $tmp_blockfolder . '/block.json'; - if (!is_dir($tmp_blockfolder) && !mkdir($tmp_blockfolder, 0770, true)) { - logger('Error creating temp export folder: ' . $tmp_blockfolder, LOGGER_NORMAL); - json_return_and_die(array('message' => 'Error creating temp export folder')); - } - file_put_contents($block_filepath, $blockinfo['body']); - file_put_contents($block_jsonpath, json_encode($blockinfo['json'], JSON_UNESCAPED_SLASHES)); - } - } - } - - $checkedlayouts = $_POST['layout']; - $layouts = []; - if (!empty($checkedlayouts)) { - foreach ($checkedlayouts as $mid) { - $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + dbesc($mid), + intval($channel['channel_id']) + ); + if ($b) { + $b = $b[0]; + $blockinfo = array( + 'body' => $b['body'], + 'mimetype' => $b['mimetype'], + 'title' => $b['title'], + 'name' => $b['v'], + 'json' => array( + 'title' => $b['title'], + 'name' => $b['v'], + 'mimetype' => $b['mimetype'], + ) + ); + switch ($blockinfo['mimetype']) { + case 'text/html': + $block_ext = 'html'; + break; + case 'text/bbcode': + $block_ext = 'bbcode'; + break; + case 'text/markdown': + $block_ext = 'md'; + break; + case 'application/x-pdl': + $block_ext = 'pdl'; + break; + case 'application/x-php': + $block_ext = 'php'; + break; + default: + $block_ext = 'bbcode'; + break; + } + $block_filename = $blockinfo['name'] . '.' . $block_ext; + $tmp_blockfolder = $tmp_folderpath . '/blocks/' . $blockinfo['name']; + $block_filepath = $tmp_blockfolder . '/' . $block_filename; + $blockinfo['json']['contentfile'] = $block_filename; + $block_jsonpath = $tmp_blockfolder . '/block.json'; + if (!is_dir($tmp_blockfolder) && !mkdir($tmp_blockfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_blockfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($block_filepath, $blockinfo['body']); + file_put_contents($block_jsonpath, json_encode($blockinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + + $checkedlayouts = $_POST['layout']; + $layouts = []; + if (!empty($checkedlayouts)) { + foreach ($checkedlayouts as $mid) { + $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig left join item on item.id = iconfig.iid where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", - dbesc($mid), - intval($channel['channel_id']) - ); - if($l) { - $l = $l[0]; - $layoutinfo = array( - 'body' => $l['body'], - 'mimetype' => $l['mimetype'], - 'description' => $l['title'], - 'name' => $l['v'], - 'json' => array( - 'description' => $l['title'], - 'name' => $l['v'], - 'mimetype' => $l['mimetype'], - ) - ); - switch ($layoutinfo['mimetype']) { - case 'text/bbcode': - default: - $layout_ext = 'bbcode'; - break; - } - $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; - $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; - $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; - $layoutinfo['json']['contentfile'] = $layout_filename; - $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; - if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { - logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); - json_return_and_die(array('message' => 'Error creating temp export folder')); - } - file_put_contents($layout_filepath, $layoutinfo['body']); - file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); - } - } - } - - $checkedpages = $_POST['page']; - $pages = []; - if (!empty($checkedpages)) { - foreach ($checkedpages as $mid) { - - $p = q("select * from iconfig left join item on iconfig.iid = item.id + dbesc($mid), + intval($channel['channel_id']) + ); + if ($l) { + $l = $l[0]; + $layoutinfo = array( + 'body' => $l['body'], + 'mimetype' => $l['mimetype'], + 'description' => $l['title'], + 'name' => $l['v'], + 'json' => array( + 'description' => $l['title'], + 'name' => $l['v'], + 'mimetype' => $l['mimetype'], + ) + ); + switch ($layoutinfo['mimetype']) { + case 'text/bbcode': + default: + $layout_ext = 'bbcode'; + break; + } + $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; + $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; + $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; + $layoutinfo['json']['contentfile'] = $layout_filename; + $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; + if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($layout_filepath, $layoutinfo['body']); + file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + + $checkedpages = $_POST['page']; + $pages = []; + if (!empty($checkedpages)) { + foreach ($checkedpages as $mid) { + + $p = q("select * from iconfig left join item on iconfig.iid = item.id where item.uid = %d and item.mid = '%s' and iconfig.cat = 'system' and iconfig.k = 'WEBPAGE' and item_type = %d", - intval($channel['channel_id']), - dbesc($mid), - intval(ITEM_TYPE_WEBPAGE) - ); - - if($p) { - foreach ($p as $pp) { - // Get the associated layout - $layoutinfo = []; - if($pp['layout_mid']) { - $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig + intval($channel['channel_id']), + dbesc($mid), + intval(ITEM_TYPE_WEBPAGE) + ); + + if ($p) { + foreach ($p as $pp) { + // Get the associated layout + $layoutinfo = []; + if ($pp['layout_mid']) { + $l = q("select iconfig.v, iconfig.k, mimetype, title, body from iconfig left join item on item.id = iconfig.iid where mid = '%s' and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'PDL' order by iconfig.v asc limit 1", - dbesc($pp['layout_mid']), - intval($channel['channel_id']) - ); - if($l) { - $l = $l[0]; - $layoutinfo = array( - 'body' => $l['body'], - 'mimetype' => $l['mimetype'], - 'description' => $l['title'], - 'name' => $l['v'], - 'json' => array( - 'description' => $l['title'], - 'name' => $l['v'], - ) - ); - switch ($layoutinfo['mimetype']) { - case 'text/bbcode': - default: - $layout_ext = 'bbcode'; - break; - } - $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; - $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; - $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; - $layoutinfo['json']['contentfile'] = $layout_filename; - $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; - if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { - logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); - json_return_and_die(array('message' => 'Error creating temp export folder')); - } - file_put_contents($layout_filepath, $layoutinfo['body']); - file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); - } - } - switch ($pp['mimetype']) { - case 'text/html': - $page_ext = 'html'; - break; - case 'text/bbcode': - $page_ext = 'bbcode'; - break; - case 'text/markdown': - $page_ext = 'md'; - break; - case 'application/x-pdl': - $page_ext = 'pdl'; - break; - case 'application/x-php': - $page_ext = 'php'; - break; - default: - break; - } - $pageinfo = array( - 'title' => $pp['title'], - 'body' => $pp['body'], - 'pagelink' => $pp['v'], - 'mimetype' => $pp['mimetype'], - 'contentfile' => $pp['v'] . '.' . $page_ext, - 'layout' => ((x($layoutinfo,'name')) ? $layoutinfo['name'] : ''), - 'json' => array( - 'title' => $pp['title'], - 'pagelink' => $pp['v'], - 'mimetype' => $pp['mimetype'], - 'layout' => ((x($layoutinfo,'name')) ? $layoutinfo['name'] : ''), - ) - ); - $page_filename = $pageinfo['pagelink'] . '.' . $page_ext; - $tmp_pagefolder = $tmp_folderpath . '/pages/' . $pageinfo['pagelink']; - $page_filepath = $tmp_pagefolder . '/' . $page_filename; - $page_jsonpath = $tmp_pagefolder . '/page.json'; - $pageinfo['json']['contentfile'] = $page_filename; - if (!is_dir($tmp_pagefolder) && !mkdir($tmp_pagefolder, 0770, true)) { - logger('Error creating temp export folder: ' . $tmp_pagefolder, LOGGER_NORMAL); - json_return_and_die(array('message' => 'Error creating temp export folder')); - } - file_put_contents($page_filepath, $pageinfo['body']); - file_put_contents($page_jsonpath, json_encode($pageinfo['json'], JSON_UNESCAPED_SLASHES)); - } - } - } - } - if($action === 'zipfile') { - // Generate the zip file - ExtendedZip::zipTree($tmp_folderpath, $zip_filepath, ZipArchive::CREATE); - // Output the file for download - header('Content-Disposition: attachment; filename="' . $zip_filename . '"'); - header("Content-Type: application/zip"); - $success = readfile($zip_filepath); - } elseif ($action === 'cloud') { // Only zipfile or cloud should be possible values for $action here - if(isset($_SESSION['exportcloudpath'])) { - require_once('include/attach.php'); - $cloudpath = urldecode($_SESSION['exportcloudpath']); - $channel = App::get_channel(); - $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); - if(!$dirpath) { - $x = attach_mkdirp($channel, $channel['channel_hash'], array('pathname' => $cloudpath)); - $folder_hash = (($x['success']) ? $x['data']['hash'] : ''); - - if (!$x['success']) { - logger('Failed to create cloud file folder', LOGGER_NORMAL); - } - $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); - if (!is_dir($dirpath)) { - logger('Failed to create cloud file folder', LOGGER_NORMAL); - } - } - - $success = copy_folder_to_cloudfiles($channel, $channel['channel_hash'], $tmp_folderpath, $cloudpath); - } - } - if(!$success) { - logger('Error exporting webpage elements', LOGGER_NORMAL); - } - - rrmdir($zip_folderpath); rrmdir($tmp_folderpath); // delete temporary files - killme(); + dbesc($pp['layout_mid']), + intval($channel['channel_id']) + ); + if ($l) { + $l = $l[0]; + $layoutinfo = array( + 'body' => $l['body'], + 'mimetype' => $l['mimetype'], + 'description' => $l['title'], + 'name' => $l['v'], + 'json' => array( + 'description' => $l['title'], + 'name' => $l['v'], + ) + ); + switch ($layoutinfo['mimetype']) { + case 'text/bbcode': + default: + $layout_ext = 'bbcode'; + break; + } + $layout_filename = $layoutinfo['name'] . '.' . $layout_ext; + $tmp_layoutfolder = $tmp_folderpath . '/layouts/' . $layoutinfo['name']; + $layout_filepath = $tmp_layoutfolder . '/' . $layout_filename; + $layoutinfo['json']['contentfile'] = $layout_filename; + $layout_jsonpath = $tmp_layoutfolder . '/layout.json'; + if (!is_dir($tmp_layoutfolder) && !mkdir($tmp_layoutfolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_layoutfolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($layout_filepath, $layoutinfo['body']); + file_put_contents($layout_jsonpath, json_encode($layoutinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + switch ($pp['mimetype']) { + case 'text/html': + $page_ext = 'html'; + break; + case 'text/bbcode': + $page_ext = 'bbcode'; + break; + case 'text/markdown': + $page_ext = 'md'; + break; + case 'application/x-pdl': + $page_ext = 'pdl'; + break; + case 'application/x-php': + $page_ext = 'php'; + break; + default: + break; + } + $pageinfo = array( + 'title' => $pp['title'], + 'body' => $pp['body'], + 'pagelink' => $pp['v'], + 'mimetype' => $pp['mimetype'], + 'contentfile' => $pp['v'] . '.' . $page_ext, + 'layout' => ((x($layoutinfo, 'name')) ? $layoutinfo['name'] : ''), + 'json' => array( + 'title' => $pp['title'], + 'pagelink' => $pp['v'], + 'mimetype' => $pp['mimetype'], + 'layout' => ((x($layoutinfo, 'name')) ? $layoutinfo['name'] : ''), + ) + ); + $page_filename = $pageinfo['pagelink'] . '.' . $page_ext; + $tmp_pagefolder = $tmp_folderpath . '/pages/' . $pageinfo['pagelink']; + $page_filepath = $tmp_pagefolder . '/' . $page_filename; + $page_jsonpath = $tmp_pagefolder . '/page.json'; + $pageinfo['json']['contentfile'] = $page_filename; + if (!is_dir($tmp_pagefolder) && !mkdir($tmp_pagefolder, 0770, true)) { + logger('Error creating temp export folder: ' . $tmp_pagefolder, LOGGER_NORMAL); + json_return_and_die(array('message' => 'Error creating temp export folder')); + } + file_put_contents($page_filepath, $pageinfo['body']); + file_put_contents($page_jsonpath, json_encode($pageinfo['json'], JSON_UNESCAPED_SLASHES)); + } + } + } + } + if ($action === 'zipfile') { + // Generate the zip file + ExtendedZip::zipTree($tmp_folderpath, $zip_filepath, ZipArchive::CREATE); + // Output the file for download + header('Content-Disposition: attachment; filename="' . $zip_filename . '"'); + header("Content-Type: application/zip"); + $success = readfile($zip_filepath); + } elseif ($action === 'cloud') { // Only zipfile or cloud should be possible values for $action here + if (isset($_SESSION['exportcloudpath'])) { + require_once('include/attach.php'); + $cloudpath = urldecode($_SESSION['exportcloudpath']); + $channel = App::get_channel(); + $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); + if (!$dirpath) { + $x = attach_mkdirp($channel, $channel['channel_hash'], array('pathname' => $cloudpath)); + $folder_hash = (($x['success']) ? $x['data']['hash'] : ''); + + if (!$x['success']) { + logger('Failed to create cloud file folder', LOGGER_NORMAL); + } + $dirpath = get_dirpath_by_cloudpath($channel, $cloudpath); + if (!is_dir($dirpath)) { + logger('Failed to create cloud file folder', LOGGER_NORMAL); + } + } + + $success = copy_folder_to_cloudfiles($channel, $channel['channel_hash'], $tmp_folderpath, $cloudpath); + } + } + if (!$success) { + logger('Error exporting webpage elements', LOGGER_NORMAL); + } + + rrmdir($zip_folderpath); + rrmdir($tmp_folderpath); // delete temporary files + killme(); + + break; + default : + break; + } + + } + + } - break; - default : - break; - } - - } - - } - } diff --git a/Zotlabs/Module/Well_known.php b/Zotlabs/Module/Well_known.php index b4fcddf26..4e3b0cb1e 100644 --- a/Zotlabs/Module/Well_known.php +++ b/Zotlabs/Module/Well_known.php @@ -6,64 +6,65 @@ use Zotlabs\Web\Controller; use Zotlabs\Module\Webfinger; use Zotlabs\Module\Oauthinfo; -class Well_known extends Controller { +class Well_known extends Controller +{ - function init() { - - if (argc() > 1) { - - $arr = [ 'server' => $_SERVER, 'request' => $_REQUEST ]; - call_hooks('well_known', $arr); - - if (! check_siteallowed($_SERVER['REMOTE_ADDR'])) { - logger('well_known: site not allowed. ' . $_SERVER['REMOTE_ADDR']); - killme(); - } - - // from php.net re: REMOTE_HOST: - // Note: Your web server must be configured to create this variable. - // For example in Apache you'll need HostnameLookups On inside httpd.conf - // for it to exist. See also gethostbyaddr(). - - if (get_config('system','siteallowed_remote_host') && (! check_siteallowed($_SERVER['REMOTE_HOST']))) { - logger('well_known: site not allowed. ' . $_SERVER['REMOTE_HOST']); - killme(); - } - - switch(argv(1)) { - - case 'webfinger': - App::$argc -= 1; - array_shift(App::$argv); - App::$argv[0] = 'webfinger'; - $module = new Webfinger(); - $module->init(); - break; - - case 'oauth-authorization-server': - case 'openid-configuration': - App::$argc -= 1; - array_shift(App::$argv); - App::$argv[0] = 'oauthinfo'; - $module = new Oauthinfo(); - $module->init(); - break; + public function init() + { - case 'dnt-policy.txt': - echo file_get_contents('doc/global/dnt-policy.txt'); - killme(); + if (argc() > 1) { - default: - if (file_exists(App::$cmd)) { - echo file_get_contents(App::$cmd); - killme(); - } - elseif (file_exists(App::$cmd . '.php')) - require_once(App::$cmd . '.php'); - break; - } - } - - http_status_exit(404); - } + $arr = ['server' => $_SERVER, 'request' => $_REQUEST]; + call_hooks('well_known', $arr); + + if (!check_siteallowed($_SERVER['REMOTE_ADDR'])) { + logger('well_known: site not allowed. ' . $_SERVER['REMOTE_ADDR']); + killme(); + } + + // from php.net re: REMOTE_HOST: + // Note: Your web server must be configured to create this variable. + // For example in Apache you'll need HostnameLookups On inside httpd.conf + // for it to exist. See also gethostbyaddr(). + + if (get_config('system', 'siteallowed_remote_host') && (!check_siteallowed($_SERVER['REMOTE_HOST']))) { + logger('well_known: site not allowed. ' . $_SERVER['REMOTE_HOST']); + killme(); + } + + switch (argv(1)) { + + case 'webfinger': + App::$argc -= 1; + array_shift(App::$argv); + App::$argv[0] = 'webfinger'; + $module = new Webfinger(); + $module->init(); + break; + + case 'oauth-authorization-server': + case 'openid-configuration': + App::$argc -= 1; + array_shift(App::$argv); + App::$argv[0] = 'oauthinfo'; + $module = new Oauthinfo(); + $module->init(); + break; + + case 'dnt-policy.txt': + echo file_get_contents('doc/global/dnt-policy.txt'); + killme(); + + default: + if (file_exists(App::$cmd)) { + echo file_get_contents(App::$cmd); + killme(); + } elseif (file_exists(App::$cmd . '.php')) + require_once(App::$cmd . '.php'); + break; + } + } + + http_status_exit(404); + } } diff --git a/Zotlabs/Module/Xchan.php b/Zotlabs/Module/Xchan.php index 97baddcce..d856ce5d7 100644 --- a/Zotlabs/Module/Xchan.php +++ b/Zotlabs/Module/Xchan.php @@ -5,45 +5,46 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Xchan extends Controller { +class Xchan extends Controller +{ + + public function get() + { + + $o = '

      ' . t('Xchan Lookup') . '

      '; + + $o .= '
      '; + $o .= t('Lookup xchan beginning with (or webbie): '); + $o .= ''; + $o .= '
      '; + $o .= '

      '; + + if (x($_GET, 'addr')) { + $addr = trim($_GET['addr']); + + $r = q("select * from xchan where xchan_hash like '%s%%' or xchan_addr = '%s' group by xchan_hash", + dbesc($addr), + dbesc($addr) + ); + + if ($r) { + foreach ($r as $rr) { + $o .= str_replace(array("\n", " "), array("
      ", " "), print_r($rr, true)) . EOL; + + $s = q("select * from hubloc where hubloc_hash like '%s'", + dbesc($r[0]['xchan_hash']) + ); + + if ($s) { + foreach ($s as $rrr) + $o .= str_replace(array("\n", " "), array("
      ", " "), print_r($rrr, true)) . EOL; + } + } + } else + notice(t('Not found.') . EOL); + + } + return $o; + } - function get() { - - $o = '

      ' . t('Xchan Lookup') . '

      '; - - $o .= '
      '; - $o .= t('Lookup xchan beginning with (or webbie): '); - $o .= ''; - $o .= '
      '; - $o .= '

      '; - - if(x($_GET, 'addr')) { - $addr = trim($_GET['addr']); - - $r = q("select * from xchan where xchan_hash like '%s%%' or xchan_addr = '%s' group by xchan_hash", - dbesc($addr), - dbesc($addr) - ); - - if($r) { - foreach($r as $rr) { - $o .= str_replace(array("\n", " "), array("
      ", " "), print_r($rr, true)) . EOL; - - $s = q("select * from hubloc where hubloc_hash like '%s'", - dbesc($r[0]['xchan_hash']) - ); - - if($s) { - foreach($s as $rrr) - $o .= str_replace(array("\n", " "), array("
      ", " "), print_r($rrr, true)) . EOL; - } - } - } - else - notice( t('Not found.') . EOL); - - } - return $o; - } - } diff --git a/Zotlabs/Module/Xp.php b/Zotlabs/Module/Xp.php index 23a4e2cea..e7fba797f 100644 --- a/Zotlabs/Module/Xp.php +++ b/Zotlabs/Module/Xp.php @@ -3,61 +3,63 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Xp extends Controller { +class Xp extends Controller +{ - function get() { - if (argc() > 1) { - $path = 'cache/xp/' . substr(argv(1),0,2) . '/' . substr(argv(1),2,2) . '/' . argv(1); + public function get() + { + if (argc() > 1) { + $path = 'cache/xp/' . substr(argv(1), 0, 2) . '/' . substr(argv(1), 2, 2) . '/' . argv(1); - if (! file_exists($path)) { - // no longer cached for some reason, perhaps expired - $resolution = substr(argv(1),(-2),2); - if ($resolution && substr($resolution,0,1) === '-') { - switch (substr($resolution,1,1)) { - case '4': - $path = get_default_profile_photo(); - break; - case '5': - $path = get_default_profile_photo(80); - break; - case '6': - $path = get_default_profile_photo(48); - break; - default: - break; - } - } - } - - if (! file_exists($path)) { - http_status_exit(404,'Not found'); - } - - $x = @getimagesize($path); - if ($x) { - header('Content-Type: ' . $x['mime']); - } + if (!file_exists($path)) { + // no longer cached for some reason, perhaps expired + $resolution = substr(argv(1), (-2), 2); + if ($resolution && substr($resolution, 0, 1) === '-') { + switch (substr($resolution, 1, 1)) { + case '4': + $path = get_default_profile_photo(); + break; + case '5': + $path = get_default_profile_photo(80); + break; + case '6': + $path = get_default_profile_photo(48); + break; + default: + break; + } + } + } - $cache = intval(get_config('system','photo_cache_time')); - if (! $cache) { - $cache = (3600 * 24); // 1 day - } - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache) . ' GMT'); - // Set browser cache age as $cache. But set timeout of 'shared caches' - // much lower in the event that infrastructure caching is present. - $smaxage = intval($cache/12); - header('Cache-Control: s-maxage=' . $smaxage . '; max-age=' . $cache . ';'); - - $infile = fopen($path,'rb'); - $outfile = fopen('php://output','wb'); - if ($infile && $outfile) { - pipe_streams($infile,$outfile); - } - fclose($infile); - fclose($outfile); - killme(); - } + if (!file_exists($path)) { + http_status_exit(404, 'Not found'); + } - http_status_exit(404,'Not found'); - } + $x = @getimagesize($path); + if ($x) { + header('Content-Type: ' . $x['mime']); + } + + $cache = intval(get_config('system', 'photo_cache_time')); + if (!$cache) { + $cache = (3600 * 24); // 1 day + } + header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $cache) . ' GMT'); + // Set browser cache age as $cache. But set timeout of 'shared caches' + // much lower in the event that infrastructure caching is present. + $smaxage = intval($cache / 12); + header('Cache-Control: s-maxage=' . $smaxage . '; max-age=' . $cache . ';'); + + $infile = fopen($path, 'rb'); + $outfile = fopen('php://output', 'wb'); + if ($infile && $outfile) { + pipe_streams($infile, $outfile); + } + fclose($infile); + fclose($outfile); + killme(); + } + + http_status_exit(404, 'Not found'); + } } diff --git a/Zotlabs/Module/Xref.php b/Zotlabs/Module/Xref.php index e6c4e4091..ea1bd24f2 100644 --- a/Zotlabs/Module/Xref.php +++ b/Zotlabs/Module/Xref.php @@ -4,25 +4,27 @@ namespace Zotlabs\Module; use Zotlabs\Web\Controller; -class Xref extends Controller { +class Xref extends Controller +{ + + public function init() + { + // Sets a referral URL using an xchan directly + // Link format: example.com/xref/[xchan]/[TargetURL] + // Target URL is optional. + // Cookie lasts 24 hours to survive a browser restart. Contains no personal + // information at all - just somebody else's xchan. + $referrer = argv(1); + $expire = time() + 60 * 60 * 2; + $path = 'xref'; + setcookie($path, $referrer, $expire, "/"); + $url = ''; + + if (argc() > 2) + $url = argv(2); + + goaway(z_root() . '/' . $url); + + } - function init() { - // Sets a referral URL using an xchan directly - // Link format: example.com/xref/[xchan]/[TargetURL] - // Target URL is optional. - // Cookie lasts 24 hours to survive a browser restart. Contains no personal - // information at all - just somebody else's xchan. - $referrer = argv(1); - $expire=time()+60*60*2; - $path = 'xref'; - setcookie($path, $referrer, $expire, "/"); - $url = ''; - - if (argc() > 2) - $url = argv(2); - - goaway (z_root() . '/' . $url); - - } - } diff --git a/Zotlabs/Module/Zot.php b/Zotlabs/Module/Zot.php index 6594287d1..bcb217d63 100644 --- a/Zotlabs/Module/Zot.php +++ b/Zotlabs/Module/Zot.php @@ -16,12 +16,13 @@ use Zotlabs\Zot6\Zot6Handler; * @brief Zot module. * */ +class Zot extends Controller +{ -class Zot extends Controller { - - function init() { - $zot = new Receiver(new Zot6Handler()); - json_return_and_die($zot->run(),'application/x-zot+json'); - } + public function init() + { + $zot = new Receiver(new Zot6Handler()); + json_return_and_die($zot->run(), 'application/x-zot+json'); + } } diff --git a/Zotlabs/Module/Zot_probe.php b/Zotlabs/Module/Zot_probe.php index 7a800dc31..9e6668881 100644 --- a/Zotlabs/Module/Zot_probe.php +++ b/Zotlabs/Module/Zot_probe.php @@ -9,48 +9,49 @@ use Zotlabs\Lib\Zotfinger; use Zotlabs\Web\Controller; use Zotlabs\Web\HTTPSig; -class Zot_probe extends Controller { +class Zot_probe extends Controller +{ - function get() { + public function get() + { - $o = replace_macros(get_markup_template('zot_probe.tpl'), [ - '$page_title' => t('Zot6 Probe Diagnostic'), - '$resource' => [ 'resource', t('Object URL') , $_REQUEST['resource'], EMPTY_STR ], - '$authf' => [ 'authf', t('Authenticated fetch'), $_REQUEST['authf'], EMPTY_STR, [ t('No'), t('Yes') ] ], - '$submit' => t('Submit') - ]); + $o = replace_macros(get_markup_template('zot_probe.tpl'), [ + '$page_title' => t('Zot6 Probe Diagnostic'), + '$resource' => ['resource', t('Object URL'), $_REQUEST['resource'], EMPTY_STR], + '$authf' => ['authf', t('Authenticated fetch'), $_REQUEST['authf'], EMPTY_STR, [t('No'), t('Yes')]], + '$submit' => t('Submit') + ]); - if(x($_GET,'resource')) { - $resource = $_GET['resource']; - $channel = (($_GET['authf']) ? App::get_channel() : null); + if (x($_GET, 'resource')) { + $resource = $_GET['resource']; + $channel = (($_GET['authf']) ? App::get_channel() : null); - if(strpos($resource,'x-zot:') === 0) { - $x = ZotURL::fetch($resource,$channel); - } - else { - $x = Zotfinger::exec($resource,$channel); + if (strpos($resource, 'x-zot:') === 0) { + $x = ZotURL::fetch($resource, $channel); + } else { + $x = Zotfinger::exec($resource, $channel); - $o .= '
      ' . htmlspecialchars(print_array($x)) . '
      '; + $o .= '
      ' . htmlspecialchars(print_array($x)) . '
      '; - $headers = 'Accept: application/x-zot+json, application/jrd+json, application/json'; + $headers = 'Accept: application/x-zot+json, application/jrd+json, application/json'; - $redirects = 0; - $x = z_fetch_url($resource,true,$redirects, [ 'headers' => [ $headers ]]); - } + $redirects = 0; + $x = z_fetch_url($resource, true, $redirects, ['headers' => [$headers]]); + } - if($x['success']) { + if ($x['success']) { - $o .= '
      ' . htmlspecialchars($x['header']) . '
      ' . EOL; + $o .= '
      ' . htmlspecialchars($x['header']) . '
      ' . EOL; - $o .= 'verify returns: ' . str_replace("\n",EOL,print_r(HTTPSig::verify($x, EMPTY_STR, 'zot6'),true)) . EOL; + $o .= 'verify returns: ' . str_replace("\n", EOL, print_r(HTTPSig::verify($x, EMPTY_STR, 'zot6'), true)) . EOL; - $o .= '
      ' . htmlspecialchars(json_encode(json_decode($x['body']),JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)) . '
      ' . EOL; + $o .= '
      ' . htmlspecialchars(json_encode(json_decode($x['body']), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)) . '
      ' . EOL; - } + } + + } + return $o; + } - } - return $o; - } - } diff --git a/Zotlabs/Module/Zotfinger.php b/Zotlabs/Module/Zotfinger.php index 9411bab82..5185312ed 100644 --- a/Zotlabs/Module/Zotfinger.php +++ b/Zotlabs/Module/Zotfinger.php @@ -15,29 +15,31 @@ use Zotlabs\Web\Controller; use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Zotfinger as Zfinger; -class Zotfinger extends Controller { +class Zotfinger extends Controller +{ - function get() { + public function get() + { - $o = replace_macros(get_markup_template('zotfinger.tpl'), [ - '$page_title' => t('Zotfinger Diagnostic'), - '$resource' => [ 'resource', t('Lookup URL') , $_GET['resource'], EMPTY_STR ], - '$submit' => t('Submit') - ]); + $o = replace_macros(get_markup_template('zotfinger.tpl'), [ + '$page_title' => t('Zotfinger Diagnostic'), + '$resource' => ['resource', t('Lookup URL'), $_GET['resource'], EMPTY_STR], + '$submit' => t('Submit') + ]); - if ($_GET['resource']) { - $channel = App::get_channel(); - $resource = trim(escape_tags($_GET['resource'])); - $do_import = ((intval($_GET['import']) && is_site_admin()) ? true : false); - - $j = Zfinger::exec($resource,$channel); + if ($_GET['resource']) { + $channel = App::get_channel(); + $resource = trim(escape_tags($_GET['resource'])); + $do_import = ((intval($_GET['import']) && is_site_admin()) ? true : false); + + $j = Zfinger::exec($resource, $channel); + + if ($do_import && $j) { + $x = Libzot::import_xchan($j['data']); + } + $o .= '
      ' . str_replace("\n", '
      ', print_array($j)) . '
      '; + } + return $o; + } - if ($do_import && $j) { - $x = Libzot::import_xchan($j['data']); - } - $o .= '
      ' .  str_replace("\n",'
      ',print_array($j)) . '
      '; - } - return $o; - } - } diff --git a/Zotlabs/Photo/PhotoDriver.php b/Zotlabs/Photo/PhotoDriver.php index d5439b9dc..ffc631fe0 100644 --- a/Zotlabs/Photo/PhotoDriver.php +++ b/Zotlabs/Photo/PhotoDriver.php @@ -24,17 +24,17 @@ abstract class PhotoDriver { protected $image; /** - * @var integer + * @var int */ protected $width; /** - * @var integer + * @var int */ protected $height; /** - * @var boolean + * @var bool */ protected $valid; @@ -72,7 +72,7 @@ abstract class PhotoDriver { * @fixme Shouldn't his method be protected, because outside of the current * driver it makes no sense at all because of the different return values. * - * @return boolean|resource|Imagick + * @return bool|resource|Imagick * false on failure, a PHP image resource for GD driver, an \Imagick object * for ImageMagick driver. */ @@ -95,7 +95,7 @@ abstract class PhotoDriver { * @param int $w width of region * @param int $h height of region * - * @return boolean|void false on failure + * @return bool|void false on failure */ abstract public function cropImageRect($maxx, $maxy, $x, $y, $w, $h); @@ -134,7 +134,7 @@ abstract class PhotoDriver { /** * @brief Is it a valid image object. * - * @return boolean + * @return bool */ public function is_valid() { return $this->valid; @@ -143,7 +143,7 @@ abstract class PhotoDriver { /** * @brief Get the width of the image. * - * @return boolean|number Width of image in pixels, or false on failure + * @return bool|number Width of image in pixels, or false on failure */ public function getWidth() { if (! $this->is_valid()) { @@ -155,7 +155,7 @@ abstract class PhotoDriver { /** * @brief Get the height of the image. * - * @return boolean|number Height of image in pixels, or false on failure + * @return bool|number Height of image in pixels, or false on failure */ public function getHeight() { if (! $this->is_valid()) { @@ -168,7 +168,7 @@ abstract class PhotoDriver { * @brief Saves the image resource to a file in filesystem. * * @param string $path Path and filename where to save the image - * @return boolean False on failure, otherwise true + * @return bool False on failure, otherwise true */ public function saveImage($path, $animated = true) { if (! $this->is_valid()) { @@ -180,7 +180,7 @@ abstract class PhotoDriver { /** * @brief Return mimetype of the image resource. * - * @return boolean|string False on failure, otherwise mimetype. + * @return bool|string False on failure, otherwise mimetype. */ public function getType() { if (! $this->is_valid()) { @@ -192,7 +192,7 @@ abstract class PhotoDriver { /** * @brief Return file extension of the image resource. * - * @return boolean|string False on failure, otherwise file extension. + * @return bool|string False on failure, otherwise file extension. */ public function getExt() { if (! $this->is_valid()) { @@ -205,10 +205,10 @@ abstract class PhotoDriver { * @brief Scale image to max pixel size in either dimension. * * @param int $max maximum pixel size in either dimension - * @param boolean $float_height (optional) + * @param bool $float_height (optional) * If true allow height to float to any length on tall images, constraining * only the width - * @return boolean|void false on failure, otherwise void + * @return bool|void false on failure, otherwise void */ public function scaleImage($max, $float_height = true) { if (! $this->is_valid()) { @@ -318,7 +318,7 @@ abstract class PhotoDriver { * @brief Scales image to a square. * * @param int $dim Pixel of square image - * @return boolean|void false on failure, otherwise void + * @return bool|void false on failure, otherwise void */ public function scaleImageSquare($dim) { if (! $this->is_valid()) { @@ -338,7 +338,7 @@ abstract class PhotoDriver { * @param int $w width of region * @param int $h height of region * - * @return boolean|void false on failure + * @return bool|void false on failure */ public function cropImage($max, $x, $y, $w, $h) { if (! $this->is_valid()) { @@ -351,7 +351,7 @@ abstract class PhotoDriver { * @brief Reads exif data from a given filename. * * @param string $filename - * @return boolean|array + * @return bool|array */ public function exif($filename) { if ((! function_exists('exif_read_data')) || (! in_array($this->getType(), ['image/jpeg', 'image/tiff']))) { @@ -381,7 +381,7 @@ abstract class PhotoDriver { * @brief Orients current image based on exif orientation information. * * @param array $exif - * @return boolean true if oriented, otherwise false + * @return bool true if oriented, otherwise false */ public function orient($exif) { if (! ($this->is_valid() && $exif)) { @@ -431,8 +431,8 @@ abstract class PhotoDriver { * @brief Save photo to database. * * @param array $arr - * @param boolean $skipcheck (optional) default false - * @return boolean|array + * @param bool $skipcheck (optional) default false + * @return bool|array */ public function save($arr, $skipcheck = false) { if (! ($skipcheck || $this->is_valid())) { @@ -520,7 +520,7 @@ abstract class PhotoDriver { * * @param array $arr * @param scale int - * @return boolean|array + * @return bool|array */ public function storeThumbnail($arr, $scale = 0, $animated = true) { diff --git a/Zotlabs/Photo/PhotoGd.php b/Zotlabs/Photo/PhotoGd.php index 450d82bc6..d16bd4244 100644 --- a/Zotlabs/Photo/PhotoGd.php +++ b/Zotlabs/Photo/PhotoGd.php @@ -77,7 +77,7 @@ class PhotoGd extends PhotoDriver { * * @see \Zotlabs\Photo\PhotoDriver::getImage() * - * @return boolean|resource + * @return bool|resource */ public function getImage() { if (! $this->is_valid()) { diff --git a/Zotlabs/Photo/PhotoImagick.php b/Zotlabs/Photo/PhotoImagick.php index e645f654e..e77837262 100644 --- a/Zotlabs/Photo/PhotoImagick.php +++ b/Zotlabs/Photo/PhotoImagick.php @@ -130,7 +130,7 @@ class PhotoImagick extends PhotoDriver { * * @see \Zotlabs\Photo\PhotoDriver::getImage() * - * @return boolean|Imagick + * @return bool|Imagick */ public function getImage() { if (! $this->is_valid()) { diff --git a/Zotlabs/Render/Comanche.php b/Zotlabs/Render/Comanche.php index 41cb55c9a..4a39a0f01 100644 --- a/Zotlabs/Render/Comanche.php +++ b/Zotlabs/Render/Comanche.php @@ -20,666 +20,666 @@ require_once('include/menu.php'); * page. The various regions have names and these names can change depending on * what layout template you choose. */ +class Comanche +{ -class Comanche { + public function parse($s, $pass = 0) + { + $matches = []; - function parse($s, $pass = 0) { - $matches = []; + $cnt = preg_match_all("/\[comment\](.*?)\[\/comment\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], '', $s); + } + } - $cnt = preg_match_all("/\[comment\](.*?)\[\/comment\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0], '', $s); - } - } + /* + * This section supports the "switch" statement of the form given by the following + * example. The [default][/default] block must be the last in the arbitrary + * list of cases. The first case that matches the switch variable is used + * and the rest are not evaluated. + * + * [switch observer.language] + * [case de] + * [block]german-content[/block] + * [/case] + * [case es] + * [block]spanish-content[/block] + * [/case] + * [default] + * [block]english-content[/block] + * [/default] + * [/switch] + */ - /* - * This section supports the "switch" statement of the form given by the following - * example. The [default][/default] block must be the last in the arbitrary - * list of cases. The first case that matches the switch variable is used - * and the rest are not evaluated. - * - * [switch observer.language] - * [case de] - * [block]german-content[/block] - * [/case] - * [case es] - * [block]spanish-content[/block] - * [/case] - * [default] - * [block]english-content[/block] - * [/default] - * [/switch] - */ + $cnt = preg_match_all("/\[switch (.*?)\](.*?)\[default\](.*?)\[\/default\]\s*\[\/switch\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $switch_done = 0; + $switch_var = $this->get_condition_var($mtch[1]); + $default = $mtch[3]; + $cases = []; + $cntt = preg_match_all("/\[case (.*?)\](.*?)\[\/case\]/ism", $mtch[2], $cases, PREG_SET_ORDER); + if ($cntt) { + foreach ($cases as $case) { + if ($case[1] === $switch_var) { + $switch_done = 1; + $s = str_replace($mtch[0], $case[2], $s); + break; + } + } + if ($switch_done === 0) { + $s = str_replace($mtch[0], $default, $s); + } + } + } + } - $cnt = preg_match_all("/\[switch (.*?)\](.*?)\[default\](.*?)\[\/default\]\s*\[\/switch\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $switch_done = 0; - $switch_var = $this->get_condition_var($mtch[1]); - $default = $mtch[3]; - $cases = []; - $cntt = preg_match_all("/\[case (.*?)\](.*?)\[\/case\]/ism", $mtch[2], $cases, PREG_SET_ORDER); - if ($cntt) { - foreach ($cases as $case) { - if ($case[1] === $switch_var) { - $switch_done = 1; - $s = str_replace($mtch[0], $case[2], $s); - break; - } - } - if ($switch_done === 0) { - $s = str_replace($mtch[0], $default, $s); - } - } - } - } + $cnt = preg_match_all("/\[if (.*?)\](.*?)\[else\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + if ($this->test_condition($mtch[1])) { + $s = str_replace($mtch[0], $mtch[2], $s); + } else { + $s = str_replace($mtch[0], $mtch[3], $s); + } + } + } else { + $cnt = preg_match_all("/\[if (.*?)\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + if ($this->test_condition($mtch[1])) { + $s = str_replace($mtch[0], $mtch[2], $s); + } else { + $s = str_replace($mtch[0], '', $s); + } + } + } + } + if ($pass == 0) { + $this->parse_pass0($s); + } else { + $this->parse_pass1($s); + } + } - $cnt = preg_match_all("/\[if (.*?)\](.*?)\[else\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - if ($this->test_condition($mtch[1])) { - $s = str_replace($mtch[0], $mtch[2], $s); - } - else { - $s = str_replace($mtch[0], $mtch[3], $s); - } - } - } - else { - $cnt = preg_match_all("/\[if (.*?)\](.*?)\[\/if\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - if ($this->test_condition($mtch[1])) { - $s = str_replace($mtch[0], $mtch[2], $s); - } - else { - $s = str_replace($mtch[0], '', $s); - } - } - } - } - if ($pass == 0) { - $this->parse_pass0($s); - } - else { - $this->parse_pass1($s); - } - } + public function parse_pass0($s) + { - function parse_pass0($s) { + $matches = null; - $matches = null; + $cnt = preg_match("/\[layout\](.*?)\[\/layout\]/ism", $s, $matches); + if ($cnt) { + App::$page['template'] = trim($matches[1]); + } - $cnt = preg_match("/\[layout\](.*?)\[\/layout\]/ism", $s, $matches); - if ($cnt) { - App::$page['template'] = trim($matches[1]); - } - - $cnt = preg_match("/\[template=(.*?)\](.*?)\[\/template\]/ism", $s, $matches); - if ($cnt) { - App::$page['template'] = trim($matches[2]); - App::$page['template_style'] = trim($matches[2]) . '_' . $matches[1]; - } + $cnt = preg_match("/\[template=(.*?)\](.*?)\[\/template\]/ism", $s, $matches); + if ($cnt) { + App::$page['template'] = trim($matches[2]); + App::$page['template_style'] = trim($matches[2]) . '_' . $matches[1]; + } - $cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $s, $matches); - if ($cnt) { - App::$page['template'] = trim($matches[1]); - } + $cnt = preg_match("/\[template\](.*?)\[\/template\]/ism", $s, $matches); + if ($cnt) { + App::$page['template'] = trim($matches[1]); + } - $cnt = preg_match("/\[theme=(.*?)\](.*?)\[\/theme\]/ism", $s, $matches); - if ($cnt) { - App::$layout['schema'] = trim($matches[1]); - App::$layout['theme'] = trim($matches[2]); - } + $cnt = preg_match("/\[theme=(.*?)\](.*?)\[\/theme\]/ism", $s, $matches); + if ($cnt) { + App::$layout['schema'] = trim($matches[1]); + App::$layout['theme'] = trim($matches[2]); + } - $cnt = preg_match("/\[theme\](.*?)\[\/theme\]/ism", $s, $matches); - if ($cnt) { - App::$layout['theme'] = trim($matches[1]); - } - - $cnt = preg_match("/\[navbar\](.*?)\[\/navbar\]/ism", $s, $matches); - if ($cnt) { - App::$layout['navbar'] = trim($matches[1]); - } + $cnt = preg_match("/\[theme\](.*?)\[\/theme\]/ism", $s, $matches); + if ($cnt) { + App::$layout['theme'] = trim($matches[1]); + } - $cnt = preg_match_all("/\[webpage\](.*?)\[\/webpage\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - // only the last webpage definition is used if there is more than one - foreach ($matches as $mtch) { - App::$layout['webpage'] = $this->webpage($a,$mtch[1]); - } - } - } + $cnt = preg_match("/\[navbar\](.*?)\[\/navbar\]/ism", $s, $matches); + if ($cnt) { + App::$layout['navbar'] = trim($matches[1]); + } - function parse_pass1($s) { - $cnt = preg_match_all("/\[region=(.*?)\](.*?)\[\/region\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - App::$layout['region_' . $mtch[1]] = $this->region($mtch[2],$mtch[1]); - } - } - } + $cnt = preg_match_all("/\[webpage\](.*?)\[\/webpage\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + // only the last webpage definition is used if there is more than one + foreach ($matches as $mtch) { + App::$layout['webpage'] = $this->webpage($a, $mtch[1]); + } + } + } - /** - * @brief Replace conditional variables with real values. - * - * Currently supported condition variables: - * * $config.xxx.yyy - get_config with cat = xxx and k = yyy - * * $request - request uri for this page - * * $observer.language - viewer's preferred language (closest match) - * * $observer.address - xchan_addr or false - * * $observer.name - xchan_name or false - * * $observer - xchan_hash of observer or empty string - * * $local_channel - logged in channel_id or false - * - * @param string $v The conditional variable name - * @return string|boolean - */ - function get_condition_var($v) { - if ($v) { - $x = explode('.', $v); - if ($x[0] == 'config') { - return get_config($x[1],$x[2]); - } - elseif ($x[0] === 'request') { - return $_SERVER['REQUEST_URI']; - } - elseif ($x[0] === 'local_channel') { - return local_channel(); - } - elseif ($x[0] === 'observer') { - if (count($x) > 1) { - if ($x[1] == 'language') { - return App::$language; - } - $y = App::get_observer(); - if (! $y) { - return false; - } - if ($x[1] == 'address') { - return $y['xchan_addr']; - } - elseif ($x[1] == 'name') { - return $y['xchan_name']; - } - elseif ($x[1] == 'webname') { - return substr($y['xchan_addr'],0,strpos($y['xchan_addr'],'@')); - } - return false; - } - return get_observer_hash(); - } - else { - return false; - } - } - return false; - } + public function parse_pass1($s) + { + $cnt = preg_match_all("/\[region=(.*?)\](.*?)\[\/region\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + App::$layout['region_' . $mtch[1]] = $this->region($mtch[2], $mtch[1]); + } + } + } - /** - * @brief Test for Conditional Execution conditions. - * - * This is extensible. The first version of variable testing supports tests of the forms: - * - * - [if $config.system.foo ~= baz] which will check if get_config('system','foo') contains the string 'baz'; - * - [if $config.system.foo == baz] which will check if get_config('system','foo') is the string 'baz'; - * - [if $config.system.foo != baz] which will check if get_config('system','foo') is not the string 'baz'; - * - [if $config.system.foo >= 3] which will check if get_config('system','foo') is greater than or equal to 3; - * - [if $config.system.foo > 3] which will check if get_config('system','foo') is greater than 3; - * - [if $config.system.foo <= 3] which will check if get_config('system','foo') is less than or equal to 3; - * - [if $config.system.foo < 3] which will check if get_config('system','foo') is less than 3; - * - * - [if $config.system.foo {} baz] which will check if 'baz' is an array element in get_config('system','foo') - * - [if $config.system.foo {*} baz] which will check if 'baz' is an array key in get_config('system','foo') - * - [if $config.system.foo] which will check for a return of a true condition for get_config('system','foo'); - * - * The values 0, '', an empty array, and an unset value will all evaluate to false. - * - * @param int|string $s - * @return boolean - */ - function test_condition($s) { + /** + * @brief Replace conditional variables with real values. + * + * Currently supported condition variables: + * * $config.xxx.yyy - get_config with cat = xxx and k = yyy + * * $request - request uri for this page + * * $observer.language - viewer's preferred language (closest match) + * * $observer.address - xchan_addr or false + * * $observer.name - xchan_name or false + * * $observer - xchan_hash of observer or empty string + * * $local_channel - logged in channel_id or false + * + * @param string $v The conditional variable name + * @return string|bool + */ + public function get_condition_var($v) + { + if ($v) { + $x = explode('.', $v); + if ($x[0] == 'config') { + return get_config($x[1], $x[2]); + } elseif ($x[0] === 'request') { + return $_SERVER['REQUEST_URI']; + } elseif ($x[0] === 'local_channel') { + return local_channel(); + } elseif ($x[0] === 'observer') { + if (count($x) > 1) { + if ($x[1] == 'language') { + return App::$language; + } + $y = App::get_observer(); + if (!$y) { + return false; + } + if ($x[1] == 'address') { + return $y['xchan_addr']; + } elseif ($x[1] == 'name') { + return $y['xchan_name']; + } elseif ($x[1] == 'webname') { + return substr($y['xchan_addr'], 0, strpos($y['xchan_addr'], '@')); + } + return false; + } + return get_observer_hash(); + } else { + return false; + } + } + return false; + } - if (preg_match('/[\$](.*?)\s\~\=\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if (stripos($x,trim($matches[2])) !== false) { - return true; - } - return false; - } + /** + * @brief Test for Conditional Execution conditions. + * + * This is extensible. The first version of variable testing supports tests of the forms: + * + * - [if $config.system.foo ~= baz] which will check if get_config('system','foo') contains the string 'baz'; + * - [if $config.system.foo == baz] which will check if get_config('system','foo') is the string 'baz'; + * - [if $config.system.foo != baz] which will check if get_config('system','foo') is not the string 'baz'; + * - [if $config.system.foo >= 3] which will check if get_config('system','foo') is greater than or equal to 3; + * - [if $config.system.foo > 3] which will check if get_config('system','foo') is greater than 3; + * - [if $config.system.foo <= 3] which will check if get_config('system','foo') is less than or equal to 3; + * - [if $config.system.foo < 3] which will check if get_config('system','foo') is less than 3; + * + * - [if $config.system.foo {} baz] which will check if 'baz' is an array element in get_config('system','foo') + * - [if $config.system.foo {*} baz] which will check if 'baz' is an array key in get_config('system','foo') + * - [if $config.system.foo] which will check for a return of a true condition for get_config('system','foo'); + * + * The values 0, '', an empty array, and an unset value will all evaluate to false. + * + * @param int|string $s + * @return bool + */ + public function test_condition($s) + { - if (preg_match('/[\$](.*?)\s\=\=\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if ($x == trim($matches[2])) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\~\=\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if (stripos($x, trim($matches[2])) !== false) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)\s\!\=\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if ($x != trim($matches[2])) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\=\=\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if ($x == trim($matches[2])) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)\s\>\=\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if ($x >= trim($matches[2])) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\!\=\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if ($x != trim($matches[2])) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)\s\<\=\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if ($x <= trim($matches[2])) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\>\=\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if ($x >= trim($matches[2])) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if ($x > trim($matches[2])) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\<\=\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if ($x <= trim($matches[2])) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)\s\>\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if ($x < trim($matches[2])) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\>\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if ($x > trim($matches[2])) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if (is_array($x) && in_array(trim($matches[2]),$x)) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\>\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if ($x < trim($matches[2])) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)\s\{\*\}\s(.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if (is_array($x) && array_key_exists(trim($matches[2]),$x)) { - return true; - } - return false; - } + if (preg_match('/[\$](.*?)\s\{\}\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if (is_array($x) && in_array(trim($matches[2]), $x)) { + return true; + } + return false; + } - if (preg_match('/[\$](.*?)$/',$s,$matches)) { - $x = $this->get_condition_var($matches[1]); - if ($x) { - return true; - } - return false; - } - return false; - } + if (preg_match('/[\$](.*?)\s\{\*\}\s(.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if (is_array($x) && array_key_exists(trim($matches[2]), $x)) { + return true; + } + return false; + } - /** - * @brief Return rendered menu for current channel_id. - * - * @see menu_render() - * @param string $s - * @param string $class (optional) default empty - * @return string - */ - function menu($s, $class = '') { + if (preg_match('/[\$](.*?)$/', $s, $matches)) { + $x = $this->get_condition_var($matches[1]); + if ($x) { + return true; + } + return false; + } + return false; + } - $channel_id = $this->get_channel_id(); - $name = $s; + /** + * @brief Return rendered menu for current channel_id. + * + * @param string $s + * @param string $class (optional) default empty + * @return string + * @see menu_render() + */ + public function menu($s, $class = '') + { - $cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $var[$mtch[1]] = $mtch[2]; - $name = str_replace($mtch[0], '', $name); - } - } + $channel_id = $this->get_channel_id(); + $name = $s; - if ($channel_id) { - $m = menu_fetch($name, $channel_id, get_observer_hash()); - return menu_render($m, $class, $edit = false, $var); - } - } + $cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $var[$mtch[1]] = $mtch[2]; + $name = str_replace($mtch[0], '', $name); + } + } + + if ($channel_id) { + $m = menu_fetch($name, $channel_id, get_observer_hash()); + return menu_render($m, $class, $edit = false, $var); + } + } - function replace_region($match) { - if (array_key_exists($match[1], App::$page)) { - return App::$page[$match[1]]; - } - } + public function replace_region($match) + { + if (array_key_exists($match[1], App::$page)) { + return App::$page[$match[1]]; + } + } - /** - * @brief Returns the channel_id of the profile owner of the page. - * - * Returns the channel_id of the profile owner of the page, or the local_channel - * if there is no profile owner. Otherwise returns 0. - * - * @return int channel_id - */ - function get_channel_id() { - $channel_id = ((is_array(App::$profile)) ? App::$profile['profile_uid'] : 0); + /** + * @brief Returns the channel_id of the profile owner of the page. + * + * Returns the channel_id of the profile owner of the page, or the local_channel + * if there is no profile owner. Otherwise returns 0. + * + * @return int channel_id + */ + public function get_channel_id() + { + $channel_id = ((is_array(App::$profile)) ? App::$profile['profile_uid'] : 0); - if ((! $channel_id) && (local_channel())) { - $channel_id = local_channel(); - } - return $channel_id; - } + if ((!$channel_id) && (local_channel())) { + $channel_id = local_channel(); + } + return $channel_id; + } - /** - * @brief Returns a parsed block. - * - * @param string $s - * @param string $class (optional) default empty - * @return string parsed HTML of block - */ - function block($s, $class = '') { - $var = []; - $matches = []; - $name = $s; - $class = (($class) ? $class : 'bblock widget'); + /** + * @brief Returns a parsed block. + * + * @param string $s + * @param string $class (optional) default empty + * @return string parsed HTML of block + */ + public function block($s, $class = '') + { + $var = []; + $matches = []; + $name = $s; + $class = (($class) ? $class : 'bblock widget'); - $cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $var[$mtch[1]] = $mtch[2]; - $name = str_replace($mtch[0], '', $name); - } - } + $cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $var[$mtch[1]] = $mtch[2]; + $name = str_replace($mtch[0], '', $name); + } + } - $o = ''; - $channel_id = $this->get_channel_id(); + $o = ''; + $channel_id = $this->get_channel_id(); - if ($channel_id) { - $r = q("select * from item inner join iconfig on iconfig.iid = item.id and item.uid = %d + if ($channel_id) { + $r = q("select * from item inner join iconfig on iconfig.iid = item.id and item.uid = %d and iconfig.cat = 'system' and iconfig.k = 'BUILDBLOCK' and iconfig.v = '%s' limit 1", - intval($channel_id), - dbesc($name) - ); + intval($channel_id), + dbesc($name) + ); - if ($r) { - //check for eventual menus in the block and parse them - $cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $r[0]['body'], $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $r[0]['body'] = str_replace($mtch[0], $this->menu(trim($mtch[1])), $r[0]['body']); - } - } - $cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $r[0]['body'], $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $r[0]['body'] = str_replace($mtch[0],$this->menu(trim($mtch[2]),$mtch[1]),$r[0]['body']); - } - } + if ($r) { + //check for eventual menus in the block and parse them + $cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $r[0]['body'], $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $r[0]['body'] = str_replace($mtch[0], $this->menu(trim($mtch[1])), $r[0]['body']); + } + } + $cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $r[0]['body'], $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $r[0]['body'] = str_replace($mtch[0], $this->menu(trim($mtch[2]), $mtch[1]), $r[0]['body']); + } + } - // emit the block - $o .= (($var['wrap'] == 'none') ? '' : '
      '); + // emit the block + $o .= (($var['wrap'] == 'none') ? '' : '
      '); - if ($r[0]['title'] && trim($r[0]['body']) != '$content') { - $o .= '

      ' . $r[0]['title'] . '

      '; - } + if ($r[0]['title'] && trim($r[0]['body']) != '$content') { + $o .= '

      ' . $r[0]['title'] . '

      '; + } - if (trim($r[0]['body']) === '$content') { - $o .= App::$page['content']; - } - else { - $o .= prepare_text($r[0]['body'], $r[0]['mimetype']); - } + if (trim($r[0]['body']) === '$content') { + $o .= App::$page['content']; + } else { + $o .= prepare_text($r[0]['body'], $r[0]['mimetype']); + } - $o .= (($var['wrap'] == 'none') ? '' : '
      '); - } - } + $o .= (($var['wrap'] == 'none') ? '' : '
      '); + } + } - return $o; - } + return $o; + } - /** - * @brief Include JS depending on framework. - * - * @param string $s - * @return string - */ - function js($s) { + /** + * @brief Include JS depending on framework. + * + * @param string $s + * @return string + */ + public function js($s) + { - switch ($s) { - case 'jquery': - $path = 'view/js/jquery.js'; - break; - case 'bootstrap': - $path = 'vendor/twbs/bootstrap/dist/js/bootstrap.bundle.min.js'; - break; - case 'foundation': - $path = 'library/foundation/js/foundation.js'; - $init = "\r\n" . ''; - break; - } + switch ($s) { + case 'jquery': + $path = 'view/js/jquery.js'; + break; + case 'bootstrap': + $path = 'vendor/twbs/bootstrap/dist/js/bootstrap.bundle.min.js'; + break; + case 'foundation': + $path = 'library/foundation/js/foundation.js'; + $init = "\r\n" . ''; + break; + } - $ret = ''; - if ($init) { - $ret .= $init; - } - return $ret; - } + $ret = ''; + if ($init) { + $ret .= $init; + } + return $ret; + } - /** - * @brief Include CSS depending on framework. - * - * @param string $s - * @return string - */ - function css($s) { + /** + * @brief Include CSS depending on framework. + * + * @param string $s + * @return string + */ + public function css($s) + { - switch ($s) { - case 'bootstrap': - $path = 'vendor/twbs/bootstrap/dist/css/bootstrap.min.css'; - break; - case 'foundation': - $path = 'library/foundation/css/foundation.min.css'; - break; - } + switch ($s) { + case 'bootstrap': + $path = 'vendor/twbs/bootstrap/dist/css/bootstrap.min.css'; + break; + case 'foundation': + $path = 'library/foundation/css/foundation.min.css'; + break; + } - $ret = ''; + $ret = ''; - return $ret; - } + return $ret; + } - /** - * This doesn't really belong in Comanche, but it could also be argued that it is the perfect place. - * We need to be able to select what kind of template and decoration to use for the webpage at the heart of our content. - * For now we'll allow an '[authored]' element which defaults to name and date, or 'none' to remove these, and perhaps - * 'full' to provide a social network style profile photo. - * - * But leave it open to have richer templating options and perhaps ultimately discard this one, once we have a better idea - * of what template and webpage options we might desire. - * - * @param[in,out] array $a - * @param string $s - * @return array - */ - function webpage(&$a, $s) { - $ret = []; - $matches = []; + /** + * This doesn't really belong in Comanche, but it could also be argued that it is the perfect place. + * We need to be able to select what kind of template and decoration to use for the webpage at the heart of our content. + * For now we'll allow an '[authored]' element which defaults to name and date, or 'none' to remove these, and perhaps + * 'full' to provide a social network style profile photo. + * + * But leave it open to have richer templating options and perhaps ultimately discard this one, once we have a better idea + * of what template and webpage options we might desire. + * + * @param[in,out] array $a + * @param string $s + * @return array + */ + public function webpage(&$a, $s) + { + $ret = []; + $matches = []; - $cnt = preg_match_all("/\[authored\](.*?)\[\/authored\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $ret['authored'] = $mtch[1]; - } - } + $cnt = preg_match_all("/\[authored\](.*?)\[\/authored\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $ret['authored'] = $mtch[1]; + } + } - return $ret; - } + return $ret; + } - /** - * @brief Render a widget. - * - * @param string $name - * @param string $text - */ - function widget($name, $text) { - $vars = []; - $matches = []; + /** + * @brief Render a widget. + * + * @param string $name + * @param string $text + */ + public function widget($name, $text) + { + $vars = []; + $matches = []; - $cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $text, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $vars[$mtch[1]] = $mtch[2]; - } - } + $cnt = preg_match_all("/\[var=(.*?)\](.*?)\[\/var\]/ism", $text, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $vars[$mtch[1]] = $mtch[2]; + } + } - if (! purify_filename($name)) { - return ''; - } + if (!purify_filename($name)) { + return ''; + } - $clsname = ucfirst($name); - $nsname = "\\Zotlabs\\Widget\\" . $clsname; + $clsname = ucfirst($name); + $nsname = "\\Zotlabs\\Widget\\" . $clsname; - $found = false; - $widgets = Widget::get(); - if ($widgets) { - foreach ($widgets as $widget) { - if (is_array($widget) && strtolower($widget[1]) === strtolower($name) && file_exists($widget[0])) { - require_once($widget[0]); - $found = true; - } - } - } + $found = false; + $widgets = Widget::get(); + if ($widgets) { + foreach ($widgets as $widget) { + if (is_array($widget) && strtolower($widget[1]) === strtolower($name) && file_exists($widget[0])) { + require_once($widget[0]); + $found = true; + } + } + } - if (! $found) { - if (file_exists('Zotlabs/SiteWidget/' . $clsname . '.php')) { - require_once('Zotlabs/SiteWidget/' . $clsname . '.php'); - } - elseif (file_exists('widget/' . $clsname . '/' . $clsname . '.php')) { - require_once('widget/' . $clsname . '/' . $clsname . '.php'); - } - elseif (file_exists('Zotlabs/Widget/' . $clsname . '.php')) { - require_once('Zotlabs/Widget/' . $clsname . '.php'); - } - else { - $pth = theme_include($clsname . '.php'); - if ($pth) { - require_once($pth); - } - } - } + if (!$found) { + if (file_exists('Zotlabs/SiteWidget/' . $clsname . '.php')) { + require_once('Zotlabs/SiteWidget/' . $clsname . '.php'); + } elseif (file_exists('widget/' . $clsname . '/' . $clsname . '.php')) { + require_once('widget/' . $clsname . '/' . $clsname . '.php'); + } elseif (file_exists('Zotlabs/Widget/' . $clsname . '.php')) { + require_once('Zotlabs/Widget/' . $clsname . '.php'); + } else { + $pth = theme_include($clsname . '.php'); + if ($pth) { + require_once($pth); + } + } + } - if (class_exists($nsname)) { - $x = new $nsname; - $f = 'widget'; - if (method_exists($x,$f)) { - return $x->$f($vars); - } - } + if (class_exists($nsname)) { + $x = new $nsname(); + $f = 'widget'; + if (method_exists($x, $f)) { + return $x->$f($vars); + } + } - $func = 'widget_' . trim($name); + $func = 'widget_' . trim($name); - if (! function_exists($func)) { - if (file_exists('widget/' . trim($name) . '.php')) { - require_once('widget/' . trim($name) . '.php'); - } - elseif (file_exists('widget/' . trim($name) . '/' . trim($name) . '.php')) { - require_once('widget/' . trim($name) . '/' . trim($name) . '.php'); - } - if (! function_exists($func)) { - $theme_widget = $func . '.php'; - if (theme_include($theme_widget)) { - require_once(theme_include($theme_widget)); - } - } - } + if (!function_exists($func)) { + if (file_exists('widget/' . trim($name) . '.php')) { + require_once('widget/' . trim($name) . '.php'); + } elseif (file_exists('widget/' . trim($name) . '/' . trim($name) . '.php')) { + require_once('widget/' . trim($name) . '/' . trim($name) . '.php'); + } + if (!function_exists($func)) { + $theme_widget = $func . '.php'; + if (theme_include($theme_widget)) { + require_once(theme_include($theme_widget)); + } + } + } - if (function_exists($func)) { - return $func($vars); - } - } + if (function_exists($func)) { + return $func($vars); + } + } - function region($s,$region_name) { + public function region($s, $region_name) + { - $s = str_replace('$region',$region_name,$s); + $s = str_replace('$region', $region_name, $s); - $matches = []; + $matches = []; - $cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0], $this->menu(trim($mtch[1])), $s); - } - } + $cnt = preg_match_all("/\[menu\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], $this->menu(trim($mtch[1])), $s); + } + } - // menu class e.g. [menu=horizontal]my_menu[/menu] or [menu=tabbed]my_menu[/menu] - // allows different menu renderings to be applied + // menu class e.g. [menu=horizontal]my_menu[/menu] or [menu=tabbed]my_menu[/menu] + // allows different menu renderings to be applied - $cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0],$this->menu(trim($mtch[2]),$mtch[1]),$s); - } - } - $cnt = preg_match_all("/\[block\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0],$this->block(trim($mtch[1])),$s); - } - } + $cnt = preg_match_all("/\[menu=(.*?)\](.*?)\[\/menu\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], $this->menu(trim($mtch[2]), $mtch[1]), $s); + } + } + $cnt = preg_match_all("/\[block\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], $this->block(trim($mtch[1])), $s); + } + } - $cnt = preg_match_all("/\[block=(.*?)\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0],$this->block(trim($mtch[2]),trim($mtch[1])),$s); - } - } + $cnt = preg_match_all("/\[block=(.*?)\](.*?)\[\/block\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], $this->block(trim($mtch[2]), trim($mtch[1])), $s); + } + } - $cnt = preg_match_all("/\[js\](.*?)\[\/js\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0],$this->js(trim($mtch[1])),$s); - } - } + $cnt = preg_match_all("/\[js\](.*?)\[\/js\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], $this->js(trim($mtch[1])), $s); + } + } - $cnt = preg_match_all("/\[css\](.*?)\[\/css\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0],$this->css(trim($mtch[1])),$s); - } - } + $cnt = preg_match_all("/\[css\](.*?)\[\/css\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], $this->css(trim($mtch[1])), $s); + } + } - $cnt = preg_match_all("/\[widget=(.*?)\](.*?)\[\/widget\]/ism", $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - $s = str_replace($mtch[0],$this->widget(trim($mtch[1]),$mtch[2]),$s); - } - } + $cnt = preg_match_all("/\[widget=(.*?)\](.*?)\[\/widget\]/ism", $s, $matches, PREG_SET_ORDER); + if ($cnt) { + foreach ($matches as $mtch) { + $s = str_replace($mtch[0], $this->widget(trim($mtch[1]), $mtch[2]), $s); + } + } - return $s; - } + return $s; + } - /** - * @brief Registers a page template/variant for use by Comanche selectors. - * - * @param array $arr - * 'template' => template name - * 'variant' => array( - * 'name' => variant name - * 'desc' => text description - * 'regions' => array( - * 'name' => name - * 'desc' => text description - * ) - * ) - */ - function register_page_template($arr) { - App::$page_layouts[$arr['template']] = array($arr['variant']); - return; - } + /** + * @brief Registers a page template/variant for use by Comanche selectors. + * + * @param array $arr + * 'template' => template name + * 'variant' => array( + * 'name' => variant name + * 'desc' => text description + * 'regions' => array( + * 'name' => name + * 'desc' => text description + * ) + * ) + */ + public function register_page_template($arr) + { + App::$page_layouts[$arr['template']] = array($arr['variant']); + return; + } } diff --git a/Zotlabs/Render/SimpleTemplate.php b/Zotlabs/Render/SimpleTemplate.php index 83b92eb28..8ba68636e 100644 --- a/Zotlabs/Render/SimpleTemplate.php +++ b/Zotlabs/Render/SimpleTemplate.php @@ -6,17 +6,17 @@ define ("KEY_NOT_EXISTS", '^R_key_not_Exists^'); class SimpleTemplate implements TemplateEngine { - static $name = 'internal'; + static public $name = 'internal'; - var $r; - var $search; - var $replace; - var $stack = []; - var $nodes = []; - var $done = false; - var $d = false; - var $lang = null; - var $debug = false; + public $r; + public $search; + public $replace; + public $stack = []; + public $nodes = []; + public $done = false; + public $d = false; + public $lang = null; + public $debug = false; private function _preg_error() { switch (preg_last_error()) { diff --git a/Zotlabs/Render/SmartyInterface.php b/Zotlabs/Render/SmartyInterface.php index 72db8116b..21d5a76ad 100644 --- a/Zotlabs/Render/SmartyInterface.php +++ b/Zotlabs/Render/SmartyInterface.php @@ -5,64 +5,69 @@ namespace Zotlabs\Render; use Smarty; use App; -class SmartyInterface extends Smarty { +class SmartyInterface extends Smarty +{ - public $filename; + public $filename; - function __construct() { - parent::__construct(); + public function __construct() + { + parent::__construct(); - $theme = Theme::current(); - $thname = $theme[0]; + $theme = Theme::current(); + $thname = $theme[0]; - // setTemplateDir can be set to an array, which Smarty will parse in order. - // The order is thus very important here + // setTemplateDir can be set to an array, which Smarty will parse in order. + // The order is thus very important here - $template_dirs = [ 'theme' => "view/theme/$thname/tpl/" ]; - if ( x(App::$theme_info,"extends") ) { - $template_dirs = $template_dirs + [ 'extends' => "view/theme/" . App::$theme_info["extends"] . '/tpl/' ]; - } - $template_dirs = $template_dirs + array('base' => 'view/tpl/'); - $this->setTemplateDir($template_dirs); + $template_dirs = ['theme' => "view/theme/$thname/tpl/"]; + if (x(App::$theme_info, "extends")) { + $template_dirs = $template_dirs + ['extends' => "view/theme/" . App::$theme_info["extends"] . '/tpl/']; + } + $template_dirs = $template_dirs + array('base' => 'view/tpl/'); + $this->setTemplateDir($template_dirs); - // Cannot use get_config() here because it is called during installation when there is no DB. - // FIXME: this may leak private information such as system pathnames. + // Cannot use get_config() here because it is called during installation when there is no DB. + // FIXME: this may leak private information such as system pathnames. - $basecompiledir = ((array_key_exists('smarty3_folder', App::$config['system'])) - ? App::$config['system']['smarty3_folder'] : ''); - if (! $basecompiledir) { - $basecompiledir = str_replace('Zotlabs','',dirname(__DIR__)) . TEMPLATE_BUILD_PATH; - } - if (! is_dir($basecompiledir)) { - @os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true); - } - if (! is_dir($basecompiledir)) { - echo "ERROR: folder $basecompiledir does not exist."; killme(); - - } + $basecompiledir = ((array_key_exists('smarty3_folder', App::$config['system'])) + ? App::$config['system']['smarty3_folder'] : ''); + if (!$basecompiledir) { + $basecompiledir = str_replace('Zotlabs', '', dirname(__DIR__)) . TEMPLATE_BUILD_PATH; + } + if (!is_dir($basecompiledir)) { + @os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true); + } + if (!is_dir($basecompiledir)) { + echo "ERROR: folder $basecompiledir does not exist."; + killme(); - if (! is_writable($basecompiledir)) { - echo "ERROR: folder $basecompiledir must be writable by webserver."; killme(); - } - App::$config['system']['smarty3_folder'] = $basecompiledir; + } - $this->setCompileDir($basecompiledir.'/compiled/'); - $this->setConfigDir($basecompiledir.'/config/'); - $this->setCacheDir($basecompiledir.'/cache/'); + if (!is_writable($basecompiledir)) { + echo "ERROR: folder $basecompiledir must be writable by webserver."; + killme(); + } + App::$config['system']['smarty3_folder'] = $basecompiledir; - $this->left_delimiter = App::get_template_ldelim('smarty3'); - $this->right_delimiter = App::get_template_rdelim('smarty3'); + $this->setCompileDir($basecompiledir . '/compiled/'); + $this->setConfigDir($basecompiledir . '/config/'); + $this->setCacheDir($basecompiledir . '/cache/'); - // Don't report errors so verbosely - $this->error_reporting = (E_ERROR | E_PARSE); - } + $this->left_delimiter = App::get_template_ldelim('smarty3'); + $this->right_delimiter = App::get_template_rdelim('smarty3'); - function parsed($template = '') { - if ($template) { - return $this->fetch('string:' . $template); - } - return $this->fetch('file:' . $this->filename); - } + // Don't report errors so verbosely + $this->error_reporting = (E_ERROR | E_PARSE); + } + + public function parsed($template = '') + { + if ($template) { + return $this->fetch('string:' . $template); + } + return $this->fetch('file:' . $this->filename); + } } diff --git a/Zotlabs/Render/SmartyTemplate.php b/Zotlabs/Render/SmartyTemplate.php index 7eaa8a55c..0c1e896c7 100644 --- a/Zotlabs/Render/SmartyTemplate.php +++ b/Zotlabs/Render/SmartyTemplate.php @@ -7,7 +7,7 @@ use App; class SmartyTemplate implements TemplateEngine { - static $name ="smarty3"; + static public $name = "smarty3"; public function __construct() { diff --git a/Zotlabs/Render/Theme.php b/Zotlabs/Render/Theme.php index 4f9b1a242..9c569bfc6 100644 --- a/Zotlabs/Render/Theme.php +++ b/Zotlabs/Render/Theme.php @@ -5,128 +5,132 @@ namespace Zotlabs\Render; use App; -class Theme { +class Theme +{ - static $system_theme = null; + static public $system_theme = null; - static $session_theme = null; + static public $session_theme = null; - /** - * @brief Array with base or fallback themes. - */ - static $base_themes = array('redbasic'); + /** + * @brief Array with base or fallback themes. + */ + static public $base_themes = array('redbasic'); - /** - * @brief Figure out the best matching theme and return it. - * - * The theme will depend on channel settings, mobile, session, core compatibility, etc. - * - * @return array - */ - static public function current(){ + /** + * @brief Figure out the best matching theme and return it. + * + * The theme will depend on channel settings, mobile, session, core compatibility, etc. + * + * @return array + */ + public static function current() + { - self::$system_theme = ((isset(App::$config['system']['theme'])) - ? App::$config['system']['theme'] : ''); - self::$session_theme = ((isset($_SESSION) && x($_SESSION, 'theme')) - ? $_SESSION['theme'] : self::$system_theme); + self::$system_theme = ((isset(App::$config['system']['theme'])) + ? App::$config['system']['theme'] : ''); + self::$session_theme = ((isset($_SESSION) && x($_SESSION, 'theme')) + ? $_SESSION['theme'] : self::$system_theme); - $page_theme = null; + $page_theme = null; - // Find the theme that belongs to the channel whose stuff we are looking at + // Find the theme that belongs to the channel whose stuff we are looking at - if(App::$profile_uid) { - $r = q("select channel_theme from channel where channel_id = %d limit 1", - intval(App::$profile_uid) - ); - if($r) { - $page_theme = $r[0]['channel_theme']; - } - } + if (App::$profile_uid) { + $r = q("select channel_theme from channel where channel_id = %d limit 1", + intval(App::$profile_uid) + ); + if ($r) { + $page_theme = $r[0]['channel_theme']; + } + } - // Themes from Comanche layouts over-ride the channel theme + // Themes from Comanche layouts over-ride the channel theme - if(array_key_exists('theme', App::$layout) && App::$layout['theme']) - $page_theme = App::$layout['theme']; + if (array_key_exists('theme', App::$layout) && App::$layout['theme']) + $page_theme = App::$layout['theme']; - $chosen_theme = self::$session_theme; + $chosen_theme = self::$session_theme; - if($page_theme) { - $chosen_theme = $page_theme; - } + if ($page_theme) { + $chosen_theme = $page_theme; + } - if(array_key_exists('theme_preview', $_GET)) - $chosen_theme = $_GET['theme_preview']; + if (array_key_exists('theme_preview', $_GET)) + $chosen_theme = $_GET['theme_preview']; - // Allow theme selection of the form 'theme_name:schema_name' - $themepair = explode(':', $chosen_theme); + // Allow theme selection of the form 'theme_name:schema_name' + $themepair = explode(':', $chosen_theme); - // Check if $chosen_theme is compatible with core. If not fall back to default - $info = get_theme_info($themepair[0]); - $compatible = check_plugin_versions($info); - if(!$compatible) { - $chosen_theme = ''; - } + // Check if $chosen_theme is compatible with core. If not fall back to default + $info = get_theme_info($themepair[0]); + $compatible = check_plugin_versions($info); + if (!$compatible) { + $chosen_theme = ''; + } - if($chosen_theme && (file_exists('view/theme/' . $themepair[0] . '/css/style.css') || file_exists('view/theme/' . $themepair[0] . '/php/style.php'))) { - return($themepair); - } + if ($chosen_theme && (file_exists('view/theme/' . $themepair[0] . '/css/style.css') || file_exists('view/theme/' . $themepair[0] . '/php/style.php'))) { + return ($themepair); + } - foreach(self::$base_themes as $t) { - if(file_exists('view/theme/' . $t . '/css/style.css') || - file_exists('view/theme/' . $t . '/php/style.php')) { - return(array($t)); - } - } + foreach (self::$base_themes as $t) { + if (file_exists('view/theme/' . $t . '/css/style.css') || + file_exists('view/theme/' . $t . '/php/style.php')) { + return (array($t)); + } + } - // Worst case scenario, the default base theme or themes don't exist; perhaps somebody renamed it/them. + // Worst case scenario, the default base theme or themes don't exist; perhaps somebody renamed it/them. - // Find any theme at all and use it. + // Find any theme at all and use it. - $fallback = array_merge(glob('view/theme/*/css/style.css'), glob('view/theme/*/php/style.php')); - if(count($fallback)) - return(array(str_replace('view/theme/', '', substr($fallback[0], 0, -14)))); - } + $fallback = array_merge(glob('view/theme/*/css/style.css'), glob('view/theme/*/php/style.php')); + if (count($fallback)) + return (array(str_replace('view/theme/', '', substr($fallback[0], 0, -14)))); + } - /** - * @brief Return full URL to theme which is currently in effect. - * - * Provide a sane default if nothing is chosen or the specified theme does not exist. - * - * @param bool $installing (optional) default false, if true return the name of the first base theme - * - * @return string - */ - static public function url($installing = false) { + /** + * @brief Return full URL to theme which is currently in effect. + * + * Provide a sane default if nothing is chosen or the specified theme does not exist. + * + * @param bool $installing (optional) default false, if true return the name of the first base theme + * + * @return string + */ + public static function url($installing = false) + { - if($installing) - return self::$base_themes[0]; + if ($installing) + return self::$base_themes[0]; - $theme = self::current(); + $theme = self::current(); - $t = $theme[0]; - $s = ((count($theme) > 1) ? $theme[1] : ''); + $t = $theme[0]; + $s = ((count($theme) > 1) ? $theme[1] : ''); - $opts = ''; - $opts = ((App::$profile_uid) ? '?f=&puid=' . App::$profile_uid : ''); + $opts = ''; + $opts = ((App::$profile_uid) ? '?f=&puid=' . App::$profile_uid : ''); - $schema_str = ((x(App::$layout,'schema')) ? '&schema=' . App::$layout['schema'] : ''); - if(($s) && (! $schema_str)) - $schema_str = '&schema=' . $s; + $schema_str = ((x(App::$layout, 'schema')) ? '&schema=' . App::$layout['schema'] : ''); + if (($s) && (!$schema_str)) + $schema_str = '&schema=' . $s; - $opts .= $schema_str; + $opts .= $schema_str; - if(file_exists('view/theme/' . $t . '/php/style.php')) - return('/view/theme/' . $t . '/php/style.pcss' . $opts); + if (file_exists('view/theme/' . $t . '/php/style.php')) + return ('/view/theme/' . $t . '/php/style.pcss' . $opts); - return('/view/theme/' . $t . '/css/style.css'); - } + return ('/view/theme/' . $t . '/css/style.css'); + } - function debug() { - logger('system_theme: ' . self::$system_theme); - logger('session_theme: ' . self::$session_theme); - } + public function debug() + { + logger('system_theme: ' . self::$system_theme); + logger('session_theme: ' . self::$session_theme); + } } diff --git a/Zotlabs/Storage/BasicAuth.php b/Zotlabs/Storage/BasicAuth.php index d5222b169..fb6cdee96 100644 --- a/Zotlabs/Storage/BasicAuth.php +++ b/Zotlabs/Storage/BasicAuth.php @@ -21,132 +21,135 @@ use Sabre\HTTP\ResponseInterface; * @link http://github.com/friendica/red * @license http://opensource.org/unlicense.org */ -class BasicAuth extends DAV\Auth\Backend\AbstractBasic { +class BasicAuth extends DAV\Auth\Backend\AbstractBasic +{ - /** - * @brief This variable holds the currently logged-in channel_address. - * - * It is used for building path in filestorage/. - * - * @var string|null $channel_name - */ - public $channel_name = null; - /** - * @brief channel_id of the current channel of the logged-in account. - * - * @var int $channel_id - */ - public $channel_id = 0; - /** - * @brief channel_hash of the current channel of the logged-in account. - * - * @var string $channel_hash - */ - public $channel_hash = ''; - /** - * @brief Set in mod/cloud.php to observer_hash. - * - * @var string $observer - */ - public $observer = ''; - /** - * - * @see Browser::set_writeable() - * @var \Sabre\\DAV\\Browser\\Plugin $browser - */ - public $browser; - /** - * @brief channel_id of the current visited path. Set in Directory::getDir(). - * - * @var int $owner_id - */ - public $owner_id = 0; - /** - * channel_name of the current visited path. Set in Directory::getDir(). - * - * Used for creating the path in cloud/ - * - * @var string $owner_nick - */ - public $owner_nick = ''; - /** - * Timezone from the visiting channel's channel_timezone. - * - * Used in @ref Browser - * - * @var string $timezone - */ - protected $timezone = ''; + /** + * @brief This variable holds the currently logged-in channel_address. + * + * It is used for building path in filestorage/. + * + * @var string|null $channel_name + */ + public $channel_name = null; + /** + * @brief channel_id of the current channel of the logged-in account. + * + * @var int $channel_id + */ + public $channel_id = 0; + /** + * @brief channel_hash of the current channel of the logged-in account. + * + * @var string $channel_hash + */ + public $channel_hash = ''; + /** + * @brief Set in mod/cloud.php to observer_hash. + * + * @var string $observer + */ + public $observer = ''; + /** + * + * @see Browser::set_writeable() + * @var \Sabre\\DAV\\Browser\\Plugin $browser + */ + public $browser; + /** + * @brief channel_id of the current visited path. Set in Directory::getDir(). + * + * @var int $owner_id + */ + public $owner_id = 0; + /** + * channel_name of the current visited path. Set in Directory::getDir(). + * + * Used for creating the path in cloud/ + * + * @var string $owner_nick + */ + public $owner_nick = ''; + /** + * Timezone from the visiting channel's channel_timezone. + * + * Used in @ref Browser + * + * @var string $timezone + */ + protected $timezone = ''; - public $module_disabled = false; + public $module_disabled = false; - /** - * @brief Validates a username and password. - * - * - * @see \\Sabre\\DAV\\Auth\\Backend\\AbstractBasic::validateUserPass - * @param string $username - * @param string $password - * @return bool - */ - protected function validateUserPass($username, $password) { + /** + * @brief Validates a username and password. + * + * + * @param string $username + * @param string $password + * @return bool + * @see \\Sabre\\DAV\\Auth\\Backend\\AbstractBasic::validateUserPass + */ + protected function validateUserPass($username, $password) + { - require_once('include/auth.php'); - $record = account_verify_password($username, $password); - if($record && $record['account']) { - if($record['channel']) - $channel = $record['channel']; - else { - $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1", - intval($record['account']['account_id']), - intval($record['account']['account_default_channel']) - ); - if($r) - $channel = $r[0]; - } - } - if($channel && $this->check_module_access($channel['channel_id'])) { - return $this->setAuthenticated($channel); - } + require_once('include/auth.php'); + $record = account_verify_password($username, $password); + if ($record && $record['account']) { + if ($record['channel']) + $channel = $record['channel']; + else { + $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1", + intval($record['account']['account_id']), + intval($record['account']['account_default_channel']) + ); + if ($r) + $channel = $r[0]; + } + } + if ($channel && $this->check_module_access($channel['channel_id'])) { + return $this->setAuthenticated($channel); + } - if($this->module_disabled) - $error = 'module not enabled for ' . $username; - else - $error = 'password failed for ' . $username; - logger($error); - log_failed_login($error); + if ($this->module_disabled) + $error = 'module not enabled for ' . $username; + else + $error = 'password failed for ' . $username; + logger($error); + log_failed_login($error); - return false; - } + return false; + } - /** - * @brief Sets variables and session parameters after successfull authentication. - * - * @param array $r - * Array with the values for the authenticated channel. - * @return bool - */ - protected function setAuthenticated($channel) { - $this->channel_name = $channel['channel_address']; - $this->channel_id = $channel['channel_id']; - $this->channel_hash = $this->observer = $channel['channel_hash']; - - if ($this->observer) { - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($this->observer) - ); - if ($r) { - App::set_observer(array_shift($r)); - } - } + /** + * @brief Sets variables and session parameters after successfull authentication. + * + * @param array $r + * Array with the values for the authenticated channel. + * @return bool + */ + protected function setAuthenticated($channel) + { + $this->channel_name = $channel['channel_address']; + $this->channel_id = $channel['channel_id']; + $this->channel_hash = $this->observer = $channel['channel_hash']; - $_SESSION['uid'] = $channel['channel_id']; - $_SESSION['account_id'] = $channel['channel_account_id']; - $_SESSION['authenticated'] = true; - return true; - } + if ($this->observer) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($this->observer) + ); + if ($r) { + App::set_observer(array_shift($r)); + } + } + + $_SESSION['uid'] = $channel['channel_id']; + $_SESSION['account_id'] = $channel['channel_account_id']; + $_SESSION['authenticated'] = true; + return true; + } /** * When this method is called, the backend must check if authentication was @@ -176,15 +179,15 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic { * @param ResponseInterface $response * @return array */ - function check(RequestInterface $request, ResponseInterface $response) { + public function check(RequestInterface $request, ResponseInterface $response) + { - if (local_channel()) { - $this->setAuthenticated(App::get_channel()); - return [ true, $this->principalPrefix . $this->channel_name ]; - } - elseif (remote_channel()) { - return [ true, $this->principalPrefix . $this->observer ]; - } + if (local_channel()) { + $this->setAuthenticated(App::get_channel()); + return [true, $this->principalPrefix . $this->channel_name]; + } elseif (remote_channel()) { + return [true, $this->principalPrefix . $this->observer]; + } $auth = new Basic( $this->realm, @@ -203,78 +206,87 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic { } - protected function check_module_access($channel_id) { - if($channel_id && in_array(App::$module,[ 'dav', 'cdav', 'snap'] )) { - return true; - } - $this->module_disabled = true; - return false; - } + protected function check_module_access($channel_id) + { + if ($channel_id && in_array(App::$module, ['dav', 'cdav', 'snap'])) { + return true; + } + $this->module_disabled = true; + return false; + } - /** - * Sets the channel_name from the currently logged-in channel. - * - * @param string $name - * The channel's name - */ - public function setCurrentUser($name) { - $this->channel_name = $name; - } - /** - * Returns information about the currently logged-in channel. - * - * If nobody is currently logged in, this method should return null. - * - * @see \\Sabre\\DAV\\Auth\\Backend\\AbstractBasic::getCurrentUser - * @return string|null - */ - public function getCurrentUser() { - return $this->channel_name; - } + /** + * Sets the channel_name from the currently logged-in channel. + * + * @param string $name + * The channel's name + */ + public function setCurrentUser($name) + { + $this->channel_name = $name; + } - /** - * @brief Sets the timezone from the channel in BasicAuth. - * - * Set in mod/cloud.php if the channel has a timezone set. - * - * @param string $timezone - * The channel's timezone. - * @return void - */ - public function setTimezone($timezone) { - $this->timezone = $timezone; - } - /** - * @brief Returns the timezone. - * - * @return string - * Return the channel's timezone. - */ - public function getTimezone() { - return $this->timezone; - } + /** + * Returns information about the currently logged-in channel. + * + * If nobody is currently logged in, this method should return null. + * + * @return string|null + * @see \\Sabre\\DAV\\Auth\\Backend\\AbstractBasic::getCurrentUser + */ + public function getCurrentUser() + { + return $this->channel_name; + } - /** - * @brief Set browser plugin for SabreDAV. - * - * @see RedBrowser::set_writeable() - * @param Plugin $browser - */ - public function setBrowserPlugin($browser) { - $this->browser = $browser; - } + /** + * @brief Sets the timezone from the channel in BasicAuth. + * + * Set in mod/cloud.php if the channel has a timezone set. + * + * @param string $timezone + * The channel's timezone. + * @return void + */ + public function setTimezone($timezone) + { + $this->timezone = $timezone; + } - /** - * @brief Prints out all BasicAuth variables to logger(). - * - * @return void - */ - public function log() { + /** + * @brief Returns the timezone. + * + * @return string + * Return the channel's timezone. + */ + public function getTimezone() + { + return $this->timezone; + } + + /** + * @brief Set browser plugin for SabreDAV. + * + * @param Plugin $browser + * @see RedBrowser::set_writeable() + */ + public function setBrowserPlugin($browser) + { + $this->browser = $browser; + } + + /** + * @brief Prints out all BasicAuth variables to logger(). + * + * @return void + */ + public function log() + { // logger('channel_name ' . $this->channel_name, LOGGER_DATA); // logger('channel_id ' . $this->channel_id, LOGGER_DATA); // logger('channel_hash ' . $this->channel_hash, LOGGER_DATA); // logger('observer ' . $this->observer, LOGGER_DATA); // logger('owner_id ' . $this->owner_id, LOGGER_DATA); // logger('owner_nick ' . $this->owner_nick, LOGGER_DATA); - } + } } diff --git a/Zotlabs/Storage/CalDAVClient.php b/Zotlabs/Storage/CalDAVClient.php index c1a8db932..30faf3784 100644 --- a/Zotlabs/Storage/CalDAVClient.php +++ b/Zotlabs/Storage/CalDAVClient.php @@ -26,52 +26,56 @@ namespace Zotlabs\Storage; // Sabre vobject provides a function to automatically expand recurring events into individual event instances. +class CalDAVClient +{ -class CalDAVClient { + private $username; + private $password; - private $username; - private $password; + private $url; - private $url; + public $filepos = 0; + public $request_data = ''; - public $filepos = 0; - public $request_data = ''; + public function __construct($user, $pass, $url) + { + $this->username = $user; + $this->password = $pass; + $this->url = $url; - function __construct($user,$pass,$url) { - $this->username = $user; - $this->password = $pass; - $this->url = $url; + } - } + private function set_data($s) + { + $this->request_data = $s; + $this->filepos = 0; + } - private function set_data($s) { - $this->request_data = $s; - $this->filepos = 0; - } + public function curl_read($ch, $fh, $size) + { - public function curl_read($ch,$fh,$size) { + if ($this->filepos < 0) { + unset($fh); + return ''; + } - if($this->filepos < 0) { - unset($fh); - return ''; - } + $s = substr($this->request_data, $this->filepos, $size); - $s = substr($this->request_data,$this->filepos,$size); + if (strlen($s) < $size) + $this->filepos = (-1); + else + $this->filepos = $this->filepos + $size; - if(strlen($s) < $size) - $this->filepos = (-1); - else - $this->filepos = $this->filepos + $size; + return $s; + } - return $s; - } + public function ctag_fetch() + { + $headers = ['Depth: 0', 'Prefer: return-minimal', 'Content-Type: application/xml; charset=utf-8']; - function ctag_fetch() { - $headers = [ 'Depth: 0', 'Prefer: return-minimal', 'Content-Type: application/xml; charset=utf-8']; + // recommended ctag fetch by sabre - // recommended ctag fetch by sabre - - $this->set_data(' + $this->set_data(' @@ -80,10 +84,10 @@ class CalDAVClient { '); - // thunderbird uses this - it's a bit more verbose on what capabilities - // are provided by the server + // thunderbird uses this - it's a bit more verbose on what capabilities + // are provided by the server - $this->set_data(' + $this->set_data(' @@ -96,33 +100,33 @@ class CalDAVClient { '); + $auth = $this->username . ':' . $this->password; - $auth = $this->username . ':' . $this->password; + $recurse = 0; - $recurse = 0; + $x = z_fetch_url($this->url, true, $recurse, + ['headers' => $headers, + 'http_auth' => $auth, + 'custom' => 'PROPFIND', + 'upload' => true, + 'infile' => 3, + 'infilesize' => strlen($this->request_data), + 'readfunc' => [$this, 'curl_read'] + ]); - $x = z_fetch_url($this->url,true,$recurse, - [ 'headers' => $headers, - 'http_auth' => $auth, - 'custom' => 'PROPFIND', - 'upload' => true, - 'infile' => 3, - 'infilesize' => strlen($this->request_data), - 'readfunc' => [ $this, 'curl_read' ] - ]); + return $x; - return $x; - - } + } - function detail_fetch() { - $headers = [ 'Depth: 1', 'Prefer: return-minimal', 'Content-Type: application/xml; charset=utf-8']; + public function detail_fetch() + { + $headers = ['Depth: 1', 'Prefer: return-minimal', 'Content-Type: application/xml; charset=utf-8']; - // this query should return all objects in the given calendar, you can filter it appropriately - // using filter options + // this query should return all objects in the given calendar, you can filter it appropriately + // using filter options - $this->set_data(' + $this->set_data(' @@ -133,23 +137,23 @@ class CalDAVClient { '); - $auth = $this->username . ':' . $this->password; + $auth = $this->username . ':' . $this->password; - $recurse = 0; - $x = z_fetch_url($this->url,true,$recurse, - [ 'headers' => $headers, - 'http_auth' => $auth, - 'custom' => 'REPORT', - 'upload' => true, - 'infile' => 3, - 'infilesize' => strlen($this->request_data), - 'readfunc' => [ $this, 'curl_read' ] - ]); + $recurse = 0; + $x = z_fetch_url($this->url, true, $recurse, + ['headers' => $headers, + 'http_auth' => $auth, + 'custom' => 'REPORT', + 'upload' => true, + 'infile' => 3, + 'infilesize' => strlen($this->request_data), + 'readfunc' => [$this, 'curl_read'] + ]); - return $x; + return $x; - } + } } diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php index db9eca4aa..21c9d2df9 100644 --- a/Zotlabs/Storage/Directory.php +++ b/Zotlabs/Storage/Directory.php @@ -22,919 +22,930 @@ require_once('include/photos.php'); * * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) */ -class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMoveTarget { +class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMoveTarget +{ - /** - * @brief The path inside /cloud - * - * @var string $red_path - */ - private $red_path; - private $folder_hash; - /** - * @brief The full path as seen in the browser. - * /cloud + $red_path - * @todo I think this is not used anywhere, we always strip '/cloud' and only use it in debug - * @var string $ext_path - */ - private $ext_path; - private $root_dir = ''; - private $auth; - /** - * @brief The real path on the filesystem. - * The actual path in store/ with the hashed names. - * - * @var string $os_path - */ - private $os_path = ''; + /** + * @brief The path inside /cloud + * + * @var string $red_path + */ + private $red_path; + private $folder_hash; + /** + * @brief The full path as seen in the browser. + * /cloud + $red_path + * @todo I think this is not used anywhere, we always strip '/cloud' and only use it in debug + * @var string $ext_path + */ + private $ext_path; + private $root_dir = ''; + private $auth; + /** + * @brief The real path on the filesystem. + * The actual path in store/ with the hashed names. + * + * @var string $os_path + */ + private $os_path = ''; - /** - * @brief Sets up the directory node, expects a full path. - * - * @param string $ext_path a full path - * @param BasicAuth &$auth_plugin - */ - public function __construct($ext_path, &$auth_plugin) { - // $ext_path = urldecode($ext_path); - logger('directory ' . $ext_path, LOGGER_DATA); - $this->ext_path = $ext_path; - // remove "/cloud" from the beginning of the path - $modulename = App::$module; - $this->red_path = ((strpos($ext_path, '/' . $modulename) === 0) ? substr($ext_path, strlen($modulename) + 1) : $ext_path); - if (! $this->red_path) { - $this->red_path = '/'; - } - $this->auth = $auth_plugin; - $this->folder_hash = ''; - $this->getDir(); + /** + * @brief Sets up the directory node, expects a full path. + * + * @param string $ext_path a full path + * @param BasicAuth &$auth_plugin + */ + public function __construct($ext_path, &$auth_plugin) + { + // $ext_path = urldecode($ext_path); + logger('directory ' . $ext_path, LOGGER_DATA); + $this->ext_path = $ext_path; + // remove "/cloud" from the beginning of the path + $modulename = App::$module; + $this->red_path = ((strpos($ext_path, '/' . $modulename) === 0) ? substr($ext_path, strlen($modulename) + 1) : $ext_path); + if (!$this->red_path) { + $this->red_path = '/'; + } + $this->auth = $auth_plugin; + $this->folder_hash = ''; + $this->getDir(); - if($this->auth->browser) { - $this->auth->browser->set_writeable(); - } - } + if ($this->auth->browser) { + $this->auth->browser->set_writeable(); + } + } - private function log() { - logger('ext_path ' . $this->ext_path, LOGGER_DATA); - logger('os_path ' . $this->os_path, LOGGER_DATA); - logger('red_path ' . $this->red_path, LOGGER_DATA); - } + private function log() + { + logger('ext_path ' . $this->ext_path, LOGGER_DATA); + logger('os_path ' . $this->os_path, LOGGER_DATA); + logger('red_path ' . $this->red_path, LOGGER_DATA); + } - /** - * @brief Returns an array with all the child nodes. - * - * @throw "\Sabre\DAV\Exception\Forbidden" - * @return array \\Sabre\\DAV\\INode[] - */ - public function getChildren() { - logger('children for ' . $this->ext_path, LOGGER_DATA); - $this->log(); + /** + * @brief Returns an array with all the child nodes. + * + * @throw "\Sabre\DAV\Exception\Forbidden" + * @return array \\Sabre\\DAV\\INode[] + */ + public function getChildren() + { + logger('children for ' . $this->ext_path, LOGGER_DATA); + $this->log(); - if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (get_config('system', 'block_public') && (!$this->auth->channel_id) && (!$this->auth->observer)) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } - if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (($this->auth->owner_id) && (!perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } - $contents = $this->CollectionData($this->red_path, $this->auth); - return $contents; - } + $contents = $this->CollectionData($this->red_path, $this->auth); + return $contents; + } - /** - * @brief Returns a child by name. - * - * @throw "\Sabre\DAV\Exception\Forbidden" - * @throw "\Sabre\DAV\Exception\NotFound" - * @param string $name - */ - public function getChild($name) { - logger($name, LOGGER_DATA); + /** + * @brief Returns a child by name. + * + * @throw "\Sabre\DAV\Exception\Forbidden" + * @throw "\Sabre\DAV\Exception\NotFound" + * @param string $name + */ + public function getChild($name) + { + logger($name, LOGGER_DATA); - if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (get_config('system', 'block_public') && (!$this->auth->channel_id) && (!$this->auth->observer)) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } - if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (($this->auth->owner_id) && (!perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } - $modulename = App::$module; - if ($this->red_path === '/' && $name === $modulename) { - return new Directory('/' . $modulename, $this->auth); - } + $modulename = App::$module; + if ($this->red_path === '/' && $name === $modulename) { + return new Directory('/' . $modulename, $this->auth); + } - $x = $this->FileData($this->ext_path . '/' . $name, $this->auth); - if ($x) { - return $x; - } + $x = $this->FileData($this->ext_path . '/' . $name, $this->auth); + if ($x) { + return $x; + } - throw new DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found.'); - } + throw new DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found.'); + } - /** - * @brief Returns the name of the directory. - * - * @return string - */ - public function getName() { - return (basename($this->red_path)); - } + /** + * @brief Returns the name of the directory. + * + * @return string + */ + public function getName() + { + return (basename($this->red_path)); + } - /** - * @brief Renames the directory. - * - * @todo handle duplicate directory name - * - * @throw "\Sabre\DAV\Exception\Forbidden" - * @param string $name The new name of the directory. - * @return void - */ - public function setName($name) { - logger('old name ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA); + /** + * @brief Renames the directory. + * + * @param string $name The new name of the directory. + * @return void + * @todo handle duplicate directory name + * + * @throw "\Sabre\DAV\Exception\Forbidden" + */ + public function setName($name) + { + logger('old name ' . basename($this->red_path) . ' -> ' . $name, LOGGER_DATA); - if ((! $name) || (! $this->auth->owner_id)) { - logger('permission denied ' . $name); - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if ((!$name) || (!$this->auth->owner_id)) { + logger('permission denied ' . $name); + throw new DAV\Exception\Forbidden('Permission denied.'); + } - if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { - logger('permission denied '. $name); - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (!perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { + logger('permission denied ' . $name); + throw new DAV\Exception\Forbidden('Permission denied.'); + } - list($parent_path, ) = \Sabre\Uri\split($this->red_path); - $new_path = $parent_path . '/' . $name; + list($parent_path,) = \Sabre\Uri\split($this->red_path); + $new_path = $parent_path . '/' . $name; - $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d", - dbesc($name), - dbesc($this->folder_hash), - intval($this->auth->owner_id) - ); + $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND uid = %d", + dbesc($name), + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); - $x = attach_syspaths($this->auth->owner_id,$this->folder_hash); + $x = attach_syspaths($this->auth->owner_id, $this->folder_hash); - $y = q("update attach set display_path = '%s' where hash = '%s' and uid = %d", - dbesc($x['path']), - dbesc($this->folder_hash), - intval($this->auth->owner_id) - ); + $y = q("update attach set display_path = '%s' where hash = '%s' and uid = %d", + dbesc($x['path']), + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); - $ch = channelx_by_n($this->auth->owner_id); - if ($ch) { - $sync = attach_export_data($ch, $this->folder_hash); - if ($sync) { - Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync))); - } - } + $ch = channelx_by_n($this->auth->owner_id); + if ($ch) { + $sync = attach_export_data($ch, $this->folder_hash); + if ($sync) { + Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync))); + } + } - $this->red_path = $new_path; - } + $this->red_path = $new_path; + } - /** - * @brief Creates a new file in the directory. - * - * Data will either be supplied as a stream resource, or in certain cases - * as a string. Keep in mind that you may have to support either. - * - * After successful creation of the file, you may choose to return the ETag - * of the new file here. - * - * @throw "\Sabre\DAV\Exception\Forbidden" - * @param string $name Name of the file - * @param resource|string $data Initial payload - * @return null|string ETag - */ - public function createFile($name, $data = null) { - logger('create file in directory ' . $name, LOGGER_DEBUG); + /** + * @brief Creates a new file in the directory. + * + * Data will either be supplied as a stream resource, or in certain cases + * as a string. Keep in mind that you may have to support either. + * + * After successful creation of the file, you may choose to return the ETag + * of the new file here. + * + * @throw "\Sabre\DAV\Exception\Forbidden" + * @param string $name Name of the file + * @param resource|string $data Initial payload + * @return null|string ETag + */ + public function createFile($name, $data = null) + { + logger('create file in directory ' . $name, LOGGER_DEBUG); - if (! $this->auth->owner_id) { - logger('permission denied ' . $name); - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (!$this->auth->owner_id) { + logger('permission denied ' . $name); + throw new DAV\Exception\Forbidden('Permission denied.'); + } - if (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { - logger('permission denied ' . $name); - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (!perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage')) { + logger('permission denied ' . $name); + throw new DAV\Exception\Forbidden('Permission denied.'); + } - $mimetype = z_mime_content_type($name); + $mimetype = z_mime_content_type($name); - $channel = channelx_by_n($this->auth->owner_id); + $channel = channelx_by_n($this->auth->owner_id); - if (! $channel) { - logger('no channel'); - throw new DAV\Exception\Forbidden('Permission denied.'); - } + if (!$channel) { + logger('no channel'); + throw new DAV\Exception\Forbidden('Permission denied.'); + } - $filesize = 0; - $hash = new_uuid(); + $filesize = 0; + $hash = new_uuid(); - $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash; + $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $hash; - $direct = null; + $direct = null; - if ($this->folder_hash) { - $r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", - dbesc($this->folder_hash), - intval($channel['channel_id']) - ); - if ($r) { - $direct = array_shift($r); - } - } + if ($this->folder_hash) { + $r = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", + dbesc($this->folder_hash), + intval($channel['channel_id']) + ); + if ($r) { + $direct = array_shift($r); + } + } - if (($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) { - $allow_cid = $direct['allow_cid']; - $allow_gid = $direct['allow_gid']; - $deny_cid = $direct['deny_cid']; - $deny_gid = $direct['deny_gid']; - } - else { - $allow_cid = $channel['channel_allow_cid']; - $allow_gid = $channel['channel_allow_gid']; - $deny_cid = $channel['channel_deny_cid']; - $deny_gid = $channel['channel_deny_gid']; - } + if (($direct) && (($direct['allow_cid']) || ($direct['allow_gid']) || ($direct['deny_cid']) || ($direct['deny_gid']))) { + $allow_cid = $direct['allow_cid']; + $allow_gid = $direct['allow_gid']; + $deny_cid = $direct['deny_cid']; + $deny_gid = $direct['deny_gid']; + } else { + $allow_cid = $channel['channel_allow_cid']; + $allow_gid = $channel['channel_allow_gid']; + $deny_cid = $channel['channel_deny_cid']; + $deny_gid = $channel['channel_deny_gid']; + } - $created = $edited = datetime_convert(); + $created = $edited = datetime_convert(); - $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, content, created, edited, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid ) + $r = q("INSERT INTO attach ( aid, uid, hash, creator, filename, folder, os_storage, filetype, filesize, revision, is_photo, content, created, edited, os_path, display_path, allow_cid, allow_gid, deny_cid, deny_gid ) VALUES ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ) ", - intval($channel['channel_account_id']), - intval($channel['channel_id']), - dbesc($hash), - dbesc($this->auth->observer), - dbesc($name), - dbesc($this->folder_hash), - intval(1), - dbesc($mimetype), - intval($filesize), - intval(0), - intval(0), - dbesc($f), - dbesc($created), - dbesc($edited), - '', - '', - dbesc($allow_cid), - dbesc($allow_gid), - dbesc($deny_cid), - dbesc($deny_gid) - ); - - // fetch the actual storage paths - - $xpath = attach_syspaths($this->auth->owner_id, $hash); - - if (is_resource($data)) { - $fp = fopen($f,'wb'); - if ($fp) { - pipe_streams($data,$fp); - fclose($fp); - } - $size = filesize($f); - } - else { - $size = file_put_contents($f, $data); - } - - // delete attach entry if file_put_contents() failed - if ($size === false) { - logger('file_put_contents() failed to ' . $f); - attach_delete($channel['channel_id'], $hash); - return; - } - - $is_photo = 0; - $gis = @getimagesize($f); - logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA); - if (($gis) && supported_imagetype($gis[2])) { - $is_photo = 1; - } - - // If we know it's a photo, over-ride the type in case the source system could not determine what it was - - if ($is_photo) { - q("update attach set filetype = '%s' where hash = '%s' and uid = %d", - dbesc($gis['mime']), - dbesc($hash), - intval($channel['channel_id']) - ); - } - - // updates entry with path and filesize - $d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d WHERE hash = '%s' AND uid = %d", - dbesc($size), - dbesc($xpath['os_path']), - dbesc($xpath['path']), - intval($is_photo), - dbesc($hash), - intval($channel['channel_id']) - ); - - // update the parent folder's lastmodified timestamp - $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", - dbesc($edited), - dbesc($this->folder_hash), - intval($channel['channel_id']) - ); - - $maxfilesize = get_config('system', 'maxfilesize'); - if (($maxfilesize) && ($size > $maxfilesize)) { - logger('system maxfilesize exceeded. Deleting uploaded file.'); - attach_delete($channel['channel_id'], $hash); - return; - } - - // check against service class quota - $limit = engr_units_to_bytes(service_class_fetch($channel['channel_id'], 'attach_upload_limit')); - if ($limit !== false) { - $z = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", - intval($channel['channel_account_id']) - ); - if (($z) && ($z[0]['total'] + $size > $limit)) { - logger('service class limit exceeded for ' . $channel['channel_name'] . ' total usage is ' . $z[0]['total'] . ' limit is ' . userReadableSize($limit)); - attach_delete($channel['channel_id'], $hash); - return; - } - } - - if ($is_photo) { - $album = ''; - if ($this->folder_hash) { - $f1 = q("select filename, display_path from attach WHERE hash = '%s' AND uid = %d", - dbesc($this->folder_hash), - intval($channel['channel_id']) - ); - if ($f1) { - $album = (($f1[0]['display_path']) ? $f1[0]['display_path'] : $f1[0]['filename']); - } - } - - $args = [ - 'resource_id' => $hash, - 'album' => $album, - 'folder' => $this->folder_hash, - 'os_syspath' => $f, - 'os_path' => $xpath['os_path'], - 'display_path' => $xpath['path'], - 'filename' => $name, - 'getimagesize' => $gis, - 'directory' => $direct - ]; - $p = photo_upload($channel, App::get_observer(), $args); - } - - Run::Summon([ 'Thumbnail' , $hash ]); - - $sync = attach_export_data($channel, $hash); - - if ($sync) { - Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); - } - } - - /** - * @brief Creates a new subdirectory. - * - * @param string $name the directory to create - * @return void - */ - public function createDirectory($name) { - logger('create directory ' . $name, LOGGER_DEBUG); - - if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - $channel = channelx_by_n($this->auth->owner_id); - - if ($channel) { - - // When initiated from DAV, set the 'force' flag on attach_mkdir(). This will cause the operation to report success even if the - // folder already exists. - - require_once('include/attach.php'); - $result = attach_mkdir($channel, $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash, 'force' => true)); - - if ($result['success']) { - $sync = attach_export_data($channel,$result['data']['hash']); - logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG); - - if ($sync) { - Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); - } - } - else { - logger('error ' . print_r($result, true), LOGGER_DEBUG); - } - } - } - - /** - * @brief delete directory - */ - public function delete() { - logger('delete file ' . basename($this->red_path), LOGGER_DEBUG); - - if ((! $this->auth->owner_id) || (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - - if ($this->auth->owner_id !== $this->auth->channel_id) { - if (($this->auth->observer !== $this->data['creator']) || intval($this->data['is_dir'])) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - } - - attach_delete($this->auth->owner_id, $this->folder_hash); - - $channel = channelx_by_n($this->auth->owner_id); - if ($channel) { - $sync = attach_export_data($channel, $this->folder_hash, true); - if ($sync) { - Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); - } - } - } - - - /** - * @brief Checks if a child exists. - * - * @param string $name - * The name to check if it exists. - * @return boolean - */ - public function childExists($name) { - // On /cloud we show a list of available channels. - // @todo what happens if no channels are available? - $modulename = App::$module; - if ($this->red_path === '/' && $name === $modulename) { - //logger('We are at ' $modulename . ' show a channel list', LOGGER_DEBUG); - return true; - } - - $x = $this->FileData($this->ext_path . '/' . $name, $this->auth, true); - //logger('FileData returns: ' . print_r($x, true), LOGGER_DATA); - if ($x) { - return true; - } - return false; - } - - - public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) { - - if (! $this->auth->owner_id) { - return false; - } - - if(! ($sourceNode->data && $sourceNode->data['hash'])) { - return false; - } - - return attach_move($this->auth->owner_id, $sourceNode->data['hash'], $this->folder_hash); - } - - - /** - * @todo add description of what this function does. - * - * @throw "\Sabre\DAV\Exception\NotFound" - * @return void - */ - function getDir() { - - logger('GetDir: ' . $this->ext_path, LOGGER_DEBUG); - $this->auth->log(); - $modulename = App::$module; - - $file = $this->ext_path; - - $x = strpos($file, '/' . $modulename); - if ($x === 0) { - $file = substr($file, strlen($modulename) + 1); - } - - if ((! $file) || ($file === '/')) { - return; - } - - $file = trim($file, '/'); - $path_arr = explode('/', $file); - - if (! $path_arr) - return; - - logger('paths: ' . print_r($path_arr, true), LOGGER_DATA); - - $channel_name = $path_arr[0]; - - $channel = channelx_by_nick($channel_name); - - if (! $channel) { - throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.'); - } - - $channel_id = $channel['channel_id']; - $this->auth->owner_id = $channel_id; - $this->auth->owner_nick = $channel_name; - - $path = '/' . $channel_name; - $folder = ''; - $os_path = ''; - - for ($x = 1; $x < count($path_arr); $x++) { - $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0", - dbesc($folder), - dbesc($path_arr[$x]), - intval($channel_id) - ); - if ($r && intval($r[0]['is_dir'])) { - $folder = $r[0]['hash']; - if (strlen($os_path)) { - $os_path .= '/'; - } - $os_path .= $folder; - $path = $path . '/' . $r[0]['filename']; - } - } - $this->folder_hash = $folder; - $this->os_path = $os_path; - } - - /** - * @brief Returns the last modification time for the directory, as a UNIX - * timestamp. - * - * It looks for the last edited file in the folder. If it is an empty folder - * it returns the lastmodified time of the folder itself, to prevent zero - * timestamps. - * - * @return int last modification time in UNIX timestamp - */ - public function getLastModified() { - $r = q("SELECT edited FROM attach WHERE folder = '%s' AND uid = %d ORDER BY edited DESC LIMIT 1", - dbesc($this->folder_hash), - intval($this->auth->owner_id) - ); - if (! $r) { - $r = q("SELECT edited FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", - dbesc($this->folder_hash), - intval($this->auth->owner_id) - ); - if (! $r) - return ''; - } - return datetime_convert('UTC', 'UTC', $r[0]['edited'], 'U'); - } - - - /** - * @brief Array with all Directory and File DAV\\Node items for the given path. - * - * @param string $file path to a directory - * @param BasicAuth &$auth - * @returns null|array \\Sabre\\DAV\\INode[] - * @throw "\Sabre\DAV\Exception\Forbidden" - * @throw "\Sabre\DAV\Exception\NotFound" - */ - function CollectionData($file, &$auth) { - $ret = []; - - $x = strpos($file, '/cloud'); - if ($x === 0) { - $file = substr($file, 6); - } - - // return a list of channel if we are not inside a channel - if ((! $file) || ($file === '/')) { - return $this->ChannelList($auth); - } - - $file = trim($file, '/'); - $path_arr = explode('/', $file); - - if (! $path_arr) { - return null; - } - - $channel_name = $path_arr[0]; - - $channel = channelx_by_nick($channel_name); - - if (! $channel) { - return null; - } - - $channel_id = $channel['channel_id']; - $perms = permissions_sql($channel_id); - - $auth->owner_id = $channel_id; - - $path = '/' . $channel_name; - - $folder = ''; - $errors = false; - $permission_error = false; - - for ($x = 1; $x < count($path_arr); $x++) { - $r = q("SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1", - dbesc($folder), - dbesc($path_arr[$x]), - intval($channel_id) - ); - if (! $r) { - // path wasn't found. Try without permissions to see if it was the result of permissions. - $errors = true; - $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1", - dbesc($folder), - basename($path_arr[$x]), - intval($channel_id) - ); - if ($r) { - $permission_error = true; - } - break; - } - - if ($r && intval($r[0]['is_dir'])) { - $folder = $r[0]['hash']; - $path = $path . '/' . $r[0]['filename']; - } - } - - if ($errors) { - if ($permission_error) { - throw new DAV\Exception\Forbidden('Permission denied.'); - } - else { - throw new DAV\Exception\NotFound('A component of the requested file path could not be found.'); - } - } - - // This should no longer be needed since we just returned errors for paths not found - if ($path !== '/' . $file) { - logger("Path mismatch: $path !== /$file"); - return NULL; - } - - $prefix = ''; - - if(! array_key_exists('cloud_sort',$_SESSION)) - $_SESSION['cloud_sort'] = 'name'; - - switch($_SESSION['cloud_sort']) { - case 'size': - $suffix = ' order by is_dir desc, filesize asc '; - break; - // The following provides inconsistent results for directories because we re-calculate the date for directories based on the most recent change - case 'date': - $suffix = ' order by is_dir desc, edited asc '; - break; - case 'name': - default: - $suffix = ' order by is_dir desc, filename asc '; - break; - } - - $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix", - dbesc($folder), - intval($channel_id) - ); - - foreach ($r as $rr) { - if (App::$module === 'cloud' && (strpos($rr['filename'],'.') === 0) && (! get_pconfig($channel_id,'system','show_dot_files')) ) { - continue; - } - - // @FIXME I don't think we use revisions currently in attach structures. - // In case we see any in the wild provide a unique filename. This - // name may or may not be accessible - - if ($rr['revision']) { - $rr['filename'] .= '-' . $rr['revision']; - } - - // logger('filename: ' . $rr['filename'], LOGGER_DEBUG); - if (intval($rr['is_dir'])) { - $ret[] = new Directory($path . '/' . $rr['filename'], $auth); - } - else { - $ret[] = new File($path . '/' . $rr['filename'], $rr, $auth); - } - } - - return $ret; - } - - - /** - * @brief Returns an array with viewable channels. - * - * Get a list of Directory objects with all the channels where the visitor - * has view_storage perms. - * - * - * @param BasicAuth &$auth - * @return array Directory[] - */ - function ChannelList(&$auth) { - $ret = []; - - $disabled = intval(get_config('system','cloud_disable_siteroot',true)); - - $r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0 and profile.is_default = 1", - intval(PAGE_HIDDEN) - ); - if ($r) { - foreach ($r as $rr) { - if ((perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) || $rr['channel_id'] == $this->auth->channel_id) { - logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA); - if ($disabled) { - $conn = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' and abook_pending = 0", - intval($rr['channel_id']), - dbesc($auth->observer) - ); - if (! $conn) { - continue; - } - } - - $ret[] = new Directory($rr['channel_address'], $auth); - } - } - } - return $ret; - } - - - /** - * @brief - * - * @param string $file - * path to file or directory - * @param BasicAuth &$auth - * @param boolean $test (optional) enable test mode - * @return File|Directory|boolean|null - * @throw "\Sabre\DAV\Exception\Forbidden" - */ - function FileData($file, &$auth, $test = false) { - logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA); - - $x = strpos($file, '/cloud'); - if ($x === 0) { - $file = substr($file, 6); - } - else { - $x = strpos($file, '/dav'); - if($x === 0) - $file = substr($file, 4); - } - - if ((! $file) || ($file === '/')) { - return new Directory('/', $auth); - } - - $file = trim($file, '/'); - - $path_arr = explode('/', $file); - - if (! $path_arr) - return null; - - $channel_name = $path_arr[0]; - - $r = q("select channel_id from channel where channel_address = '%s' limit 1", - dbesc($channel_name) - ); - - if (! $r) - return null; - - $channel_id = $r[0]['channel_id']; - - $path = '/' . $channel_name; - - $auth->owner_id = $channel_id; - - $permission_error = false; - - $folder = ''; - - require_once('include/security.php'); - $perms = permissions_sql($channel_id); - - $errors = false; - - for ($x = 1; $x < count($path_arr); $x++) { - $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms", - dbesc($folder), - dbesc($path_arr[$x]), - intval($channel_id) - ); - - if ($r && intval($r[0]['is_dir'])) { - $folder = $r[0]['hash']; - $path = $path . '/' . $r[0]['filename']; - } - if (! $r) { - $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach + intval($channel['channel_account_id']), + intval($channel['channel_id']), + dbesc($hash), + dbesc($this->auth->observer), + dbesc($name), + dbesc($this->folder_hash), + intval(1), + dbesc($mimetype), + intval($filesize), + intval(0), + intval(0), + dbesc($f), + dbesc($created), + dbesc($edited), + '', + '', + dbesc($allow_cid), + dbesc($allow_gid), + dbesc($deny_cid), + dbesc($deny_gid) + ); + + // fetch the actual storage paths + + $xpath = attach_syspaths($this->auth->owner_id, $hash); + + if (is_resource($data)) { + $fp = fopen($f, 'wb'); + if ($fp) { + pipe_streams($data, $fp); + fclose($fp); + } + $size = filesize($f); + } else { + $size = file_put_contents($f, $data); + } + + // delete attach entry if file_put_contents() failed + if ($size === false) { + logger('file_put_contents() failed to ' . $f); + attach_delete($channel['channel_id'], $hash); + return; + } + + $is_photo = 0; + $gis = @getimagesize($f); + logger('getimagesize: ' . print_r($gis, true), LOGGER_DATA); + if (($gis) && supported_imagetype($gis[2])) { + $is_photo = 1; + } + + // If we know it's a photo, over-ride the type in case the source system could not determine what it was + + if ($is_photo) { + q("update attach set filetype = '%s' where hash = '%s' and uid = %d", + dbesc($gis['mime']), + dbesc($hash), + intval($channel['channel_id']) + ); + } + + // updates entry with path and filesize + $d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d WHERE hash = '%s' AND uid = %d", + dbesc($size), + dbesc($xpath['os_path']), + dbesc($xpath['path']), + intval($is_photo), + dbesc($hash), + intval($channel['channel_id']) + ); + + // update the parent folder's lastmodified timestamp + $e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d", + dbesc($edited), + dbesc($this->folder_hash), + intval($channel['channel_id']) + ); + + $maxfilesize = get_config('system', 'maxfilesize'); + if (($maxfilesize) && ($size > $maxfilesize)) { + logger('system maxfilesize exceeded. Deleting uploaded file.'); + attach_delete($channel['channel_id'], $hash); + return; + } + + // check against service class quota + $limit = engr_units_to_bytes(service_class_fetch($channel['channel_id'], 'attach_upload_limit')); + if ($limit !== false) { + $z = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", + intval($channel['channel_account_id']) + ); + if (($z) && ($z[0]['total'] + $size > $limit)) { + logger('service class limit exceeded for ' . $channel['channel_name'] . ' total usage is ' . $z[0]['total'] . ' limit is ' . userReadableSize($limit)); + attach_delete($channel['channel_id'], $hash); + return; + } + } + + if ($is_photo) { + $album = ''; + if ($this->folder_hash) { + $f1 = q("select filename, display_path from attach WHERE hash = '%s' AND uid = %d", + dbesc($this->folder_hash), + intval($channel['channel_id']) + ); + if ($f1) { + $album = (($f1[0]['display_path']) ? $f1[0]['display_path'] : $f1[0]['filename']); + } + } + + $args = [ + 'resource_id' => $hash, + 'album' => $album, + 'folder' => $this->folder_hash, + 'os_syspath' => $f, + 'os_path' => $xpath['os_path'], + 'display_path' => $xpath['path'], + 'filename' => $name, + 'getimagesize' => $gis, + 'directory' => $direct + ]; + $p = photo_upload($channel, App::get_observer(), $args); + } + + Run::Summon(['Thumbnail', $hash]); + + $sync = attach_export_data($channel, $hash); + + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } + } + + /** + * @brief Creates a new subdirectory. + * + * @param string $name the directory to create + * @return void + */ + public function createDirectory($name) + { + logger('create directory ' . $name, LOGGER_DEBUG); + + if ((!$this->auth->owner_id) || (!perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + $channel = channelx_by_n($this->auth->owner_id); + + if ($channel) { + + // When initiated from DAV, set the 'force' flag on attach_mkdir(). This will cause the operation to report success even if the + // folder already exists. + + require_once('include/attach.php'); + $result = attach_mkdir($channel, $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash, 'force' => true)); + + if ($result['success']) { + $sync = attach_export_data($channel, $result['data']['hash']); + logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG); + + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } + } else { + logger('error ' . print_r($result, true), LOGGER_DEBUG); + } + } + } + + /** + * @brief delete directory + */ + public function delete() + { + logger('delete file ' . basename($this->red_path), LOGGER_DEBUG); + + if ((!$this->auth->owner_id) || (!perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'write_storage'))) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + + if ($this->auth->owner_id !== $this->auth->channel_id) { + if (($this->auth->observer !== $this->data['creator']) || intval($this->data['is_dir'])) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } + } + + attach_delete($this->auth->owner_id, $this->folder_hash); + + $channel = channelx_by_n($this->auth->owner_id); + if ($channel) { + $sync = attach_export_data($channel, $this->folder_hash, true); + if ($sync) { + Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); + } + } + } + + + /** + * @brief Checks if a child exists. + * + * @param string $name + * The name to check if it exists. + * @return bool + */ + public function childExists($name) + { + // On /cloud we show a list of available channels. + // @todo what happens if no channels are available? + $modulename = App::$module; + if ($this->red_path === '/' && $name === $modulename) { + //logger('We are at ' $modulename . ' show a channel list', LOGGER_DEBUG); + return true; + } + + $x = $this->FileData($this->ext_path . '/' . $name, $this->auth, true); + //logger('FileData returns: ' . print_r($x, true), LOGGER_DATA); + if ($x) { + return true; + } + return false; + } + + + public function moveInto($targetName, $sourcePath, DAV\INode $sourceNode) + { + + if (!$this->auth->owner_id) { + return false; + } + + if (!($sourceNode->data && $sourceNode->data['hash'])) { + return false; + } + + return attach_move($this->auth->owner_id, $sourceNode->data['hash'], $this->folder_hash); + } + + + /** + * @return void + * @todo add description of what this function does. + * + * @throw "\Sabre\DAV\Exception\NotFound" + */ + public function getDir() + { + + logger('GetDir: ' . $this->ext_path, LOGGER_DEBUG); + $this->auth->log(); + $modulename = App::$module; + + $file = $this->ext_path; + + $x = strpos($file, '/' . $modulename); + if ($x === 0) { + $file = substr($file, strlen($modulename) + 1); + } + + if ((!$file) || ($file === '/')) { + return; + } + + $file = trim($file, '/'); + $path_arr = explode('/', $file); + + if (!$path_arr) + return; + + logger('paths: ' . print_r($path_arr, true), LOGGER_DATA); + + $channel_name = $path_arr[0]; + + $channel = channelx_by_nick($channel_name); + + if (!$channel) { + throw new DAV\Exception\NotFound('The file with name: ' . $channel_name . ' could not be found.'); + } + + $channel_id = $channel['channel_id']; + $this->auth->owner_id = $channel_id; + $this->auth->owner_nick = $channel_name; + + $path = '/' . $channel_name; + $folder = ''; + $os_path = ''; + + for ($x = 1; $x < count($path_arr); $x++) { + $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0", + dbesc($folder), + dbesc($path_arr[$x]), + intval($channel_id) + ); + if ($r && intval($r[0]['is_dir'])) { + $folder = $r[0]['hash']; + if (strlen($os_path)) { + $os_path .= '/'; + } + $os_path .= $folder; + $path = $path . '/' . $r[0]['filename']; + } + } + $this->folder_hash = $folder; + $this->os_path = $os_path; + } + + /** + * @brief Returns the last modification time for the directory, as a UNIX + * timestamp. + * + * It looks for the last edited file in the folder. If it is an empty folder + * it returns the lastmodified time of the folder itself, to prevent zero + * timestamps. + * + * @return int last modification time in UNIX timestamp + */ + public function getLastModified() + { + $r = q("SELECT edited FROM attach WHERE folder = '%s' AND uid = %d ORDER BY edited DESC LIMIT 1", + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); + if (!$r) { + $r = q("SELECT edited FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); + if (!$r) + return ''; + } + return datetime_convert('UTC', 'UTC', $r[0]['edited'], 'U'); + } + + + /** + * @brief Array with all Directory and File DAV\\Node items for the given path. + * + * @param string $file path to a directory + * @param BasicAuth &$auth + * @returns null|array \\Sabre\\DAV\\INode[] + * @throw "\Sabre\DAV\Exception\Forbidden" + * @throw "\Sabre\DAV\Exception\NotFound" + */ + public function CollectionData($file, &$auth) + { + $ret = []; + + $x = strpos($file, '/cloud'); + if ($x === 0) { + $file = substr($file, 6); + } + + // return a list of channel if we are not inside a channel + if ((!$file) || ($file === '/')) { + return $this->ChannelList($auth); + } + + $file = trim($file, '/'); + $path_arr = explode('/', $file); + + if (!$path_arr) { + return null; + } + + $channel_name = $path_arr[0]; + + $channel = channelx_by_nick($channel_name); + + if (!$channel) { + return null; + } + + $channel_id = $channel['channel_id']; + $perms = permissions_sql($channel_id); + + $auth->owner_id = $channel_id; + + $path = '/' . $channel_name; + + $folder = ''; + $errors = false; + $permission_error = false; + + for ($x = 1; $x < count($path_arr); $x++) { + $r = q("SELECT id, hash, filename, flags, is_dir FROM attach WHERE folder = '%s' AND filename = '%s' AND uid = %d AND is_dir != 0 $perms LIMIT 1", + dbesc($folder), + dbesc($path_arr[$x]), + intval($channel_id) + ); + if (!$r) { + // path wasn't found. Try without permissions to see if it was the result of permissions. + $errors = true; + $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 limit 1", + dbesc($folder), + basename($path_arr[$x]), + intval($channel_id) + ); + if ($r) { + $permission_error = true; + } + break; + } + + if ($r && intval($r[0]['is_dir'])) { + $folder = $r[0]['hash']; + $path = $path . '/' . $r[0]['filename']; + } + } + + if ($errors) { + if ($permission_error) { + throw new DAV\Exception\Forbidden('Permission denied.'); + } else { + throw new DAV\Exception\NotFound('A component of the requested file path could not be found.'); + } + } + + // This should no longer be needed since we just returned errors for paths not found + if ($path !== '/' . $file) { + logger("Path mismatch: $path !== /$file"); + return NULL; + } + + $prefix = ''; + + if (!array_key_exists('cloud_sort', $_SESSION)) + $_SESSION['cloud_sort'] = 'name'; + + switch ($_SESSION['cloud_sort']) { + case 'size': + $suffix = ' order by is_dir desc, filesize asc '; + break; + // The following provides inconsistent results for directories because we re-calculate the date for directories based on the most recent change + case 'date': + $suffix = ' order by is_dir desc, edited asc '; + break; + case 'name': + default: + $suffix = ' order by is_dir desc, filename asc '; + break; + } + + $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix", + dbesc($folder), + intval($channel_id) + ); + + foreach ($r as $rr) { + if (App::$module === 'cloud' && (strpos($rr['filename'], '.') === 0) && (!get_pconfig($channel_id, 'system', 'show_dot_files'))) { + continue; + } + + // @FIXME I don't think we use revisions currently in attach structures. + // In case we see any in the wild provide a unique filename. This + // name may or may not be accessible + + if ($rr['revision']) { + $rr['filename'] .= '-' . $rr['revision']; + } + + // logger('filename: ' . $rr['filename'], LOGGER_DEBUG); + if (intval($rr['is_dir'])) { + $ret[] = new Directory($path . '/' . $rr['filename'], $auth); + } else { + $ret[] = new File($path . '/' . $rr['filename'], $rr, $auth); + } + } + + return $ret; + } + + + /** + * @brief Returns an array with viewable channels. + * + * Get a list of Directory objects with all the channels where the visitor + * has view_storage perms. + * + * + * @param BasicAuth &$auth + * @return array Directory[] + */ + public function ChannelList(&$auth) + { + $ret = []; + + $disabled = intval(get_config('system', 'cloud_disable_siteroot', true)); + + $r = q("SELECT channel_id, channel_address, profile.publish FROM channel left join profile on profile.uid = channel.channel_id WHERE channel_removed = 0 AND channel_system = 0 AND (channel_pageflags & %d) = 0 and profile.is_default = 1", + intval(PAGE_HIDDEN) + ); + if ($r) { + foreach ($r as $rr) { + if ((perm_is_allowed($rr['channel_id'], $auth->observer, 'view_storage') && $rr['publish']) || $rr['channel_id'] == $this->auth->channel_id) { + logger('found channel: /cloud/' . $rr['channel_address'], LOGGER_DATA); + if ($disabled) { + $conn = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' and abook_pending = 0", + intval($rr['channel_id']), + dbesc($auth->observer) + ); + if (!$conn) { + continue; + } + } + + $ret[] = new Directory($rr['channel_address'], $auth); + } + } + } + return $ret; + } + + + /** + * @brief + * + * @param string $file + * path to file or directory + * @param BasicAuth &$auth + * @param bool $test (optional) enable test mode + * @return File|Directory|bool|null + * @throw "\Sabre\DAV\Exception\Forbidden" + */ + public function FileData($file, &$auth, $test = false) + { + logger($file . (($test) ? ' (test mode) ' : ''), LOGGER_DATA); + + $x = strpos($file, '/cloud'); + if ($x === 0) { + $file = substr($file, 6); + } else { + $x = strpos($file, '/dav'); + if ($x === 0) + $file = substr($file, 4); + } + + if ((!$file) || ($file === '/')) { + return new Directory('/', $auth); + } + + $file = trim($file, '/'); + + $path_arr = explode('/', $file); + + if (!$path_arr) + return null; + + $channel_name = $path_arr[0]; + + $r = q("select channel_id from channel where channel_address = '%s' limit 1", + dbesc($channel_name) + ); + + if (!$r) + return null; + + $channel_id = $r[0]['channel_id']; + + $path = '/' . $channel_name; + + $auth->owner_id = $channel_id; + + $permission_error = false; + + $folder = ''; + + require_once('include/security.php'); + $perms = permissions_sql($channel_id); + + $errors = false; + + for ($x = 1; $x < count($path_arr); $x++) { + $r = q("select id, hash, filename, flags, is_dir from attach where folder = '%s' and filename = '%s' and uid = %d and is_dir != 0 $perms", + dbesc($folder), + dbesc($path_arr[$x]), + intval($channel_id) + ); + + if ($r && intval($r[0]['is_dir'])) { + $folder = $r[0]['hash']; + $path = $path . '/' . $r[0]['filename']; + } + if (!$r) { + $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d $perms order by filename limit 1", - dbesc($folder), - dbesc(basename($file)), - intval($channel_id) - ); - } - if (! $r) { - $errors = true; - $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach + dbesc($folder), + dbesc(basename($file)), + intval($channel_id) + ); + } + if (!$r) { + $errors = true; + $r = q("select id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, os_storage, created, edited from attach where folder = '%s' and filename = '%s' and uid = %d order by filename limit 1", - dbesc($folder), - dbesc(basename($file)), - intval($channel_id) - ); - if ($r) - $permission_error = true; - } - } + dbesc($folder), + dbesc(basename($file)), + intval($channel_id) + ); + if ($r) + $permission_error = true; + } + } - if ($path === '/' . $file) { - if ($test) - return true; - // final component was a directory. - return new Directory($file, $auth); - } + if ($path === '/' . $file) { + if ($test) + return true; + // final component was a directory. + return new Directory($file, $auth); + } - if ($errors) { - logger('not found ' . $file); - if ($test) - return false; - if ($permission_error) { - logger('permission error ' . $file); - throw new DAV\Exception\Forbidden('Permission denied.'); - } - return; - } + if ($errors) { + logger('not found ' . $file); + if ($test) + return false; + if ($permission_error) { + logger('permission error ' . $file); + throw new DAV\Exception\Forbidden('Permission denied.'); + } + return; + } - if ($r) { - if ($test) - return true; + if ($r) { + if ($test) + return true; - if (intval($r[0]['is_dir'])) { - return new Directory($path . '/' . $r[0]['filename'], $auth); - } - else { - return new File($path . '/' . $r[0]['filename'], $r[0], $auth); - } - } - return false; - } + if (intval($r[0]['is_dir'])) { + return new Directory($path . '/' . $r[0]['filename'], $auth); + } else { + return new File($path . '/' . $r[0]['filename'], $r[0], $auth); + } + } + return false; + } - public function getQuotaInfo() { + public function getQuotaInfo() + { - /** - * Returns the quota information - * - * This method MUST return an array with 2 values, the first being the total used space, - * the second the available space (in bytes) - */ + /** + * Returns the quota information + * + * This method MUST return an array with 2 values, the first being the total used space, + * the second the available space (in bytes) + */ - $used = 0; - $limit = 0; - $free = 0; - - if ($this->auth->owner_id) { - $channel = channelx_by_n($this->auth->owner_id); - if($channel) { - $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d", - intval($channel['channel_account_id']) - ); - $used = (($r) ? (float) $r[0]['total'] : 0); - $limit = (float) engr_units_to_bytes(service_class_fetch($this->auth->owner_id, 'attach_upload_limit')); - if($limit) { - // Don't let the result go negative - $free = (($limit > $used) ? $limit - $used : 0); - } - } - } + $used = 0; + $limit = 0; + $free = 0; - if(! $limit) { - $free = disk_free_space('store'); - $used = disk_total_space('store') - $free; - } + if ($this->auth->owner_id) { + $channel = channelx_by_n($this->auth->owner_id); + if ($channel) { + $r = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d", + intval($channel['channel_account_id']) + ); + $used = (($r) ? (float)$r[0]['total'] : 0); + $limit = (float)engr_units_to_bytes(service_class_fetch($this->auth->owner_id, 'attach_upload_limit')); + if ($limit) { + // Don't let the result go negative + $free = (($limit > $used) ? $limit - $used : 0); + } + } + } - // prevent integer overflow on 32-bit systems + if (!$limit) { + $free = disk_free_space('store'); + $used = disk_total_space('store') - $free; + } - if($used > (float) PHP_INT_MAX) - $used = PHP_INT_MAX; - if($free > (float) PHP_INT_MAX) - $free = PHP_INT_MAX; + // prevent integer overflow on 32-bit systems - return [ (int) $used, (int) $free ]; + if ($used > (float)PHP_INT_MAX) + $used = PHP_INT_MAX; + if ($free > (float)PHP_INT_MAX) + $free = PHP_INT_MAX; - } + return [(int)$used, (int)$free]; + + } } diff --git a/Zotlabs/Storage/GitRepo.php b/Zotlabs/Storage/GitRepo.php index c934e435c..16a1a6045 100644 --- a/Zotlabs/Storage/GitRepo.php +++ b/Zotlabs/Storage/GitRepo.php @@ -11,149 +11,161 @@ use PHPGit\Git as PHPGit; * * @author Andrew Manning */ -class GitRepo { +class GitRepo +{ - public $url = null; - public $name = null; - private $path = null; - private $channel = null; - public $git = null; - private $repoBasePath = null; + public $url = null; + public $name = null; + private $path = null; + private $channel = null; + public $git = null; + private $repoBasePath = null; - function __construct($channel = 'sys', $url = null, $clone = false, $name = null, $path = null) { + public function __construct($channel = 'sys', $url = null, $clone = false, $name = null, $path = null) + { - if ($channel === 'sys' && !is_site_admin()) { - logger('Only admin can use channel sys'); - return null; - } + if ($channel === 'sys' && !is_site_admin()) { + logger('Only admin can use channel sys'); + return null; + } - $this->repoBasePath = 'store/git'; - $this->channel = $channel; - $this->git = new PHPGit(); + $this->repoBasePath = 'store/git'; + $this->channel = $channel; + $this->git = new PHPGit(); - // Allow custom path for repo in the case of , for example - if ($path) { - $this->path = $path; - } else { - $this->path = $this->repoBasePath . "/" . $this->channel . "/" . $this->name; - } + // Allow custom path for repo in the case of , for example + if ($path) { + $this->path = $path; + } else { + $this->path = $this->repoBasePath . "/" . $this->channel . "/" . $this->name; + } - if ($this->isValidGitRepoURL($url)) { - $this->url = $url; - } + if ($this->isValidGitRepoURL($url)) { + $this->url = $url; + } - if ($name) { - $this->name = $name; - } else { - $this->name = $this->getRepoNameFromURL($url); - } - if (!$this->name) { - logger('Error creating GitRepo. No repo name found.'); - return null; - } + if ($name) { + $this->name = $name; + } else { + $this->name = $this->getRepoNameFromURL($url); + } + if (!$this->name) { + logger('Error creating GitRepo. No repo name found.'); + return null; + } - if (is_dir($this->path)) { - // ignore the $url input if it exists - // TODO: Check if the path is either empty or is a valid git repo and error if not - $this->git->setRepository($this->path); - // TODO: get repo metadata - return; - } + if (is_dir($this->path)) { + // ignore the $url input if it exists + // TODO: Check if the path is either empty or is a valid git repo and error if not + $this->git->setRepository($this->path); + // TODO: get repo metadata + return; + } - if ($this->url) { - // create the folder and clone the repo at url to that folder if $clone is true - if ($clone) { - if (mkdir($this->path, 0770, true)) { - $this->git->setRepository($this->path); - if (!$this->cloneRepo()) { - // TODO: throw error - logger('git clone failed: ' . json_encode($this->git)); - } - } else { - logger('git repo path could not be created: ' . json_encode($this->git)); - } - } - } - } - - public function initRepo() { - if(!$this->path) return false; - try { - return $this->git->init($this->path); - } catch (GitException $ex) { - return false; - } - } + if ($this->url) { + // create the folder and clone the repo at url to that folder if $clone is true + if ($clone) { + if (mkdir($this->path, 0770, true)) { + $this->git->setRepository($this->path); + if (!$this->cloneRepo()) { + // TODO: throw error + logger('git clone failed: ' . json_encode($this->git)); + } + } else { + logger('git repo path could not be created: ' . json_encode($this->git)); + } + } + } + } - public function pull() { - try { - $success = $this->git->pull(); - } catch (GitException $ex) { - return false; - } - return $success; - } + public function initRepo() + { + if (!$this->path) return false; + try { + return $this->git->init($this->path); + } catch (GitException $ex) { + return false; + } + } - public function getRepoPath() { - return $this->path; - } + public function pull() + { + try { + $success = $this->git->pull(); + } catch (GitException $ex) { + return false; + } + return $success; + } - public function setRepoPath($directory) { - if (is_dir($directory)) { - $this->path->$directory; - $this->git->setRepository($directory); - return true; - } - return false; - } + public function getRepoPath() + { + return $this->path; + } - public function setIdentity($user_name, $user_email) { - // setup user for commit messages - $this->git->config->set("user.name", $user_name, ['global' => false, 'system' => false]); - $this->git->config->set("user.email", $user_email, ['global' => false, 'system' => false]); - } + public function setRepoPath($directory) + { + if (is_dir($directory)) { + $this->path->$directory; + $this->git->setRepository($directory); + return true; + } + return false; + } - public function cloneRepo() { - if (validate_url($this->url) && $this->isValidGitRepoURL($this->url) && is_dir($this->path)) { - return $this->git->clone($this->url, $this->path); - } - } + public function setIdentity($user_name, $user_email) + { + // setup user for commit messages + $this->git->config->set("user.name", $user_name, ['global' => false, 'system' => false]); + $this->git->config->set("user.email", $user_email, ['global' => false, 'system' => false]); + } - public function probeRepo() { - $git = $this->git; - $repo = []; - $repo['remote'] = $git->remote(); - $repo['branches'] = $git->branch(['all' => true]); - $repo['logs'] = $git->log(array('limit' => 50)); - return $repo; - } - - // Commit changes to the repo. Default is to stage all changes and commit everything. - public function commit($msg, $options = []) { - try { - return $this->git->commit($msg, $options); - } catch (GitException $ex) { - return false; - } - } + public function cloneRepo() + { + if (validate_url($this->url) && $this->isValidGitRepoURL($this->url) && is_dir($this->path)) { + return $this->git->clone($this->url, $this->path); + } + } - public static function isValidGitRepoURL($url) { - if (validate_url($url) && strrpos(parse_url($url, PHP_URL_PATH), '.')) { - return true; - } else { - return false; - } - } + public function probeRepo() + { + $git = $this->git; + $repo = []; + $repo['remote'] = $git->remote(); + $repo['branches'] = $git->branch(['all' => true]); + $repo['logs'] = $git->log(array('limit' => 50)); + return $repo; + } - public static function getRepoNameFromURL($url) { - $urlpath = parse_url($url, PHP_URL_PATH); - $lastslash = strrpos($urlpath, '/') + 1; - $gitext = strrpos($urlpath, '.'); - if ($gitext) { - return substr($urlpath, $lastslash, $gitext - $lastslash); - } else { - return null; - } - } + // Commit changes to the repo. Default is to stage all changes and commit everything. + public function commit($msg, $options = []) + { + try { + return $this->git->commit($msg, $options); + } catch (GitException $ex) { + return false; + } + } + + public static function isValidGitRepoURL($url) + { + if (validate_url($url) && strrpos(parse_url($url, PHP_URL_PATH), '.')) { + return true; + } else { + return false; + } + } + + public static function getRepoNameFromURL($url) + { + $urlpath = parse_url($url, PHP_URL_PATH); + $lastslash = strrpos($urlpath, '/') + 1; + $gitext = strrpos($urlpath, '.'); + if ($gitext) { + return substr($urlpath, $lastslash, $gitext - $lastslash); + } else { + return null; + } + } } diff --git a/Zotlabs/Text/Tagadelic.php b/Zotlabs/Text/Tagadelic.php index 8b898b3cb..3f0c1b572 100644 --- a/Zotlabs/Text/Tagadelic.php +++ b/Zotlabs/Text/Tagadelic.php @@ -5,7 +5,7 @@ namespace Zotlabs\Text; class Tagadelic { - static public function calc($arr) { + public static function calc($arr) { $tags = []; $min = 1e9; @@ -36,7 +36,7 @@ class Tagadelic { return $tags; } - static public function tags_sort($a,$b) { + public static function tags_sort($a, $b) { if (strtolower($a[0]) === strtolower($b[0])) { return 0; } diff --git a/Zotlabs/Thumbs/Epubthumb.php b/Zotlabs/Thumbs/Epubthumb.php index 3f283dfa0..c81471691 100644 --- a/Zotlabs/Thumbs/Epubthumb.php +++ b/Zotlabs/Thumbs/Epubthumb.php @@ -10,52 +10,54 @@ use Epub; * @brief Thumbnail creation for epub files. * */ +class Epubthumb +{ -class Epubthumb { + /** + * @brief Match for application/epub+zip. + * + * @param string $type MimeType + * @return bool + */ - /** - * @brief Match for application/epub+zip. - * - * @param string $type MimeType - * @return boolean - */ + public function Match($type) + { + return (($type === 'application/epub+zip') ? true : false); + } - function Match($type) { - return(($type === 'application/epub+zip') ? true : false ); - } + /** + * @brief + * + * @param array $attach + * @param number $preview_style unused + * @param number $height (optional) default 300 + * @param number $width (optional) default 300 + */ - /** - * @brief - * - * @param array $attach - * @param number $preview_style unused - * @param number $height (optional) default 300 - * @param number $width (optional) default 300 - */ - - function Thumb($attach, $preview_style, $height = 300, $width = 300) { + public function Thumb($attach, $preview_style, $height = 300, $width = 300) + { - $photo = false; + $photo = false; - $ep = new EPub(dbunescbin($attach['content'])); - $data = $ep->Cover(); + $ep = new EPub(dbunescbin($attach['content'])); + $data = $ep->Cover(); - if ($data['found']) { - $photo = $data['data']; - } + if ($data['found']) { + $photo = $data['data']; + } - if ($photo) { - $image = imagecreatefromstring($photo); - $dest = imagecreatetruecolor($width, $height); - $srcwidth = imagesx($image); - $srcheight = imagesy($image); + if ($photo) { + $image = imagecreatefromstring($photo); + $dest = imagecreatetruecolor($width, $height); + $srcwidth = imagesx($image); + $srcheight = imagesy($image); - imagealphablending($dest, false); - imagesavealpha($dest, true); - imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight); - imagedestroy($image); - imagejpeg($dest, dbunescbin($attach['content']) . '.thumb'); - } - } + imagealphablending($dest, false); + imagesavealpha($dest, true); + imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight); + imagedestroy($image); + imagejpeg($dest, dbunescbin($attach['content']) . '.thumb'); + } + } } diff --git a/Zotlabs/Thumbs/Mp3audio.php b/Zotlabs/Thumbs/Mp3audio.php index 71260381f..4c85dfe5a 100644 --- a/Zotlabs/Thumbs/Mp3audio.php +++ b/Zotlabs/Thumbs/Mp3audio.php @@ -8,40 +8,43 @@ require_once('library/php-id3/PhpId3/Id3Tags.php'); use PhpId3\Id3TagsReader; -class Mp3audio { +class Mp3audio +{ - function Match($type) { - return(($type === 'audio/mpeg') ? true : false ); - } + public function Match($type) + { + return (($type === 'audio/mpeg') ? true : false); + } - function Thumb($attach,$preview_style,$height = 300, $width = 300) { + public function Thumb($attach, $preview_style, $height = 300, $width = 300) + { - $fh = @fopen(dbunescbin($attach['content']),'rb'); - if ($fh === false) { - return; - } - $id3 = new Id3TagsReader($fh); - $id3->readAllTags(); + $fh = @fopen(dbunescbin($attach['content']), 'rb'); + if ($fh === false) { + return; + } + $id3 = new Id3TagsReader($fh); + $id3->readAllTags(); - $image = $id3->getImage(); - if (is_array($image)) { - $photo = $image[1]; - } + $image = $id3->getImage(); + if (is_array($image)) { + $photo = $image[1]; + } + + fclose($fh); - fclose($fh); - if ($photo) { - $image = imagecreatefromstring($photo); - $dest = imagecreatetruecolor( $width, $height ); - $srcwidth = imagesx($image); - $srcheight = imagesy($image); + $image = imagecreatefromstring($photo); + $dest = imagecreatetruecolor($width, $height); + $srcwidth = imagesx($image); + $srcheight = imagesy($image); - imagealphablending($dest, false); - imagesavealpha($dest, true); - imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight); + imagealphablending($dest, false); + imagesavealpha($dest, true); + imagecopyresampled($dest, $image, 0, 0, 0, 0, $width, $height, $srcwidth, $srcheight); imagedestroy($image); - imagejpeg($dest,dbunescbin($attach['content']) . '.thumb'); - } - } + imagejpeg($dest, dbunescbin($attach['content']) . '.thumb'); + } + } } diff --git a/Zotlabs/Thumbs/Pdf.php b/Zotlabs/Thumbs/Pdf.php index 53b7d22f8..6d76e5da2 100644 --- a/Zotlabs/Thumbs/Pdf.php +++ b/Zotlabs/Thumbs/Pdf.php @@ -3,47 +3,49 @@ namespace Zotlabs\Thumbs; -class Pdf { +class Pdf +{ - function Match($type) { - return(($type === 'application/pdf') ? true : false ); - } + public function Match($type) + { + return (($type === 'application/pdf') ? true : false); + } - function Thumb($attach,$preview_style,$height = 300, $width = 300) { + public function Thumb($attach, $preview_style, $height = 300, $width = 300) + { - $photo = false; + $photo = false; - $file = dbunescbin($attach['content']); - $tmpfile = $file . '.pdf'; - $outfile = $file . '.jpg'; + $file = dbunescbin($attach['content']); + $tmpfile = $file . '.pdf'; + $outfile = $file . '.jpg'; - $istream = fopen($file,'rb'); - $ostream = fopen($tmpfile,'wb'); - if ($istream && $ostream) { - pipe_streams($istream,$ostream); - fclose($istream); - fclose($ostream); - } + $istream = fopen($file, 'rb'); + $ostream = fopen($tmpfile, 'wb'); + if ($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } - $imagick_path = get_config('system','imagick_convert_path'); - if ($imagick_path && @file_exists($imagick_path)) { - $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -resize ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile); - // logger('imagick thumbnail command: ' . $cmd); - for ($x = 0; $x < 4; $x ++) { - exec($cmd); - if (! file_exists($outfile)) { - logger('imagick scale failed. Retrying.'); - continue; - } - } - if (! file_exists($outfile)) { - logger('imagick scale failed.'); - } - else { - @rename($outfile,$file . '.thumb'); - } - } - @unlink($tmpfile); - } + $imagick_path = get_config('system', 'imagick_convert_path'); + if ($imagick_path && @file_exists($imagick_path)) { + $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -resize ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile); + // logger('imagick thumbnail command: ' . $cmd); + for ($x = 0; $x < 4; $x++) { + exec($cmd); + if (!file_exists($outfile)) { + logger('imagick scale failed. Retrying.'); + continue; + } + } + if (!file_exists($outfile)) { + logger('imagick scale failed.'); + } else { + @rename($outfile, $file . '.thumb'); + } + } + @unlink($tmpfile); + } } diff --git a/Zotlabs/Thumbs/Text.php b/Zotlabs/Thumbs/Text.php index 0f6632238..e2d11175f 100644 --- a/Zotlabs/Thumbs/Text.php +++ b/Zotlabs/Thumbs/Text.php @@ -3,47 +3,50 @@ namespace Zotlabs\Thumbs; -class Text { +class Text +{ - function MatchDefault($type) { - return(($type === 'text') ? true : false ); - } + public function MatchDefault($type) + { + return (($type === 'text') ? true : false); + } - function Thumb($attach,$preview_style,$height = 300, $width = 300) { + public function Thumb($attach, $preview_style, $height = 300, $width = 300) + { - $stream = @fopen(dbunescbin($attach['content']),'rb'); - if ($stream) { - $content = trim(stream_get_contents($stream,4096)); - $content = str_replace("\r",'',$content); - $content_a = explode("\n",$content); - } - if ($content_a) { - $fsize = 4; - $lsize = 8; - $image = imagecreate($width,$height); - imagecolorallocate($image,255,255,255); - $colour = imagecolorallocate($image,0,0,0); - $border = imagecolorallocate($image,208,208,208); + $stream = @fopen(dbunescbin($attach['content']), 'rb'); + if ($stream) { + $content = trim(stream_get_contents($stream, 4096)); + $content = str_replace("\r", '', $content); + $content_a = explode("\n", $content); + } + if ($content_a) { + $fsize = 4; + $lsize = 8; + $image = imagecreate($width, $height); + imagecolorallocate($image, 255, 255, 255); + $colour = imagecolorallocate($image, 0, 0, 0); + $border = imagecolorallocate($image, 208, 208, 208); - $x1 = 0; - $y1 = 0; - $x2 = ImageSX($image) - 1; - $y2 = ImageSY($image) - 1; + $x1 = 0; + $y1 = 0; + $x2 = ImageSX($image) - 1; + $y2 = ImageSY($image) - 1; - for ($i = 0; $i < 2; $i++) { - ImageRectangle($image, $x1++, $y1++, $x2--, $y2--, $border); - } + for ($i = 0; $i < 2; $i++) { + ImageRectangle($image, $x1++, $y1++, $x2--, $y2--, $border); + } - foreach ($content_a as $l => $t) { - $l = $l + 1; - $x = 3; - $y = ($l * $lsize) + 3 - $fsize; - imagestring($image,1,$x,$y,$t,$colour); - if (($l * $lsize) >= $height) { - break; - } - } - imagejpeg($image,dbunescbin($attach['content']) . '.thumb'); - } - } + foreach ($content_a as $l => $t) { + $l = $l + 1; + $x = 3; + $y = ($l * $lsize) + 3 - $fsize; + imagestring($image, 1, $x, $y, $t, $colour); + if (($l * $lsize) >= $height) { + break; + } + } + imagejpeg($image, dbunescbin($attach['content']) . '.thumb'); + } + } } \ No newline at end of file diff --git a/Zotlabs/Thumbs/Video.php b/Zotlabs/Thumbs/Video.php index cf20c561b..9b56ada4b 100644 --- a/Zotlabs/Thumbs/Video.php +++ b/Zotlabs/Thumbs/Video.php @@ -3,66 +3,67 @@ namespace Zotlabs\Thumbs; -class Video { +class Video +{ - function MatchDefault($type) { - return(($type === 'video') ? true : false ); - } + public function MatchDefault($type) + { + return (($type === 'video') ? true : false); + } - function Thumb($attach,$preview_style,$height = 300, $width = 300) { + public function Thumb($attach, $preview_style, $height = 300, $width = 300) + { - $photo = false; + $photo = false; - $t = explode('/',$attach['filetype']); - if ($t[1]) { - $extension = '.' . $t[1]; - } - else { - return; - } + $t = explode('/', $attach['filetype']); + if ($t[1]) { + $extension = '.' . $t[1]; + } else { + return; + } - $file = dbunescbin($attach['content']); - $tmpfile = $file . $extension; - $outfile = $file . '.jpg'; + $file = dbunescbin($attach['content']); + $tmpfile = $file . $extension; + $outfile = $file . '.jpg'; - $istream = fopen($file,'rb'); - $ostream = fopen($tmpfile,'wb'); - if ($istream && $ostream) { - pipe_streams($istream,$ostream); - fclose($istream); - fclose($ostream); - } + $istream = fopen($file, 'rb'); + $ostream = fopen($tmpfile, 'wb'); + if ($istream && $ostream) { + pipe_streams($istream, $ostream); + fclose($istream); + fclose($ostream); + } - /* - * Note: imagick convert may try to call 'ffmpeg' (or other conversion utilities) under - * the covers for this particular operation. If this is not installed or not in the path - * for the web server user, errors may be reported in the web server logs. - */ + /* + * Note: imagick convert may try to call 'ffmpeg' (or other conversion utilities) under + * the covers for this particular operation. If this is not installed or not in the path + * for the web server user, errors may be reported in the web server logs. + */ - $ffmpeg = trim(shell_exec('which ffmpeg')); - if (! $ffmpeg) { - logger('ffmpeg not found in path. Video thumbnails may fail.'); - } + $ffmpeg = trim(shell_exec('which ffmpeg')); + if (!$ffmpeg) { + logger('ffmpeg not found in path. Video thumbnails may fail.'); + } - $imagick_path = get_config('system','imagick_convert_path'); - if ($imagick_path && @file_exists($imagick_path)) { - $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -resize ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile); - // logger('imagick thumbnail command: ' . $cmd); + $imagick_path = get_config('system', 'imagick_convert_path'); + if ($imagick_path && @file_exists($imagick_path)) { + $cmd = $imagick_path . ' ' . escapeshellarg(PROJECT_BASE . '/' . $tmpfile . '[0]') . ' -resize ' . $width . 'x' . $height . ' ' . escapeshellarg(PROJECT_BASE . '/' . $outfile); + // logger('imagick thumbnail command: ' . $cmd); - /** @scrutinizer ignore-unhandled */ - @exec($cmd); + /** @scrutinizer ignore-unhandled */ + @exec($cmd); - if (! file_exists($outfile)) { - logger('imagick scale failed.'); - } - else { - @rename($outfile,$file . '.thumb'); - } - } - - @unlink($tmpfile); - } + if (!file_exists($outfile)) { + logger('imagick scale failed.'); + } else { + @rename($outfile, $file . '.thumb'); + } + } + + @unlink($tmpfile); + } } diff --git a/Zotlabs/Update/_1000.php b/Zotlabs/Update/_1000.php index 02787db38..716f79174 100644 --- a/Zotlabs/Update/_1000.php +++ b/Zotlabs/Update/_1000.php @@ -2,14 +2,15 @@ namespace Zotlabs\Update; -class _1000 { -function run() { - $r = q("ALTER TABLE `channel` ADD `channel_a_delegate` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0', ADD INDEX ( `channel_a_delegate` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - +class _1000 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD `channel_a_delegate` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0', ADD INDEX ( `channel_a_delegate` )"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1001.php b/Zotlabs/Update/_1001.php index 9acc96373..5c8e63d12 100644 --- a/Zotlabs/Update/_1001.php +++ b/Zotlabs/Update/_1001.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1001 { -function run() { - $r = q("CREATE TABLE if not exists `verify` ( +class _1001 +{ + public function run() + { + $r = q("CREATE TABLE if not exists `verify` ( `id` INT(10) UNSIGNED NOT NULL , `channel` INT(10) UNSIGNED NOT NULL DEFAULT '0', `type` CHAR( 32 ) NOT NULL DEFAULT '', @@ -14,14 +16,13 @@ function run() { PRIMARY KEY ( `id` ) ) ENGINE = MYISAM DEFAULT CHARSET=utf8"); - $r2 = q("alter table `verify` add index (`channel`), add index (`type`), add index (`token`), + $r2 = q("alter table `verify` add index (`channel`), add index (`type`), add index (`token`), add index (`meta`), add index (`created`)"); - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1002.php b/Zotlabs/Update/_1002.php index 1f42449c6..06a12d96d 100644 --- a/Zotlabs/Update/_1002.php +++ b/Zotlabs/Update/_1002.php @@ -2,19 +2,20 @@ namespace Zotlabs\Update; -class _1002 { -function run() { - $r = q("ALTER TABLE `event` CHANGE `account` `aid` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r2 = q("alter table `event` drop index `account`, add index (`aid`)"); +class _1002 +{ + public function run() + { + $r = q("ALTER TABLE `event` CHANGE `account` `aid` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r2 = q("alter table `event` drop index `account`, add index (`aid`)"); - q("drop table contact"); - q("drop table deliverq"); - - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + q("drop table contact"); + q("drop table deliverq"); + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1003.php b/Zotlabs/Update/_1003.php index 18d99f985..4d59784d0 100644 --- a/Zotlabs/Update/_1003.php +++ b/Zotlabs/Update/_1003.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1003 { -function run() { - $r = q("ALTER TABLE `xchan` ADD `xchan_flags` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `xchan_network` , +class _1003 +{ + public function run() + { + $r = q("ALTER TABLE `xchan` ADD `xchan_flags` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `xchan_network` , ADD INDEX ( `xchan_flags` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1004.php b/Zotlabs/Update/_1004.php index a86f5d824..1dfff94fb 100644 --- a/Zotlabs/Update/_1004.php +++ b/Zotlabs/Update/_1004.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1004 { -function run() { - $r = q("CREATE TABLE if not exists `site` ( +class _1004 +{ + public function run() + { + $r = q("CREATE TABLE if not exists `site` ( `site_url` CHAR( 255 ) NOT NULL , `site_flags` INT NOT NULL DEFAULT '0', `site_update` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -12,13 +14,12 @@ function run() { PRIMARY KEY ( `site_url` ) ) ENGINE = MYISAM DEFAULT CHARSET=utf8"); - $r2 = q("alter table site add index (site_flags), add index (site_update), add index (site_directory) "); - - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r2 = q("alter table site add index (site_flags), add index (site_update), add index (site_directory) "); + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1005.php b/Zotlabs/Update/_1005.php index ee8621a8d..e4eee62df 100644 --- a/Zotlabs/Update/_1005.php +++ b/Zotlabs/Update/_1005.php @@ -2,12 +2,14 @@ namespace Zotlabs\Update; -class _1005 { -function run() { - q("drop table guid"); - q("drop table `notify-threads`"); - return UPDATE_SUCCESS; -} +class _1005 +{ + public function run() + { + q("drop table guid"); + q("drop table `notify-threads`"); + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1006.php b/Zotlabs/Update/_1006.php index 43a2bb951..cd3dd5617 100644 --- a/Zotlabs/Update/_1006.php +++ b/Zotlabs/Update/_1006.php @@ -2,10 +2,12 @@ namespace Zotlabs\Update; -class _1006 { -function run() { +class _1006 +{ + public function run() + { - $r = q("CREATE TABLE IF NOT EXISTS `xprof` ( + $r = q("CREATE TABLE IF NOT EXISTS `xprof` ( `xprof_hash` char(255) NOT NULL, `xprof_desc` char(255) NOT NULL DEFAULT '', `xprof_dob` char(12) NOT NULL DEFAULT '', @@ -28,18 +30,17 @@ function run() { KEY `xprof_country` (`xprof_country`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - $r2 = q("CREATE TABLE IF NOT EXISTS `xtag` ( + $r2 = q("CREATE TABLE IF NOT EXISTS `xtag` ( `xtag_hash` char(255) NOT NULL, `xtag_term` char(255) NOT NULL DEFAULT '', PRIMARY KEY (`xtag_hash`), KEY `xtag_term` (`xtag_term`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1007.php b/Zotlabs/Update/_1007.php index eb52c5bc5..a8622a134 100644 --- a/Zotlabs/Update/_1007.php +++ b/Zotlabs/Update/_1007.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1007 { -function run() { - $r = q("ALTER TABLE `channel` ADD `channel_r_storage` INT UNSIGNED NOT NULL DEFAULT '128', ADD `channel_w_storage` INT UNSIGNED NOT NULL DEFAULT '128', add index ( channel_r_storage ), add index ( channel_w_storage )"); +class _1007 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD `channel_r_storage` INT UNSIGNED NOT NULL DEFAULT '128', ADD `channel_w_storage` INT UNSIGNED NOT NULL DEFAULT '128', add index ( channel_r_storage ), add index ( channel_w_storage )"); - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1008.php b/Zotlabs/Update/_1008.php index d5db24bc0..9be2c485a 100644 --- a/Zotlabs/Update/_1008.php +++ b/Zotlabs/Update/_1008.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1008 { -function run() { - $r = q("alter table profile drop prv_keywords, CHANGE `pub_keywords` `keywords` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, drop index pub_keywords"); +class _1008 +{ + public function run() + { + $r = q("alter table profile drop prv_keywords, CHANGE `pub_keywords` `keywords` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, drop index pub_keywords"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1009.php b/Zotlabs/Update/_1009.php index afb0d5e96..353a1c46f 100644 --- a/Zotlabs/Update/_1009.php +++ b/Zotlabs/Update/_1009.php @@ -2,14 +2,15 @@ namespace Zotlabs\Update; -class _1009 { -function run() { - $r = q("ALTER TABLE `xprof` ADD `xprof_keywords` TEXT NOT NULL"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - +class _1009 +{ + public function run() + { + $r = q("ALTER TABLE `xprof` ADD `xprof_keywords` TEXT NOT NULL"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1010.php b/Zotlabs/Update/_1010.php index 92405cce4..d02a6a77e 100644 --- a/Zotlabs/Update/_1010.php +++ b/Zotlabs/Update/_1010.php @@ -2,17 +2,19 @@ namespace Zotlabs\Update; -class _1010 { -function run() { - $r = q("ALTER TABLE `abook` ADD `abook_dob` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `abook_connnected` , +class _1010 +{ + public function run() + { + $r = q("ALTER TABLE `abook` ADD `abook_dob` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `abook_connnected` , ADD INDEX ( `abook_dob` )"); - $r2 = q("ALTER TABLE `profile` ADD `dob_tz` CHAR( 255 ) NOT NULL DEFAULT 'UTC' AFTER `dob`"); + $r2 = q("ALTER TABLE `profile` ADD `dob_tz` CHAR( 255 ) NOT NULL DEFAULT 'UTC' AFTER `dob`"); - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1011.php b/Zotlabs/Update/_1011.php index b6841a9fe..ea628e38b 100644 --- a/Zotlabs/Update/_1011.php +++ b/Zotlabs/Update/_1011.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1011 { -function run() { - $r = q("ALTER TABLE `item` ADD `expires` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `edited` , +class _1011 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `expires` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `edited` , ADD INDEX ( `expires` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } + } \ No newline at end of file diff --git a/Zotlabs/Update/_1012.php b/Zotlabs/Update/_1012.php index 3ae5caf65..2a9c8c1f7 100644 --- a/Zotlabs/Update/_1012.php +++ b/Zotlabs/Update/_1012.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1012 { -function run() { - $r = q("ALTER TABLE `xchan` ADD `xchan_connurl` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `xchan_url` , +class _1012 +{ + public function run() + { + $r = q("ALTER TABLE `xchan` ADD `xchan_connurl` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `xchan_url` , ADD INDEX ( `xchan_connurl` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1013.php b/Zotlabs/Update/_1013.php index 68fc9071d..d3726fde9 100644 --- a/Zotlabs/Update/_1013.php +++ b/Zotlabs/Update/_1013.php @@ -2,20 +2,22 @@ namespace Zotlabs\Update; -class _1013 { -function run() { - $r = q("CREATE TABLE if not exists `xlink` ( +class _1013 +{ + public function run() + { + $r = q("CREATE TABLE if not exists `xlink` ( `xlink_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `xlink_xchan` CHAR( 255 ) NOT NULL DEFAULT '', `xlink_link` CHAR( 255 ) NOT NULL DEFAULT '', `xlink_updated` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' ) ENGINE = MYISAM DEFAULT CHARSET=utf8"); - $r2 = q("alter table xlink add index ( xlink_xchan ), add index ( xlink_link ), add index ( xlink_updated ) "); - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r2 = q("alter table xlink add index ( xlink_xchan ), add index ( xlink_link ), add index ( xlink_updated ) "); + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1014.php b/Zotlabs/Update/_1014.php index e9b3a89e0..8f657ba3d 100644 --- a/Zotlabs/Update/_1014.php +++ b/Zotlabs/Update/_1014.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1014 { -function run() { - $r = q("ALTER TABLE `verify` CHANGE `id` `id` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1014 +{ + public function run() + { + $r = q("ALTER TABLE `verify` CHANGE `id` `id` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1015.php b/Zotlabs/Update/_1015.php index d9d2d2f27..9bf4c1b5f 100644 --- a/Zotlabs/Update/_1015.php +++ b/Zotlabs/Update/_1015.php @@ -2,18 +2,19 @@ namespace Zotlabs\Update; -class _1015 { -function run() { - $r = q("ALTER TABLE `channel` ADD `channel_r_pages` INT UNSIGNED NOT NULL DEFAULT '128', +class _1015 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD `channel_r_pages` INT UNSIGNED NOT NULL DEFAULT '128', ADD `channel_w_pages` INT UNSIGNED NOT NULL DEFAULT '128'"); - $r2 = q("ALTER TABLE `channel` ADD INDEX ( `channel_r_pages` ) , ADD INDEX ( `channel_w_pages` ) "); - - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r2 = q("ALTER TABLE `channel` ADD INDEX ( `channel_r_pages` ) , ADD INDEX ( `channel_w_pages` ) "); + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1016.php b/Zotlabs/Update/_1016.php index 93f71a474..e985339f6 100644 --- a/Zotlabs/Update/_1016.php +++ b/Zotlabs/Update/_1016.php @@ -2,10 +2,12 @@ namespace Zotlabs\Update; -class _1016 { -function run() { +class _1016 +{ + public function run() + { - $r = q("CREATE TABLE IF NOT EXISTS `menu` ( + $r = q("CREATE TABLE IF NOT EXISTS `menu` ( `menu_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `menu_channel_id` int(10) unsigned NOT NULL DEFAULT '0', `menu_desc` char(255) NOT NULL DEFAULT '', @@ -13,7 +15,7 @@ function run() { KEY `menu_channel_id` (`menu_channel_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - $r2 = q("CREATE TABLE IF NOT EXISTS `menu_item` ( + $r2 = q("CREATE TABLE IF NOT EXISTS `menu_item` ( `mitem_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `mitem_link` char(255) NOT NULL DEFAULT '', `mitem_desc` char(255) NOT NULL DEFAULT '', @@ -30,10 +32,10 @@ function run() { ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - if($r && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1017.php b/Zotlabs/Update/_1017.php index 429eda67b..66437ad0d 100644 --- a/Zotlabs/Update/_1017.php +++ b/Zotlabs/Update/_1017.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1017 { -function run() { - $r = q("ALTER TABLE `event` CHANGE `cid` `event_xchan` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `event_xchan` ), drop index cid "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1017 +{ + public function run() + { + $r = q("ALTER TABLE `event` CHANGE `cid` `event_xchan` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `event_xchan` ), drop index cid "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1018.php b/Zotlabs/Update/_1018.php index 546ebffca..c4fb1df4e 100644 --- a/Zotlabs/Update/_1018.php +++ b/Zotlabs/Update/_1018.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1018 { -function run() { - $r = q("ALTER TABLE `event` ADD `event_hash` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `event_xchan` , +class _1018 +{ + public function run() + { + $r = q("ALTER TABLE `event` ADD `event_hash` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `event_xchan` , ADD INDEX ( `event_hash` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1019.php b/Zotlabs/Update/_1019.php index a7103c98c..615455c3d 100644 --- a/Zotlabs/Update/_1019.php +++ b/Zotlabs/Update/_1019.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1019 { -function run() { - $r = q("ALTER TABLE `event` DROP `message_id` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1019 +{ + public function run() + { + $r = q("ALTER TABLE `event` DROP `message_id` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1020.php b/Zotlabs/Update/_1020.php index c898f31c2..91615a9b2 100644 --- a/Zotlabs/Update/_1020.php +++ b/Zotlabs/Update/_1020.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1020 { -function run() { - $r = q("alter table photo drop `contact-id`, drop guid, drop index `resource-id`, add index ( `resource_id` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1020 +{ + public function run() + { + $r = q("alter table photo drop `contact-id`, drop guid, drop index `resource-id`, add index ( `resource_id` )"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1021.php b/Zotlabs/Update/_1021.php index 72203fadb..45e4b7d20 100644 --- a/Zotlabs/Update/_1021.php +++ b/Zotlabs/Update/_1021.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1021 { -function run() { +class _1021 +{ + public function run() + { - $r = q("ALTER TABLE `abook` CHANGE `abook_connnected` `abook_connected` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', + $r = q("ALTER TABLE `abook` CHANGE `abook_connnected` `abook_connected` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', drop index `abook_connnected`, add index ( `abook_connected` ) "); - - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1022.php b/Zotlabs/Update/_1022.php index 7e13250c4..a0736a5c3 100644 --- a/Zotlabs/Update/_1022.php +++ b/Zotlabs/Update/_1022.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1022 { -function run() { - $r = q("alter table attach add index ( filename ), add index ( filetype ), add index ( filesize ), add index ( created ), add index ( edited ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1022 +{ + public function run() + { + $r = q("alter table attach add index ( filename ), add index ( filetype ), add index ( filesize ), add index ( created ), add index ( edited ) "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1023.php b/Zotlabs/Update/_1023.php index 0a8dd2f00..76c5a1a7d 100644 --- a/Zotlabs/Update/_1023.php +++ b/Zotlabs/Update/_1023.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1023 { -function run() { - $r = q("ALTER TABLE `item` ADD `revision` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `lang` , add index ( revision ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1023 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `revision` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `lang` , add index ( revision ) "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1024.php b/Zotlabs/Update/_1024.php index 004d8967a..965a37976 100644 --- a/Zotlabs/Update/_1024.php +++ b/Zotlabs/Update/_1024.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1024 { -function run() { - $r = q("ALTER TABLE `attach` ADD `revision` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `filesize` , +class _1024 +{ + public function run() + { + $r = q("ALTER TABLE `attach` ADD `revision` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `filesize` , ADD INDEX ( `revision` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1025.php b/Zotlabs/Update/_1025.php index d498233b3..cbc60c0fb 100644 --- a/Zotlabs/Update/_1025.php +++ b/Zotlabs/Update/_1025.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1025 { -function run() { - $r = q("ALTER TABLE `attach` ADD `folder` CHAR( 64 ) NOT NULL DEFAULT '' AFTER `revision` , +class _1025 +{ + public function run() + { + $r = q("ALTER TABLE `attach` ADD `folder` CHAR( 64 ) NOT NULL DEFAULT '' AFTER `revision` , ADD `flags` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `folder` , add index ( folder ), add index ( flags )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1026.php b/Zotlabs/Update/_1026.php index d57fdec37..354b91910 100644 --- a/Zotlabs/Update/_1026.php +++ b/Zotlabs/Update/_1026.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1026 { -function run() { - $r = q("ALTER TABLE `item` ADD `mimetype` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `author_xchan` , +class _1026 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `mimetype` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `author_xchan` , ADD INDEX ( `mimetype` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1027.php b/Zotlabs/Update/_1027.php index 04d09d202..3c1e73797 100644 --- a/Zotlabs/Update/_1027.php +++ b/Zotlabs/Update/_1027.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1027 { -function run() { - $r = q("ALTER TABLE `abook` ADD `abook_rating` INT NOT NULL DEFAULT '0' AFTER `abook_closeness` , +class _1027 +{ + public function run() + { + $r = q("ALTER TABLE `abook` ADD `abook_rating` INT NOT NULL DEFAULT '0' AFTER `abook_closeness` , ADD INDEX ( `abook_rating` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1028.php b/Zotlabs/Update/_1028.php index a58784a01..154b70315 100644 --- a/Zotlabs/Update/_1028.php +++ b/Zotlabs/Update/_1028.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1028 { -function run() { - $r = q("ALTER TABLE `xlink` ADD `xlink_rating` INT NOT NULL DEFAULT '0' AFTER `xlink_link` , +class _1028 +{ + public function run() + { + $r = q("ALTER TABLE `xlink` ADD `xlink_rating` INT NOT NULL DEFAULT '0' AFTER `xlink_link` , ADD INDEX ( `xlink_rating` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1029.php b/Zotlabs/Update/_1029.php index 7072647cb..96efff6d9 100644 --- a/Zotlabs/Update/_1029.php +++ b/Zotlabs/Update/_1029.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1029 { -function run() { - $r = q("ALTER TABLE `channel` ADD `channel_deleted` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `channel_pageflags` , +class _1029 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD `channel_deleted` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `channel_pageflags` , ADD INDEX ( `channel_deleted` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1030.php b/Zotlabs/Update/_1030.php index 7aebde49e..9f047260b 100644 --- a/Zotlabs/Update/_1030.php +++ b/Zotlabs/Update/_1030.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1030 { -function run() { - $r = q("CREATE TABLE IF NOT EXISTS `issue` ( +class _1030 +{ + public function run() + { + $r = q("CREATE TABLE IF NOT EXISTS `issue` ( `issue_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `issue_created` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', `issue_updated` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', @@ -20,10 +22,10 @@ KEY `issue_status` (`issue_status`), KEY `issue_component` (`issue_component`) ) ENGINE = MYISAM DEFAULT CHARSET=utf8"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1031.php b/Zotlabs/Update/_1031.php index 4463c9e04..072fab31a 100644 --- a/Zotlabs/Update/_1031.php +++ b/Zotlabs/Update/_1031.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1031 { -function run() { - $r = q("ALTER TABLE `account` ADD `account_external` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `account_email` , +class _1031 +{ + public function run() + { + $r = q("ALTER TABLE `account` ADD `account_external` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `account_email` , ADD INDEX ( `account_external` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1032.php b/Zotlabs/Update/_1032.php index a9fbeca9e..590ad8958 100644 --- a/Zotlabs/Update/_1032.php +++ b/Zotlabs/Update/_1032.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1032 { -function run() { - $r = q("CREATE TABLE if not exists `xign` ( +class _1032 +{ + public function run() + { + $r = q("CREATE TABLE if not exists `xign` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `uid` INT NOT NULL DEFAULT '0', `xchan` CHAR( 255 ) NOT NULL DEFAULT '', @@ -12,10 +14,10 @@ KEY `uid` (`uid`), KEY `xchan` (`xchan`) ) ENGINE = MYISAM DEFAULT CHARSET = utf8"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1033.php b/Zotlabs/Update/_1033.php index a201e1d1f..c77add106 100644 --- a/Zotlabs/Update/_1033.php +++ b/Zotlabs/Update/_1033.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1033 { -function run() { - $r = q("CREATE TABLE if not exists `shares` ( +class _1033 +{ + public function run() + { + $r = q("CREATE TABLE if not exists `shares` ( `share_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `share_type` INT NOT NULL DEFAULT '0', `share_target` INT UNSIGNED NOT NULL DEFAULT '0', @@ -14,16 +16,16 @@ KEY `share_target` (`share_target`), KEY `share_xchan` (`share_xchan`) ) ENGINE = MYISAM DEFAULT CHARSET = utf8"); - // if these fail don't bother reporting it + // if these fail don't bother reporting it - q("drop table gcign"); - q("drop table gcontact"); - q("drop table glink"); + q("drop table gcign"); + q("drop table gcontact"); + q("drop table glink"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1034.php b/Zotlabs/Update/_1034.php index 646182cc0..cb9507c5d 100644 --- a/Zotlabs/Update/_1034.php +++ b/Zotlabs/Update/_1034.php @@ -2,19 +2,21 @@ namespace Zotlabs\Update; -class _1034 { -function run() { - $r = q("CREATE TABLE if not exists `updates` ( +class _1034 +{ + public function run() + { + $r = q("CREATE TABLE if not exists `updates` ( `ud_hash` CHAR( 128 ) NOT NULL , `ud_date` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY ( `ud_hash` ), KEY `ud_date` ( `ud_date` ) ) ENGINE = MYISAM DEFAULT CHARSET = utf8"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1035.php b/Zotlabs/Update/_1035.php index 44e95189d..7a87b1627 100644 --- a/Zotlabs/Update/_1035.php +++ b/Zotlabs/Update/_1035.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1035 { -function run() { - $r = q("CREATE TABLE if not exists `xconfig` ( +class _1035 +{ + public function run() + { + $r = q("CREATE TABLE if not exists `xconfig` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `xchan` CHAR( 255 ) NOT NULL , `cat` CHAR( 255 ) NOT NULL , @@ -15,10 +17,10 @@ KEY `cat` ( `cat` ), KEY `k` ( `k` ) ) ENGINE = MYISAM DEFAULT CHARSET = utf8"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1036.php b/Zotlabs/Update/_1036.php index 700a82e12..c242ab2a7 100644 --- a/Zotlabs/Update/_1036.php +++ b/Zotlabs/Update/_1036.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1036 { -function run() { - $r = q("ALTER TABLE `profile` ADD `channels` TEXT NOT NULL AFTER `contact` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - -} +class _1036 +{ + public function run() + { + $r = q("ALTER TABLE `profile` ADD `channels` TEXT NOT NULL AFTER `contact` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1037.php b/Zotlabs/Update/_1037.php index a1ad20aa8..b2a4cb35b 100644 --- a/Zotlabs/Update/_1037.php +++ b/Zotlabs/Update/_1037.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1037 { -function run() { - $r1 = q("ALTER TABLE `item` CHANGE `uri` `mid` CHAR( 255 ) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '', +class _1037 +{ + public function run() + { + $r1 = q("ALTER TABLE `item` CHANGE `uri` `mid` CHAR( 255 ) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '', CHANGE `parent_uri` `parent_mid` CHAR( 255 ) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '', DROP INDEX `uri` , ADD INDEX `mid` ( `mid` ), @@ -13,18 +15,17 @@ ADD INDEX `parent_mid` ( `parent_mid` ), DROP INDEX `uid_uri` , ADD INDEX `uid_mid` ( `mid` , `uid` ) "); - $r2 = q("ALTER TABLE `mail` CHANGE `uri` `mid` CHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , + $r2 = q("ALTER TABLE `mail` CHANGE `uri` `mid` CHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , CHANGE `parent_uri` `parent_mid` CHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL , DROP INDEX `uri` , ADD INDEX `mid` ( `mid` ), DROP INDEX `parent_uri` , ADD INDEX `parent_mid` ( `parent_mid` ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1038.php b/Zotlabs/Update/_1038.php index b4a86f41e..7ebb574c0 100644 --- a/Zotlabs/Update/_1038.php +++ b/Zotlabs/Update/_1038.php @@ -2,16 +2,17 @@ namespace Zotlabs\Update; -class _1038 { -function run() { - $r = q("ALTER TABLE `manage` CHANGE `mid` `xchan` CHAR( 255 ) NOT NULL DEFAULT '', drop index `mid`, ADD INDEX ( `xchan` )"); +class _1038 +{ + public function run() + { + $r = q("ALTER TABLE `manage` CHANGE `mid` `xchan` CHAR( 255 ) NOT NULL DEFAULT '', drop index `mid`, ADD INDEX ( `xchan` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} - + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1039.php b/Zotlabs/Update/_1039.php index 9214cdc4a..79798e6dd 100644 --- a/Zotlabs/Update/_1039.php +++ b/Zotlabs/Update/_1039.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1039 { -function run() { - $r = q("ALTER TABLE `channel` CHANGE `channel_default_gid` `channel_default_group` CHAR( 255 ) NOT NULL DEFAULT ''"); +class _1039 +{ + public function run() + { + $r = q("ALTER TABLE `channel` CHANGE `channel_default_gid` `channel_default_group` CHAR( 255 ) NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1040.php b/Zotlabs/Update/_1040.php index 77dc75a48..f2a57852f 100644 --- a/Zotlabs/Update/_1040.php +++ b/Zotlabs/Update/_1040.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1040 { -function run() { - $r1 = q("ALTER TABLE `session` CHANGE `expire` `expire` BIGINT UNSIGNED NOT NULL "); - $r2 = q("ALTER TABLE `tokens` CHANGE `expires` `expires` BIGINT UNSIGNED NOT NULL "); +class _1040 +{ + public function run() + { + $r1 = q("ALTER TABLE `session` CHANGE `expire` `expire` BIGINT UNSIGNED NOT NULL "); + $r2 = q("ALTER TABLE `tokens` CHANGE `expires` `expires` BIGINT UNSIGNED NOT NULL "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1041.php b/Zotlabs/Update/_1041.php index 4ed436e61..4ecf07675 100644 --- a/Zotlabs/Update/_1041.php +++ b/Zotlabs/Update/_1041.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1041 { -function run() { - $r = q("ALTER TABLE `outq` ADD `outq_driver` CHAR( 32 ) NOT NULL DEFAULT '' AFTER `outq_channel` "); - - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1041 +{ + public function run() + { + $r = q("ALTER TABLE `outq` ADD `outq_driver` CHAR( 32 ) NOT NULL DEFAULT '' AFTER `outq_channel` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1042.php b/Zotlabs/Update/_1042.php index 56298b6a3..2feaf3ef0 100644 --- a/Zotlabs/Update/_1042.php +++ b/Zotlabs/Update/_1042.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1042 { -function run() { - $r = q("ALTER TABLE `hubloc` ADD `hubloc_updated` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', +class _1042 +{ + public function run() + { + $r = q("ALTER TABLE `hubloc` ADD `hubloc_updated` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD `hubloc_connected` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD INDEX ( `hubloc_updated` ), ADD INDEX ( `hubloc_connected` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1043.php b/Zotlabs/Update/_1043.php index b28203731..ed713f291 100644 --- a/Zotlabs/Update/_1043.php +++ b/Zotlabs/Update/_1043.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1043 { -function run() { - $r = q("ALTER TABLE `item` ADD `comment_policy` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `coord` , +class _1043 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `comment_policy` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `coord` , ADD INDEX ( `comment_policy` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1044.php b/Zotlabs/Update/_1044.php index fc7e5438f..b3e691f06 100644 --- a/Zotlabs/Update/_1044.php +++ b/Zotlabs/Update/_1044.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1044 { -function run() { - $r = q("ALTER TABLE `term` ADD `imgurl` CHAR( 255 ) NOT NULL , +class _1044 +{ + public function run() + { + $r = q("ALTER TABLE `term` ADD `imgurl` CHAR( 255 ) NOT NULL , ADD INDEX ( `imgurl` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1045.php b/Zotlabs/Update/_1045.php index 73570c316..8db73efae 100644 --- a/Zotlabs/Update/_1045.php +++ b/Zotlabs/Update/_1045.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1045 { -function run() { - $r = q("ALTER TABLE `site` ADD `site_register` INT NOT NULL DEFAULT '0', +class _1045 +{ + public function run() + { + $r = q("ALTER TABLE `site` ADD `site_register` INT NOT NULL DEFAULT '0', ADD INDEX ( `site_register` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } + } \ No newline at end of file diff --git a/Zotlabs/Update/_1046.php b/Zotlabs/Update/_1046.php index 219d53e17..212162299 100644 --- a/Zotlabs/Update/_1046.php +++ b/Zotlabs/Update/_1046.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1046 { -function run() { - $r = q("ALTER TABLE `term` ADD `term_hash` CHAR( 255 ) NOT NULL DEFAULT '', +class _1046 +{ + public function run() + { + $r = q("ALTER TABLE `term` ADD `term_hash` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `term_hash` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1047.php b/Zotlabs/Update/_1047.php index 930c13eb8..a519aaff7 100644 --- a/Zotlabs/Update/_1047.php +++ b/Zotlabs/Update/_1047.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1047 { -function run() { - $r = q("ALTER TABLE `xprof` ADD `xprof_age` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `xprof_hash` , +class _1047 +{ + public function run() + { + $r = q("ALTER TABLE `xprof` ADD `xprof_age` TINYINT( 3 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `xprof_hash` , ADD INDEX ( `xprof_age` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1048.php b/Zotlabs/Update/_1048.php index 20c8931d7..ceb2e22f5 100644 --- a/Zotlabs/Update/_1048.php +++ b/Zotlabs/Update/_1048.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1048 { -function run() { - $r = q("CREATE TABLE IF NOT EXISTS `obj` ( +class _1048 +{ + public function run() + { + $r = q("CREATE TABLE IF NOT EXISTS `obj` ( `obj_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `obj_page` char(64) NOT NULL DEFAULT '', `obj_verb` char(255) NOT NULL DEFAULT '', @@ -19,11 +21,10 @@ function run() { KEY `obj_obj` (`obj_obj`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1049.php b/Zotlabs/Update/_1049.php index 622847727..dc8ce68a4 100644 --- a/Zotlabs/Update/_1049.php +++ b/Zotlabs/Update/_1049.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1049 { -function run() { - $r = q("ALTER TABLE `term` ADD `parent_hash` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `term_hash` , ADD INDEX ( `parent_hash` ) "); +class _1049 +{ + public function run() + { + $r = q("ALTER TABLE `term` ADD `parent_hash` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `term_hash` , ADD INDEX ( `parent_hash` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1050.php b/Zotlabs/Update/_1050.php index 1939d346f..ae6588788 100644 --- a/Zotlabs/Update/_1050.php +++ b/Zotlabs/Update/_1050.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1050 { -function run() { - $r = q("ALTER TABLE `xtag` DROP PRIMARY KEY , ADD `xtag_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST , ADD INDEX ( `xtag_hash` ) "); +class _1050 +{ + public function run() + { + $r = q("ALTER TABLE `xtag` DROP PRIMARY KEY , ADD `xtag_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST , ADD INDEX ( `xtag_hash` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1051.php b/Zotlabs/Update/_1051.php index 041b51f21..526ee2cf1 100644 --- a/Zotlabs/Update/_1051.php +++ b/Zotlabs/Update/_1051.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1051 { -function run() { - $r = q("ALTER TABLE `photo` ADD `photo_flags` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `profile` , ADD INDEX ( `photo_flags` ) "); - - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1051 +{ + public function run() + { + $r = q("ALTER TABLE `photo` ADD `photo_flags` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `profile` , ADD INDEX ( `photo_flags` ) "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1052.php b/Zotlabs/Update/_1052.php index 05addf21f..24b915312 100644 --- a/Zotlabs/Update/_1052.php +++ b/Zotlabs/Update/_1052.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1052 { -function run() { - $r = q("ALTER TABLE `channel` ADD UNIQUE (`channel_address`) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1052 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD UNIQUE (`channel_address`) "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1053.php b/Zotlabs/Update/_1053.php index 4752dca62..3b4a65176 100644 --- a/Zotlabs/Update/_1053.php +++ b/Zotlabs/Update/_1053.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1053 { -function run() { - $r = q("ALTER TABLE `profile` ADD `chandesc` TEXT NOT NULL DEFAULT '' AFTER `pdesc` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1053 +{ + public function run() + { + $r = q("ALTER TABLE `profile` ADD `chandesc` TEXT NOT NULL DEFAULT '' AFTER `pdesc` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1054.php b/Zotlabs/Update/_1054.php index f4fc2eb5b..97bb42a2f 100644 --- a/Zotlabs/Update/_1054.php +++ b/Zotlabs/Update/_1054.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1054 { -function run() { - $r = q("ALTER TABLE `item` CHANGE `title` `title` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1054 +{ + public function run() + { + $r = q("ALTER TABLE `item` CHANGE `title` `title` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1055.php b/Zotlabs/Update/_1055.php index 6b3a4c1d9..38a5a6dfd 100644 --- a/Zotlabs/Update/_1055.php +++ b/Zotlabs/Update/_1055.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1055 { -function run() { - $r = q("ALTER TABLE `mail` CHANGE `title` `title` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1055 +{ + public function run() + { + $r = q("ALTER TABLE `mail` CHANGE `title` `title` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1056.php b/Zotlabs/Update/_1056.php index 6c0510f88..085d57904 100644 --- a/Zotlabs/Update/_1056.php +++ b/Zotlabs/Update/_1056.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1056 { -function run() { - $r = q("ALTER TABLE `xchan` ADD `xchan_instance_url` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `xchan_network` , +class _1056 +{ + public function run() + { + $r = q("ALTER TABLE `xchan` ADD `xchan_instance_url` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `xchan_network` , ADD INDEX ( `xchan_instance_url` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1057.php b/Zotlabs/Update/_1057.php index 081e82d1f..f6694e327 100644 --- a/Zotlabs/Update/_1057.php +++ b/Zotlabs/Update/_1057.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1057 { -function run() { - $r = q("drop table intro"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1057 +{ + public function run() + { + $r = q("drop table intro"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1058.php b/Zotlabs/Update/_1058.php index 8e3ffdd6a..8347b957f 100644 --- a/Zotlabs/Update/_1058.php +++ b/Zotlabs/Update/_1058.php @@ -2,18 +2,20 @@ namespace Zotlabs\Update; -class _1058 { -function run() { - $r1 = q("ALTER TABLE `menu` ADD `menu_name` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `menu_channel_id` , +class _1058 +{ + public function run() + { + $r1 = q("ALTER TABLE `menu` ADD `menu_name` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `menu_channel_id` , ADD INDEX ( `menu_name` ) "); - $r2 = q("ALTER TABLE `menu_item` ADD `mitem_flags` INT NOT NULL DEFAULT '0' AFTER `mitem_desc` , + $r2 = q("ALTER TABLE `menu_item` ADD `mitem_flags` INT NOT NULL DEFAULT '0' AFTER `mitem_desc` , ADD INDEX ( `mitem_flags` ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1059.php b/Zotlabs/Update/_1059.php index e035efb2c..989bd76b3 100644 --- a/Zotlabs/Update/_1059.php +++ b/Zotlabs/Update/_1059.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1059 { -function run() { - $r = q("ALTER TABLE `mail` ADD `attach` MEDIUMTEXT NOT NULL DEFAULT '' AFTER `body` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1059 +{ + public function run() + { + $r = q("ALTER TABLE `mail` ADD `attach` MEDIUMTEXT NOT NULL DEFAULT '' AFTER `body` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1060.php b/Zotlabs/Update/_1060.php index 5182b803a..e22a370e0 100644 --- a/Zotlabs/Update/_1060.php +++ b/Zotlabs/Update/_1060.php @@ -2,10 +2,12 @@ namespace Zotlabs\Update; -class _1060 { -function run() { +class _1060 +{ + public function run() + { - $r = q("CREATE TABLE IF NOT EXISTS `vote` ( + $r = q("CREATE TABLE IF NOT EXISTS `vote` ( `vote_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `vote_poll` int(11) NOT NULL DEFAULT '0', `vote_element` int(11) NOT NULL DEFAULT '0', @@ -15,10 +17,10 @@ function run() { UNIQUE KEY `vote_vote` (`vote_poll`,`vote_element`,`vote_xchan`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1061.php b/Zotlabs/Update/_1061.php index e7af5bcb1..d1b2d2554 100644 --- a/Zotlabs/Update/_1061.php +++ b/Zotlabs/Update/_1061.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1061 { -function run() { - $r = q("ALTER TABLE `vote` ADD INDEX ( `vote_poll` ), ADD INDEX ( `vote_element` ) "); +class _1061 +{ + public function run() + { + $r = q("ALTER TABLE `vote` ADD INDEX ( `vote_poll` ), ADD INDEX ( `vote_element` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1062.php b/Zotlabs/Update/_1062.php index 39aa80e8a..e6fd22fc6 100644 --- a/Zotlabs/Update/_1062.php +++ b/Zotlabs/Update/_1062.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1062 { -function run() { - $r1 = q("CREATE TABLE IF NOT EXISTS `poll` ( +class _1062 +{ + public function run() + { + $r1 = q("CREATE TABLE IF NOT EXISTS `poll` ( `poll_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `poll_channel` INT UNSIGNED NOT NULL DEFAULT '0', `poll_desc` TEXT NOT NULL DEFAULT '', @@ -15,7 +17,7 @@ KEY `poll_flags` (`poll_flags`), KEY `poll_votes` (`poll_votes`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - $r2 = q("CREATE TABLE IF NOT EXISTS `poll_elm` ( + $r2 = q("CREATE TABLE IF NOT EXISTS `poll_elm` ( `pelm_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `pelm_poll` INT UNSIGNED NOT NULL DEFAULT '0', `pelm_desc` TEXT NOT NULL DEFAULT '', @@ -25,10 +27,10 @@ KEY `pelm_poll` (`pelm_poll`), KEY `pelm_result` (`pelm_result`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1063.php b/Zotlabs/Update/_1063.php index 04d523df6..71fdcb8bf 100644 --- a/Zotlabs/Update/_1063.php +++ b/Zotlabs/Update/_1063.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1063 { -function run() { - $r = q("ALTER TABLE `xchan` ADD `xchan_follow` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `xchan_connurl` , +class _1063 +{ + public function run() + { + $r = q("ALTER TABLE `xchan` ADD `xchan_follow` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `xchan_connurl` , ADD `xchan_connpage` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `xchan_follow` , ADD INDEX ( `xchan_follow` ), ADD INDEX ( `xchan_connpage`) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1064.php b/Zotlabs/Update/_1064.php index 295dd96c5..d5811ad75 100644 --- a/Zotlabs/Update/_1064.php +++ b/Zotlabs/Update/_1064.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1064 { -function run() { - $r = q("ALTER TABLE `updates` ADD `ud_guid` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `ud_hash` , +class _1064 +{ + public function run() + { + $r = q("ALTER TABLE `updates` ADD `ud_guid` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `ud_hash` , ADD INDEX ( `ud_guid` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1065.php b/Zotlabs/Update/_1065.php index 0a3e9082e..2658f42d7 100644 --- a/Zotlabs/Update/_1065.php +++ b/Zotlabs/Update/_1065.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1065 { -function run() { - $r = q("ALTER TABLE `item` DROP `wall`, ADD `layout_mid` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `target` , +class _1065 +{ + public function run() + { + $r = q("ALTER TABLE `item` DROP `wall`, ADD `layout_mid` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `target` , ADD INDEX ( `layout_mid` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1066.php b/Zotlabs/Update/_1066.php index e7d3fbbb4..a17a5efb9 100644 --- a/Zotlabs/Update/_1066.php +++ b/Zotlabs/Update/_1066.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1066 { -function run() { - $r = q("ALTER TABLE `site` ADD `site_access` INT NOT NULL DEFAULT '0' AFTER `site_url` , +class _1066 +{ + public function run() + { + $r = q("ALTER TABLE `site` ADD `site_access` INT NOT NULL DEFAULT '0' AFTER `site_url` , ADD INDEX ( `site_access` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1067.php b/Zotlabs/Update/_1067.php index 94782a15e..911dc7300 100644 --- a/Zotlabs/Update/_1067.php +++ b/Zotlabs/Update/_1067.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1067 { -function run() { - $r = q("ALTER TABLE `updates` DROP PRIMARY KEY , ADD `ud_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST, ADD INDEX ( `ud_hash` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1067 +{ + public function run() + { + $r = q("ALTER TABLE `updates` DROP PRIMARY KEY , ADD `ud_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST, ADD INDEX ( `ud_hash` ) "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1068.php b/Zotlabs/Update/_1068.php index e2a70684f..c7834c6cf 100644 --- a/Zotlabs/Update/_1068.php +++ b/Zotlabs/Update/_1068.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1068 { -function run(){ +class _1068 +{ + public function run() + { $r = q("ALTER TABLE `hubloc` ADD `hubloc_status` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `hubloc_flags` , ADD INDEX ( `hubloc_status` )"); - if($r) - return UPDATE_SUCCESS; + if ($r) + return UPDATE_SUCCESS; return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1069.php b/Zotlabs/Update/_1069.php index 437c7ffef..7306be8d4 100644 --- a/Zotlabs/Update/_1069.php +++ b/Zotlabs/Update/_1069.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1069 { -function run() { - $r = q("ALTER TABLE `site` ADD `site_sellpage` CHAR( 255 ) NOT NULL DEFAULT '', +class _1069 +{ + public function run() + { + $r = q("ALTER TABLE `site` ADD `site_sellpage` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `site_sellpage` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1070.php b/Zotlabs/Update/_1070.php index 2ec03f752..b9cf90982 100644 --- a/Zotlabs/Update/_1070.php +++ b/Zotlabs/Update/_1070.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1070 { -function run() { - $r = q("ALTER TABLE `updates` ADD `ud_flags` INT NOT NULL DEFAULT '0', +class _1070 +{ + public function run() + { + $r = q("ALTER TABLE `updates` ADD `ud_flags` INT NOT NULL DEFAULT '0', ADD INDEX ( `ud_flags` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1071.php b/Zotlabs/Update/_1071.php index f4e627e7f..b3afa990b 100644 --- a/Zotlabs/Update/_1071.php +++ b/Zotlabs/Update/_1071.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1071 { -function run() { - $r = q("ALTER TABLE `updates` ADD `ud_addr` CHAR( 255 ) NOT NULL DEFAULT '', +class _1071 +{ + public function run() + { + $r = q("ALTER TABLE `updates` ADD `ud_addr` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `ud_addr` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1072.php b/Zotlabs/Update/_1072.php index 191893547..10166999d 100644 --- a/Zotlabs/Update/_1072.php +++ b/Zotlabs/Update/_1072.php @@ -2,16 +2,17 @@ namespace Zotlabs\Update; -class _1072 { -function run() { - $r = q("ALTER TABLE `xtag` ADD `xtag_flags` INT NOT NULL DEFAULT '0', +class _1072 +{ + public function run() + { + $r = q("ALTER TABLE `xtag` ADD `xtag_flags` INT NOT NULL DEFAULT '0', ADD INDEX ( `xtag_flags` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1073.php b/Zotlabs/Update/_1073.php index f238d7a36..042304447 100644 --- a/Zotlabs/Update/_1073.php +++ b/Zotlabs/Update/_1073.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1073 { -function run() { - $r1 = q("CREATE TABLE IF NOT EXISTS `source` ( +class _1073 +{ + public function run() + { + $r1 = q("CREATE TABLE IF NOT EXISTS `source` ( `src_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `src_channel_id` INT UNSIGNED NOT NULL DEFAULT '0', `src_channel_xchan` CHAR( 255 ) NOT NULL DEFAULT '', @@ -12,12 +14,12 @@ function run() { `src_patt` MEDIUMTEXT NOT NULL DEFAULT '' ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - $r2 = q("ALTER TABLE `source` ADD INDEX ( `src_channel_id` ), ADD INDEX ( `src_channel_xchan` ), ADD INDEX ( `src_xchan` ) "); + $r2 = q("ALTER TABLE `source` ADD INDEX ( `src_channel_id` ), ADD INDEX ( `src_channel_xchan` ), ADD INDEX ( `src_xchan` ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1074.php b/Zotlabs/Update/_1074.php index d331b935a..286dea0f0 100644 --- a/Zotlabs/Update/_1074.php +++ b/Zotlabs/Update/_1074.php @@ -2,18 +2,19 @@ namespace Zotlabs\Update; -class _1074 { -function run() { - $r1 = q("ALTER TABLE `site` ADD `site_sync` DATETIME NOT NULL AFTER `site_update` "); +class _1074 +{ + public function run() + { + $r1 = q("ALTER TABLE `site` ADD `site_sync` DATETIME NOT NULL AFTER `site_update` "); - $r2 = q("ALTER TABLE `updates` ADD `ud_last` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `ud_date` , + $r2 = q("ALTER TABLE `updates` ADD `ud_last` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `ud_date` , ADD INDEX ( `ud_last` ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1075.php b/Zotlabs/Update/_1075.php index ac7c48f71..047a39de2 100644 --- a/Zotlabs/Update/_1075.php +++ b/Zotlabs/Update/_1075.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1075 { -function run() { - $r = q("ALTER TABLE `channel` ADD `channel_a_republish` INT UNSIGNED NOT NULL DEFAULT '128', +class _1075 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD `channel_a_republish` INT UNSIGNED NOT NULL DEFAULT '128', ADD INDEX ( `channel_a_republish` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1076.php b/Zotlabs/Update/_1076.php index c8c631822..cafbd63d4 100644 --- a/Zotlabs/Update/_1076.php +++ b/Zotlabs/Update/_1076.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1076 { -function run() { - $r = q("ALTER TABLE `item` CHANGE `inform` `sig` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1076 +{ + public function run() + { + $r = q("ALTER TABLE `item` CHANGE `inform` `sig` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1077.php b/Zotlabs/Update/_1077.php index 3c23affbc..1d784aa26 100644 --- a/Zotlabs/Update/_1077.php +++ b/Zotlabs/Update/_1077.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1077 { -function run() { - $r = q("ALTER TABLE `item` ADD `source_xchan` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `author_xchan` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1077 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `source_xchan` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `author_xchan` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1078.php b/Zotlabs/Update/_1078.php index c832a1c2a..9851b9de3 100644 --- a/Zotlabs/Update/_1078.php +++ b/Zotlabs/Update/_1078.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1078 { -function run() { - $r = q("ALTER TABLE `channel` ADD `channel_dirdate` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `channel_pageflags` , ADD INDEX ( `channel_dirdate` )"); +class _1078 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD `channel_dirdate` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `channel_pageflags` , ADD INDEX ( `channel_dirdate` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1079.php b/Zotlabs/Update/_1079.php index b10e2e7ae..013827d10 100644 --- a/Zotlabs/Update/_1079.php +++ b/Zotlabs/Update/_1079.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1079 { -function run() { - $r = q("ALTER TABLE `site` ADD `site_location` CHAR( 255 ) NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1079 +{ + public function run() + { + $r = q("ALTER TABLE `site` ADD `site_location` CHAR( 255 ) NOT NULL DEFAULT ''"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1080.php b/Zotlabs/Update/_1080.php index ab9c4c2f8..537aa53ac 100644 --- a/Zotlabs/Update/_1080.php +++ b/Zotlabs/Update/_1080.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1080 { -function run() { - $r = q("ALTER TABLE `mail` ADD `expires` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', +class _1080 +{ + public function run() + { + $r = q("ALTER TABLE `mail` ADD `expires` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD INDEX ( `expires` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1081.php b/Zotlabs/Update/_1081.php index 521a39893..1562d3524 100644 --- a/Zotlabs/Update/_1081.php +++ b/Zotlabs/Update/_1081.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1081 { -function run() { - $r = q("DROP TABLE `queue` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1081 +{ + public function run() + { + $r = q("DROP TABLE `queue` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1082.php b/Zotlabs/Update/_1082.php index 8ce8d20c1..89e1f3526 100644 --- a/Zotlabs/Update/_1082.php +++ b/Zotlabs/Update/_1082.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1082 { -function run() { - $r = q("DROP TABLE `challenge` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1082 +{ + public function run() + { + $r = q("DROP TABLE `challenge` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1083.php b/Zotlabs/Update/_1083.php index becb2b702..3d6e3a1ff 100644 --- a/Zotlabs/Update/_1083.php +++ b/Zotlabs/Update/_1083.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1083 { -function run() { - $r = q("ALTER TABLE `notify` ADD `aid` INT NOT NULL AFTER `msg` , +class _1083 +{ + public function run() + { + $r = q("ALTER TABLE `notify` ADD `aid` INT NOT NULL AFTER `msg` , ADD INDEX ( `aid` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1084.php b/Zotlabs/Update/_1084.php index 621d0346d..ffacc8b15 100644 --- a/Zotlabs/Update/_1084.php +++ b/Zotlabs/Update/_1084.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1084 { -function run() { +class _1084 +{ + public function run() + { - $r = q("CREATE TABLE if not exists `sys_perms` ( + $r = q("CREATE TABLE if not exists `sys_perms` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `cat` CHAR( 255 ) NOT NULL , `k` CHAR( 255 ) NOT NULL , @@ -14,11 +16,11 @@ function run() { `public_perm` TINYINT( 1 ) UNSIGNED NOT NULL ) ENGINE = MYISAM DEFAULT CHARSET = utf8"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1085.php b/Zotlabs/Update/_1085.php index f50e56319..ef5127b02 100644 --- a/Zotlabs/Update/_1085.php +++ b/Zotlabs/Update/_1085.php @@ -2,19 +2,21 @@ namespace Zotlabs\Update; -class _1085 { -function run() { - $r1 = q("ALTER TABLE `photo` CHANGE `desc` `description` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL "); +class _1085 +{ + public function run() + { + $r1 = q("ALTER TABLE `photo` CHANGE `desc` `description` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL "); - $r2 = q("RENAME TABLE `group` TO `groups`"); + $r2 = q("RENAME TABLE `group` TO `groups`"); - $r3 = q("ALTER TABLE `event` CHANGE `desc` `description` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL "); + $r3 = q("ALTER TABLE `event` CHANGE `desc` `description` TEXT CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL "); - if($r1 && $r2 && $r3) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2 && $r3) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1086.php b/Zotlabs/Update/_1086.php index 1b034daac..79dd90e02 100644 --- a/Zotlabs/Update/_1086.php +++ b/Zotlabs/Update/_1086.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1086 { -function run() { - $r = q("ALTER TABLE `account` ADD `account_level` INT UNSIGNED NOT NULL DEFAULT '0', +class _1086 +{ + public function run() + { + $r = q("ALTER TABLE `account` ADD `account_level` INT UNSIGNED NOT NULL DEFAULT '0', ADD INDEX ( `account_level` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1087.php b/Zotlabs/Update/_1087.php index 839c16d91..c0813e7d5 100644 --- a/Zotlabs/Update/_1087.php +++ b/Zotlabs/Update/_1087.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1087 { -function run() { - $r = q("ALTER TABLE `xprof` ADD `xprof_about` TEXT NOT NULL DEFAULT '', +class _1087 +{ + public function run() + { + $r = q("ALTER TABLE `xprof` ADD `xprof_about` TEXT NOT NULL DEFAULT '', ADD `xprof_homepage` CHAR( 255 ) NOT NULL DEFAULT '', ADD `xprof_hometown` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `xprof_hometown` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1088.php b/Zotlabs/Update/_1088.php index 5f478d0a1..41ede1cd8 100644 --- a/Zotlabs/Update/_1088.php +++ b/Zotlabs/Update/_1088.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1088 { -function run() { - $r = q("ALTER TABLE `obj` ADD `allow_cid` MEDIUMTEXT NOT NULL DEFAULT '', +class _1088 +{ + public function run() + { + $r = q("ALTER TABLE `obj` ADD `allow_cid` MEDIUMTEXT NOT NULL DEFAULT '', ADD `allow_gid` MEDIUMTEXT NOT NULL DEFAULT '', ADD `deny_cid` MEDIUMTEXT NOT NULL DEFAULT '', ADD `deny_gid` MEDIUMTEXT NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1089.php b/Zotlabs/Update/_1089.php index 0a8a1d55b..1cf985f26 100644 --- a/Zotlabs/Update/_1089.php +++ b/Zotlabs/Update/_1089.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1089 { -function run() { - $r = q("ALTER TABLE `attach` ADD `creator` CHAR( 128 ) NOT NULL DEFAULT '' AFTER `hash` , +class _1089 +{ + public function run() + { + $r = q("ALTER TABLE `attach` ADD `creator` CHAR( 128 ) NOT NULL DEFAULT '' AFTER `hash` , ADD INDEX ( `creator` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1090.php b/Zotlabs/Update/_1090.php index efa7db7c2..1abc2a8fc 100644 --- a/Zotlabs/Update/_1090.php +++ b/Zotlabs/Update/_1090.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1090 { -function run() { - $r = q("ALTER TABLE `menu` ADD `menu_flags` INT NOT NULL DEFAULT '0', +class _1090 +{ + public function run() + { + $r = q("ALTER TABLE `menu` ADD `menu_flags` INT NOT NULL DEFAULT '0', ADD INDEX ( `menu_flags` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1091.php b/Zotlabs/Update/_1091.php index 0b287b45f..f69e20a4d 100644 --- a/Zotlabs/Update/_1091.php +++ b/Zotlabs/Update/_1091.php @@ -2,12 +2,14 @@ namespace Zotlabs\Update; -class _1091 { -function run() { - @os_mkdir('cache/smarty3',STORAGE_DEFAULT_PERMISSIONS,true); - @file_put_contents('cache/locks',''); - return UPDATE_SUCCESS; -} +class _1091 +{ + public function run() + { + @os_mkdir('cache/smarty3', STORAGE_DEFAULT_PERMISSIONS, true); + @file_put_contents('cache/locks', ''); + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1092.php b/Zotlabs/Update/_1092.php index 897c0c20b..756fda41a 100644 --- a/Zotlabs/Update/_1092.php +++ b/Zotlabs/Update/_1092.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1092 { -function run() { - $r1 = q("CREATE TABLE IF NOT EXISTS `chat` ( +class _1092 +{ + public function run() + { + $r1 = q("CREATE TABLE IF NOT EXISTS `chat` ( `chat_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `chat_room` int(10) unsigned NOT NULL DEFAULT '0', `chat_xchan` char(255) NOT NULL DEFAULT '', @@ -16,7 +18,7 @@ function run() { KEY `created` (`created`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - $r2 = q("CREATE TABLE IF NOT EXISTS `chatpresence` ( + $r2 = q("CREATE TABLE IF NOT EXISTS `chatpresence` ( `cp_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `cp_room` int(10) unsigned NOT NULL DEFAULT '0', `cp_xchan` char(255) NOT NULL DEFAULT '', @@ -29,7 +31,7 @@ function run() { KEY `cp_status` (`cp_status`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - $r3 = q("CREATE TABLE IF NOT EXISTS `chatroom` ( + $r3 = q("CREATE TABLE IF NOT EXISTS `chatroom` ( `cr_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `cr_aid` int(10) unsigned NOT NULL DEFAULT '0', `cr_uid` int(10) unsigned NOT NULL DEFAULT '0', @@ -49,13 +51,10 @@ function run() { ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - if($r1 && $r2 && $r3) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - - - + if ($r1 && $r2 && $r3) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1093.php b/Zotlabs/Update/_1093.php index eb692e0b7..7f546a774 100644 --- a/Zotlabs/Update/_1093.php +++ b/Zotlabs/Update/_1093.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1093 { -function run() { - $r = q("ALTER TABLE `chatpresence` ADD `cp_client` CHAR( 128 ) NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1093 +{ + public function run() + { + $r = q("ALTER TABLE `chatpresence` ADD `cp_client` CHAR( 128 ) NOT NULL DEFAULT ''"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1094.php b/Zotlabs/Update/_1094.php index c502c7a06..19f98c04f 100644 --- a/Zotlabs/Update/_1094.php +++ b/Zotlabs/Update/_1094.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1094 { -function run() { - $r = q("ALTER TABLE `chatroom` ADD `cr_expire` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `cr_edited` , +class _1094 +{ + public function run() + { + $r = q("ALTER TABLE `chatroom` ADD `cr_expire` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `cr_edited` , ADD INDEX ( `cr_expire` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1095.php b/Zotlabs/Update/_1095.php index 0f11fda62..341f5db40 100644 --- a/Zotlabs/Update/_1095.php +++ b/Zotlabs/Update/_1095.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1095 { -function run() { - $r = q("ALTER TABLE `channel` ADD `channel_a_bookmark` INT UNSIGNED NOT NULL DEFAULT '128', +class _1095 +{ + public function run() + { + $r = q("ALTER TABLE `channel` ADD `channel_a_bookmark` INT UNSIGNED NOT NULL DEFAULT '128', ADD INDEX ( `channel_a_bookmark` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1096.php b/Zotlabs/Update/_1096.php index 67abb9ee2..1d11a8409 100644 --- a/Zotlabs/Update/_1096.php +++ b/Zotlabs/Update/_1096.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1096 { -function run() { - $r = q("ALTER TABLE `account` CHANGE `account_level` `account_level` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1096 +{ + public function run() + { + $r = q("ALTER TABLE `account` CHANGE `account_level` `account_level` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1097.php b/Zotlabs/Update/_1097.php index bfe04cf5f..43b249b9c 100644 --- a/Zotlabs/Update/_1097.php +++ b/Zotlabs/Update/_1097.php @@ -2,23 +2,25 @@ namespace Zotlabs\Update; -class _1097 { -function run() { +class _1097 +{ + public function run() + { - // fix some mangled hublocs from a bug long ago + // fix some mangled hublocs from a bug long ago - $r = q("select hubloc_id, hubloc_addr from hubloc where hubloc_addr like '%%/%%'"); - if($r) { - foreach($r as $rr) { - q("update hubloc set hubloc_addr = '%s' where hubloc_id = %d", - dbesc(substr($rr['hubloc_addr'],0,strpos($rr['hubloc_addr'],'/'))), - intval($rr['hubloc_id']) - ); - } - } - return UPDATE_SUCCESS; - -} + $r = q("select hubloc_id, hubloc_addr from hubloc where hubloc_addr like '%%/%%'"); + if ($r) { + foreach ($r as $rr) { + q("update hubloc set hubloc_addr = '%s' where hubloc_id = %d", + dbesc(substr($rr['hubloc_addr'], 0, strpos($rr['hubloc_addr'], '/'))), + intval($rr['hubloc_id']) + ); + } + } + return UPDATE_SUCCESS; + + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1098.php b/Zotlabs/Update/_1098.php index e74ba640c..54851c0cc 100644 --- a/Zotlabs/Update/_1098.php +++ b/Zotlabs/Update/_1098.php @@ -2,24 +2,26 @@ namespace Zotlabs\Update; -class _1098 { -function run() { - $r = q("ALTER TABLE `channel` CHANGE `channel_r_stream` `channel_r_stream` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r2 = q("ALTER TABLE `channel` CHANGE `channel_r_profile` `channel_r_profile` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r3 = q("ALTER TABLE `channel` CHANGE `channel_r_photos` `channel_r_photos` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r4 = q("ALTER TABLE `channel` CHANGE `channel_r_abook` `channel_r_abook` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r4 = q("ALTER TABLE `channel` CHANGE `channel_w_stream` `channel_w_stream` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r5 = q("ALTER TABLE `channel` CHANGE `channel_w_wall` `channel_w_wall` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r6 = q("ALTER TABLE `channel` CHANGE `channel_w_tagwall` `channel_w_tagwall` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r7 = q("ALTER TABLE `channel` CHANGE `channel_w_comment` `channel_w_comment` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r8 = q("ALTER TABLE `channel` CHANGE `channel_w_mail` `channel_w_mail` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r9 = q("ALTER TABLE `channel` CHANGE `channel_w_photos` `channel_w_photos` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r10 = q("ALTER TABLE `channel` CHANGE `channel_w_chat` `channel_w_chat` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - $r11 = q("ALTER TABLE `channel` CHANGE `channel_a_delegate` `channel_a_delegate` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); - if($r && $r2 && $r3 && $r3 && $r5 && $r6 && $r7 && $r8 && $r9 && $r9 && $r10 && $r11) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1098 +{ + public function run() + { + $r = q("ALTER TABLE `channel` CHANGE `channel_r_stream` `channel_r_stream` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r2 = q("ALTER TABLE `channel` CHANGE `channel_r_profile` `channel_r_profile` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r3 = q("ALTER TABLE `channel` CHANGE `channel_r_photos` `channel_r_photos` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r4 = q("ALTER TABLE `channel` CHANGE `channel_r_abook` `channel_r_abook` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r4 = q("ALTER TABLE `channel` CHANGE `channel_w_stream` `channel_w_stream` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r5 = q("ALTER TABLE `channel` CHANGE `channel_w_wall` `channel_w_wall` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r6 = q("ALTER TABLE `channel` CHANGE `channel_w_tagwall` `channel_w_tagwall` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r7 = q("ALTER TABLE `channel` CHANGE `channel_w_comment` `channel_w_comment` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r8 = q("ALTER TABLE `channel` CHANGE `channel_w_mail` `channel_w_mail` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r9 = q("ALTER TABLE `channel` CHANGE `channel_w_photos` `channel_w_photos` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r10 = q("ALTER TABLE `channel` CHANGE `channel_w_chat` `channel_w_chat` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + $r11 = q("ALTER TABLE `channel` CHANGE `channel_a_delegate` `channel_a_delegate` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0'"); + if ($r && $r2 && $r3 && $r3 && $r5 && $r6 && $r7 && $r8 && $r9 && $r9 && $r10 && $r11) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1099.php b/Zotlabs/Update/_1099.php index a49e38c7c..99b74da5b 100644 --- a/Zotlabs/Update/_1099.php +++ b/Zotlabs/Update/_1099.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1099 { -function run() { - $r = q("CREATE TABLE IF NOT EXISTS `xchat` ( +class _1099 +{ + public function run() + { + $r = q("CREATE TABLE IF NOT EXISTS `xchat` ( `xchat_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `xchat_url` char(255) NOT NULL DEFAULT '', `xchat_desc` char(255) NOT NULL DEFAULT '', @@ -15,10 +17,10 @@ function run() { KEY `xchat_xchan` (`xchat_xchan`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1100.php b/Zotlabs/Update/_1100.php index ffcd7dc1d..e65bdbf6f 100644 --- a/Zotlabs/Update/_1100.php +++ b/Zotlabs/Update/_1100.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1100 { -function run() { - $r = q("ALTER TABLE `xchat` ADD `xchat_edited` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', +class _1100 +{ + public function run() + { + $r = q("ALTER TABLE `xchat` ADD `xchat_edited` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD INDEX ( `xchat_edited` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1101.php b/Zotlabs/Update/_1101.php index 709b6fa0a..4ce98e633 100644 --- a/Zotlabs/Update/_1101.php +++ b/Zotlabs/Update/_1101.php @@ -2,12 +2,14 @@ namespace Zotlabs\Update; -class _1101 { -function run() { - $r = q("update updates set ud_flags = 2 where ud_flags = (-1)"); - $r = q("update updates set ud_flags = 0 where ud_flags = 4096"); - return UPDATE_SUCCESS; -} +class _1101 +{ + public function run() + { + $r = q("update updates set ud_flags = 2 where ud_flags = (-1)"); + $r = q("update updates set ud_flags = 0 where ud_flags = 4096"); + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1102.php b/Zotlabs/Update/_1102.php index d25979b1f..26cadcee7 100644 --- a/Zotlabs/Update/_1102.php +++ b/Zotlabs/Update/_1102.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1102 { -function run() { - $r = q("update abook set abook_flags = (abook_flags - %d) +class _1102 +{ + public function run() + { + $r = q("update abook set abook_flags = (abook_flags - %d) where ( abook_flags & %d)", - intval(ABOOK_FLAG_UNCONNECTED), - intval(ABOOK_FLAG_UNCONNECTED) - ); - return UPDATE_SUCCESS; -} + intval(ABOOK_FLAG_UNCONNECTED), + intval(ABOOK_FLAG_UNCONNECTED) + ); + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1103.php b/Zotlabs/Update/_1103.php index 3f9a9286c..7bb136cb0 100644 --- a/Zotlabs/Update/_1103.php +++ b/Zotlabs/Update/_1103.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1103 { -function run() { - $x = curl_version(); - if(stristr($x['ssl_version'],'openssl')) - set_config('system','curl_ssl_ciphers','ALL:!eNULL'); - return UPDATE_SUCCESS; -} +class _1103 +{ + public function run() + { + $x = curl_version(); + if (stristr($x['ssl_version'], 'openssl')) + set_config('system', 'curl_ssl_ciphers', 'ALL:!eNULL'); + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1104.php b/Zotlabs/Update/_1104.php index 0d299095b..3b56f1927 100644 --- a/Zotlabs/Update/_1104.php +++ b/Zotlabs/Update/_1104.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1104 { -function run() { - $r = q("ALTER TABLE `item` ADD `route` TEXT NOT NULL DEFAULT '' AFTER `postopts` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1104 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `route` TEXT NOT NULL DEFAULT '' AFTER `postopts` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1105.php b/Zotlabs/Update/_1105.php index a96600150..86d4fd6d6 100644 --- a/Zotlabs/Update/_1105.php +++ b/Zotlabs/Update/_1105.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1105 { -function run() { - $r = q("ALTER TABLE `site` ADD `site_pull` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `site_update` , +class _1105 +{ + public function run() + { + $r = q("ALTER TABLE `site` ADD `site_pull` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `site_update` , CHANGE `site_sync` `site_sync` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD INDEX ( `site_pull` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1106.php b/Zotlabs/Update/_1106.php index 7e13d8993..77b80efac 100644 --- a/Zotlabs/Update/_1106.php +++ b/Zotlabs/Update/_1106.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1106 { -function run() { - $r = q("ALTER TABLE `notify` CHANGE `parent` `parent` CHAR( 255 ) NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1106 +{ + public function run() + { + $r = q("ALTER TABLE `notify` CHANGE `parent` `parent` CHAR( 255 ) NOT NULL DEFAULT ''"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1107.php b/Zotlabs/Update/_1107.php index bcac6cf19..08e05bde9 100644 --- a/Zotlabs/Update/_1107.php +++ b/Zotlabs/Update/_1107.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1107 { -function run() { - $r = q("CREATE TABLE IF NOT EXISTS `app` ( +class _1107 +{ + public function run() + { + $r = q("CREATE TABLE IF NOT EXISTS `app` ( `id` int(11) NOT NULL AUTO_INCREMENT, `app_id` char(64) NOT NULL DEFAULT '', `app_sig` char(255) NOT NULL DEFAULT '', @@ -24,11 +26,10 @@ function run() { KEY `app_channel` (`app_channel`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1108.php b/Zotlabs/Update/_1108.php index d9d9b0c18..e6a090c74 100644 --- a/Zotlabs/Update/_1108.php +++ b/Zotlabs/Update/_1108.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1108 { -function run() { - $r = q("ALTER TABLE `app` ADD `app_addr` CHAR( 255 ) NOT NULL DEFAULT '', +class _1108 +{ + public function run() + { + $r = q("ALTER TABLE `app` ADD `app_addr` CHAR( 255 ) NOT NULL DEFAULT '', ADD `app_price` CHAR( 255 ) NOT NULL DEFAULT '', ADD `app_page` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `app_price` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1109.php b/Zotlabs/Update/_1109.php index 6a0aed28f..b454632ea 100644 --- a/Zotlabs/Update/_1109.php +++ b/Zotlabs/Update/_1109.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1109 { -function run() { - $r = q("ALTER TABLE `app` CHANGE `app_id` `app_id` CHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1109 +{ + public function run() + { + $r = q("ALTER TABLE `app` CHANGE `app_id` `app_id` CHAR( 255 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT ''"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } // We ended up with an extra zero in the name for 1108, so do it over and ignore the result. diff --git a/Zotlabs/Update/_1110.php b/Zotlabs/Update/_1110.php index 62bcbd0c8..2bae3e698 100644 --- a/Zotlabs/Update/_1110.php +++ b/Zotlabs/Update/_1110.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1110 { -function run() { - $r = q("ALTER TABLE `app` ADD `app_addr` CHAR( 255 ) NOT NULL DEFAULT '', +class _1110 +{ + public function run() + { + $r = q("ALTER TABLE `app` ADD `app_addr` CHAR( 255 ) NOT NULL DEFAULT '', ADD `app_price` CHAR( 255 ) NOT NULL DEFAULT '', ADD `app_page` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `app_price` )"); - return UPDATE_SUCCESS; + return UPDATE_SUCCESS; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1111.php b/Zotlabs/Update/_1111.php index a3080b465..50e4c2340 100644 --- a/Zotlabs/Update/_1111.php +++ b/Zotlabs/Update/_1111.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1111 { -function run() { - $r = q("ALTER TABLE `app` ADD `app_requires` CHAR( 255 ) NOT NULL DEFAULT '' "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1111 +{ + public function run() + { + $r = q("ALTER TABLE `app` ADD `app_requires` CHAR( 255 ) NOT NULL DEFAULT '' "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1112.php b/Zotlabs/Update/_1112.php index e81780519..8febcfce7 100644 --- a/Zotlabs/Update/_1112.php +++ b/Zotlabs/Update/_1112.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1112 { -function run() { - $r = q("CREATE TABLE IF NOT EXISTS `likes` ( +class _1112 +{ + public function run() + { + $r = q("CREATE TABLE IF NOT EXISTS `likes` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `liker` char(128) NOT NULL DEFAULT '', `likee` char(128) NOT NULL DEFAULT '', @@ -20,10 +22,10 @@ function run() { KEY `target_type` (`target_type`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1113.php b/Zotlabs/Update/_1113.php index 0a726dcc3..791b7e12f 100644 --- a/Zotlabs/Update/_1113.php +++ b/Zotlabs/Update/_1113.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1113 { -function run() { - $r = q("ALTER TABLE `likes` ADD `channel_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `id` , +class _1113 +{ + public function run() + { + $r = q("ALTER TABLE `likes` ADD `channel_id` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `id` , CHANGE `iid` `iid` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0', ADD INDEX ( `channel_id` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1114.php b/Zotlabs/Update/_1114.php index 5b564d513..59bb1feac 100644 --- a/Zotlabs/Update/_1114.php +++ b/Zotlabs/Update/_1114.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1114 { -function run() { - $r = q("ALTER TABLE `likes` ADD `target_id` CHAR( 128 ) NOT NULL DEFAULT '' AFTER `target_type` , +class _1114 +{ + public function run() + { + $r = q("ALTER TABLE `likes` ADD `target_id` CHAR( 128 ) NOT NULL DEFAULT '' AFTER `target_type` , ADD INDEX ( `target_id` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } + } \ No newline at end of file diff --git a/Zotlabs/Update/_1115.php b/Zotlabs/Update/_1115.php index 4edf63b85..f4516289c 100644 --- a/Zotlabs/Update/_1115.php +++ b/Zotlabs/Update/_1115.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1115 { -function run() { +class _1115 +{ + public function run() + { - // Introducing email verification. Mark all existing accounts as verified or they - // won't be able to login. + // Introducing email verification. Mark all existing accounts as verified or they + // won't be able to login. - $r = q("update account set account_flags = (account_flags ^ 1) where (account_flags & 1) "); - return UPDATE_SUCCESS; -} + $r = q("update account set account_flags = (account_flags ^ 1) where (account_flags & 1) "); + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1116.php b/Zotlabs/Update/_1116.php index 3d6d30f09..f289e2b50 100644 --- a/Zotlabs/Update/_1116.php +++ b/Zotlabs/Update/_1116.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1116 { -function run() { - @os_mkdir('cache/smarty3',STORAGE_DEFAULT_PERMISSIONS,true); - return UPDATE_SUCCESS; -} +class _1116 +{ + public function run() + { + @os_mkdir('cache/smarty3', STORAGE_DEFAULT_PERMISSIONS, true); + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1117.php b/Zotlabs/Update/_1117.php index cc8edb3c9..82d9dfa62 100644 --- a/Zotlabs/Update/_1117.php +++ b/Zotlabs/Update/_1117.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1117 { -function run() { - $r = q("ALTER TABLE `channel` CHANGE `channel_a_bookmark` `channel_w_like` INT( 10 ) UNSIGNED NOT NULL DEFAULT '128', +class _1117 +{ + public function run() + { + $r = q("ALTER TABLE `channel` CHANGE `channel_a_bookmark` `channel_w_like` INT( 10 ) UNSIGNED NOT NULL DEFAULT '128', DROP INDEX `channel_a_bookmark` , ADD INDEX `channel_w_like` ( `channel_w_like` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1118.php b/Zotlabs/Update/_1118.php index 22cfc2357..89ef11dd3 100644 --- a/Zotlabs/Update/_1118.php +++ b/Zotlabs/Update/_1118.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1118 { -function run() { - $r = q("ALTER TABLE `account` ADD `account_password_changed` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', +class _1118 +{ + public function run() + { + $r = q("ALTER TABLE `account` ADD `account_password_changed` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD INDEX ( `account_password_changed` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1119.php b/Zotlabs/Update/_1119.php index ccf03e45a..667ac0adc 100644 --- a/Zotlabs/Update/_1119.php +++ b/Zotlabs/Update/_1119.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1119 { -function run() { - $r1 = q("CREATE TABLE IF NOT EXISTS `profdef` ( +class _1119 +{ + public function run() + { + $r1 = q("CREATE TABLE IF NOT EXISTS `profdef` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `field_name` char(255) NOT NULL DEFAULT '', `field_type` char(16) NOT NULL DEFAULT '', @@ -14,7 +16,7 @@ function run() { KEY `field_name` (`field_name`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - $r2 = q("CREATE TABLE IF NOT EXISTS `profext` ( + $r2 = q("CREATE TABLE IF NOT EXISTS `profext` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `channel_id` int(10) unsigned NOT NULL DEFAULT '0', `hash` char(255) NOT NULL DEFAULT '', @@ -26,10 +28,10 @@ function run() { KEY `k` (`k`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8"); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1120.php b/Zotlabs/Update/_1120.php index c1f7e98d7..8c6f71bda 100644 --- a/Zotlabs/Update/_1120.php +++ b/Zotlabs/Update/_1120.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1120 { -function run() { - $r = q("ALTER TABLE `item` ADD `public_policy` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `coord` , +class _1120 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `public_policy` CHAR( 255 ) NOT NULL DEFAULT '' AFTER `coord` , ADD INDEX ( `public_policy` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1121.php b/Zotlabs/Update/_1121.php index c5ff00694..c03c604c5 100644 --- a/Zotlabs/Update/_1121.php +++ b/Zotlabs/Update/_1121.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1121 { -function run() { - $r = q("ALTER TABLE `site` ADD `site_realm` CHAR( 255 ) NOT NULL DEFAULT '', +class _1121 +{ + public function run() + { + $r = q("ALTER TABLE `site` ADD `site_realm` CHAR( 255 ) NOT NULL DEFAULT '', ADD INDEX ( `site_realm` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1122.php b/Zotlabs/Update/_1122.php index 903e3aaeb..597db9087 100644 --- a/Zotlabs/Update/_1122.php +++ b/Zotlabs/Update/_1122.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1122 { -function run() { - $r = q("update site set site_realm = '%s' where true", - dbesc(DIRECTORY_REALM) - ); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1122 +{ + public function run() + { + $r = q("update site set site_realm = '%s' where true", + dbesc(DIRECTORY_REALM) + ); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1123.php b/Zotlabs/Update/_1123.php index 96096beac..d4e5e9546 100644 --- a/Zotlabs/Update/_1123.php +++ b/Zotlabs/Update/_1123.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1123 { -function run() { - $r1 = q("ALTER TABLE `hubloc` ADD `hubloc_network` CHAR( 32 ) NOT NULL DEFAULT '' AFTER `hubloc_addr` , +class _1123 +{ + public function run() + { + $r1 = q("ALTER TABLE `hubloc` ADD `hubloc_network` CHAR( 32 ) NOT NULL DEFAULT '' AFTER `hubloc_addr` , ADD INDEX ( `hubloc_network` )"); - $r2 = q("update hubloc set hubloc_network = 'zot' where true"); + $r2 = q("update hubloc set hubloc_network = 'zot' where true"); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1124.php b/Zotlabs/Update/_1124.php index 1320b8b55..15c126a4e 100644 --- a/Zotlabs/Update/_1124.php +++ b/Zotlabs/Update/_1124.php @@ -2,9 +2,11 @@ namespace Zotlabs\Update; -class _1124 { -function run() { - $r1 = q("CREATE TABLE IF NOT EXISTS `sign` ( +class _1124 +{ + public function run() + { + $r1 = q("CREATE TABLE IF NOT EXISTS `sign` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `iid` int(10) unsigned NOT NULL DEFAULT '0', `retract_iid` int(10) unsigned NOT NULL DEFAULT '0', @@ -16,7 +18,7 @@ function run() { KEY `retract_iid` (`retract_iid`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - $r2 = q("CREATE TABLE IF NOT EXISTS `conv` ( + $r2 = q("CREATE TABLE IF NOT EXISTS `conv` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `guid` char(255) NOT NULL, `recips` mediumtext NOT NULL, @@ -30,12 +32,12 @@ function run() { KEY `updated` (`updated`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1125.php b/Zotlabs/Update/_1125.php index 03f9640a4..ce25ca1a5 100644 --- a/Zotlabs/Update/_1125.php +++ b/Zotlabs/Update/_1125.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1125 { -function run() { - $r = q("ALTER TABLE `profdef` ADD `field_inputs` MEDIUMTEXT NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - -} +class _1125 +{ + public function run() + { + $r = q("ALTER TABLE `profdef` ADD `field_inputs` MEDIUMTEXT NOT NULL DEFAULT ''"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1126.php b/Zotlabs/Update/_1126.php index f657cc6b2..24549325b 100644 --- a/Zotlabs/Update/_1126.php +++ b/Zotlabs/Update/_1126.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1126 { -function run() { - $r = q("ALTER TABLE `mail` ADD `convid` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `id` , +class _1126 +{ + public function run() + { + $r = q("ALTER TABLE `mail` ADD `convid` INT UNSIGNED NOT NULL DEFAULT '0' AFTER `id` , ADD INDEX ( `convid` )"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1127.php b/Zotlabs/Update/_1127.php index 8dec64ae4..a08c06a17 100644 --- a/Zotlabs/Update/_1127.php +++ b/Zotlabs/Update/_1127.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1127 { -function run() { - $r = q("ALTER TABLE `item` ADD `comments_closed` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `changed` , +class _1127 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `comments_closed` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `changed` , ADD INDEX ( `comments_closed` ), ADD INDEX ( `changed` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1128.php b/Zotlabs/Update/_1128.php index 8ee6d225e..dd4679daf 100644 --- a/Zotlabs/Update/_1128.php +++ b/Zotlabs/Update/_1128.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1128 { -function run() { - $r = q("ALTER TABLE `item` ADD `diaspora_meta` MEDIUMTEXT NOT NULL DEFAULT '' AFTER `sig` "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; +class _1128 +{ + public function run() + { + $r = q("ALTER TABLE `item` ADD `diaspora_meta` MEDIUMTEXT NOT NULL DEFAULT '' AFTER `sig` "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1129.php b/Zotlabs/Update/_1129.php index 76bd155ee..5669b5394 100644 --- a/Zotlabs/Update/_1129.php +++ b/Zotlabs/Update/_1129.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1129 { -function run() { - $r = q("update hubloc set hubloc_network = 'zot' where hubloc_network = ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1129 +{ + public function run() + { + $r = q("update hubloc set hubloc_network = 'zot' where hubloc_network = ''"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1130.php b/Zotlabs/Update/_1130.php index 1322a0b13..9a94c6763 100644 --- a/Zotlabs/Update/_1130.php +++ b/Zotlabs/Update/_1130.php @@ -2,27 +2,29 @@ namespace Zotlabs\Update; -class _1130 { -function run() { - $myperms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK - |PERMS_W_STREAM|PERMS_W_WALL|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT - |PERMS_R_STORAGE|PERMS_R_PAGES|PERMS_W_LIKE; +class _1130 +{ + public function run() + { + $myperms = PERMS_R_STREAM | PERMS_R_PROFILE | PERMS_R_PHOTOS | PERMS_R_ABOOK + | PERMS_W_STREAM | PERMS_W_WALL | PERMS_W_COMMENT | PERMS_W_MAIL | PERMS_W_CHAT + | PERMS_R_STORAGE | PERMS_R_PAGES | PERMS_W_LIKE; - $r = q("select abook_channel, abook_my_perms from abook where (abook_flags & %d) and abook_my_perms != 0", - intval(ABOOK_FLAG_SELF) - ); - if($r) { - foreach($r as $rr) { - set_pconfig($rr['abook_channel'],'system','autoperms',$rr['abook_my_perms']); - } - } - $r = q("update abook set abook_my_perms = %d where (abook_flags & %d) and abook_my_perms = 0", - intval($myperms), - intval(ABOOK_FLAG_SELF) - ); + $r = q("select abook_channel, abook_my_perms from abook where (abook_flags & %d) and abook_my_perms != 0", + intval(ABOOK_FLAG_SELF) + ); + if ($r) { + foreach ($r as $rr) { + set_pconfig($rr['abook_channel'], 'system', 'autoperms', $rr['abook_my_perms']); + } + } + $r = q("update abook set abook_my_perms = %d where (abook_flags & %d) and abook_my_perms = 0", + intval($myperms), + intval(ABOOK_FLAG_SELF) + ); - return UPDATE_SUCCESS; -} + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1131.php b/Zotlabs/Update/_1131.php index 72e968f67..a91de863a 100644 --- a/Zotlabs/Update/_1131.php +++ b/Zotlabs/Update/_1131.php @@ -2,19 +2,21 @@ namespace Zotlabs\Update; -class _1131 { -function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) // make sure this gets skipped for anyone who hasn't run it yet, it will fail on pg - return UPDATE_SUCCESS; - - $r1 = q("ALTER TABLE `abook` ADD `abook_rating_text` TEXT NOT NULL DEFAULT '' AFTER `abook_rating` "); - $r2 = q("ALTER TABLE `xlink` ADD `xlink_rating_text` TEXT NOT NULL DEFAULT '' AFTER `xlink_rating` "); +class _1131 +{ + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) // make sure this gets skipped for anyone who hasn't run it yet, it will fail on pg + return UPDATE_SUCCESS; - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + $r1 = q("ALTER TABLE `abook` ADD `abook_rating_text` TEXT NOT NULL DEFAULT '' AFTER `abook_rating` "); + $r2 = q("ALTER TABLE `xlink` ADD `xlink_rating_text` TEXT NOT NULL DEFAULT '' AFTER `xlink_rating` "); -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1132.php b/Zotlabs/Update/_1132.php index 9e085a351..211064702 100644 --- a/Zotlabs/Update/_1132.php +++ b/Zotlabs/Update/_1132.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1132 { -function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { // correct previous failed update - $r1 = q("ALTER TABLE abook ADD abook_rating_text TEXT NOT NULL DEFAULT '' "); - $r2 = q("ALTER TABLE xlink ADD xlink_rating_text TEXT NOT NULL DEFAULT '' "); - if(!$r1 || !$r2) - return UPDATE_FAILED; - } - return UPDATE_SUCCESS; -} +class _1132 +{ + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { // correct previous failed update + $r1 = q("ALTER TABLE abook ADD abook_rating_text TEXT NOT NULL DEFAULT '' "); + $r2 = q("ALTER TABLE xlink ADD xlink_rating_text TEXT NOT NULL DEFAULT '' "); + if (!$r1 || !$r2) + return UPDATE_FAILED; + } + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1133.php b/Zotlabs/Update/_1133.php index 3820ef1ee..5e8a1e47f 100644 --- a/Zotlabs/Update/_1133.php +++ b/Zotlabs/Update/_1133.php @@ -2,23 +2,24 @@ namespace Zotlabs\Update; -class _1133 { -function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE xperm ( +class _1133 +{ + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE TABLE xperm ( xp_id serial NOT NULL, xp_client varchar( 20 ) NOT NULL DEFAULT '', xp_channel bigint NOT NULL DEFAULT '0', xp_perm varchar( 64 ) NOT NULL DEFAULT '', PRIMARY KEY (xp_id) )"); - $r2 = 0; - foreach(array('xp_client', 'xp_channel', 'xp_perm') as $fld) - $r2 += ((q("create index $fld on xperm ($fld)") == false) ? 0 : 1); - - $r = (($r1 && $r2) ? true : false); - } - else { - $r = q("CREATE TABLE IF NOT EXISTS `xperm` ( + $r2 = 0; + foreach (array('xp_client', 'xp_channel', 'xp_perm') as $fld) + $r2 += ((q("create index $fld on xperm ($fld)") == false) ? 0 : 1); + + $r = (($r1 && $r2) ? true : false); + } else { + $r = q("CREATE TABLE IF NOT EXISTS `xperm` ( `xp_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY , `xp_client` VARCHAR( 20 ) NOT NULL DEFAULT '', `xp_channel` INT UNSIGNED NOT NULL DEFAULT '0', @@ -27,12 +28,12 @@ function run() { KEY `xp_channel` (`xp_channel`), KEY `xp_perm` (`xp_perm`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1134.php b/Zotlabs/Update/_1134.php index d52bab044..b2b3a0697 100644 --- a/Zotlabs/Update/_1134.php +++ b/Zotlabs/Update/_1134.php @@ -2,19 +2,20 @@ namespace Zotlabs\Update; -class _1134 { -function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE xlink ADD xlink_static numeric(1) NOT NULL DEFAULT '0' "); - $r2 = q("create index xlink_static on xlink ( xlink_static ) "); - $r = $r1 && $r2; - } - else - $r = q("ALTER TABLE xlink ADD xlink_static TINYINT( 1 ) NOT NULL DEFAULT '0', ADD INDEX ( xlink_static ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1134 +{ + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE xlink ADD xlink_static numeric(1) NOT NULL DEFAULT '0' "); + $r2 = q("create index xlink_static on xlink ( xlink_static ) "); + $r = $r1 && $r2; + } else + $r = q("ALTER TABLE xlink ADD xlink_static TINYINT( 1 ) NOT NULL DEFAULT '0', ADD INDEX ( xlink_static ) "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1135.php b/Zotlabs/Update/_1135.php index 92a3e04b6..f854ba18d 100644 --- a/Zotlabs/Update/_1135.php +++ b/Zotlabs/Update/_1135.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1135 { -function run() { - $r = q("ALTER TABLE xlink ADD xlink_sig TEXT NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1135 +{ + public function run() + { + $r = q("ALTER TABLE xlink ADD xlink_sig TEXT NOT NULL DEFAULT ''"); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1136.php b/Zotlabs/Update/_1136.php index 0c1691fcb..44aad8681 100644 --- a/Zotlabs/Update/_1136.php +++ b/Zotlabs/Update/_1136.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1136 { -function run() { - $r1 = q("alter table item add item_unseen smallint not null default '0' "); - $r2 = q("create index item_unseen on item ( item_unseen ) "); - $r3 = q("update item set item_unseen = 1 where ( item_flags & 2 ) > 0 "); +class _1136 +{ + public function run() + { + $r1 = q("alter table item add item_unseen smallint not null default '0' "); + $r2 = q("create index item_unseen on item ( item_unseen ) "); + $r3 = q("update item set item_unseen = 1 where ( item_flags & 2 ) > 0 "); - if($r1 && $r2 && $r3) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2 && $r3) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1137.php b/Zotlabs/Update/_1137.php index ab11fe3db..eb27388e8 100644 --- a/Zotlabs/Update/_1137.php +++ b/Zotlabs/Update/_1137.php @@ -2,15 +2,16 @@ namespace Zotlabs\Update; -class _1137 { -function run() { - $r1 = q("alter table site add site_valid smallint not null default '0' "); - $r2 = q("create index site_valid on site ( site_valid ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} - +class _1137 +{ + public function run() + { + $r1 = q("alter table site add site_valid smallint not null default '0' "); + $r2 = q("create index site_valid on site ( site_valid ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1138.php b/Zotlabs/Update/_1138.php index b2eac12af..83c145d06 100644 --- a/Zotlabs/Update/_1138.php +++ b/Zotlabs/Update/_1138.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1138 { -function run() { - $r1 = q("alter table outq add outq_priority smallint not null default '0' "); - $r2 = q("create index outq_priority on outq ( outq_priority ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1138 +{ + public function run() + { + $r1 = q("alter table outq add outq_priority smallint not null default '0' "); + $r2 = q("create index outq_priority on outq ( outq_priority ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1139.php b/Zotlabs/Update/_1139.php index aa4863fc1..ac912f06a 100644 --- a/Zotlabs/Update/_1139.php +++ b/Zotlabs/Update/_1139.php @@ -2,20 +2,21 @@ namespace Zotlabs\Update; -class _1139 { -function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE channel ADD channel_lastpost timestamp NOT NULL DEFAULT '0001-01-01 00:00:00'"); - $r2 = q("create index channel_lastpost on channel ( channel_lastpost ) "); - $r = $r1 && $r2; - } - else - $r = q("ALTER TABLE `channel` ADD `channel_lastpost` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `channel_dirdate` , ADD INDEX ( `channel_lastpost` ) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; +class _1139 +{ + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE channel ADD channel_lastpost timestamp NOT NULL DEFAULT '0001-01-01 00:00:00'"); + $r2 = q("create index channel_lastpost on channel ( channel_lastpost ) "); + $r = $r1 && $r2; + } else + $r = q("ALTER TABLE `channel` ADD `channel_lastpost` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' AFTER `channel_dirdate` , ADD INDEX ( `channel_lastpost` ) "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1140.php b/Zotlabs/Update/_1140.php index 5b4c8f801..a04ce90b7 100644 --- a/Zotlabs/Update/_1140.php +++ b/Zotlabs/Update/_1140.php @@ -2,26 +2,27 @@ namespace Zotlabs\Update; -class _1140 { -function run() { - $r = q("select * from clients where true"); - $x = false; - if($r) { - foreach($r as $rr) { - $m = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", - dbesc($rr['client_id']), - intval($rr['uid']), - dbesc('all') - ); - if(! $m) - $x = true; - } - } - if($x) - return UPDATE_FAILED; - return UPDATE_SUCCESS; -} - +class _1140 +{ + public function run() + { + $r = q("select * from clients where true"); + $x = false; + if ($r) { + foreach ($r as $rr) { + $m = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", + dbesc($rr['client_id']), + intval($rr['uid']), + dbesc('all') + ); + if (!$m) + $x = true; + } + } + if ($x) + return UPDATE_FAILED; + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1141.php b/Zotlabs/Update/_1141.php index e1f84f469..1b02468e0 100644 --- a/Zotlabs/Update/_1141.php +++ b/Zotlabs/Update/_1141.php @@ -2,29 +2,30 @@ namespace Zotlabs\Update; -class _1141 { -function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE menu ADD menu_created timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', ADD menu_edited timestamp NOT NULL DEFAULT '0001-01-01 00:00:00'"); - $r2 = q("create index menu_created on menu ( menu_created ) "); - $r3 = q("create index menu_edited on menu ( menu_edited ) "); - $r = $r1 && $r2; - } - else - $r = q("ALTER TABLE menu ADD menu_created DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD menu_edited DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD INDEX ( menu_created ), ADD INDEX ( menu_edited ) "); +class _1141 +{ + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE menu ADD menu_created timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', ADD menu_edited timestamp NOT NULL DEFAULT '0001-01-01 00:00:00'"); + $r2 = q("create index menu_created on menu ( menu_created ) "); + $r3 = q("create index menu_edited on menu ( menu_edited ) "); + $r = $r1 && $r2; + } else + $r = q("ALTER TABLE menu ADD menu_created DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD menu_edited DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD INDEX ( menu_created ), ADD INDEX ( menu_edited ) "); - $t = datetime_convert(); - q("update menu set menu_created = '%s', menu_edited = '%s' where true", - dbesc($t), - dbesc($t) - ); + $t = datetime_convert(); + q("update menu set menu_created = '%s', menu_edited = '%s' where true", + dbesc($t), + dbesc($t) + ); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1142.php b/Zotlabs/Update/_1142.php index a8ffcc182..f2207fb8c 100644 --- a/Zotlabs/Update/_1142.php +++ b/Zotlabs/Update/_1142.php @@ -2,17 +2,19 @@ namespace Zotlabs\Update; -class _1142 { -function run() { +class _1142 +{ + public function run() + { - $r1 = q("alter table site add site_dead smallint not null default '0' "); - $r2 = q("create index site_dead on site ( site_dead ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + $r1 = q("alter table site add site_dead smallint not null default '0' "); + $r2 = q("create index site_dead on site ( site_dead ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1143.php b/Zotlabs/Update/_1143.php index 99f23af61..efdb1c28c 100644 --- a/Zotlabs/Update/_1143.php +++ b/Zotlabs/Update/_1143.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1143 { -function run() { +class _1143 +{ + public function run() + { - $r1 = q("ALTER TABLE abook ADD abook_incl TEXT NOT NULL DEFAULT ''"); - $r2 = q("ALTER TABLE abook ADD abook_excl TEXT NOT NULL DEFAULT '' "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + $r1 = q("ALTER TABLE abook ADD abook_incl TEXT NOT NULL DEFAULT ''"); + $r2 = q("ALTER TABLE abook ADD abook_excl TEXT NOT NULL DEFAULT '' "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1144.php b/Zotlabs/Update/_1144.php index 848897de7..35c476df3 100644 --- a/Zotlabs/Update/_1144.php +++ b/Zotlabs/Update/_1144.php @@ -2,26 +2,28 @@ namespace Zotlabs\Update; -class _1144 { -function run() { - $r = q("select flags, id from attach where flags != 0"); - if($r) { - foreach($r as $rr) { - if($rr['flags'] & 1) { - q("update attach set is_dir = 1 where id = %d", - intval($rr['id']) - ); - } - if($rr['flags'] & 2) { - q("update attach set os_storage = 1 where id = %d", - intval($rr['id']) - ); - } - } - } +class _1144 +{ + public function run() + { + $r = q("select flags, id from attach where flags != 0"); + if ($r) { + foreach ($r as $rr) { + if ($rr['flags'] & 1) { + q("update attach set is_dir = 1 where id = %d", + intval($rr['id']) + ); + } + if ($rr['flags'] & 2) { + q("update attach set os_storage = 1 where id = %d", + intval($rr['id']) + ); + } + } + } - return UPDATE_SUCCESS; -} + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1145.php b/Zotlabs/Update/_1145.php index 5102acc8a..6dd278489 100644 --- a/Zotlabs/Update/_1145.php +++ b/Zotlabs/Update/_1145.php @@ -2,29 +2,30 @@ namespace Zotlabs\Update; -class _1145 { -function run() { +class _1145 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE event ADD event_status char(255) NOT NULL DEFAULT '', + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE event ADD event_status char(255) NOT NULL DEFAULT '', ADD event_status_date timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', ADD event_percent SMALLINT NOT NULL DEFAULT '0', ADD event_repeat TEXT NOT NULL DEFAULT '' "); - $r2 = q("create index event_status on event ( event_status )"); - $r = $r1 && $r2; - } - else { - $r = q("ALTER TABLE `event` ADD `event_status` CHAR( 255 ) NOT NULL DEFAULT '', + $r2 = q("create index event_status on event ( event_status )"); + $r = $r1 && $r2; + } else { + $r = q("ALTER TABLE `event` ADD `event_status` CHAR( 255 ) NOT NULL DEFAULT '', ADD `event_status_date` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD `event_percent` SMALLINT NOT NULL DEFAULT '0', ADD `event_repeat` TEXT NOT NULL DEFAULT '', ADD INDEX ( `event_status` ) "); - } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1146.php b/Zotlabs/Update/_1146.php index 92a26adaf..29d8d1d75 100644 --- a/Zotlabs/Update/_1146.php +++ b/Zotlabs/Update/_1146.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1146 { -function run() { +class _1146 +{ + public function run() + { - $r1 = q("alter table event add event_sequence smallint not null default '0' "); - $r2 = q("create index event_sequence on event ( event_sequence ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r1 = q("alter table event add event_sequence smallint not null default '0' "); + $r2 = q("create index event_sequence on event ( event_sequence ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1147.php b/Zotlabs/Update/_1147.php index b8f6716f7..296551c0c 100644 --- a/Zotlabs/Update/_1147.php +++ b/Zotlabs/Update/_1147.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1147 { -function run() { +class _1147 +{ + public function run() + { - $r1 = q("alter table event add event_priority smallint not null default '0' "); - $r2 = q("create index event_priority on event ( event_priority ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r1 = q("alter table event add event_priority smallint not null default '0' "); + $r2 = q("create index event_priority on event ( event_priority ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1148.php b/Zotlabs/Update/_1148.php index ed9a4d93a..620bb8c40 100644 --- a/Zotlabs/Update/_1148.php +++ b/Zotlabs/Update/_1148.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1148 { -function run() { - $r1 = q("alter table likes add i_mid char(255) not null default '' "); - $r2 = q("create index i_mid on likes ( i_mid ) "); +class _1148 +{ + public function run() + { + $r1 = q("alter table likes add i_mid char(255) not null default '' "); + $r2 = q("create index i_mid on likes ( i_mid ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1149.php b/Zotlabs/Update/_1149.php index f45bd995b..f43cac9dd 100644 --- a/Zotlabs/Update/_1149.php +++ b/Zotlabs/Update/_1149.php @@ -2,34 +2,35 @@ namespace Zotlabs\Update; -class _1149 { -function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE obj ADD obj_term CHAR( 255 ) NOT NULL DEFAULT '', +class _1149 +{ + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE obj ADD obj_term CHAR( 255 ) NOT NULL DEFAULT '', ADD obj_url CHAR( 255 ) NOT NULL DEFAULT '', ADD obj_imgurl CHAR( 255 ) NOT NULL DEFAULT '', ADD obj_created timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', ADD obj_edited timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - } - else { - $r1 = q("ALTER TABLE obj ADD obj_term CHAR( 255 ) NOT NULL DEFAULT '', + } else { + $r1 = q("ALTER TABLE obj ADD obj_term CHAR( 255 ) NOT NULL DEFAULT '', ADD obj_url CHAR( 255 ) NOT NULL DEFAULT '', ADD obj_imgurl CHAR( 255 ) NOT NULL DEFAULT '', ADD obj_created DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD obj_edited DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); - } + } - $r2 = q("create index obj_term on obj ( obj_term ) "); - $r3 = q("create index obj_url on obj ( obj_url ) "); - $r4 = q("create index obj_imgurl on obj ( obj_imgurl ) "); - $r5 = q("create index obj_created on obj ( obj_created ) "); - $r6 = q("create index obj_edited on obj ( obj_edited ) "); - $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6; - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + $r2 = q("create index obj_term on obj ( obj_term ) "); + $r3 = q("create index obj_url on obj ( obj_url ) "); + $r4 = q("create index obj_imgurl on obj ( obj_imgurl ) "); + $r5 = q("create index obj_created on obj ( obj_created ) "); + $r6 = q("create index obj_edited on obj ( obj_edited ) "); + $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1150.php b/Zotlabs/Update/_1150.php index 896fc75e3..ead9a3c6f 100644 --- a/Zotlabs/Update/_1150.php +++ b/Zotlabs/Update/_1150.php @@ -2,27 +2,28 @@ namespace Zotlabs\Update; -class _1150 { -function run() { +class _1150 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE app ADD app_created timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE app ADD app_created timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', ADD app_edited timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - } - else { - $r1 = q("ALTER TABLE app ADD app_created DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', + } else { + $r1 = q("ALTER TABLE app ADD app_created DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00', ADD app_edited DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); - } + } - $r2 = q("create index app_created on app ( app_created ) "); - $r3 = q("create index app_edited on app ( app_edited ) "); + $r2 = q("create index app_created on app ( app_created ) "); + $r3 = q("create index app_edited on app ( app_edited ) "); - $r = $r1 && $r2 && $r3; - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + $r = $r1 && $r2 && $r3; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1151.php b/Zotlabs/Update/_1151.php index d14baabb1..66506d3c5 100644 --- a/Zotlabs/Update/_1151.php +++ b/Zotlabs/Update/_1151.php @@ -2,23 +2,25 @@ namespace Zotlabs\Update; -class _1151 { -function run() { +class _1151 +{ + public function run() + { - $r3 = q("select likes.*, item.mid from likes left join item on likes.iid = item.id"); - if($r3) { - foreach($r3 as $rr) { - q("update likes set i_mid = '%s' where id = $d", - dbesc($rr['mid']), - intval($rr['id']) - ); - } - } + $r3 = q("select likes.*, item.mid from likes left join item on likes.iid = item.id"); + if ($r3) { + foreach ($r3 as $rr) { + q("update likes set i_mid = '%s' where id = $d", + dbesc($rr['mid']), + intval($rr['id']) + ); + } + } - return UPDATE_SUCCESS; + return UPDATE_SUCCESS; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1152.php b/Zotlabs/Update/_1152.php index 54393d590..e80d9f99b 100644 --- a/Zotlabs/Update/_1152.php +++ b/Zotlabs/Update/_1152.php @@ -2,12 +2,14 @@ namespace Zotlabs\Update; -class _1152 { -function run() { +class _1152 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE IF NOT EXISTS \"dreport\" ( + $r1 = q("CREATE TABLE IF NOT EXISTS \"dreport\" ( \"dreport_id\" serial NOT NULL, \"dreport_channel\" int(11) NOT NULL DEFAULT '0', \"dreport_mid\" char(255) NOT NULL DEFAULT '', @@ -18,17 +20,16 @@ function run() { \"dreport_xchan\" char(255) NOT NULL DEFAULT '', PRIMARY KEY (\"dreport_id\") "); - $r2 = q("create index \"dreport_mid\" on dreport (\"dreport_mid\") "); - $r3 = q("create index \"dreport_site\" on dreport (\"dreport_site\") "); - $r4 = q("create index \"dreport_time\" on dreport (\"dreport_time\") "); - $r5 = q("create index \"dreport_xchan\" on dreport (\"dreport_xchan\") "); - $r6 = q("create index \"dreport_channel\" on dreport (\"dreport_channel\") "); + $r2 = q("create index \"dreport_mid\" on dreport (\"dreport_mid\") "); + $r3 = q("create index \"dreport_site\" on dreport (\"dreport_site\") "); + $r4 = q("create index \"dreport_time\" on dreport (\"dreport_time\") "); + $r5 = q("create index \"dreport_xchan\" on dreport (\"dreport_xchan\") "); + $r6 = q("create index \"dreport_channel\" on dreport (\"dreport_channel\") "); - $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6; + $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6; - } - else { - $r = q("CREATE TABLE IF NOT EXISTS `dreport` ( + } else { + $r = q("CREATE TABLE IF NOT EXISTS `dreport` ( `dreport_id` int(11) NOT NULL AUTO_INCREMENT, `dreport_channel` int(11) NOT NULL DEFAULT '0', `dreport_mid` char(255) NOT NULL DEFAULT '', @@ -45,13 +46,13 @@ function run() { KEY `dreport_channel` (`dreport_channel`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - } + } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1153.php b/Zotlabs/Update/_1153.php index cf8d451b4..74ae9b943 100644 --- a/Zotlabs/Update/_1153.php +++ b/Zotlabs/Update/_1153.php @@ -2,17 +2,19 @@ namespace Zotlabs\Update; -class _1153 { -function run() { +class _1153 +{ + public function run() + { - $r1 = q("ALTER TABLE dreport ADD dreport_queue CHAR( 255 ) NOT NULL DEFAULT '' "); - $r2 = q("create index dreport_queue on dreport ( dreport_queue) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + $r1 = q("ALTER TABLE dreport ADD dreport_queue CHAR( 255 ) NOT NULL DEFAULT '' "); + $r2 = q("create index dreport_queue on dreport ( dreport_queue) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1154.php b/Zotlabs/Update/_1154.php index 6e92f525d..310acefb7 100644 --- a/Zotlabs/Update/_1154.php +++ b/Zotlabs/Update/_1154.php @@ -2,16 +2,17 @@ namespace Zotlabs\Update; -class _1154 { -function run() { +class _1154 +{ + public function run() + { - $r = q("ALTER TABLE event ADD event_vdata text NOT NULL "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - -} + $r = q("ALTER TABLE event ADD event_vdata text NOT NULL "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1155.php b/Zotlabs/Update/_1155.php index 8f2553b3e..09985f4d0 100644 --- a/Zotlabs/Update/_1155.php +++ b/Zotlabs/Update/_1155.php @@ -2,16 +2,17 @@ namespace Zotlabs\Update; -class _1155 { -function run() { - - $r1 = q("alter table site add site_type smallint not null default '0' "); - $r2 = q("create index site_type on site ( site_type ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1155 +{ + public function run() + { + $r1 = q("alter table site add site_type smallint not null default '0' "); + $r2 = q("create index site_type on site ( site_type ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1156.php b/Zotlabs/Update/_1156.php index 536a219d8..d540d0828 100644 --- a/Zotlabs/Update/_1156.php +++ b/Zotlabs/Update/_1156.php @@ -2,27 +2,29 @@ namespace Zotlabs\Update; -class _1156 { -function run() { - $r1 = q("ALTER TABLE mail ADD conv_guid CHAR( 255 ) NOT NULL DEFAULT '' "); - $r2 = q("create index conv_guid on mail ( conv_guid ) "); +class _1156 +{ + public function run() + { + $r1 = q("ALTER TABLE mail ADD conv_guid CHAR( 255 ) NOT NULL DEFAULT '' "); + $r2 = q("create index conv_guid on mail ( conv_guid ) "); - $r3 = q("select mail.id, mail.convid, conv.guid from mail left join conv on mail.convid = conv.id where true"); - if($r3) { - foreach($r3 as $rr) { - if($rr['convid']) { - q("update mail set conv_guid = '%s' where id = %d", - dbesc($rr['guid']), - intval($rr['id']) - ); - } - } - } - - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r3 = q("select mail.id, mail.convid, conv.guid from mail left join conv on mail.convid = conv.id where true"); + if ($r3) { + foreach ($r3 as $rr) { + if ($rr['convid']) { + q("update mail set conv_guid = '%s' where id = %d", + dbesc($rr['guid']), + intval($rr['id']) + ); + } + } + } + + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1157.php b/Zotlabs/Update/_1157.php index 01f452f32..cc109b6c0 100644 --- a/Zotlabs/Update/_1157.php +++ b/Zotlabs/Update/_1157.php @@ -2,16 +2,17 @@ namespace Zotlabs\Update; -class _1157 { -function run() { - $r1 = q("alter table site add site_project char(255) not null default '' "); - $r2 = q("create index site_project on site ( site_project ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - -} +class _1157 +{ + public function run() + { + $r1 = q("alter table site add site_project char(255) not null default '' "); + $r2 = q("create index site_project on site ( site_project ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1158.php b/Zotlabs/Update/_1158.php index 89ac3daa1..3542834f8 100644 --- a/Zotlabs/Update/_1158.php +++ b/Zotlabs/Update/_1158.php @@ -2,21 +2,22 @@ namespace Zotlabs\Update; -class _1158 { -function run() { - $r = q("select attach.id, attach.data, channel_address from attach left join channel on attach.uid = channel_id where os_storage = 1 and not attach.data like '%%store%%' "); - if($r) { - foreach($r as $rr) { - $has_slash = ((substr($rr['data'],0,1) === '/') ? true : false); - q("update attach set data = '%s' where id = %d", - dbesc('store/' . $rr['channel_address']. (($has_slash) ? '' : '/' . $rr['data'])), - dbesc($rr['id']) - ); - } - } - return UPDATE_SUCCESS; -} - +class _1158 +{ + public function run() + { + $r = q("select attach.id, attach.data, channel_address from attach left join channel on attach.uid = channel_id where os_storage = 1 and not attach.data like '%%store%%' "); + if ($r) { + foreach ($r as $rr) { + $has_slash = ((substr($rr['data'], 0, 1) === '/') ? true : false); + q("update attach set data = '%s' where id = %d", + dbesc('store/' . $rr['channel_address'] . (($has_slash) ? '' : '/' . $rr['data'])), + dbesc($rr['id']) + ); + } + } + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1159.php b/Zotlabs/Update/_1159.php index 1445092ad..d03a03b5f 100644 --- a/Zotlabs/Update/_1159.php +++ b/Zotlabs/Update/_1159.php @@ -2,24 +2,25 @@ namespace Zotlabs\Update; -class _1159 { -function run() { - $r = q("select attach.id, attach.data, attach.hash, channel_address from attach left join channel on attach.uid = channel_id where os_storage = 1 "); - if($r) { - foreach($r as $rr) { - $x = dbunescbin($rr['data']); - $has_slash = (($x === 'store/' . $rr['channel_address'] . '/') ? true : false); - if(($x === 'store/' . $rr['channel_address']) || ($has_slash)) { - q("update attach set data = '%s' where id = %d", - dbesc('store/' . $rr['channel_address']. (($has_slash) ? '' : '/' . $rr['hash'])), - dbesc($rr['id']) - ); - } - } - } - return UPDATE_SUCCESS; -} - +class _1159 +{ + public function run() + { + $r = q("select attach.id, attach.data, attach.hash, channel_address from attach left join channel on attach.uid = channel_id where os_storage = 1 "); + if ($r) { + foreach ($r as $rr) { + $x = dbunescbin($rr['data']); + $has_slash = (($x === 'store/' . $rr['channel_address'] . '/') ? true : false); + if (($x === 'store/' . $rr['channel_address']) || ($has_slash)) { + q("update attach set data = '%s' where id = %d", + dbesc('store/' . $rr['channel_address'] . (($has_slash) ? '' : '/' . $rr['hash'])), + dbesc($rr['id']) + ); + } + } + } + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1160.php b/Zotlabs/Update/_1160.php index b7b67076f..fcf8c1c4e 100644 --- a/Zotlabs/Update/_1160.php +++ b/Zotlabs/Update/_1160.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1160 { -function run() { - $r = q("alter table abook add abook_instance text not null default '' "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} +class _1160 +{ + public function run() + { + $r = q("alter table abook add abook_instance text not null default '' "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1161.php b/Zotlabs/Update/_1161.php index a4be310b9..3180ee50b 100644 --- a/Zotlabs/Update/_1161.php +++ b/Zotlabs/Update/_1161.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1161 { -function run() { +class _1161 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE \"iconfig\" ( + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE TABLE \"iconfig\" ( \"id\" serial NOT NULL, \"iid\" bigint NOT NULL DEFAULT '0', \"cat\" text NOT NULL DEFAULT '', @@ -14,13 +16,12 @@ function run() { \"v\" text NOT NULL DEFAULT '', PRIMARY_KEY(\"id\") ) "); -$r2 = q("create index \"iconfig_iid\" on iconfig (\"iid\") "); - $r3 = q("create index \"iconfig_cat\" on iconfig (\"cat\") "); -$r4 = q("create index \"iconfig_k\" on iconfig (\"k\") "); - $r = $r1 && $r2 && $r3 && $r4; - } - else { - $r = q("CREATE TABLE IF NOT EXISTS `iconfig` ( + $r2 = q("create index \"iconfig_iid\" on iconfig (\"iid\") "); + $r3 = q("create index \"iconfig_cat\" on iconfig (\"cat\") "); + $r4 = q("create index \"iconfig_k\" on iconfig (\"k\") "); + $r = $r1 && $r2 && $r3 && $r4; + } else { + $r = q("CREATE TABLE IF NOT EXISTS `iconfig` ( `id` int(11) NOT NULL AUTO_INCREMENT, `iid` int(11) NOT NULL DEFAULT '0', `cat` char(255) NOT NULL DEFAULT '', @@ -32,12 +33,12 @@ $r4 = q("create index \"iconfig_k\" on iconfig (\"k\") "); KEY `k` (`k`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - } + } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1162.php b/Zotlabs/Update/_1162.php index 683ea9802..2b9b40db8 100644 --- a/Zotlabs/Update/_1162.php +++ b/Zotlabs/Update/_1162.php @@ -2,18 +2,20 @@ namespace Zotlabs\Update; -class _1162 { -function run() { - $r1 = q("alter table iconfig add sharing int not null default '0' "); +class _1162 +{ + public function run() + { + $r1 = q("alter table iconfig add sharing int not null default '0' "); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) - $r2 = q("create index \"iconfig_sharing\" on iconfig (\"sharing\") "); - else - $r2 = q("alter table iconfig add index ( sharing ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) + $r2 = q("create index \"iconfig_sharing\" on iconfig (\"sharing\") "); + else + $r2 = q("alter table iconfig add index ( sharing ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1163.php b/Zotlabs/Update/_1163.php index 376447aea..e12eafdab 100644 --- a/Zotlabs/Update/_1163.php +++ b/Zotlabs/Update/_1163.php @@ -2,21 +2,22 @@ namespace Zotlabs\Update; -class _1163 { -function run() { +class _1163 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("alter table channel add channel_moved text not null default '' "); - $r2 = q("create index \"channel_channel_moved\" on channel (\"channel_moved\") "); - } - else { - $r1 = q("alter table channel add channel_moved char(255) not null default '' "); - $r2 = q("alter table channel add index ( channel_moved ) "); - } - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("alter table channel add channel_moved text not null default '' "); + $r2 = q("create index \"channel_channel_moved\" on channel (\"channel_moved\") "); + } else { + $r1 = q("alter table channel add channel_moved char(255) not null default '' "); + $r2 = q("alter table channel add index ( channel_moved ) "); + } + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1164.php b/Zotlabs/Update/_1164.php index bad9193d1..bdc741671 100644 --- a/Zotlabs/Update/_1164.php +++ b/Zotlabs/Update/_1164.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1164 { -function run() { +class _1164 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE \"abconfig\" ( + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE TABLE \"abconfig\" ( \"id\" serial NOT NULL, \"chan\" text NOT NULL, \"xchan\" text NOT NULL, @@ -14,14 +16,13 @@ function run() { \"k\" text NOT NULL, \"v\" text NOT NULL, PRIMARY KEY (\"id\") "); - $r2 = q("create index \"abconfig_chan\" on abconfig (\"chan\") "); - $r3 = q("create index \"abconfig_xchan\" on abconfig (\"xchan\") "); - $r4 = q("create index \"abconfig_cat\" on abconfig (\"cat\") "); - $r5 = q("create index \"abconfig_k\" on abconfig (\"k\") "); - $r = $r1 && $r2 && $r3 && $r4 && $r5; - } - else { - $r = q("CREATE TABLE IF NOT EXISTS `abconfig` ( + $r2 = q("create index \"abconfig_chan\" on abconfig (\"chan\") "); + $r3 = q("create index \"abconfig_xchan\" on abconfig (\"xchan\") "); + $r4 = q("create index \"abconfig_cat\" on abconfig (\"cat\") "); + $r5 = q("create index \"abconfig_k\" on abconfig (\"k\") "); + $r = $r1 && $r2 && $r3 && $r4 && $r5; + } else { + $r = q("CREATE TABLE IF NOT EXISTS `abconfig` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `chan` char(255) NOT NULL DEFAULT '', `xchan` char(255) NOT NULL DEFAULT '', @@ -35,11 +36,11 @@ function run() { KEY `k` (`k`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1165.php b/Zotlabs/Update/_1165.php index fcea38dc8..9b1a40f1f 100644 --- a/Zotlabs/Update/_1165.php +++ b/Zotlabs/Update/_1165.php @@ -2,19 +2,21 @@ namespace Zotlabs\Update; -class _1165 { -function run() { +class _1165 +{ + public function run() + { - $r1 = q("alter table hook add hook_version int not null default '0' "); + $r1 = q("alter table hook add hook_version int not null default '0' "); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) - $r2 = q("create index \"hook_version_idx\" on hook (\"hook_version\") "); - else - $r2 = q("alter table hook add index ( hook_version ) "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) + $r2 = q("create index \"hook_version_idx\" on hook (\"hook_version\") "); + else + $r2 = q("alter table hook add index ( hook_version ) "); + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1166.php b/Zotlabs/Update/_1166.php index e320d5bc0..4c19b78ac 100644 --- a/Zotlabs/Update/_1166.php +++ b/Zotlabs/Update/_1166.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1166 { -function run() { +class _1166 +{ + public function run() + { - $r = q("alter table source add src_tag text not null default '' "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r = q("alter table source add src_tag text not null default '' "); + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1167.php b/Zotlabs/Update/_1167.php index b5510a21f..11f5be478 100644 --- a/Zotlabs/Update/_1167.php +++ b/Zotlabs/Update/_1167.php @@ -2,25 +2,26 @@ namespace Zotlabs\Update; -class _1167 { -function run() { +class _1167 +{ + public function run() + { - $r1 = q("alter table app add app_deleted int not null default '0' "); - $r2 = q("alter table app add app_system int not null default '0' "); + $r1 = q("alter table app add app_deleted int not null default '0' "); + $r2 = q("alter table app add app_system int not null default '0' "); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r3 = q("create index \"app_deleted_idx\" on app (\"app_deleted\") "); - $r4 = q("create index \"app_system_idx\" on app (\"app_system\") "); - } - else { - $r3 = q("alter table app add index ( app_deleted ) "); - $r4 = q("alter table app add index ( app_system ) "); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r3 = q("create index \"app_deleted_idx\" on app (\"app_deleted\") "); + $r4 = q("create index \"app_system_idx\" on app (\"app_system\") "); + } else { + $r3 = q("alter table app add index ( app_deleted ) "); + $r4 = q("alter table app add index ( app_system ) "); + } - if($r1 && $r2 && $r3 && $r4) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2 && $r3 && $r4) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1168.php b/Zotlabs/Update/_1168.php index cf7d2689a..8392f72ec 100644 --- a/Zotlabs/Update/_1168.php +++ b/Zotlabs/Update/_1168.php @@ -2,22 +2,23 @@ namespace Zotlabs\Update; -class _1168 { -function run() { +class _1168 +{ + public function run() + { - $r1 = q("alter table obj add obj_quantity int not null default '0' "); + $r1 = q("alter table obj add obj_quantity int not null default '0' "); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r2 = q("create index \"obj_quantity_idx\" on obj (\"obj_quantity\") "); - } - else { - $r2 = q("alter table obj add index ( obj_quantity ) "); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r2 = q("create index \"obj_quantity_idx\" on obj (\"obj_quantity\") "); + } else { + $r2 = q("alter table obj add index ( obj_quantity ) "); + } - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1169.php b/Zotlabs/Update/_1169.php index cfe4dbcd8..572ee6b59 100644 --- a/Zotlabs/Update/_1169.php +++ b/Zotlabs/Update/_1169.php @@ -2,26 +2,26 @@ namespace Zotlabs\Update; -class _1169 { -function run() { +class _1169 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE `addon` CHANGE `timestamp` `tstamp` numeric( 20 ) UNSIGNED NOT NULL DEFAULT '0' "); - $r2 = q("ALTER TABLE `addon` CHANGE `name` `aname` text NOT NULL DEFAULT '' "); - $r3 = q("ALTER TABLE `hook` CHANGE `function` `fn` text NOT NULL DEFAULT '' "); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE `addon` CHANGE `timestamp` `tstamp` numeric( 20 ) UNSIGNED NOT NULL DEFAULT '0' "); + $r2 = q("ALTER TABLE `addon` CHANGE `name` `aname` text NOT NULL DEFAULT '' "); + $r3 = q("ALTER TABLE `hook` CHANGE `function` `fn` text NOT NULL DEFAULT '' "); - } - else { - $r1 = q("ALTER TABLE `addon` CHANGE `timestamp` `tstamp` BIGINT( 20 ) UNSIGNED NOT NULL DEFAULT '0' "); - $r2 = q("ALTER TABLE `addon` CHANGE `name` `aname` CHAR(255) NOT NULL DEFAULT '' "); - $r3 = q("ALTER TABLE `hook` CHANGE `function` `fn` CHAR(255) NOT NULL DEFAULT '' "); - } - - if($r1 && $r2 && $r3) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + } else { + $r1 = q("ALTER TABLE `addon` CHANGE `timestamp` `tstamp` BIGINT( 20 ) UNSIGNED NOT NULL DEFAULT '0' "); + $r2 = q("ALTER TABLE `addon` CHANGE `name` `aname` CHAR(255) NOT NULL DEFAULT '' "); + $r3 = q("ALTER TABLE `hook` CHANGE `function` `fn` CHAR(255) NOT NULL DEFAULT '' "); + } + if ($r1 && $r2 && $r3) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1170.php b/Zotlabs/Update/_1170.php index 215aeebc7..69262276e 100644 --- a/Zotlabs/Update/_1170.php +++ b/Zotlabs/Update/_1170.php @@ -2,20 +2,22 @@ namespace Zotlabs\Update; -class _1170 { -function run() { +class _1170 +{ + public function run() + { - $r1 = q("drop table fcontact"); - $r2 = q("drop table ffinder"); - $r3 = q("drop table fserver"); - $r4 = q("drop table fsuggest"); - $r5 = q("drop table spam"); + $r1 = q("drop table fcontact"); + $r2 = q("drop table ffinder"); + $r3 = q("drop table fserver"); + $r4 = q("drop table fsuggest"); + $r5 = q("drop table spam"); - if($r1 && $r2 && $r3 && $r4 && $r5) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2 && $r3 && $r4 && $r5) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1171.php b/Zotlabs/Update/_1171.php index 5cbf0ca21..9c381fe15 100644 --- a/Zotlabs/Update/_1171.php +++ b/Zotlabs/Update/_1171.php @@ -2,23 +2,24 @@ namespace Zotlabs\Update; -class _1171 { -function run() { +class _1171 +{ + public function run() + { - $r1 = q("ALTER TABLE verify CHANGE `type` `vtype` varchar(32) NOT NULL DEFAULT '' "); - $r2 = q("ALTER TABLE tokens CHANGE `scope` `auth_scope` varchar(512) NOT NULL DEFAULT '' "); - $r3 = q("ALTER TABLE auth_codes CHANGE `scope` `auth_scope` varchar(512) NOT NULL DEFAULT '' "); - $r4 = q("ALTER TABLE clients CHANGE `name` `clname` TEXT "); - $r5 = q("ALTER TABLE session CHANGE `data` `sess_data` TEXT NOT NULL "); - $r6 = q("ALTER TABLE register CHANGE `language` `lang` varchar(16) NOT NULL DEFAULT '' "); + $r1 = q("ALTER TABLE verify CHANGE `type` `vtype` varchar(32) NOT NULL DEFAULT '' "); + $r2 = q("ALTER TABLE tokens CHANGE `scope` `auth_scope` varchar(512) NOT NULL DEFAULT '' "); + $r3 = q("ALTER TABLE auth_codes CHANGE `scope` `auth_scope` varchar(512) NOT NULL DEFAULT '' "); + $r4 = q("ALTER TABLE clients CHANGE `name` `clname` TEXT "); + $r5 = q("ALTER TABLE session CHANGE `data` `sess_data` TEXT NOT NULL "); + $r6 = q("ALTER TABLE register CHANGE `language` `lang` varchar(16) NOT NULL DEFAULT '' "); - if($r1 && $r2 && $r3 && $r4 && $r5 && $r6) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2 && $r3 && $r4 && $r5 && $r6) + return UPDATE_SUCCESS; + return UPDATE_FAILED; - -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1172.php b/Zotlabs/Update/_1172.php index 117e87fa1..4367e6bb6 100644 --- a/Zotlabs/Update/_1172.php +++ b/Zotlabs/Update/_1172.php @@ -2,28 +2,29 @@ namespace Zotlabs\Update; -class _1172 { -function run() { +class _1172 +{ + public function run() + { - $r1 = q("ALTER TABLE term CHANGE `type` `ttype` int(3) NOT NULL DEFAULT '0' "); + $r1 = q("ALTER TABLE term CHANGE `type` `ttype` int(3) NOT NULL DEFAULT '0' "); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r2 = q("ALTER TABLE groups CHANGE `name` `gname` TEXT NOT NULL "); - $r3 = q("ALTER TABLE profile CHANGE `name` `fullname` TEXT NOT NULL "); - $r4 = q("ALTER TABLE profile CHANGE `with` `partner` TEXT NOT NULL "); - $r5 = q("ALTER TABLE profile CHANGE `work` `employment` TEXT NOT NULL "); - } - else { - $r2 = q("ALTER TABLE groups CHANGE `name` `gname` char(255) NOT NULL DEFAULT '' "); - $r3 = q("ALTER TABLE profile CHANGE `name` `fullname` char(255) NOT NULL DEFAULT '' "); - $r4 = q("ALTER TABLE profile CHANGE `with` `partner` char(255) NOT NULL DEFAULT '' "); - $r5 = q("ALTER TABLE profile CHANGE `work` `employment` TEXT NOT NULL "); - } - if($r1 && $r2 && $r3 && $r4 && $r5) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r2 = q("ALTER TABLE groups CHANGE `name` `gname` TEXT NOT NULL "); + $r3 = q("ALTER TABLE profile CHANGE `name` `fullname` TEXT NOT NULL "); + $r4 = q("ALTER TABLE profile CHANGE `with` `partner` TEXT NOT NULL "); + $r5 = q("ALTER TABLE profile CHANGE `work` `employment` TEXT NOT NULL "); + } else { + $r2 = q("ALTER TABLE groups CHANGE `name` `gname` char(255) NOT NULL DEFAULT '' "); + $r3 = q("ALTER TABLE profile CHANGE `name` `fullname` char(255) NOT NULL DEFAULT '' "); + $r4 = q("ALTER TABLE profile CHANGE `with` `partner` char(255) NOT NULL DEFAULT '' "); + $r5 = q("ALTER TABLE profile CHANGE `work` `employment` TEXT NOT NULL "); + } + if ($r1 && $r2 && $r3 && $r4 && $r5) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1173.php b/Zotlabs/Update/_1173.php index 7c0d76c73..60579226c 100644 --- a/Zotlabs/Update/_1173.php +++ b/Zotlabs/Update/_1173.php @@ -2,26 +2,27 @@ namespace Zotlabs\Update; -class _1173 { -function run() { +class _1173 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE notify CHANGE `name` `xname` TEXT NOT NULL "); - $r2 = q("ALTER TABLE notify CHANGE `date` `created` timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r3 = q("ALTER TABLE notify CHANGE `type` `ntype` numeric(3) NOT NULL DEFAULT '0' "); - } - else { - $r1 = q("ALTER TABLE notify CHANGE `name` `xname` char(255) NOT NULL DEFAULT '' "); - $r2 = q("ALTER TABLE notify CHANGE `date` `created` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r3 = q("ALTER TABLE notify CHANGE `type` `ntype` smallint(3) NOT NULL DEFAULT '0' "); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE notify CHANGE `name` `xname` TEXT NOT NULL "); + $r2 = q("ALTER TABLE notify CHANGE `date` `created` timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r3 = q("ALTER TABLE notify CHANGE `type` `ntype` numeric(3) NOT NULL DEFAULT '0' "); + } else { + $r1 = q("ALTER TABLE notify CHANGE `name` `xname` char(255) NOT NULL DEFAULT '' "); + $r2 = q("ALTER TABLE notify CHANGE `date` `created` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r3 = q("ALTER TABLE notify CHANGE `type` `ntype` smallint(3) NOT NULL DEFAULT '0' "); + } - if($r1 && $r2 && $r3) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2 && $r3) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1174.php b/Zotlabs/Update/_1174.php index 0d68b2d65..3d6763132 100644 --- a/Zotlabs/Update/_1174.php +++ b/Zotlabs/Update/_1174.php @@ -2,31 +2,32 @@ namespace Zotlabs\Update; -class _1174 { -function run() { +class _1174 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE event CHANGE `type` `etype` varchar(255) NOT NULL DEFAULT '' "); - $r2 = q("ALTER TABLE event CHANGE `start` `dtstart` timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r3 = q("ALTER TABLE event CHANGE `finish` `dtend` timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r4 = q("ALTER TABLE event CHANGE `ignore` `dismissed` numeric(1) NOT NULL DEFAULT '0' "); - $r5 = q("ALTER TABLE attach CHANGE `data` `content` bytea NOT NULL "); - $r6 = q("ALTER TABLE photo CHANGE `data` `content` bytea NOT NULL "); - } - else { - $r1 = q("ALTER TABLE event CHANGE `type` `etype` char(255) NOT NULL DEFAULT '' "); - $r2 = q("ALTER TABLE event CHANGE `start` `dtstart` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r3 = q("ALTER TABLE event CHANGE `finish` `dtend` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r4 = q("ALTER TABLE event CHANGE `ignore` `dismissed` tinyint(1) NOT NULL DEFAULT '0' "); - $r5 = q("ALTER TABLE attach CHANGE `data` `content` longblob NOT NULL "); - $r6 = q("ALTER TABLE photo CHANGE `data` `content` mediumblob NOT NULL "); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE event CHANGE `type` `etype` varchar(255) NOT NULL DEFAULT '' "); + $r2 = q("ALTER TABLE event CHANGE `start` `dtstart` timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r3 = q("ALTER TABLE event CHANGE `finish` `dtend` timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r4 = q("ALTER TABLE event CHANGE `ignore` `dismissed` numeric(1) NOT NULL DEFAULT '0' "); + $r5 = q("ALTER TABLE attach CHANGE `data` `content` bytea NOT NULL "); + $r6 = q("ALTER TABLE photo CHANGE `data` `content` bytea NOT NULL "); + } else { + $r1 = q("ALTER TABLE event CHANGE `type` `etype` char(255) NOT NULL DEFAULT '' "); + $r2 = q("ALTER TABLE event CHANGE `start` `dtstart` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r3 = q("ALTER TABLE event CHANGE `finish` `dtend` DATETIME NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r4 = q("ALTER TABLE event CHANGE `ignore` `dismissed` tinyint(1) NOT NULL DEFAULT '0' "); + $r5 = q("ALTER TABLE attach CHANGE `data` `content` longblob NOT NULL "); + $r6 = q("ALTER TABLE photo CHANGE `data` `content` mediumblob NOT NULL "); + } - if($r1 && $r2 && $r3 && $r4 && $r5 && $r6) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2 && $r3 && $r4 && $r5 && $r6) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1175.php b/Zotlabs/Update/_1175.php index 188586084..cf1d36259 100644 --- a/Zotlabs/Update/_1175.php +++ b/Zotlabs/Update/_1175.php @@ -2,30 +2,30 @@ namespace Zotlabs\Update; -class _1175 { -function run() { +class _1175 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE item CHANGE `object` `obj` text NOT NULL"); - $r2 = q("ALTER TABLE photo CHANGE `size` `filesize` bigint NOT NULL DEFAULT '0' "); - $r3 = q("ALTER TABLE photo CHANGE `scale` `imgscale` numeric(3) NOT NULL DEFAULT '0' "); - $r4 = q("ALTER TABLE photo CHANGE `type` `mimetype` varchar(128) NOT NULL DEFAULT 'image/jpeg' "); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE item CHANGE `object` `obj` text NOT NULL"); + $r2 = q("ALTER TABLE photo CHANGE `size` `filesize` bigint NOT NULL DEFAULT '0' "); + $r3 = q("ALTER TABLE photo CHANGE `scale` `imgscale` numeric(3) NOT NULL DEFAULT '0' "); + $r4 = q("ALTER TABLE photo CHANGE `type` `mimetype` varchar(128) NOT NULL DEFAULT 'image/jpeg' "); - } - else { - $r1 = q("ALTER TABLE item CHANGE `object` `obj` text NOT NULL"); - $r2 = q("ALTER TABLE photo CHANGE `size` `filesize` int(10) unsigned NOT NULL DEFAULT '0' "); - $r3 = q("ALTER TABLE photo CHANGE `scale` `imgscale` tinyint(3) unsigned NOT NULL DEFAULT '0' "); - $r4 = q("ALTER TABLE photo CHANGE `type` `mimetype` char(128) NOT NULL DEFAULT 'image/jpeg' "); + } else { + $r1 = q("ALTER TABLE item CHANGE `object` `obj` text NOT NULL"); + $r2 = q("ALTER TABLE photo CHANGE `size` `filesize` int(10) unsigned NOT NULL DEFAULT '0' "); + $r3 = q("ALTER TABLE photo CHANGE `scale` `imgscale` tinyint(3) unsigned NOT NULL DEFAULT '0' "); + $r4 = q("ALTER TABLE photo CHANGE `type` `mimetype` char(128) NOT NULL DEFAULT 'image/jpeg' "); - } + } - if($r1 && $r2 && $r3 && $r4) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - -} + if ($r1 && $r2 && $r3 && $r4) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1176.php b/Zotlabs/Update/_1176.php index b7e5d33fa..af9bdecce 100644 --- a/Zotlabs/Update/_1176.php +++ b/Zotlabs/Update/_1176.php @@ -4,18 +4,20 @@ namespace Zotlabs\Update; use Zotlabs\Lib\IConfig; -class _1176 { -function run() { +class _1176 +{ + public function run() + { - $r = q("select * from item_id where true"); - if($r) { - foreach($r as $rr) { - IConfig::Set($rr['iid'],'system',$rr['service'],$rr['sid'],true); - } - } - return UPDATE_SUCCESS; + $r = q("select * from item_id where true"); + if ($r) { + foreach ($r as $rr) { + IConfig::Set($rr['iid'], 'system', $rr['service'], $rr['sid'], true); + } + } + return UPDATE_SUCCESS; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1177.php b/Zotlabs/Update/_1177.php index 119e48ee8..35ef9dfd0 100644 --- a/Zotlabs/Update/_1177.php +++ b/Zotlabs/Update/_1177.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1177 { -function run() { +class _1177 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("alter table event add cal_id bigint NOT NULL DEFAULT '0'"); - $r2 = q("create index \"event_cal_idx\" on event (\"cal_id\") "); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("alter table event add cal_id bigint NOT NULL DEFAULT '0'"); + $r2 = q("create index \"event_cal_idx\" on event (\"cal_id\") "); - $r3 = q("CREATE TABLE \"cal\" ( + $r3 = q("CREATE TABLE \"cal\" ( \"cal_id\" serial NOT NULL, \"cal_aid\" bigint NOT NULL DEFAULT '0', \"cal_uid\" bigint NOT NULL DEFAULT '0', @@ -22,18 +24,17 @@ function run() { \"synctoken\" text NOT NULL, \"cal_types\" text NOT NULL, PRIMARY KEY (\"cal_id\") "); - $r4 = q("create index \"cal_hash_idx\" on cal (\"cal_hash\") "); - $r5 = q("create index \"cal_name_idx\" on cal (\"cal_name\") "); - $r6 = q("create index \"cal_types_idx\" on cal (\"cal_types\") "); - $r7 = q("create index \"cal_aid_idx\" on cal (\"cal_aid\") "); - $r8 = q("create index \"cal_uid_idx\" on cal (\"cal_uid\") "); - $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8; - } - else { - $r1 = q("alter table event add cal_id int(10) unsigned NOT NULL DEFAULT '0', + $r4 = q("create index \"cal_hash_idx\" on cal (\"cal_hash\") "); + $r5 = q("create index \"cal_name_idx\" on cal (\"cal_name\") "); + $r6 = q("create index \"cal_types_idx\" on cal (\"cal_types\") "); + $r7 = q("create index \"cal_aid_idx\" on cal (\"cal_aid\") "); + $r8 = q("create index \"cal_uid_idx\" on cal (\"cal_uid\") "); + $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8; + } else { + $r1 = q("alter table event add cal_id int(10) unsigned NOT NULL DEFAULT '0', add index ( cal_id ) "); - $r2 = q("CREATE TABLE IF NOT EXISTS `cal` ( + $r2 = q("CREATE TABLE IF NOT EXISTS `cal` ( `cal_id` int(10) unsigned NOT NULL AUTO_INCREMENT, `cal_aid` int(10) unsigned NOT NULL DEFAULT '0', `cal_uid` int(10) unsigned NOT NULL DEFAULT '0', @@ -53,14 +54,13 @@ function run() { KEY `cal_types` (`cal_types`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - $r = $r1 && $r2; - } - - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r = $r1 && $r2; + } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1178.php b/Zotlabs/Update/_1178.php index 97c42a16d..80035095d 100644 --- a/Zotlabs/Update/_1178.php +++ b/Zotlabs/Update/_1178.php @@ -2,41 +2,43 @@ namespace Zotlabs\Update; -class _1178 { -function run() { +class _1178 +{ + public function run() + { - $c2 = null; + $c2 = null; - $c1 = q("SELECT channel_id, channel_hash from channel where true"); - if($c1) { - $c2 = q("SELECT id, chan from abconfig where true"); - if($c2) { - for($x = 0; $x < count($c2); $x ++) { - foreach($c1 as $c) { - if($c['channel_hash'] == $c2[$x]['chan']) { - $c2[$x]['chan'] = $c['channel_id']; - break; - } - } - } - } - } + $c1 = q("SELECT channel_id, channel_hash from channel where true"); + if ($c1) { + $c2 = q("SELECT id, chan from abconfig where true"); + if ($c2) { + for ($x = 0; $x < count($c2); $x++) { + foreach ($c1 as $c) { + if ($c['channel_hash'] == $c2[$x]['chan']) { + $c2[$x]['chan'] = $c['channel_id']; + break; + } + } + } + } + } - $r1 = q("ALTER TABLE abconfig CHANGE chan chan int(10) unsigned NOT NULL DEFAULT '0' "); + $r1 = q("ALTER TABLE abconfig CHANGE chan chan int(10) unsigned NOT NULL DEFAULT '0' "); - if($c2) { - foreach($c2 as $c) { - q("UPDATE abconfig SET chan = %d where id = %d", - intval($c['chan']), - intval($c['id']) - ); - } - } + if ($c2) { + foreach ($c2 as $c) { + q("UPDATE abconfig SET chan = %d where id = %d", + intval($c['chan']), + intval($c['id']) + ); + } + } - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1179.php b/Zotlabs/Update/_1179.php index 44227c8d3..7f3286415 100644 --- a/Zotlabs/Update/_1179.php +++ b/Zotlabs/Update/_1179.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1179 { -function run() { +class _1179 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE atoken ( + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE TABLE atoken ( atoken_id serial NOT NULL, atoken_aid bigint NOT NULL DEFAULT 0, atoken_uid bigint NOT NULL DEFAULT 0, @@ -14,17 +16,16 @@ function run() { atoken_token varchar(255) NOT NULL DEFAULT '', atoken_expires timestamp NOT NULL DEFAULT '0001-01-01 00:00:00', PRIMARY KEY (atoken_id)) "); - $r2 = q("create index atoken_aid on atoken (atoken_aid)"); - $r3 = q("create index atoken_uid on atoken (atoken_uid)"); - $r4 = q("create index atoken_name on atoken (atoken_name)"); - $r5 = q("create index atoken_token on atoken (atoken_token)"); - $r6 = q("create index atoken_expires on atoken (atoken_expires)"); + $r2 = q("create index atoken_aid on atoken (atoken_aid)"); + $r3 = q("create index atoken_uid on atoken (atoken_uid)"); + $r4 = q("create index atoken_name on atoken (atoken_name)"); + $r5 = q("create index atoken_token on atoken (atoken_token)"); + $r6 = q("create index atoken_expires on atoken (atoken_expires)"); - $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6; - - } - else { - $r = q("CREATE TABLE IF NOT EXISTS `atoken` ( + $r = $r1 && $r2 && $r3 && $r4 && $r5 && $r6; + + } else { + $r = q("CREATE TABLE IF NOT EXISTS `atoken` ( `atoken_id` int(11) NOT NULL AUTO_INCREMENT, `atoken_aid` int(11) NOT NULL DEFAULT 0, `atoken_uid` int(11) NOT NULL DEFAULT 0, @@ -38,12 +39,12 @@ function run() { KEY `atoken_token` (`atoken_token`), KEY `atoken_expires` (`atoken_expires`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 "); - } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - -} + } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1180.php b/Zotlabs/Update/_1180.php index f02f46231..f88b89cf6 100644 --- a/Zotlabs/Update/_1180.php +++ b/Zotlabs/Update/_1180.php @@ -2,31 +2,33 @@ namespace Zotlabs\Update; -class _1180 { -function run() { +class _1180 +{ + public function run() + { - require_once('include/perm_upgrade.php'); + require_once('include/perm_upgrade.php'); - $r1 = q("select * from channel where true"); - if($r1) { - foreach($r1 as $rr) { - perm_limits_upgrade($rr); - autoperms_upgrade($rr); - } - } + $r1 = q("select * from channel where true"); + if ($r1) { + foreach ($r1 as $rr) { + perm_limits_upgrade($rr); + autoperms_upgrade($rr); + } + } - $r2 = q("select * from abook where true"); - if($r2) { - foreach($r2 as $rr) { - perm_abook_upgrade($rr); - } - } - - $r = $r1 && $r2; - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r2 = q("select * from abook where true"); + if ($r2) { + foreach ($r2 as $rr) { + perm_abook_upgrade($rr); + } + } + + $r = $r1 && $r2; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1181.php b/Zotlabs/Update/_1181.php index 3366efde1..1cdb962a8 100644 --- a/Zotlabs/Update/_1181.php +++ b/Zotlabs/Update/_1181.php @@ -2,13 +2,15 @@ namespace Zotlabs\Update; -class _1181 { -function run() { +class _1181 +{ + public function run() + { // if(\Zotlabs\Lib\System::get_server_role() == 'pro') { // q("update account set account_level = 5 where true"); // } - return UPDATE_SUCCESS; -} + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1182.php b/Zotlabs/Update/_1182.php index d652f432e..b4a5a48ed 100644 --- a/Zotlabs/Update/_1182.php +++ b/Zotlabs/Update/_1182.php @@ -2,16 +2,17 @@ namespace Zotlabs\Update; -class _1182 { -function run() { +class _1182 +{ + public function run() + { - $r1 = q("alter table site add site_version varchar(32) not null default '' "); - - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + $r1 = q("alter table site add site_version varchar(32) not null default '' "); + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1183.php b/Zotlabs/Update/_1183.php index 6e9f89271..75aec02ae 100644 --- a/Zotlabs/Update/_1183.php +++ b/Zotlabs/Update/_1183.php @@ -2,24 +2,25 @@ namespace Zotlabs\Update; -class _1183 { -function run() { +class _1183 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("alter table hook ALTER COLUMN priority TYPE smallint"); - $r2 = q("alter table hook ALTER COLUMN priority SET NOT NULL"); - $r3 = q("alter table hook ALTER COLUMN priority SET DEFAULT '0'"); - $r1 = $r1 && $r2 && $r3; - } - else { - $r1 = q("alter table hook CHANGE priority priority smallint NOT NULL DEFAULT '0' "); - } - $r2 = q("create index priority_idx on hook (priority)"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("alter table hook ALTER COLUMN priority TYPE smallint"); + $r2 = q("alter table hook ALTER COLUMN priority SET NOT NULL"); + $r3 = q("alter table hook ALTER COLUMN priority SET DEFAULT '0'"); + $r1 = $r1 && $r2 && $r3; + } else { + $r1 = q("alter table hook CHANGE priority priority smallint NOT NULL DEFAULT '0' "); + } + $r2 = q("create index priority_idx on hook (priority)"); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1184.php b/Zotlabs/Update/_1184.php index e8c37888c..653216faf 100644 --- a/Zotlabs/Update/_1184.php +++ b/Zotlabs/Update/_1184.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1184 { -function run() { +class _1184 +{ + public function run() + { - $r1 = q("alter table site add site_crypto text not null default '' "); + $r1 = q("alter table site add site_crypto text not null default '' "); - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1185.php b/Zotlabs/Update/_1185.php index c7f4f1bd4..5b6a14cb9 100644 --- a/Zotlabs/Update/_1185.php +++ b/Zotlabs/Update/_1185.php @@ -2,15 +2,17 @@ namespace Zotlabs\Update; -class _1185 { -function run() { +class _1185 +{ + public function run() + { - $r1 = q("alter table app add app_plugin text not null default '' "); + $r1 = q("alter table app add app_plugin text not null default '' "); - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1186.php b/Zotlabs/Update/_1186.php index a9c4f0e36..c1f4070c9 100644 --- a/Zotlabs/Update/_1186.php +++ b/Zotlabs/Update/_1186.php @@ -2,17 +2,19 @@ namespace Zotlabs\Update; -class _1186 { -function run() { +class _1186 +{ + public function run() + { - $r1 = q("alter table profile add profile_vcard text not null"); + $r1 = q("alter table profile add profile_vcard text not null"); - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1187.php b/Zotlabs/Update/_1187.php index 0fce5aa05..2eb00279f 100644 --- a/Zotlabs/Update/_1187.php +++ b/Zotlabs/Update/_1187.php @@ -2,23 +2,24 @@ namespace Zotlabs\Update; -class _1187 { -function run() { +class _1187 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("alter table outq add outq_scheduled timestamp not null default '0001-01-01 00:00:00' "); - } - else { - $r1 = q("alter table outq add outq_scheduled datetime not null default '0001-01-01 00:00:00' "); - } - $r2 = q("create index outq_scheduled_idx on outq (outq_scheduled)"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("alter table outq add outq_scheduled timestamp not null default '0001-01-01 00:00:00' "); + } else { + $r1 = q("alter table outq add outq_scheduled datetime not null default '0001-01-01 00:00:00' "); + } + $r2 = q("create index outq_scheduled_idx on outq (outq_scheduled)"); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1188.php b/Zotlabs/Update/_1188.php index eb0335aab..efb435c7e 100644 --- a/Zotlabs/Update/_1188.php +++ b/Zotlabs/Update/_1188.php @@ -2,17 +2,19 @@ namespace Zotlabs\Update; -class _1188 { -function run() { +class _1188 +{ + public function run() + { - $r1 = q("alter table channel add channel_password varchar(255) not null default '' "); - $r2 = q("alter table channel add channel_salt varchar(255) not null default '' "); + $r1 = q("alter table channel add channel_password varchar(255) not null default '' "); + $r2 = q("alter table channel add channel_salt varchar(255) not null default '' "); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1189.php b/Zotlabs/Update/_1189.php index 5cd180fbd..43b5ffd31 100644 --- a/Zotlabs/Update/_1189.php +++ b/Zotlabs/Update/_1189.php @@ -2,22 +2,23 @@ namespace Zotlabs\Update; -class _1189 { -function run() { +class _1189 +{ + public function run() + { - $r1 = q("alter table mail add mail_mimetype varchar(64) not null default 'text/bbcode' "); + $r1 = q("alter table mail add mail_mimetype varchar(64) not null default 'text/bbcode' "); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r2 = q("alter table mail add mail_raw smallint not null default 0 "); - } - else { - $r2 = q("alter table mail add mail_raw tinyint(4) not null default 0 "); - } - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r2 = q("alter table mail add mail_raw smallint not null default 0 "); + } else { + $r2 = q("alter table mail add mail_raw tinyint(4) not null default 0 "); + } + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; -} + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1190.php b/Zotlabs/Update/_1190.php index 9321b82b8..e47d64a06 100644 --- a/Zotlabs/Update/_1190.php +++ b/Zotlabs/Update/_1190.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1190 { -function run() { - $r1 = q("alter table abook add abook_not_here smallint not null default 0 "); +class _1190 +{ + public function run() + { + $r1 = q("alter table abook add abook_not_here smallint not null default 0 "); - $r2 = q("create index abook_not_here on abook (abook_not_here)"); + $r2 = q("create index abook_not_here on abook (abook_not_here)"); - if($r1 && $r2) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1 && $r2) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1191.php b/Zotlabs/Update/_1191.php index 015b9a2ca..3bf9d2582 100644 --- a/Zotlabs/Update/_1191.php +++ b/Zotlabs/Update/_1191.php @@ -2,17 +2,18 @@ namespace Zotlabs\Update; -class _1191 { -function run() { +class _1191 +{ + public function run() + { - $r = q("SELECT 1 FROM principals LIMIT 1"); + $r = q("SELECT 1 FROM principals LIMIT 1"); - if($r !== false) { - return UPDATE_SUCCESS; - } - else { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE addressbooks ( + if ($r !== false) { + return UPDATE_SUCCESS; + } else { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE TABLE addressbooks ( id SERIAL NOT NULL, principaluri VARCHAR(255), displayname VARCHAR(255), @@ -20,13 +21,13 @@ function run() { description TEXT, synctoken INTEGER NOT NULL DEFAULT 1 );" - ); + ); - $r2 = q("ALTER TABLE ONLY addressbooks ADD CONSTRAINT addressbooks_pkey PRIMARY KEY (id);"); + $r2 = q("ALTER TABLE ONLY addressbooks ADD CONSTRAINT addressbooks_pkey PRIMARY KEY (id);"); - $r3 = q("CREATE UNIQUE INDEX addressbooks_ukey ON addressbooks USING btree (principaluri, uri);"); + $r3 = q("CREATE UNIQUE INDEX addressbooks_ukey ON addressbooks USING btree (principaluri, uri);"); - $r4 = q("CREATE TABLE cards ( + $r4 = q("CREATE TABLE cards ( id SERIAL NOT NULL, addressbookid INTEGER NOT NULL, carddata BYTEA, @@ -35,26 +36,26 @@ function run() { etag VARCHAR(32), size INTEGER NOT NULL );" - ); + ); - $r5 = q("ALTER TABLE ONLY cards ADD CONSTRAINT cards_pkey PRIMARY KEY (id);"); + $r5 = q("ALTER TABLE ONLY cards ADD CONSTRAINT cards_pkey PRIMARY KEY (id);"); - $r6 = q("CREATE UNIQUE INDEX cards_ukey ON cards USING btree (addressbookid, uri);"); + $r6 = q("CREATE UNIQUE INDEX cards_ukey ON cards USING btree (addressbookid, uri);"); - $r7 = q("CREATE TABLE addressbookchanges ( + $r7 = q("CREATE TABLE addressbookchanges ( id SERIAL NOT NULL, uri VARCHAR(200) NOT NULL, synctoken INTEGER NOT NULL, addressbookid INTEGER NOT NULL, operation SMALLINT NOT NULL );" - ); + ); - $r8 = q("ALTER TABLE ONLY addressbookchanges ADD CONSTRAINT addressbookchanges_pkey PRIMARY KEY (id);"); + $r8 = q("ALTER TABLE ONLY addressbookchanges ADD CONSTRAINT addressbookchanges_pkey PRIMARY KEY (id);"); - $r9 = q("CREATE INDEX addressbookchanges_addressbookid_synctoken_ix ON addressbookchanges USING btree (addressbookid, synctoken);"); + $r9 = q("CREATE INDEX addressbookchanges_addressbookid_synctoken_ix ON addressbookchanges USING btree (addressbookid, synctoken);"); - $r10 = q("CREATE TABLE calendarobjects ( + $r10 = q("CREATE TABLE calendarobjects ( id SERIAL NOT NULL, calendardata BYTEA, uri VARCHAR(200), @@ -67,22 +68,22 @@ function run() { lastoccurence INTEGER, uid VARCHAR(200) );" - ); + ); - $r11 = q("ALTER TABLE ONLY calendarobjects ADD CONSTRAINT calendarobjects_pkey PRIMARY KEY (id);"); + $r11 = q("ALTER TABLE ONLY calendarobjects ADD CONSTRAINT calendarobjects_pkey PRIMARY KEY (id);"); - $r12 = q("CREATE UNIQUE INDEX calendarobjects_ukey ON calendarobjects USING btree (calendarid, uri);"); + $r12 = q("CREATE UNIQUE INDEX calendarobjects_ukey ON calendarobjects USING btree (calendarid, uri);"); - $r13 = q("CREATE TABLE calendars ( + $r13 = q("CREATE TABLE calendars ( id SERIAL NOT NULL, synctoken INTEGER NOT NULL DEFAULT 1, components VARCHAR(21) );" - ); + ); - $r14 = q("ALTER TABLE ONLY calendars ADD CONSTRAINT calendars_pkey PRIMARY KEY (id);"); + $r14 = q("ALTER TABLE ONLY calendars ADD CONSTRAINT calendars_pkey PRIMARY KEY (id);"); - $r15 = q("CREATE TABLE calendarinstances ( + $r15 = q("CREATE TABLE calendarinstances ( id SERIAL NOT NULL, calendarid INTEGER NOT NULL, principaluri VARCHAR(100), @@ -98,17 +99,17 @@ function run() { share_displayname VARCHAR(100), share_invitestatus SMALLINT NOT NULL DEFAULT '2' -- '1 = noresponse, 2 = accepted, 3 = declined, 4 = invalid' );" - ); + ); - $r16 = q("ALTER TABLE ONLY calendarinstances ADD CONSTRAINT calendarinstances_pkey PRIMARY KEY (id);"); + $r16 = q("ALTER TABLE ONLY calendarinstances ADD CONSTRAINT calendarinstances_pkey PRIMARY KEY (id);"); - $r17 = q("CREATE UNIQUE INDEX calendarinstances_principaluri_uri ON calendarinstances USING btree (principaluri, uri);"); + $r17 = q("CREATE UNIQUE INDEX calendarinstances_principaluri_uri ON calendarinstances USING btree (principaluri, uri);"); - $r18 = q("CREATE UNIQUE INDEX calendarinstances_principaluri_calendarid ON calendarinstances USING btree (principaluri, calendarid);"); + $r18 = q("CREATE UNIQUE INDEX calendarinstances_principaluri_calendarid ON calendarinstances USING btree (principaluri, calendarid);"); - $r19 = q("CREATE UNIQUE INDEX calendarinstances_principaluri_share_href ON calendarinstances USING btree (principaluri, share_href);"); + $r19 = q("CREATE UNIQUE INDEX calendarinstances_principaluri_share_href ON calendarinstances USING btree (principaluri, share_href);"); - $r20 = q("CREATE TABLE calendarsubscriptions ( + $r20 = q("CREATE TABLE calendarsubscriptions ( id SERIAL NOT NULL, uri VARCHAR(200) NOT NULL, principaluri VARCHAR(100) NOT NULL, @@ -122,26 +123,26 @@ function run() { stripattachments SMALLINT NULL, lastmodified INTEGER );" - ); + ); - $r21 = q("ALTER TABLE ONLY calendarsubscriptions ADD CONSTRAINT calendarsubscriptions_pkey PRIMARY KEY (id);"); + $r21 = q("ALTER TABLE ONLY calendarsubscriptions ADD CONSTRAINT calendarsubscriptions_pkey PRIMARY KEY (id);"); - $r22 = q("CREATE UNIQUE INDEX calendarsubscriptions_ukey ON calendarsubscriptions USING btree (principaluri, uri);"); + $r22 = q("CREATE UNIQUE INDEX calendarsubscriptions_ukey ON calendarsubscriptions USING btree (principaluri, uri);"); - $r23 = q("CREATE TABLE calendarchanges ( + $r23 = q("CREATE TABLE calendarchanges ( id SERIAL NOT NULL, uri VARCHAR(200) NOT NULL, synctoken INTEGER NOT NULL, calendarid INTEGER NOT NULL, operation SMALLINT NOT NULL DEFAULT 0 );" - ); + ); - $r24 = q("ALTER TABLE ONLY calendarchanges ADD CONSTRAINT calendarchanges_pkey PRIMARY KEY (id);"); + $r24 = q("ALTER TABLE ONLY calendarchanges ADD CONSTRAINT calendarchanges_pkey PRIMARY KEY (id);"); - $r25 = q("CREATE INDEX calendarchanges_calendarid_synctoken_ix ON calendarchanges USING btree (calendarid, synctoken);"); + $r25 = q("CREATE INDEX calendarchanges_calendarid_synctoken_ix ON calendarchanges USING btree (calendarid, synctoken);"); - $r26 = q("CREATE TABLE schedulingobjects ( + $r26 = q("CREATE TABLE schedulingobjects ( id SERIAL NOT NULL, principaluri VARCHAR(255), calendardata BYTEA, @@ -150,9 +151,9 @@ function run() { etag VARCHAR(32), size INTEGER NOT NULL );" - ); + ); - $r27 = q("CREATE TABLE locks ( + $r27 = q("CREATE TABLE locks ( id SERIAL NOT NULL, owner VARCHAR(100), timeout INTEGER, @@ -162,73 +163,72 @@ function run() { depth SMALLINT, uri TEXT );" - ); + ); - $r28 = q("ALTER TABLE ONLY locks ADD CONSTRAINT locks_pkey PRIMARY KEY (id);"); + $r28 = q("ALTER TABLE ONLY locks ADD CONSTRAINT locks_pkey PRIMARY KEY (id);"); - $r29 = q("CREATE INDEX locks_token_ix ON locks USING btree (token);"); + $r29 = q("CREATE INDEX locks_token_ix ON locks USING btree (token);"); - $r30 = q("CREATE INDEX locks_uri_ix ON locks USING btree (uri);"); + $r30 = q("CREATE INDEX locks_uri_ix ON locks USING btree (uri);"); - $r31 = q("CREATE TABLE principals ( + $r31 = q("CREATE TABLE principals ( id SERIAL NOT NULL, uri VARCHAR(200) NOT NULL, email VARCHAR(80), displayname VARCHAR(80) );" - ); + ); - $r32 = q("ALTER TABLE ONLY principals ADD CONSTRAINT principals_pkey PRIMARY KEY (id);"); + $r32 = q("ALTER TABLE ONLY principals ADD CONSTRAINT principals_pkey PRIMARY KEY (id);"); - $r33 = q("CREATE UNIQUE INDEX principals_ukey ON principals USING btree (uri);"); + $r33 = q("CREATE UNIQUE INDEX principals_ukey ON principals USING btree (uri);"); - $r34 = q("CREATE TABLE groupmembers ( + $r34 = q("CREATE TABLE groupmembers ( id SERIAL NOT NULL, principal_id INTEGER NOT NULL, member_id INTEGER NOT NULL );" - ); + ); - $r35 = q("ALTER TABLE ONLY groupmembers ADD CONSTRAINT groupmembers_pkey PRIMARY KEY (id);"); + $r35 = q("ALTER TABLE ONLY groupmembers ADD CONSTRAINT groupmembers_pkey PRIMARY KEY (id);"); - $r36 = q("CREATE UNIQUE INDEX groupmembers_ukey ON groupmembers USING btree (principal_id, member_id);"); + $r36 = q("CREATE UNIQUE INDEX groupmembers_ukey ON groupmembers USING btree (principal_id, member_id);"); - $r37 = q("CREATE TABLE propertystorage ( + $r37 = q("CREATE TABLE propertystorage ( id SERIAL NOT NULL, path VARCHAR(1024) NOT NULL, name VARCHAR(100) NOT NULL, valuetype INT, value BYTEA );" - ); + ); - $r38 = q("ALTER TABLE ONLY propertystorage ADD CONSTRAINT propertystorage_pkey PRIMARY KEY (id);"); + $r38 = q("ALTER TABLE ONLY propertystorage ADD CONSTRAINT propertystorage_pkey PRIMARY KEY (id);"); - $r39 = q("CREATE UNIQUE INDEX propertystorage_ukey ON propertystorage (path, name);"); + $r39 = q("CREATE UNIQUE INDEX propertystorage_ukey ON propertystorage (path, name);"); - $r40 = q("CREATE TABLE users ( + $r40 = q("CREATE TABLE users ( id SERIAL NOT NULL, username VARCHAR(50), digesta1 VARCHAR(32) );" - ); + ); - $r41 = q("ALTER TABLE ONLY users ADD CONSTRAINT users_pkey PRIMARY KEY (id);"); + $r41 = q("ALTER TABLE ONLY users ADD CONSTRAINT users_pkey PRIMARY KEY (id);"); - $r42 = q("CREATE UNIQUE INDEX users_ukey ON users USING btree (username);"); + $r42 = q("CREATE UNIQUE INDEX users_ukey ON users USING btree (username);"); - if( - $r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8 && $r9 && $r10 - && $r11 && $r12 && $r13 && $r14 && $r15 && $r16 && $r17 && $r18 && $r19 && $r20 - && $r21 && $r22 && $r23 && $r24 && $r25 && $r26 && $r27 && $r28 && $r29 && $r30 - && $r31 && $r32 && $r33 && $r34 && $r35 && $r36 && $r37 && $r38 && $r39 && $r40 - && $r41 && $r42 - ) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - else { - $r1 = q("CREATE TABLE if not exists addressbooks ( + if ( + $r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8 && $r9 && $r10 + && $r11 && $r12 && $r13 && $r14 && $r15 && $r16 && $r17 && $r18 && $r19 && $r20 + && $r21 && $r22 && $r23 && $r24 && $r25 && $r26 && $r27 && $r28 && $r29 && $r30 + && $r31 && $r32 && $r33 && $r34 && $r35 && $r36 && $r37 && $r38 && $r39 && $r40 + && $r41 && $r42 + ) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } else { + $r1 = q("CREATE TABLE if not exists addressbooks ( id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, principaluri VARBINARY(255), displayname VARCHAR(255), @@ -237,9 +237,9 @@ function run() { synctoken INT(11) UNSIGNED NOT NULL DEFAULT '1', UNIQUE(principaluri(100), uri(100)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r2 = q("CREATE TABLE if not exists cards ( + $r2 = q("CREATE TABLE if not exists cards ( id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, addressbookid INT(11) UNSIGNED NOT NULL, carddata MEDIUMBLOB, @@ -248,9 +248,9 @@ function run() { etag VARBINARY(32), size INT(11) UNSIGNED NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r3 = q("CREATE TABLE if not exists addressbookchanges ( + $r3 = q("CREATE TABLE if not exists addressbookchanges ( id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, uri VARBINARY(200) NOT NULL, synctoken INT(11) UNSIGNED NOT NULL, @@ -258,9 +258,9 @@ function run() { operation TINYINT(1) NOT NULL, INDEX addressbookid_synctoken (addressbookid, synctoken) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r4 = q("CREATE TABLE if not exists calendarobjects ( + $r4 = q("CREATE TABLE if not exists calendarobjects ( id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, calendardata MEDIUMBLOB, uri VARBINARY(200), @@ -275,16 +275,16 @@ function run() { UNIQUE(calendarid, uri), INDEX calendarid_time (calendarid, firstoccurence) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r5 = q("CREATE TABLE if not exists calendars ( + $r5 = q("CREATE TABLE if not exists calendars ( id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, synctoken INTEGER UNSIGNED NOT NULL DEFAULT '1', components VARBINARY(21) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r6 = q("CREATE TABLE if not exists calendarinstances ( + $r6 = q("CREATE TABLE if not exists calendarinstances ( id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, calendarid INTEGER UNSIGNED NOT NULL, principaluri VARBINARY(100), @@ -303,9 +303,9 @@ function run() { UNIQUE(calendarid, principaluri), UNIQUE(calendarid, share_href) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r7 = q("CREATE TABLE if not exists calendarchanges ( + $r7 = q("CREATE TABLE if not exists calendarchanges ( id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, uri VARBINARY(200) NOT NULL, synctoken INT(11) UNSIGNED NOT NULL, @@ -313,9 +313,9 @@ function run() { operation TINYINT(1) NOT NULL, INDEX calendarid_synctoken (calendarid, synctoken) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r8 = q("CREATE TABLE if not exists calendarsubscriptions ( + $r8 = q("CREATE TABLE if not exists calendarsubscriptions ( id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, uri VARBINARY(200) NOT NULL, principaluri VARBINARY(100) NOT NULL, @@ -330,9 +330,9 @@ function run() { lastmodified INT(11) UNSIGNED, UNIQUE(principaluri, uri) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r9 = q("CREATE TABLE if not exists schedulingobjects ( + $r9 = q("CREATE TABLE if not exists schedulingobjects ( id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, principaluri VARBINARY(255), calendardata MEDIUMBLOB, @@ -341,9 +341,9 @@ function run() { etag VARBINARY(32), size INT(11) UNSIGNED NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r10 = q("CREATE TABLE if not exists locks ( + $r10 = q("CREATE TABLE if not exists locks ( id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, owner VARCHAR(100), timeout INTEGER UNSIGNED, @@ -355,45 +355,45 @@ function run() { INDEX(token), INDEX(uri(100)) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r11 = q("CREATE TABLE if not exists principals ( + $r11 = q("CREATE TABLE if not exists principals ( id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, uri VARBINARY(200) NOT NULL, email VARBINARY(80), displayname VARCHAR(80), UNIQUE(uri) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r12 = q("CREATE TABLE if not exists groupmembers ( + $r12 = q("CREATE TABLE if not exists groupmembers ( id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, principal_id INTEGER UNSIGNED NOT NULL, member_id INTEGER UNSIGNED NOT NULL, UNIQUE(principal_id, member_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r13 = q("CREATE TABLE if not exists propertystorage ( + $r13 = q("CREATE TABLE if not exists propertystorage ( id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, path VARBINARY(1024) NOT NULL, name VARBINARY(100) NOT NULL, valuetype INT UNSIGNED, value MEDIUMBLOB ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r14 = q("CREATE UNIQUE INDEX path_property ON propertystorage (path(600), name(100));"); + $r14 = q("CREATE UNIQUE INDEX path_property ON propertystorage (path(600), name(100));"); - $r15 = q("CREATE TABLE if not exists users ( + $r15 = q("CREATE TABLE if not exists users ( id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, username VARBINARY(50), digesta1 VARBINARY(32), UNIQUE(username) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - $r16 = q("CREATE TABLE if not exists calendarinstances ( + $r16 = q("CREATE TABLE if not exists calendarinstances ( id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, calendarid INTEGER UNSIGNED NOT NULL, principaluri VARBINARY(100), @@ -412,14 +412,14 @@ function run() { UNIQUE(calendarid, principaluri), UNIQUE(calendarid, share_href) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;" - ); + ); - if($r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8 && $r9 && $r10 && $r11 && $r12 && $r13 && $r14 && $r15 && $r16) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - } -} + if ($r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8 && $r9 && $r10 && $r11 && $r12 && $r13 && $r14 && $r15 && $r16) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } + } + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1192.php b/Zotlabs/Update/_1192.php index f2445da05..b82fef39b 100644 --- a/Zotlabs/Update/_1192.php +++ b/Zotlabs/Update/_1192.php @@ -2,20 +2,21 @@ namespace Zotlabs\Update; -class _1192 { -function run() { +class _1192 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE INDEX item_obj_type ON item (obj_type)"); - } - else { - $r1 = q("ALTER TABLE item ADD INDEX (obj_type)"); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE INDEX item_obj_type ON item (obj_type)"); + } else { + $r1 = q("ALTER TABLE item ADD INDEX (obj_type)"); + } - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1193.php b/Zotlabs/Update/_1193.php index 267e16da1..e5f4899f0 100644 --- a/Zotlabs/Update/_1193.php +++ b/Zotlabs/Update/_1193.php @@ -2,21 +2,21 @@ namespace Zotlabs\Update; -class _1193 { -function run() { +class _1193 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE INDEX item_uid_unseen ON item (uid, item_unseen)"); - } - else { - $r1 = q("ALTER TABLE item ADD INDEX uid_item_unseen (uid, item_unseen)"); - } - - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE INDEX item_uid_unseen ON item (uid, item_unseen)"); + } else { + $r1 = q("ALTER TABLE item ADD INDEX uid_item_unseen (uid, item_unseen)"); + } + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1194.php b/Zotlabs/Update/_1194.php index 916723eaa..1bee1108e 100644 --- a/Zotlabs/Update/_1194.php +++ b/Zotlabs/Update/_1194.php @@ -2,21 +2,23 @@ namespace Zotlabs\Update; -class _1194 { -function run() { - $r = q("select id, resource_id from item where resource_type = 'nwiki'"); - if($r) { - foreach($r as $rv) { - $mimetype = get_iconfig($rv['id'],'wiki','mimeType'); - q("update item set mimetype = '%s' where resource_type = 'nwikipage' and resource_id = '%s'", - dbesc($mimetype), - dbesc($rv['resource_id']) - ); - } - } +class _1194 +{ + public function run() + { + $r = q("select id, resource_id from item where resource_type = 'nwiki'"); + if ($r) { + foreach ($r as $rv) { + $mimetype = get_iconfig($rv['id'], 'wiki', 'mimeType'); + q("update item set mimetype = '%s' where resource_type = 'nwikipage' and resource_id = '%s'", + dbesc($mimetype), + dbesc($rv['resource_id']) + ); + } + } - return UPDATE_SUCCESS; -} + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1195.php b/Zotlabs/Update/_1195.php index 248e9a34a..d674860b2 100644 --- a/Zotlabs/Update/_1195.php +++ b/Zotlabs/Update/_1195.php @@ -2,20 +2,21 @@ namespace Zotlabs\Update; -class _1195 { -function run() { +class _1195 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE INDEX item_resource_id ON item (resource_id)"); - } - else { - $r1 = q("ALTER TABLE item ADD INDEX (resource_id)"); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE INDEX item_resource_id ON item (resource_id)"); + } else { + $r1 = q("ALTER TABLE item ADD INDEX (resource_id)"); + } - if($r1) - return UPDATE_SUCCESS; - return UPDATE_FAILED; -} + if ($r1) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1196.php b/Zotlabs/Update/_1196.php index 720252bf8..c2c55c9d7 100644 --- a/Zotlabs/Update/_1196.php +++ b/Zotlabs/Update/_1196.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1196 { -function run() { +class _1196 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE \"pchan\" ( + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE TABLE \"pchan\" ( \"pchan_id\" serial NOT NULL, \"pchan_guid\" text NOT NULL, \"pchan_hash\" text NOT NULL, @@ -15,15 +17,14 @@ function run() { PRIMARY KEY (\"pchan_id\") )"); - $r2 = q("create index \"pchan_guid\" on pchan (\"pchan_guid\")"); - $r3 = q("create index \"pchan_hash\" on pchan (\"pchan_hash\")"); + $r2 = q("create index \"pchan_guid\" on pchan (\"pchan_guid\")"); + $r3 = q("create index \"pchan_hash\" on pchan (\"pchan_hash\")"); - if($r1 && $r2 && $r3) { - return UPDATE_SUCCESS; - } - } - else { - $r1 = q("CREATE TABLE IF NOT EXISTS pchan ( + if ($r1 && $r2 && $r3) { + return UPDATE_SUCCESS; + } + } else { + $r1 = q("CREATE TABLE IF NOT EXISTS pchan ( pchan_id int(11) UNSIGNED NOT NULL AUTO_INCREMENT, pchan_guid char(191) NOT NULL DEFAULT '', pchan_hash char(191) NOT NULL DEFAULT '', @@ -33,13 +34,13 @@ function run() { KEY pchan_guid (pchan_guid), KEY pchan_hash (pchan_hash) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); - if($r1) { - return UPDATE_SUCCESS; - } - } + if ($r1) { + return UPDATE_SUCCESS; + } + } - return UPDATE_FAILED; -} + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1197.php b/Zotlabs/Update/_1197.php index 72e4ca59d..567c86353 100644 --- a/Zotlabs/Update/_1197.php +++ b/Zotlabs/Update/_1197.php @@ -2,16 +2,18 @@ namespace Zotlabs\Update; -class _1197 { -function run() { +class _1197 +{ + public function run() + { - $r = q("select diaspora_meta from item where true limit 1"); - if($r) { - $r = q("ALTER TABLE item DROP diaspora_meta"); - } + $r = q("select diaspora_meta from item where true limit 1"); + if ($r) { + $r = q("ALTER TABLE item DROP diaspora_meta"); + } - return UPDATE_SUCCESS; -} + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1198.php b/Zotlabs/Update/_1198.php index d188c94f6..a4f5d7a82 100644 --- a/Zotlabs/Update/_1198.php +++ b/Zotlabs/Update/_1198.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1198 { -function run() { +class _1198 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("ALTER TABLE item + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE item DROP INDEX item_blocked, DROP INDEX item_unpublished, DROP INDEX item_deleted, @@ -15,10 +17,10 @@ function run() { DROP INDEX item_pending_remove, DROP INDEX item_type "); - } + } - return UPDATE_SUCCESS; -} + return UPDATE_SUCCESS; + } } diff --git a/Zotlabs/Update/_1199.php b/Zotlabs/Update/_1199.php index 7ab03b073..ba05c1db4 100644 --- a/Zotlabs/Update/_1199.php +++ b/Zotlabs/Update/_1199.php @@ -2,18 +2,20 @@ namespace Zotlabs\Update; -class _1199 { -function run() { +class _1199 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("ALTER TABLE item + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE item DROP INDEX uid, ADD INDEX (item_type) "); - } + } - return UPDATE_SUCCESS; -} + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1200.php b/Zotlabs/Update/_1200.php index 9f7bfb152..544648744 100644 --- a/Zotlabs/Update/_1200.php +++ b/Zotlabs/Update/_1200.php @@ -2,23 +2,24 @@ namespace Zotlabs\Update; -class _1200 { -function run() { +class _1200 +{ + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("ALTER TABLE item + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE item DROP INDEX item_type, ADD INDEX uid_item_type (uid, item_type) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - else { - return UPDATE_SUCCESS; - } - -} + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } else { + return UPDATE_SUCCESS; + } + + } } diff --git a/Zotlabs/Update/_1201.php b/Zotlabs/Update/_1201.php index 920a7401e..633e96514 100644 --- a/Zotlabs/Update/_1201.php +++ b/Zotlabs/Update/_1201.php @@ -2,26 +2,27 @@ namespace Zotlabs\Update; -class _1201 { +class _1201 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("ALTER TABLE item + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE item DROP INDEX item_thread_top, ADD INDEX uid_item_thread_top (uid, item_thread_top), ADD INDEX uid_item_blocked (uid, item_blocked), ADD INDEX item_deleted_pending_remove_changed (item_deleted, item_pending_remove, changed) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - else { - return UPDATE_SUCCESS; - } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } else { + return UPDATE_SUCCESS; + } - } + } } diff --git a/Zotlabs/Update/_1202.php b/Zotlabs/Update/_1202.php index c9ccd157b..9e3595e5a 100644 --- a/Zotlabs/Update/_1202.php +++ b/Zotlabs/Update/_1202.php @@ -2,14 +2,16 @@ namespace Zotlabs\Update; -class _1202 { +class _1202 +{ - function run() { + public function run() + { - // empty update in order to make the DB_UPDATE_VERSION equal to the current maximum update function - // rather than being one greater than the last known update + // empty update in order to make the DB_UPDATE_VERSION equal to the current maximum update function + // rather than being one greater than the last known update - return UPDATE_SUCCESS; + return UPDATE_SUCCESS; - } + } } diff --git a/Zotlabs/Update/_1203.php b/Zotlabs/Update/_1203.php index 2968d209d..5897903a4 100644 --- a/Zotlabs/Update/_1203.php +++ b/Zotlabs/Update/_1203.php @@ -2,12 +2,14 @@ namespace Zotlabs\Update; -class _1203 { +class _1203 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("ALTER TABLE item + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE item DROP INDEX item_wall, DROP INDEX item_starred, DROP INDEX item_retained, @@ -16,14 +18,13 @@ class _1203 { ADD INDEX uid_item_retained (uid, item_retained) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - else { - return UPDATE_SUCCESS; - } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } else { + return UPDATE_SUCCESS; + } - } + } } diff --git a/Zotlabs/Update/_1204.php b/Zotlabs/Update/_1204.php index 0b9204b9b..bbb4d9d45 100644 --- a/Zotlabs/Update/_1204.php +++ b/Zotlabs/Update/_1204.php @@ -2,33 +2,34 @@ namespace Zotlabs\Update; -class _1204 { +class _1204 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE poll ADD poll_guid text NOT NULL"); - $r2 = q("create index \"poll_guid_idx\" on poll (\"poll_guid\")"); - $r3 = q("ALTER TABLE poll_elm ADD pelm_guid text NOT NULL"); - $r4 = q("create index \"pelm_guid_idx\" on poll_elm (\"pelm_guid\")"); - $r5 = q("ALTER TABLE vote ADD vote_guid text NOT NULL"); - $r6 = q("create index \"vote_guid_idx\" on vote (\"vote_guid\")"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE poll ADD poll_guid text NOT NULL"); + $r2 = q("create index \"poll_guid_idx\" on poll (\"poll_guid\")"); + $r3 = q("ALTER TABLE poll_elm ADD pelm_guid text NOT NULL"); + $r4 = q("create index \"pelm_guid_idx\" on poll_elm (\"pelm_guid\")"); + $r5 = q("ALTER TABLE vote ADD vote_guid text NOT NULL"); + $r6 = q("create index \"vote_guid_idx\" on vote (\"vote_guid\")"); - $r = ($r1 && $r2 && $r3 && $r4 && $r5 && $r6); - } - else { - $r1 = q("ALTER TABLE `poll` ADD `poll_guid` VARCHAR(191) NOT NULL, ADD INDEX `poll_guid` (`poll_guid`) "); - $r2 = q("ALTER TABLE `poll_elm` ADD `pelm_guid` VARCHAR(191) NOT NULL, ADD INDEX `pelm_guid` (`pelm_guid`) "); - $r3 = q("ALTER TABLE `vote` ADD `vote_guid` VARCHAR(191) NOT NULL, ADD INDEX `vote_guid` (`vote_guid`) "); + $r = ($r1 && $r2 && $r3 && $r4 && $r5 && $r6); + } else { + $r1 = q("ALTER TABLE `poll` ADD `poll_guid` VARCHAR(191) NOT NULL, ADD INDEX `poll_guid` (`poll_guid`) "); + $r2 = q("ALTER TABLE `poll_elm` ADD `pelm_guid` VARCHAR(191) NOT NULL, ADD INDEX `pelm_guid` (`pelm_guid`) "); + $r3 = q("ALTER TABLE `vote` ADD `vote_guid` VARCHAR(191) NOT NULL, ADD INDEX `vote_guid` (`vote_guid`) "); - $r = ($r1 && $r2 && $r3); - } - - if($r) - return UPDATE_SUCCESS; + $r = ($r1 && $r2 && $r3); + } - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; - } + return UPDATE_FAILED; + + } } diff --git a/Zotlabs/Update/_1205.php b/Zotlabs/Update/_1205.php index 968833726..e4da42f2d 100644 --- a/Zotlabs/Update/_1205.php +++ b/Zotlabs/Update/_1205.php @@ -2,37 +2,38 @@ namespace Zotlabs\Update; -class _1205 { +class _1205 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { - q("ALTER TABLE item DROP INDEX title"); - q("ALTER TABLE item DROP INDEX body"); - q("ALTER TABLE item DROP INDEX allow_cid"); - q("ALTER TABLE item DROP INDEX allow_gid"); - q("ALTER TABLE item DROP INDEX deny_cid"); - q("ALTER TABLE item DROP INDEX deny_gid"); - q("ALTER TABLE item DROP INDEX item_flags"); - q("ALTER TABLE item DROP INDEX item_restrict"); - q("ALTER TABLE item DROP INDEX aid"); + q("ALTER TABLE item DROP INDEX title"); + q("ALTER TABLE item DROP INDEX body"); + q("ALTER TABLE item DROP INDEX allow_cid"); + q("ALTER TABLE item DROP INDEX allow_gid"); + q("ALTER TABLE item DROP INDEX deny_cid"); + q("ALTER TABLE item DROP INDEX deny_gid"); + q("ALTER TABLE item DROP INDEX item_flags"); + q("ALTER TABLE item DROP INDEX item_restrict"); + q("ALTER TABLE item DROP INDEX aid"); - $r = q("ALTER TABLE item + $r = q("ALTER TABLE item DROP INDEX item_private, ADD INDEX uid_item_private (uid, item_private), ADD INDEX item_wall (item_wall), ADD INDEX item_pending_remove_changed (item_pending_remove, changed) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - else { - return UPDATE_SUCCESS; - } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } else { + return UPDATE_SUCCESS; + } - } + } } diff --git a/Zotlabs/Update/_1206.php b/Zotlabs/Update/_1206.php index 351d53ff6..e9517b2a2 100644 --- a/Zotlabs/Update/_1206.php +++ b/Zotlabs/Update/_1206.php @@ -2,23 +2,24 @@ namespace Zotlabs\Update; -class _1206 { +class _1206 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("ALTER TABLE item + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE item ADD INDEX uid_resource_type (uid, resource_type) "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - else { - return UPDATE_SUCCESS; - } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } else { + return UPDATE_SUCCESS; + } - } + } } diff --git a/Zotlabs/Update/_1207.php b/Zotlabs/Update/_1207.php index f53bc46ae..36b9a49ae 100644 --- a/Zotlabs/Update/_1207.php +++ b/Zotlabs/Update/_1207.php @@ -2,23 +2,24 @@ namespace Zotlabs\Update; -class _1207 { +class _1207 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("ALTER TABLE item + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("ALTER TABLE item DROP INDEX resource_type "); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; - } - else { - return UPDATE_SUCCESS; - } + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; + } else { + return UPDATE_SUCCESS; + } - } + } } diff --git a/Zotlabs/Update/_1208.php b/Zotlabs/Update/_1208.php index 840252694..f5097af60 100644 --- a/Zotlabs/Update/_1208.php +++ b/Zotlabs/Update/_1208.php @@ -2,25 +2,26 @@ namespace Zotlabs\Update; -class _1208 { +class _1208 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE poll ADD poll_author text NOT NULL"); - $r2 = q("create index \"poll_author_idx\" on poll (\"poll_author\") "); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE poll ADD poll_author text NOT NULL"); + $r2 = q("create index \"poll_author_idx\" on poll (\"poll_author\") "); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `poll` ADD `poll_author` VARCHAR(191) NOT NULL AFTER `poll_votes`, + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `poll` ADD `poll_author` VARCHAR(191) NOT NULL AFTER `poll_votes`, ADD INDEX `poll_author` (`poll_author`)"); - } + } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1209.php b/Zotlabs/Update/_1209.php index dc95c3166..59ef79939 100644 --- a/Zotlabs/Update/_1209.php +++ b/Zotlabs/Update/_1209.php @@ -2,25 +2,26 @@ namespace Zotlabs\Update; -class _1209 { +class _1209 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE poll_elm ADD pelm_order numeric(6) NOT NULL DEFAULT '0' "); - $r2 = q("create index \"pelm_order_idx\" on poll_elm (\"pelm_order\")"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE poll_elm ADD pelm_order numeric(6) NOT NULL DEFAULT '0' "); + $r2 = q("create index \"pelm_order_idx\" on poll_elm (\"pelm_order\")"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `poll_elm` ADD `pelm_order` int(11) NOT NULL DEFAULT 0, + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `poll_elm` ADD `pelm_order` int(11) NOT NULL DEFAULT 0, ADD INDEX `pelm_order` (`pelm_order`)"); - } + } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1210.php b/Zotlabs/Update/_1210.php index 813e3fe82..51b21233d 100644 --- a/Zotlabs/Update/_1210.php +++ b/Zotlabs/Update/_1210.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1210 { +class _1210 +{ - function run() { + public function run() + { - $sql = "CREATE TABLE oauth_clients ( + $sql = "CREATE TABLE oauth_clients ( client_id VARCHAR(80) NOT NULL, client_secret VARCHAR(80), redirect_uri VARCHAR(2000), @@ -58,21 +60,21 @@ CREATE TABLE oauth_jwt ( ); "; - $arr = explode(';', $sql); - $errors = 0; - foreach($arr as $a) { - if(strlen(trim($a))) { - $r = dbq(trim($a)); - if(! $r) { - $errors ++; - } - } - } + $arr = explode(';', $sql); + $errors = 0; + foreach ($arr as $a) { + if (strlen(trim($a))) { + $r = dbq(trim($a)); + if (!$r) { + $errors++; + } + } + } - if(! $errors) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if (!$errors) + return UPDATE_SUCCESS; + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1211.php b/Zotlabs/Update/_1211.php index 26e25536d..46994ef38 100644 --- a/Zotlabs/Update/_1211.php +++ b/Zotlabs/Update/_1211.php @@ -2,25 +2,26 @@ namespace Zotlabs\Update; -class _1211 { +class _1211 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE channel ADD channel_active timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r2 = q("create index \"channel_active_idx\" on channel (\"channel_active\")"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE channel ADD channel_active timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r2 = q("create index \"channel_active_idx\" on channel (\"channel_active\")"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `channel` ADD `channel_active` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `channel` ADD `channel_active` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , ADD INDEX `channel_active` (`channel_active`)"); - } + } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1212.php b/Zotlabs/Update/_1212.php index ad10f5627..459b5c609 100644 --- a/Zotlabs/Update/_1212.php +++ b/Zotlabs/Update/_1212.php @@ -4,25 +4,27 @@ namespace Zotlabs\Update; use Zotlabs\Access\PermissionRoles; -class _1212 { +class _1212 +{ - function run() { + public function run() + { - $r = q("select channel_id from channel where true"); - if($r) { - foreach($r as $rv) { - $role = get_pconfig($rv['channel_id'],'system','permissions_role'); - if($role !== 'custom') { - $role_permissions = PermissionRoles::role_perms($role); - if(array_key_exists('limits',$role_permissions) && array_key_exists('post_comments',$role_permissions['limits'])) { - set_pconfig($rv['channel_id'],'perm_limits','post_comments',$role_permissions['limits']['post_comments']); - } - } - } - } + $r = q("select channel_id from channel where true"); + if ($r) { + foreach ($r as $rv) { + $role = get_pconfig($rv['channel_id'], 'system', 'permissions_role'); + if ($role !== 'custom') { + $role_permissions = PermissionRoles::role_perms($role); + if (array_key_exists('limits', $role_permissions) && array_key_exists('post_comments', $role_permissions['limits'])) { + set_pconfig($rv['channel_id'], 'perm_limits', 'post_comments', $role_permissions['limits']['post_comments']); + } + } + } + } - return UPDATE_SUCCESS; + return UPDATE_SUCCESS; - } + } } diff --git a/Zotlabs/Update/_1213.php b/Zotlabs/Update/_1213.php index d396829a6..a06ec8e2f 100644 --- a/Zotlabs/Update/_1213.php +++ b/Zotlabs/Update/_1213.php @@ -2,27 +2,28 @@ namespace Zotlabs\Update; -class _1213 { +class _1213 +{ - function run() { - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - q("START TRANSACTION"); + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + q("START TRANSACTION"); - $r = q("ALTER TABLE abconfig + $r = q("ALTER TABLE abconfig DROP INDEX chan, DROP INDEX xchan, ADD INDEX chan_xchan (chan, xchan) "); - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } - else { - q("ROLLBACK"); - return UPDATE_FAILED; - } - } - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } else { + q("ROLLBACK"); + return UPDATE_FAILED; + } + } + } } diff --git a/Zotlabs/Update/_1214.php b/Zotlabs/Update/_1214.php index 06e5d96ed..166589c0f 100644 --- a/Zotlabs/Update/_1214.php +++ b/Zotlabs/Update/_1214.php @@ -2,56 +2,55 @@ namespace Zotlabs\Update; -class _1214 { +class _1214 +{ - function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - q("START TRANSACTION"); + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + q("START TRANSACTION"); - $r1 = q("ALTER TABLE oauth_clients ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); - $r2 = q("ALTER TABLE oauth_clients ALTER COLUMN user_id SET NOT NULL"); - $r3 = q("ALTER TABLE oauth_clients ALTER COLUMN user_id SET DEFAULT 0"); + $r1 = q("ALTER TABLE oauth_clients ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); + $r2 = q("ALTER TABLE oauth_clients ALTER COLUMN user_id SET NOT NULL"); + $r3 = q("ALTER TABLE oauth_clients ALTER COLUMN user_id SET DEFAULT 0"); - $r4 = q("ALTER TABLE oauth_access_tokens ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); - $r5 = q("ALTER TABLE oauth_access_tokens ALTER COLUMN user_id SET NOT NULL"); - $r6 = q("ALTER TABLE oauth_access_tokens ALTER COLUMN user_id SET DEFAULT 0"); + $r4 = q("ALTER TABLE oauth_access_tokens ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); + $r5 = q("ALTER TABLE oauth_access_tokens ALTER COLUMN user_id SET NOT NULL"); + $r6 = q("ALTER TABLE oauth_access_tokens ALTER COLUMN user_id SET DEFAULT 0"); - $r7 = q("ALTER TABLE oauth_authorization_codes ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); - $r8 = q("ALTER TABLE oauth_authorization_codes ALTER COLUMN user_id SET NOT NULL"); - $r9 = q("ALTER TABLE oauth_authorization_codes ALTER COLUMN user_id SET DEFAULT 0"); + $r7 = q("ALTER TABLE oauth_authorization_codes ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); + $r8 = q("ALTER TABLE oauth_authorization_codes ALTER COLUMN user_id SET NOT NULL"); + $r9 = q("ALTER TABLE oauth_authorization_codes ALTER COLUMN user_id SET DEFAULT 0"); - $r10 = q("ALTER TABLE oauth_refresh_tokens ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); - $r11 = q("ALTER TABLE oauth_refresh_tokens ALTER COLUMN user_id SET NOT NULL"); - $r12 = q("ALTER TABLE oauth_refresh_tokens ALTER COLUMN user_id SET DEFAULT 0"); + $r10 = q("ALTER TABLE oauth_refresh_tokens ALTER COLUMN user_id TYPE bigint USING user_id::bigint"); + $r11 = q("ALTER TABLE oauth_refresh_tokens ALTER COLUMN user_id SET NOT NULL"); + $r12 = q("ALTER TABLE oauth_refresh_tokens ALTER COLUMN user_id SET DEFAULT 0"); - if($r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8 && $r9 && $r10 && $r11 && $r12) { - q("COMMIT"); - return UPDATE_SUCCESS; - } - else { - q("ROLLBACK"); - return UPDATE_FAILED; - } - } - else { - q("START TRANSACTION"); + if ($r1 && $r2 && $r3 && $r4 && $r5 && $r6 && $r7 && $r8 && $r9 && $r10 && $r11 && $r12) { + q("COMMIT"); + return UPDATE_SUCCESS; + } else { + q("ROLLBACK"); + return UPDATE_FAILED; + } + } else { + q("START TRANSACTION"); - $r1 = q("ALTER TABLE oauth_clients MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); - $r2 = q("ALTER TABLE oauth_access_tokens MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); - $r3 = q("ALTER TABLE oauth_authorization_codes MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); - $r4 = q("ALTER TABLE oauth_refresh_tokens MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); + $r1 = q("ALTER TABLE oauth_clients MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); + $r2 = q("ALTER TABLE oauth_access_tokens MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); + $r3 = q("ALTER TABLE oauth_authorization_codes MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); + $r4 = q("ALTER TABLE oauth_refresh_tokens MODIFY COLUMN user_id int(10) unsigned NOT NULL DEFAULT 0"); - if($r1 && $r2 && $r3 && $r4) { - q("COMMIT"); - return UPDATE_SUCCESS; - } - else { - q("ROLLBACK"); - return UPDATE_FAILED; - } + if ($r1 && $r2 && $r3 && $r4) { + q("COMMIT"); + return UPDATE_SUCCESS; + } else { + q("ROLLBACK"); + return UPDATE_FAILED; + } - } - } + } + } } diff --git a/Zotlabs/Update/_1215.php b/Zotlabs/Update/_1215.php index 3acaab587..65db4418b 100644 --- a/Zotlabs/Update/_1215.php +++ b/Zotlabs/Update/_1215.php @@ -2,25 +2,26 @@ namespace Zotlabs\Update; -class _1215 { +class _1215 +{ - function run() { - q("START TRANSACTION"); + public function run() + { + q("START TRANSACTION"); - // this will fix mastodon hubloc_url - $r1 = q("UPDATE hubloc SET hubloc_url = LEFT(hubloc_url, POSITION('/users' IN hubloc_url)-1) WHERE POSITION('/users' IN hubloc_url)>0"); + // this will fix mastodon hubloc_url + $r1 = q("UPDATE hubloc SET hubloc_url = LEFT(hubloc_url, POSITION('/users' IN hubloc_url)-1) WHERE POSITION('/users' IN hubloc_url)>0"); - // this will fix peertube hubloc_url - $r2 = q("UPDATE hubloc SET hubloc_url = LEFT(hubloc_url, POSITION('/account' IN hubloc_url)-1) WHERE POSITION('/account' IN hubloc_url)>0"); + // this will fix peertube hubloc_url + $r2 = q("UPDATE hubloc SET hubloc_url = LEFT(hubloc_url, POSITION('/account' IN hubloc_url)-1) WHERE POSITION('/account' IN hubloc_url)>0"); - if($r1 && $r2) { - q("COMMIT"); - return UPDATE_SUCCESS; - } - else { - q("ROLLBACK"); - return UPDATE_FAILED; - } - } + if ($r1 && $r2) { + q("COMMIT"); + return UPDATE_SUCCESS; + } else { + q("ROLLBACK"); + return UPDATE_FAILED; + } + } } diff --git a/Zotlabs/Update/_1216.php b/Zotlabs/Update/_1216.php index 69f2be15a..09752d484 100644 --- a/Zotlabs/Update/_1216.php +++ b/Zotlabs/Update/_1216.php @@ -2,18 +2,19 @@ namespace Zotlabs\Update; -class _1216 { +class _1216 +{ - function run() { + public function run() + { - $r = dbq("UPDATE xchan set xchan_name = 'unknown' where xchan_name like '%<%' "); + $r = dbq("UPDATE xchan set xchan_name = 'unknown' where xchan_name like '%<%' "); - if($r) { - return UPDATE_SUCCESS; - } - else { - return UPDATE_FAILED; - } - } + if ($r) { + return UPDATE_SUCCESS; + } else { + return UPDATE_FAILED; + } + } } diff --git a/Zotlabs/Update/_1217.php b/Zotlabs/Update/_1217.php index 15d2d06b3..c61589e1f 100644 --- a/Zotlabs/Update/_1217.php +++ b/Zotlabs/Update/_1217.php @@ -2,21 +2,22 @@ namespace Zotlabs\Update; -class _1217 { +class _1217 +{ - function run() { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r = q("ALTER TABLE app ADD app_options smallint NOT NULL DEFAULT '0' "); - } - else { - $r = q("ALTER TABLE app ADD app_options int(11) NOT NULL DEFAULT 0 "); - - } + public function run() + { + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r = q("ALTER TABLE app ADD app_options smallint NOT NULL DEFAULT '0' "); + } else { + $r = q("ALTER TABLE app ADD app_options int(11) NOT NULL DEFAULT 0 "); - if($r) { - return UPDATE_SUCCESS; - } - return UPDATE_FAILED; - } + } + + if ($r) { + return UPDATE_SUCCESS; + } + return UPDATE_FAILED; + } } diff --git a/Zotlabs/Update/_1218.php b/Zotlabs/Update/_1218.php index 07c7dba20..b9eb6681f 100644 --- a/Zotlabs/Update/_1218.php +++ b/Zotlabs/Update/_1218.php @@ -2,30 +2,32 @@ namespace Zotlabs\Update; -class _1218 { +class _1218 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE hubloc add hubloc_id_url text NOT NULL DEFAULT ''"); - $r2 = q("create index \"hubloc_id_url\" on hubloc (\"hubloc_id_url\")"); - $r3 = q("ALTER TABLE hubloc add hubloc_site_id text NOT NULL DEFAULT ''"); - $r4 = q("create index \"hubloc_site_id\" on hubloc (\"hubloc_site_id\")"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE hubloc add hubloc_id_url text NOT NULL DEFAULT ''"); + $r2 = q("create index \"hubloc_id_url\" on hubloc (\"hubloc_id_url\")"); + $r3 = q("ALTER TABLE hubloc add hubloc_site_id text NOT NULL DEFAULT ''"); + $r4 = q("create index \"hubloc_site_id\" on hubloc (\"hubloc_site_id\")"); - $r = $r1 && $r2 && $r3 && $r4; - } + $r = $r1 && $r2 && $r3 && $r4; + } - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r1 = q("ALTER TABLE hubloc add hubloc_id_url varchar(191) NOT NULL, ADD INDEX hubloc_id_url (hubloc_id_url)"); - $r2 = q("ALTER TABLE hubloc add hubloc_site_id varchar(191) NOT NULL, ADD INDEX hubloc_site_id (hubloc_site_id)"); + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r1 = q("ALTER TABLE hubloc add hubloc_id_url varchar(191) NOT NULL, ADD INDEX hubloc_id_url (hubloc_id_url)"); + $r2 = q("ALTER TABLE hubloc add hubloc_site_id varchar(191) NOT NULL, ADD INDEX hubloc_site_id (hubloc_site_id)"); - $r = $r1 && $r2; - } + $r = $r1 && $r2; + } - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1219.php b/Zotlabs/Update/_1219.php index be2534001..58b80cc17 100644 --- a/Zotlabs/Update/_1219.php +++ b/Zotlabs/Update/_1219.php @@ -2,25 +2,26 @@ namespace Zotlabs\Update; -class _1219 { +class _1219 +{ - function run() { - q("START TRANSACTION"); + public function run() + { + q("START TRANSACTION"); - $r = q("DELETE FROM xchan WHERE + $r = q("DELETE FROM xchan WHERE xchan_hash like '%s' AND xchan_network = 'activitypub'", - dbesc(z_root()) . '%' - ); + dbesc(z_root()) . '%' + ); - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } - else { - q("ROLLBACK"); - return UPDATE_FAILED; - } - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } else { + q("ROLLBACK"); + return UPDATE_FAILED; + } + } } diff --git a/Zotlabs/Update/_1220.php b/Zotlabs/Update/_1220.php index 6ce09c16b..db66d8845 100644 --- a/Zotlabs/Update/_1220.php +++ b/Zotlabs/Update/_1220.php @@ -2,12 +2,14 @@ namespace Zotlabs\Update; -class _1220 { +class _1220 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("CREATE TABLE listeners ( + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("CREATE TABLE listeners ( id serial NOT NULL, target_id text NOT NULL, portable_id text NOT NULL, @@ -15,16 +17,16 @@ class _1220 { PRIMARY KEY (id) )"); - $r2 = q("create index \"target_id_idx\" on listeners (\"target_id\")"); - $r3 = q("create index \"portable_id_idx\" on listeners (\"portable_id\")"); - $r4 = q("create index \"ltype_idx\" on listeners (\"ltype\")"); + $r2 = q("create index \"target_id_idx\" on listeners (\"target_id\")"); + $r3 = q("create index \"portable_id_idx\" on listeners (\"portable_id\")"); + $r4 = q("create index \"ltype_idx\" on listeners (\"ltype\")"); - $r = $r1 && $r2 && $r3 && $r4; + $r = $r1 && $r2 && $r3 && $r4; - } + } - if(ACTIVE_DBTYPE == DBTYPE_MYSQL) { - $r = q("CREATE TABLE IF NOT EXISTS listeners ( + if (ACTIVE_DBTYPE == DBTYPE_MYSQL) { + $r = q("CREATE TABLE IF NOT EXISTS listeners ( id int(11) NOT NULL AUTO_INCREMENT, target_id varchar(191) NOT NULL DEFAULT '', portable_id varchar(191) NOT NULL DEFAULT '', @@ -35,13 +37,13 @@ class _1220 { KEY ltype (ltype) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4"); - } + } - if($r) { - return UPDATE_SUCCESS; - } - return UPDATE_FAILED; + if ($r) { + return UPDATE_SUCCESS; + } + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1221.php b/Zotlabs/Update/_1221.php index 252fcaa90..807cd718c 100644 --- a/Zotlabs/Update/_1221.php +++ b/Zotlabs/Update/_1221.php @@ -2,19 +2,21 @@ namespace Zotlabs\Update; -class _1221 { +class _1221 +{ - function run() { + public function run() + { - $r1 = q("ALTER table " . TQUOT . 'groups' . TQUOT . " rename to pgrp "); - $r2 = q("ALTER table " . TQUOT . 'group_member' . TQUOT . " rename to pgrp_member "); + $r1 = q("ALTER table " . TQUOT . 'groups' . TQUOT . " rename to pgrp "); + $r2 = q("ALTER table " . TQUOT . 'group_member' . TQUOT . " rename to pgrp_member "); - if($r1 && $r2) { - return UPDATE_SUCCESS; - } - return UPDATE_FAILED; + if ($r1 && $r2) { + return UPDATE_SUCCESS; + } + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1222.php b/Zotlabs/Update/_1222.php index 1db49edff..183726343 100644 --- a/Zotlabs/Update/_1222.php +++ b/Zotlabs/Update/_1222.php @@ -2,18 +2,19 @@ namespace Zotlabs\Update; -class _1222 { +class _1222 +{ - function run() { + public function run() + { - $r = dbq("UPDATE hubloc set hubloc_id_url = hubloc_hash where hubloc_id_url = '' "); + $r = dbq("UPDATE hubloc set hubloc_id_url = hubloc_hash where hubloc_id_url = '' "); - if($r) { - return UPDATE_SUCCESS; - } - else { - return UPDATE_FAILED; - } - } + if ($r) { + return UPDATE_SUCCESS; + } else { + return UPDATE_FAILED; + } + } } diff --git a/Zotlabs/Update/_1223.php b/Zotlabs/Update/_1223.php index bc50b385d..8d53bc3e1 100644 --- a/Zotlabs/Update/_1223.php +++ b/Zotlabs/Update/_1223.php @@ -2,32 +2,34 @@ namespace Zotlabs\Update; -class _1223 { - - function run() { - foreach( [ 'abconfig','config','pconfig','xconfig','iconfig' ] as $tbl) { - while(1) { - $r = q("select id, v from %s where v like '%s' limit 100 ", - dbesc($tbl), - dbesc('a:%') - ); - if(! $r) { - break; - } - foreach($r as $rv) { - $s = unserialize($rv['v']); - if($s && is_array($s)) - $s = serialise($s); - else - $s = $rv['v']; - q("update %s set v = '%s' where id = %d", - dbesc($tbl), - dbesc($s), - dbesc($rv['id']) - ); - } - } - } - return UPDATE_SUCCESS; - } +class _1223 +{ + + public function run() + { + foreach (['abconfig', 'config', 'pconfig', 'xconfig', 'iconfig'] as $tbl) { + while (1) { + $r = q("select id, v from %s where v like '%s' limit 100 ", + dbesc($tbl), + dbesc('a:%') + ); + if (!$r) { + break; + } + foreach ($r as $rv) { + $s = unserialize($rv['v']); + if ($s && is_array($s)) + $s = serialise($s); + else + $s = $rv['v']; + q("update %s set v = '%s' where id = %d", + dbesc($tbl), + dbesc($s), + dbesc($rv['id']) + ); + } + } + } + return UPDATE_SUCCESS; + } } diff --git a/Zotlabs/Update/_1224.php b/Zotlabs/Update/_1224.php index cdbf1a52f..ce19db338 100644 --- a/Zotlabs/Update/_1224.php +++ b/Zotlabs/Update/_1224.php @@ -2,11 +2,13 @@ namespace Zotlabs\Update; -class _1224 { - - function run() { - q("update abook set abook_closeness = 80 where abook_closeness = 0 and abook_self = 0"); - return UPDATE_SUCCESS; +class _1224 +{ - } + public function run() + { + q("update abook set abook_closeness = 80 where abook_closeness = 0 and abook_self = 0"); + return UPDATE_SUCCESS; + + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1225.php b/Zotlabs/Update/_1225.php index f387dbfc1..ebe8f5ab6 100644 --- a/Zotlabs/Update/_1225.php +++ b/Zotlabs/Update/_1225.php @@ -4,22 +4,24 @@ namespace Zotlabs\Update; use Zotlabs\Lib\Apps; -class _1225 { - - function run() { - q("delete from app where app_channel = 0"); +class _1225 +{ - $apps = Apps::get_system_apps(false); + public function run() + { + q("delete from app where app_channel = 0"); - if($apps) { - foreach($apps as $app) { - $app['uid'] = 0; - $app['guid'] = hash('whirlpool',$app['name']); - $app['system'] = 1; - Apps::app_install(0,$app); - } - } + $apps = Apps::get_system_apps(false); - return UPDATE_SUCCESS; - } + if ($apps) { + foreach ($apps as $app) { + $app['uid'] = 0; + $app['guid'] = hash('whirlpool', $app['name']); + $app['system'] = 1; + Apps::app_install(0, $app); + } + } + + return UPDATE_SUCCESS; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1226.php b/Zotlabs/Update/_1226.php index c112683d5..c9c13efda 100644 --- a/Zotlabs/Update/_1226.php +++ b/Zotlabs/Update/_1226.php @@ -3,20 +3,21 @@ namespace Zotlabs\Update; -class _1226 { - - function run() { +class _1226 +{ - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r = q("alter table item add item_level bigint NOT NULL DEFAULT '0'"); - } - else { - $r = q("alter table item add item_level int(10) NOT NULL DEFAULT 0 "); - } + public function run() + { - if($r) { - return UPDATE_SUCCESS; - } - return UPDATE_FAILED; - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r = q("alter table item add item_level bigint NOT NULL DEFAULT '0'"); + } else { + $r = q("alter table item add item_level int(10) NOT NULL DEFAULT 0 "); + } + + if ($r) { + return UPDATE_SUCCESS; + } + return UPDATE_FAILED; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1227.php b/Zotlabs/Update/_1227.php index 9fedd7083..a997eb8d4 100644 --- a/Zotlabs/Update/_1227.php +++ b/Zotlabs/Update/_1227.php @@ -3,30 +3,31 @@ namespace Zotlabs\Update; -class _1227 { +class _1227 +{ - function run() { + public function run() + { - q("START TRANSACTION"); + q("START TRANSACTION"); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE item ADD uuid text NOT NULL DEFAULT '' "); - $r2 = q("create index \"uuid_idx\" on item (\"uuid\")"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE item ADD uuid text NOT NULL DEFAULT '' "); + $r2 = q("create index \"uuid_idx\" on item (\"uuid\")"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `item` ADD `uuid` char(191) NOT NULL DEFAULT '' , + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `item` ADD `uuid` char(191) NOT NULL DEFAULT '' , ADD INDEX `uuid` (`uuid`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; - } + q("ROLLBACK"); + return UPDATE_FAILED; + } } diff --git a/Zotlabs/Update/_1228.php b/Zotlabs/Update/_1228.php index 525eab402..7803b84a8 100644 --- a/Zotlabs/Update/_1228.php +++ b/Zotlabs/Update/_1228.php @@ -4,19 +4,21 @@ namespace Zotlabs\Update; use Zotlabs\Lib\PConfig; -class _1228 { +class _1228 +{ - function run() { + public function run() + { - $r = q("select channel_id from channel where true"); - if ($r) { - foreach ($r as $rv) { - PConfig::Set($rv['channel_id'],'perm_limits','moderated', (string) PERMS_SPECIFIC); - } - } + $r = q("select channel_id from channel where true"); + if ($r) { + foreach ($r as $rv) { + PConfig::Set($rv['channel_id'], 'perm_limits', 'moderated', (string)PERMS_SPECIFIC); + } + } - return UPDATE_SUCCESS; + return UPDATE_SUCCESS; - } + } } diff --git a/Zotlabs/Update/_1229.php b/Zotlabs/Update/_1229.php index a8fbd1cb1..ff0ebe6de 100644 --- a/Zotlabs/Update/_1229.php +++ b/Zotlabs/Update/_1229.php @@ -2,22 +2,23 @@ namespace Zotlabs\Update; -class _1229 { +class _1229 +{ - function run() { + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " RENAME COLUMN xchan_pubforum to xchan_type "); - } - else { - $r = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " CHANGE xchan_pubforum xchan_type tinyint(1) NOT NULL default 0 "); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " RENAME COLUMN xchan_pubforum to xchan_type "); + } else { + $r = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " CHANGE xchan_pubforum xchan_type tinyint(1) NOT NULL default 0 "); + } - if($r) { - return UPDATE_SUCCESS; - } - return UPDATE_FAILED; + if ($r) { + return UPDATE_SUCCESS; + } + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1230.php b/Zotlabs/Update/_1230.php index 824d9be6a..c04fb407b 100644 --- a/Zotlabs/Update/_1230.php +++ b/Zotlabs/Update/_1230.php @@ -2,18 +2,20 @@ namespace Zotlabs\Update; -class _1230 { +class _1230 +{ - function run() { + public function run() + { - $r1 = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " DROP COLUMN xchan_instance_url "); - $r2 = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " DROP COLUMN xchan_flags "); + $r1 = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " DROP COLUMN xchan_instance_url "); + $r2 = q("ALTER TABLE " . TQUOT . 'xchan' . TQUOT . " DROP COLUMN xchan_flags "); - if($r1 && $r2) { - return UPDATE_SUCCESS; - } - return UPDATE_FAILED; + if ($r1 && $r2) { + return UPDATE_SUCCESS; + } + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1231.php b/Zotlabs/Update/_1231.php index beec7ac72..7ac0034ab 100644 --- a/Zotlabs/Update/_1231.php +++ b/Zotlabs/Update/_1231.php @@ -3,30 +3,31 @@ namespace Zotlabs\Update; -class _1231 { +class _1231 +{ - function run() { + public function run() + { - q("START TRANSACTION"); + q("START TRANSACTION"); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE channel ADD channel_parent text NOT NULL DEFAULT '' "); - $r2 = q("create index \"channel_parent\" on channel (\"channel_parent\")"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE channel ADD channel_parent text NOT NULL DEFAULT '' "); + $r2 = q("create index \"channel_parent\" on channel (\"channel_parent\")"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `channel` ADD `channel_parent` char(191) NOT NULL DEFAULT '' , + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `channel` ADD `channel_parent` char(191) NOT NULL DEFAULT '' , ADD INDEX `channel_parent` (`channel_parent`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; - } + q("ROLLBACK"); + return UPDATE_FAILED; + } } diff --git a/Zotlabs/Update/_1232.php b/Zotlabs/Update/_1232.php index 89236a8c5..9bb2aacb0 100644 --- a/Zotlabs/Update/_1232.php +++ b/Zotlabs/Update/_1232.php @@ -2,31 +2,32 @@ namespace Zotlabs\Update; -class _1232 { +class _1232 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE photo ADD expires timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r2 = q("create index \"photo_expires_idx\" on photo (\"expires\")"); + q("START TRANSACTION"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `photo` ADD `expires` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE photo ADD expires timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r2 = q("create index \"photo_expires_idx\" on photo (\"expires\")"); + + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `photo` ADD `expires` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , ADD INDEX `expires` (`expires`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; + q("ROLLBACK"); + return UPDATE_FAILED; - } + } } diff --git a/Zotlabs/Update/_1233.php b/Zotlabs/Update/_1233.php index 392fd3590..611ea15b1 100644 --- a/Zotlabs/Update/_1233.php +++ b/Zotlabs/Update/_1233.php @@ -2,33 +2,36 @@ namespace Zotlabs\Update; -class _1233 { +class _1233 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - $r = q("ALTER TABLE abook ADD abook_censor INT UNSIGNED NOT NULL DEFAULT '0' "); + q("START TRANSACTION"); - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + $r = q("ALTER TABLE abook ADD abook_censor INT UNSIGNED NOT NULL DEFAULT '0' "); - q("ROLLBACK"); - return UPDATE_FAILED; + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - } + q("ROLLBACK"); + return UPDATE_FAILED; - function verify() { + } - $columns = db_columns('abook'); + public function verify() + { - if(in_array('abook_censor',$columns)) { - return true; - } + $columns = db_columns('abook'); - return false; - } + if (in_array('abook_censor', $columns)) { + return true; + } + + return false; + } } diff --git a/Zotlabs/Update/_1234.php b/Zotlabs/Update/_1234.php index 229669d14..3110bf7e7 100644 --- a/Zotlabs/Update/_1234.php +++ b/Zotlabs/Update/_1234.php @@ -2,33 +2,36 @@ namespace Zotlabs\Update; -class _1234 { +class _1234 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - $r = q("ALTER TABLE oauth_clients ADD client_name VARCHAR(80) "); + q("START TRANSACTION"); - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + $r = q("ALTER TABLE oauth_clients ADD client_name VARCHAR(80) "); - q("ROLLBACK"); - return UPDATE_FAILED; + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - } + q("ROLLBACK"); + return UPDATE_FAILED; - function verify() { + } - $columns = db_columns('oauth_clients'); + public function verify() + { - if(in_array('client_name',$columns)) { - return true; - } + $columns = db_columns('oauth_clients'); - return false; - } + if (in_array('client_name', $columns)) { + return true; + } + + return false; + } } diff --git a/Zotlabs/Update/_1235.php b/Zotlabs/Update/_1235.php index 414306b93..d86a51e35 100644 --- a/Zotlabs/Update/_1235.php +++ b/Zotlabs/Update/_1235.php @@ -2,28 +2,31 @@ namespace Zotlabs\Update; -class _1235 { +class _1235 +{ - function run() { + public function run() + { - $r = q("ALTER TABLE item add replyto text NOT NULL DEFAULT ''"); + $r = q("ALTER TABLE item add replyto text NOT NULL DEFAULT ''"); - if($r) - return UPDATE_SUCCESS; - return UPDATE_FAILED; + if ($r) + return UPDATE_SUCCESS; + return UPDATE_FAILED; - } + } - function verify() { + public function verify() + { - $columns = db_columns('item'); + $columns = db_columns('item'); - if(in_array('replyto',$columns)) { - return true; - } + if (in_array('replyto', $columns)) { + return true; + } - return false; + return false; - } + } } diff --git a/Zotlabs/Update/_1236.php b/Zotlabs/Update/_1236.php index 8535abb63..fdbf3d770 100644 --- a/Zotlabs/Update/_1236.php +++ b/Zotlabs/Update/_1236.php @@ -2,42 +2,44 @@ namespace Zotlabs\Update; -class _1236 { +class _1236 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE abook ADD abook_alias text NOT NULL"); - $r2 = q("create index \"abook_alias_idx\" on photo (\"abook_alias\")"); + q("START TRANSACTION"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `abook` ADD `abook_alias` char(191) NOT NULL DEFAULT '' , + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE abook ADD abook_alias text NOT NULL"); + $r2 = q("create index \"abook_alias_idx\" on photo (\"abook_alias\")"); + + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `abook` ADD `abook_alias` char(191) NOT NULL DEFAULT '' , ADD INDEX `abook_alias` (`abook_alias`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; + q("ROLLBACK"); + return UPDATE_FAILED; - } + } - function verify() { + public function verify() + { - $columns = db_columns('abook'); + $columns = db_columns('abook'); - if(in_array('abook_alias',$columns)) { - return true; - } + if (in_array('abook_alias', $columns)) { + return true; + } + + return false; + } - return false; - } - } diff --git a/Zotlabs/Update/_1237.php b/Zotlabs/Update/_1237.php index fc3fe7120..67d340c2a 100644 --- a/Zotlabs/Update/_1237.php +++ b/Zotlabs/Update/_1237.php @@ -2,22 +2,25 @@ namespace Zotlabs\Update; -class _1237 { +class _1237 +{ - function run() { - q("update app set app_url = '%s' where app_url = '%s' ", - dbesc(z_root() . '/stream'), - dbesc(z_root() . '/network') - ); - q("update app set app_url = '%s' where app_url = '%s' ", - dbesc('$baseurl/stream'), - dbesc('$baseurl/network') - ); + public function run() + { + q("update app set app_url = '%s' where app_url = '%s' ", + dbesc(z_root() . '/stream'), + dbesc(z_root() . '/network') + ); + q("update app set app_url = '%s' where app_url = '%s' ", + dbesc('$baseurl/stream'), + dbesc('$baseurl/network') + ); - return UPDATE_SUCCESS; - } + return UPDATE_SUCCESS; + } - function verify() { - return true; - } + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1238.php b/Zotlabs/Update/_1238.php index e5c13a191..c4314754d 100644 --- a/Zotlabs/Update/_1238.php +++ b/Zotlabs/Update/_1238.php @@ -2,40 +2,42 @@ namespace Zotlabs\Update; -class _1238 { +class _1238 +{ - function run() { + public function run() + { - $r1 = q("CREATE TABLE " . TQUOT . 'block' . TQUOT . " ( + $r1 = q("CREATE TABLE " . TQUOT . 'block' . TQUOT . " ( block_id int(10) UNSIGNED NOT NULL, block_channel_id int(10) UNSIGNED NOT NULL, block_entity text NOT NULL, block_type int(11) NOT NULL, block_comment mediumtext NOT NULL) "); - $r2 = q("ALTER TABLE " . TQUOT . 'block' . TQUOT . " + $r2 = q("ALTER TABLE " . TQUOT . 'block' . TQUOT . " ADD PRIMARY KEY (block_id), ADD KEY block_channel_id (block_channel_id), ADD KEY block_entity (block_entity(191)), ADD KEY block_type (block_type) "); - $r3 = q("ALTER TABLE " . TQUOT . 'block' . TQUOT . " + $r3 = q("ALTER TABLE " . TQUOT . 'block' . TQUOT . " MODIFY block_id int(10) UNSIGNED NOT NULL AUTO_INCREMENT "); - - return (($r1 && $r2 && $r3) ? UPDATE_SUCCESS : UPDATE_FAILED); - } + return (($r1 && $r2 && $r3) ? UPDATE_SUCCESS : UPDATE_FAILED); + + } - function verify() { + public function verify() + { - $columns = db_columns('block'); + $columns = db_columns('block'); - if(in_array('block_id',$columns)) { - return true; - } - - return false; - } + if (in_array('block_id', $columns)) { + return true; + } + return false; + } } diff --git a/Zotlabs/Update/_1239.php b/Zotlabs/Update/_1239.php index ae22ec6d8..c9e732c39 100644 --- a/Zotlabs/Update/_1239.php +++ b/Zotlabs/Update/_1239.php @@ -4,42 +4,45 @@ namespace Zotlabs\Update; use Zotlabs\Lib\LibBlock; -class _1239 { +class _1239 +{ - function run() { - $r = q("select channel_id from channel where true"); - if ($r) { - foreach ($r as $rv) { - $a = get_pconfig($rv['channel_id'],'system','blocked'); - if ($a) { - $list = explode(',',$a); - if ($list) { - foreach ($list as $l) { - if (trim($l)) { - LibBlock::store( [ - 'block_channel_id' => intval($rv['channel_id']), - 'block_type' => 0, - 'block_entity' => trim($l), - 'block_comment' => t('Added by superblock') - ]); - } - } - } - del_pconfig($rv['channel_id'],'system','blocked'); - } - } - } - return UPDATE_SUCCESS; - } + public function run() + { + $r = q("select channel_id from channel where true"); + if ($r) { + foreach ($r as $rv) { + $a = get_pconfig($rv['channel_id'], 'system', 'blocked'); + if ($a) { + $list = explode(',', $a); + if ($list) { + foreach ($list as $l) { + if (trim($l)) { + LibBlock::store([ + 'block_channel_id' => intval($rv['channel_id']), + 'block_type' => 0, + 'block_entity' => trim($l), + 'block_comment' => t('Added by superblock') + ]); + } + } + } + del_pconfig($rv['channel_id'], 'system', 'blocked'); + } + } + } + return UPDATE_SUCCESS; + } - function verify() { + public function verify() + { - $r = q("select * from pconfig where cat = 'system' and k = 'blocked'"); - if ($r) { - return false; - } - return true; - } + $r = q("select * from pconfig where cat = 'system' and k = 'blocked'"); + if ($r) { + return false; + } + return true; + } } diff --git a/Zotlabs/Update/_1240.php b/Zotlabs/Update/_1240.php index d66f97088..b6e271942 100644 --- a/Zotlabs/Update/_1240.php +++ b/Zotlabs/Update/_1240.php @@ -4,38 +4,41 @@ namespace Zotlabs\Update; use Zotlabs\Lib\Config; -class _1240 { +class _1240 +{ - function run() { + public function run() + { -Config::Set('system','allowed_sites',Config::Get('system','whitelisted_sites','')); - Config::Delete('system','whitelisted_sites'); - Config::Set('system','denied_sites',Config::Get('system','blacklisted_sites','')); - Config::Delete('system','blacklisted_sites'); + Config::Set('system', 'allowed_sites', Config::Get('system', 'whitelisted_sites', '')); + Config::Delete('system', 'whitelisted_sites'); + Config::Set('system', 'denied_sites', Config::Get('system', 'blacklisted_sites', '')); + Config::Delete('system', 'blacklisted_sites'); - Config::Set('system','pubstream_allowed_sites',Config::Get('system','pubstream_whitelisted_sites','')); - Config::Delete('system','pubstream_whitelisted_sites'); - Config::Set('system','pubstream_denied_sites',Config::Get('system','pubstream_blacklisted_sites','')); - Config::Delete('system','pubstream_blacklisted_sites'); + Config::Set('system', 'pubstream_allowed_sites', Config::Get('system', 'pubstream_whitelisted_sites', '')); + Config::Delete('system', 'pubstream_whitelisted_sites'); + Config::Set('system', 'pubstream_denied_sites', Config::Get('system', 'pubstream_blacklisted_sites', '')); + Config::Delete('system', 'pubstream_blacklisted_sites'); - Config::Set('system','allowed_sites',Config::Get('system','whitelisted_sites','')); - Config::Delete('system','whitelisted_sites'); - Config::Set('system','denied_sites',Config::Get('system','blacklisted_sites','')); - Config::Delete('system','blacklisted_sites'); + Config::Set('system', 'allowed_sites', Config::Get('system', 'whitelisted_sites', '')); + Config::Delete('system', 'whitelisted_sites'); + Config::Set('system', 'denied_sites', Config::Get('system', 'blacklisted_sites', '')); + Config::Delete('system', 'blacklisted_sites'); - Config::Set('system','pubstream_allowed_sites',Config::Get('system','pubstream_whitelisted_sites','')); - Config::Delete('system','pubstream_whitelisted_sites'); - Config::Set('system','pubstream_denied_sites',Config::Get('system','pubstream_blacklisted_sites','')); - Config::Delete('system','pubstream_blacklisted_sites'); - return UPDATE_SUCCESS; - } - - function verify() { - if (Config::Get('system','blacklisted_sites') !== null) { - return false; - } - return true; - } + Config::Set('system', 'pubstream_allowed_sites', Config::Get('system', 'pubstream_whitelisted_sites', '')); + Config::Delete('system', 'pubstream_whitelisted_sites'); + Config::Set('system', 'pubstream_denied_sites', Config::Get('system', 'pubstream_blacklisted_sites', '')); + Config::Delete('system', 'pubstream_blacklisted_sites'); + return UPDATE_SUCCESS; + } + + public function verify() + { + if (Config::Get('system', 'blacklisted_sites') !== null) { + return false; + } + return true; + } } \ No newline at end of file diff --git a/Zotlabs/Update/_1241.php b/Zotlabs/Update/_1241.php index de8a847f3..56f898b4d 100644 --- a/Zotlabs/Update/_1241.php +++ b/Zotlabs/Update/_1241.php @@ -2,41 +2,43 @@ namespace Zotlabs\Update; -class _1241 { +class _1241 +{ - function run() { - q("START TRANSACTION"); + public function run() + { + q("START TRANSACTION"); - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE pgrp ADD \"rule\" text NOT NULL DEFAULT '' "); - $r2 = q("create index \"group_rule_idx\" on pgrp (\"rule\")"); + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE pgrp ADD \"rule\" text NOT NULL DEFAULT '' "); + $r2 = q("create index \"group_rule_idx\" on pgrp (\"rule\")"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `pgrp` ADD `rule` char(191) NOT NULL DEFAULT '' , + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `pgrp` ADD `rule` char(191) NOT NULL DEFAULT '' , ADD INDEX `rule` (`rule`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; - } + q("ROLLBACK"); + return UPDATE_FAILED; + } - function verify() { + public function verify() + { - $columns = db_columns('pgrp'); + $columns = db_columns('pgrp'); - if(in_array('rule',$columns)) { - return true; - } + if (in_array('rule', $columns)) { + return true; + } - return false; - } + return false; + } } diff --git a/Zotlabs/Update/_1242.php b/Zotlabs/Update/_1242.php index 425d0f58c..f0bd93d8e 100644 --- a/Zotlabs/Update/_1242.php +++ b/Zotlabs/Update/_1242.php @@ -2,45 +2,45 @@ namespace Zotlabs\Update; -class _1242 { +class _1242 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE xchan ADD xchan_updated timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r2 = q("create index \"xchan_updated_idx\" on xchan (\"xchan_updated\")"); + q("START TRANSACTION"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `xchan` ADD `xchan_updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE xchan ADD xchan_updated timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r2 = q("create index \"xchan_updated_idx\" on xchan (\"xchan_updated\")"); + + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `xchan` ADD `xchan_updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , ADD INDEX `xchan_updated` (`xchan_updated`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; + q("ROLLBACK"); + return UPDATE_FAILED; - } + } - function verify() { + public function verify() + { - $columns = db_columns('xchan'); - - if(in_array('xchan_updated',$columns)) { - return true; - } - - return false; - } + $columns = db_columns('xchan'); + if (in_array('xchan_updated', $columns)) { + return true; + } + return false; + } } diff --git a/Zotlabs/Update/_1243.php b/Zotlabs/Update/_1243.php index 137c60c81..f0af225d7 100644 --- a/Zotlabs/Update/_1243.php +++ b/Zotlabs/Update/_1243.php @@ -2,47 +2,47 @@ namespace Zotlabs\Update; -class _1243 { +class _1243 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE profile ADD pronouns text NOT NULL DEFAULT '' "); - $r2 = q("ALTER TABLE xprof ADD xprof_pronouns text NOT NULL DEFAULT '' "); + q("START TRANSACTION"); - $r = ($r1 && $r2); - } - else { - $r1 = q("ALTER TABLE `profile` ADD `pronouns` char(191) NOT NULL DEFAULT '' "); - $r2 = q("ALTER TABLE `xprof` ADD `xprof_pronouns` char(191) NOT NULL DEFAULT '' "); - $r = ($r1 && $r2); - } + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE profile ADD pronouns text NOT NULL DEFAULT '' "); + $r2 = q("ALTER TABLE xprof ADD xprof_pronouns text NOT NULL DEFAULT '' "); - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + $r = ($r1 && $r2); + } else { + $r1 = q("ALTER TABLE `profile` ADD `pronouns` char(191) NOT NULL DEFAULT '' "); + $r2 = q("ALTER TABLE `xprof` ADD `xprof_pronouns` char(191) NOT NULL DEFAULT '' "); + $r = ($r1 && $r2); + } - q("ROLLBACK"); - return UPDATE_FAILED; + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - } + q("ROLLBACK"); + return UPDATE_FAILED; - function verify() { + } - $columns = db_columns('profile'); - $columns2 = db_columns('xprof'); - - if(in_array('pronouns',$columns) && in_array('xprof_pronouns',$columns2)) { - return true; - } + public function verify() + { - return false; - } + $columns = db_columns('profile'); + $columns2 = db_columns('xprof'); + if (in_array('pronouns', $columns) && in_array('xprof_pronouns', $columns2)) { + return true; + } + return false; + } } diff --git a/Zotlabs/Update/_1244.php b/Zotlabs/Update/_1244.php index d14f7a121..1929bf545 100644 --- a/Zotlabs/Update/_1244.php +++ b/Zotlabs/Update/_1244.php @@ -2,42 +2,44 @@ namespace Zotlabs\Update; -class _1244 { +class _1244 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE xchan ADD xchan_created timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); - $r2 = q("create index \"xchan_created_idx\" on xchan (\"xchan_created\")"); + q("START TRANSACTION"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `xchan` ADD `xchan_created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE xchan ADD xchan_created timestamp NOT NULL DEFAULT '0001-01-01 00:00:00' "); + $r2 = q("create index \"xchan_created_idx\" on xchan (\"xchan_created\")"); + + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `xchan` ADD `xchan_created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' , ADD INDEX `xchan_created` (`xchan_created`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; + q("ROLLBACK"); + return UPDATE_FAILED; - } + } - function verify() { + public function verify() + { - $columns = db_columns('xchan'); + $columns = db_columns('xchan'); - if(in_array('xchan_created',$columns)) { - return true; - } + if (in_array('xchan_created', $columns)) { + return true; + } - return false; - } + return false; + } } diff --git a/Zotlabs/Update/_1245.php b/Zotlabs/Update/_1245.php index ba9a77791..d8adf6df2 100644 --- a/Zotlabs/Update/_1245.php +++ b/Zotlabs/Update/_1245.php @@ -2,17 +2,20 @@ namespace Zotlabs\Update; -class _1245 { +class _1245 +{ - function run() { + public function run() + { - q("delete from app where app_url like '%%/nocomment'"); - return UPDATE_SUCCESS; + q("delete from app where app_url like '%%/nocomment'"); + return UPDATE_SUCCESS; - } + } - function verify() { - return true; - } + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1246.php b/Zotlabs/Update/_1246.php index 5526f6106..70fa5736b 100644 --- a/Zotlabs/Update/_1246.php +++ b/Zotlabs/Update/_1246.php @@ -2,22 +2,25 @@ namespace Zotlabs\Update; -class _1246 { +class _1246 +{ - function run() { - // remove deprecated apps from system list - - $network = 'bee400a93e3b95225374f02dcc74bfa37445f628bb10d05e3904aa8e3dd12c3b337a0caed2455a32ea85d8aaebc310f5b8571e7471f10a19bcfd77a7a997681f'; - $affinity = '76eecd5b73a0df8cddfcda430f0970ce82fefddb2b6440397b8318ccf4ae8011953fe249b0e450a1fe8829d5d3b5a62588818fd859087bbddc65a99c856d8b7d'; - + public function run() + { + // remove deprecated apps from system list - q("delete from app where (app_id = '$network' OR app_id = '$affinity')"); - return UPDATE_SUCCESS; + $network = 'bee400a93e3b95225374f02dcc74bfa37445f628bb10d05e3904aa8e3dd12c3b337a0caed2455a32ea85d8aaebc310f5b8571e7471f10a19bcfd77a7a997681f'; + $affinity = '76eecd5b73a0df8cddfcda430f0970ce82fefddb2b6440397b8318ccf4ae8011953fe249b0e450a1fe8829d5d3b5a62588818fd859087bbddc65a99c856d8b7d'; - } - function verify() { - return true; - } + q("delete from app where (app_id = '$network' OR app_id = '$affinity')"); + return UPDATE_SUCCESS; + + } + + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1247.php b/Zotlabs/Update/_1247.php index e922105be..ab8173819 100644 --- a/Zotlabs/Update/_1247.php +++ b/Zotlabs/Update/_1247.php @@ -2,19 +2,22 @@ namespace Zotlabs\Update; -class _1247 { +class _1247 +{ - function run() { - // remove deprecated apps from system list - $access = 'a2e9cee1a71e8b82f662d131a7cda1606b84b9be283715c967544e19cb34dd0821b65580c942ca38d7620638a44f26034536597a2c3a5c969e2dbaedfcd1d282'; + public function run() + { + // remove deprecated apps from system list + $access = 'a2e9cee1a71e8b82f662d131a7cda1606b84b9be283715c967544e19cb34dd0821b65580c942ca38d7620638a44f26034536597a2c3a5c969e2dbaedfcd1d282'; - q("delete from app where app_id = '$access' "); - return UPDATE_SUCCESS; + q("delete from app where app_id = '$access' "); + return UPDATE_SUCCESS; - } + } - function verify() { - return true; - } + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1248.php b/Zotlabs/Update/_1248.php index cb82d2f5b..049dd5577 100644 --- a/Zotlabs/Update/_1248.php +++ b/Zotlabs/Update/_1248.php @@ -2,42 +2,44 @@ namespace Zotlabs\Update; -class _1248 { +class _1248 +{ - function run() { - - q("START TRANSACTION"); + public function run() + { - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $r1 = q("ALTER TABLE atoken ADD atoken_guid NOT NULL DEFAULT '' "); - $r2 = q("create index \"atoken_guid\" on xchan (\"atoken_guid\")"); + q("START TRANSACTION"); - $r = ($r1 && $r2); - } - else { - $r = q("ALTER TABLE `atoken` ADD `atoken_guid` char(191) NOT NULL DEFAULT '' , + if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $r1 = q("ALTER TABLE atoken ADD atoken_guid NOT NULL DEFAULT '' "); + $r2 = q("create index \"atoken_guid\" on xchan (\"atoken_guid\")"); + + $r = ($r1 && $r2); + } else { + $r = q("ALTER TABLE `atoken` ADD `atoken_guid` char(191) NOT NULL DEFAULT '' , ADD INDEX `atoken_guid` (`atoken_guid`)"); - } + } - if($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; + q("ROLLBACK"); + return UPDATE_FAILED; - } + } - function verify() { + public function verify() + { - $columns = db_columns('atoken'); + $columns = db_columns('atoken'); - if(in_array('atoken_guid',$columns)) { - return true; - } + if (in_array('atoken_guid', $columns)) { + return true; + } - return false; - } + return false; + } } diff --git a/Zotlabs/Update/_1249.php b/Zotlabs/Update/_1249.php index a38137b50..ef4033f00 100644 --- a/Zotlabs/Update/_1249.php +++ b/Zotlabs/Update/_1249.php @@ -4,36 +4,39 @@ namespace Zotlabs\Update; use Zotlabs\Access\Permissions; -class _1249 { +class _1249 +{ - function run() { + public function run() + { - $channels = []; + $channels = []; - $r = q("select * from abook where abook_self = 0"); - if ($r) { - foreach ($r as $rv) { - if (! in_array(intval($rv['abook_channel']),$channels)) { - set_pconfig($rv['abook_channel'], 'perm_limits', 'post_mail', PERMS_SPECIFIC); - $channels[] = intval($rv['abook_channel']); - } + $r = q("select * from abook where abook_self = 0"); + if ($r) { + foreach ($r as $rv) { + if (!in_array(intval($rv['abook_channel']), $channels)) { + set_pconfig($rv['abook_channel'], 'perm_limits', 'post_mail', PERMS_SPECIFIC); + $channels[] = intval($rv['abook_channel']); + } - $x = get_abconfig($rv['abook_channel'],$rv['abook_xchan'],'system','my_perms'); - if ($x) { - $y = explode(',',$x); - if ($y && in_array('post_comments',$y) && ! in_array('post_mail',$y)) { - $y[] = 'post_mail'; - set_abconfig($rv['abook_channel'],$rv['abook_xchan'],'system','my_perms', implode(',',$y)); - } - } - } - } + $x = get_abconfig($rv['abook_channel'], $rv['abook_xchan'], 'system', 'my_perms'); + if ($x) { + $y = explode(',', $x); + if ($y && in_array('post_comments', $y) && !in_array('post_mail', $y)) { + $y[] = 'post_mail'; + set_abconfig($rv['abook_channel'], $rv['abook_xchan'], 'system', 'my_perms', implode(',', $y)); + } + } + } + } - return UPDATE_SUCCESS; - } + return UPDATE_SUCCESS; + } - function verify() { - return true; - } + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1250.php b/Zotlabs/Update/_1250.php index 61f31d471..8fa7285f8 100644 --- a/Zotlabs/Update/_1250.php +++ b/Zotlabs/Update/_1250.php @@ -2,19 +2,22 @@ namespace Zotlabs\Update; -class _1250 { +class _1250 +{ - function run() { - // remove deprecated apps from system list - $access = '067b70e92e35cc1b729c8c386bf8289cbec2618911a87c460a9b4705f2c151f8535402d468d469eeb630fad2c9cdd9aced80fb2b7cb29e47ae8f9c22c83ee7f2'; + public function run() + { + // remove deprecated apps from system list + $access = '067b70e92e35cc1b729c8c386bf8289cbec2618911a87c460a9b4705f2c151f8535402d468d469eeb630fad2c9cdd9aced80fb2b7cb29e47ae8f9c22c83ee7f2'; - q("delete from app where app_id = '$access' "); - return UPDATE_SUCCESS; + q("delete from app where app_id = '$access' "); + return UPDATE_SUCCESS; - } + } - function verify() { - return true; - } + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1251.php b/Zotlabs/Update/_1251.php index a2b33f3b8..b83532893 100644 --- a/Zotlabs/Update/_1251.php +++ b/Zotlabs/Update/_1251.php @@ -2,34 +2,37 @@ namespace Zotlabs\Update; -class _1251 { +class _1251 +{ - function run() { + public function run() + { - $default = ((ACTIVE_DBTYPE == DBTYPE_POSTGRES) ? " default ''" : ''); + $default = ((ACTIVE_DBTYPE == DBTYPE_POSTGRES) ? " default ''" : ''); - q("START TRANSACTION"); - $r = q("ALTER TABLE dreport ADD dreport_log text NOT NULL $default"); + q("START TRANSACTION"); + $r = q("ALTER TABLE dreport ADD dreport_log text NOT NULL $default"); - if ($r) { - q("COMMIT"); - return UPDATE_SUCCESS; - } + if ($r) { + q("COMMIT"); + return UPDATE_SUCCESS; + } - q("ROLLBACK"); - return UPDATE_FAILED; + q("ROLLBACK"); + return UPDATE_FAILED; - } + } - function verify() { + public function verify() + { - $columns = db_columns('dreport'); + $columns = db_columns('dreport'); - if (in_array('dreport_log',$columns)) { - return true; - } + if (in_array('dreport_log', $columns)) { + return true; + } - return false; - } + return false; + } } diff --git a/Zotlabs/Update/_1252.php b/Zotlabs/Update/_1252.php index f1505c533..98139c5db 100644 --- a/Zotlabs/Update/_1252.php +++ b/Zotlabs/Update/_1252.php @@ -2,41 +2,44 @@ namespace Zotlabs\Update; -class _1252 { +class _1252 +{ - function run() { - $sys = get_sys_channel(); - if ($sys) { - $sitename = get_config('system','sitename'); - $siteinfo = get_config('system','siteinfo'); + public function run() + { + $sys = get_sys_channel(); + if ($sys) { + $sitename = get_config('system', 'sitename'); + $siteinfo = get_config('system', 'siteinfo'); - if ($sitename) { - q("update channel set channel_name = '%s' where channel_id = %d", - dbesc($sitename), - intval($sys['channel_id']) - ); - q("update profile set fullname = '%s' where uid = %d and is_default = 1", - dbesc($sitename), - intval($sys['channel_id']) - ); - q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", - dbesc($sitename), - dbesc(datetime_convert()), - dbesc($sys['channel_hash']) - ); - } - if ($siteinfo) { - q("update profile set about = '%s' where uid = %d and is_default = 1", - dbesc($siteinfo), - intval($sys['channel_id']) - ); - } - } - return UPDATE_SUCCESS; - } + if ($sitename) { + q("update channel set channel_name = '%s' where channel_id = %d", + dbesc($sitename), + intval($sys['channel_id']) + ); + q("update profile set fullname = '%s' where uid = %d and is_default = 1", + dbesc($sitename), + intval($sys['channel_id']) + ); + q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", + dbesc($sitename), + dbesc(datetime_convert()), + dbesc($sys['channel_hash']) + ); + } + if ($siteinfo) { + q("update profile set about = '%s' where uid = %d and is_default = 1", + dbesc($siteinfo), + intval($sys['channel_id']) + ); + } + } + return UPDATE_SUCCESS; + } - function verify() { - return true; - } + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1253.php b/Zotlabs/Update/_1253.php index 4874ff51d..0b338bbe5 100644 --- a/Zotlabs/Update/_1253.php +++ b/Zotlabs/Update/_1253.php @@ -4,25 +4,28 @@ namespace Zotlabs\Update; use Zotlabs\Lib\Config; -class _1253 { +class _1253 +{ - function run() { - $mode = PUBLIC_STREAM_NONE; - if (Config::Get('system','site_firehose')) { - $mode = PUBLIC_STREAM_SITE; - } - if (intval(Config::Get('system','disable_discover_tab',1)) === 0) { - $mode = PUBLIC_STREAM_FULL; - } - Config::Set('system','public_stream_mode', $mode); - Config::Delete('system','disable_discover_tab'); - Config::Delete('system','site_firehose'); - - return UPDATE_SUCCESS; - } + public function run() + { + $mode = PUBLIC_STREAM_NONE; + if (Config::Get('system', 'site_firehose')) { + $mode = PUBLIC_STREAM_SITE; + } + if (intval(Config::Get('system', 'disable_discover_tab', 1)) === 0) { + $mode = PUBLIC_STREAM_FULL; + } + Config::Set('system', 'public_stream_mode', $mode); + Config::Delete('system', 'disable_discover_tab'); + Config::Delete('system', 'site_firehose'); - function verify() { - return true; - } + return UPDATE_SUCCESS; + } + + public function verify() + { + return true; + } } diff --git a/Zotlabs/Update/_1254.php b/Zotlabs/Update/_1254.php index 460642861..d443d5183 100644 --- a/Zotlabs/Update/_1254.php +++ b/Zotlabs/Update/_1254.php @@ -4,17 +4,20 @@ namespace Zotlabs\Update; use Zotlabs\Lib\Config; -class _1254 { +class _1254 +{ - function run() { - q("UPDATE channel SET channel_notifyflags = channel_notifyflags + %d WHERE true", - intval(NOTIFY_RESHARE) - ); - return UPDATE_SUCCESS; - } + public function run() + { + q("UPDATE channel SET channel_notifyflags = channel_notifyflags + %d WHERE true", + intval(NOTIFY_RESHARE) + ); + return UPDATE_SUCCESS; + } - function verify() { - return true; - } + public function verify() + { + return true; + } } diff --git a/Zotlabs/Web/Controller.php b/Zotlabs/Web/Controller.php index a31737c1e..bccecaf96 100644 --- a/Zotlabs/Web/Controller.php +++ b/Zotlabs/Web/Controller.php @@ -7,11 +7,20 @@ namespace Zotlabs\Web; * */ -class Controller { +class Controller +{ - function init() {} - function post() {} - function get() {} + public function init() + { + } + + public function post() + { + } + + public function get() + { + } } diff --git a/Zotlabs/Web/HTTPHeaders.php b/Zotlabs/Web/HTTPHeaders.php index 832e82dfa..44590cc5e 100644 --- a/Zotlabs/Web/HTTPHeaders.php +++ b/Zotlabs/Web/HTTPHeaders.php @@ -2,57 +2,60 @@ namespace Zotlabs\Web; -class HTTPHeaders { +class HTTPHeaders +{ - private $in_progress = []; - private $parsed = []; + private $in_progress = []; + private $parsed = []; - function __construct($headers) { + public function __construct($headers) + { - $lines = explode("\n",str_replace("\r",'',$headers)); - if ($lines) { - foreach ($lines as $line) { - if (preg_match('/^\s+/',$line,$matches) && trim($line)) { - if (isset($this->in_progress['k'])) { - $this->in_progress['v'] .= ' ' . ltrim($line); - continue; - } - } - else { - if (isset($this->in_progress['k'])) { - $this->parsed[] = [ $this->in_progress['k'] => $this->in_progress['v'] ]; - $this->in_progress = []; - } - $key = strtolower(substr($line,0,strpos($line,':'))); - if ($key) { - $this->in_progress['k'] = $key; - $this->in_progress['v'] = ltrim(substr($line,strpos($line,':') + 1)); - } - } + $lines = explode("\n", str_replace("\r", '', $headers)); + if ($lines) { + foreach ($lines as $line) { + if (preg_match('/^\s+/', $line, $matches) && trim($line)) { + if (isset($this->in_progress['k'])) { + $this->in_progress['v'] .= ' ' . ltrim($line); + continue; + } + } else { + if (isset($this->in_progress['k'])) { + $this->parsed[] = [$this->in_progress['k'] => $this->in_progress['v']]; + $this->in_progress = []; + } + $key = strtolower(substr($line, 0, strpos($line, ':'))); + if ($key) { + $this->in_progress['k'] = $key; + $this->in_progress['v'] = ltrim(substr($line, strpos($line, ':') + 1)); + } + } - } - if (isset($this->in_progress['k'])) { - $this->parsed[] = [ $this->in_progress['k'] => $this->in_progress['v'] ]; - $this->in_progress = []; - } - } - } + } + if (isset($this->in_progress['k'])) { + $this->parsed[] = [$this->in_progress['k'] => $this->in_progress['v']]; + $this->in_progress = []; + } + } + } - function fetch() { - return $this->parsed; - } + public function fetch() + { + return $this->parsed; + } - function fetcharr() { - $ret = []; - if ($this->parsed) { - foreach ($this->parsed as $x) { - foreach ($x as $y => $z) { - $ret[$y] = $z; - } - } - } - return $ret; - } + public function fetcharr() + { + $ret = []; + if ($this->parsed) { + foreach ($this->parsed as $x) { + foreach ($x as $y => $z) { + $ret[$y] = $z; + } + } + } + return $ret; + } } diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php index 2baebf8ef..947f4ba1b 100644 --- a/Zotlabs/Web/HTTPSig.php +++ b/Zotlabs/Web/HTTPSig.php @@ -17,677 +17,683 @@ use Zotlabs\Lib\Keyutils; * * @see https://tools.ietf.org/html/draft-cavage-http-signatures-10 */ +class HTTPSig +{ + + /** + * @brief RFC5843 + * + * @see https://tools.ietf.org/html/rfc5843 + * + * @param string $body The value to create the digest for + * @param string $alg hash algorithm (one of 'sha256','sha512') + * @return string The generated digest header string for $body + */ + + public static function generate_digest_header($body, $alg = 'sha256') + { + + $digest = base64_encode(hash($alg, $body, true)); + switch ($alg) { + case 'sha512': + return 'SHA-512=' . $digest; + case 'sha256': + default: + return 'SHA-256=' . $digest; + break; + } + } + + + public static function find_headers($data, &$body) + { + + // decide if $data arrived via controller submission or curl + // changes $body for the caller + + if (is_array($data) && array_key_exists('header', $data)) { + if (!$data['success']) { + $body = EMPTY_STR; + return []; + } + + if (!$data['header']) { + $body = EMPTY_STR; + return []; + } + + $h = new HTTPHeaders($data['header']); + $headers = $h->fetcharr(); + $body = $data['body']; + $headers['(request-target)'] = $data['request_target']; + } else { + $headers = []; + $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; + $headers['content-type'] = $_SERVER['CONTENT_TYPE']; + $headers['content-length'] = $_SERVER['CONTENT_LENGTH']; + + foreach ($_SERVER as $k => $v) { + if (strpos($k, 'HTTP_') === 0) { + $field = str_replace('_', '-', strtolower(substr($k, 5))); + $headers[$field] = $v; + } + } + } + + //logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL); + //logger('headers: ' . print_r($headers,true), LOGGER_ALL); + + return $headers; + } + + + // See draft-cavage-http-signatures-10 + + public static function verify($data, $key = '', $keytype = '') + { + + $body = $data; + $headers = null; + + $result = [ + 'signer' => '', + 'portable_id' => '', + 'header_signed' => false, + 'header_valid' => false, + 'content_signed' => false, + 'content_valid' => false + ]; + + + $headers = self::find_headers($data, $body); + + if (!$headers) { + return $result; + } + + if (is_array($body)) { + btlogger('body is array!' . print_r($body, true)); + } + + + $sig_block = null; + + if (array_key_exists('signature', $headers)) { + $sig_block = self::parse_sigheader($headers['signature']); + } elseif (array_key_exists('authorization', $headers)) { + $sig_block = self::parse_sigheader($headers['authorization']); + } + + if (!$sig_block) { + logger('no signature provided.', LOGGER_DEBUG); + return $result; + } + + // Warning: This log statement includes binary data + // logger('sig_block: ' . print_r($sig_block,true), LOGGER_DATA); + + $result['header_signed'] = true; + + $signed_headers = $sig_block['headers']; + if (!$signed_headers) { + $signed_headers = ['date']; + } + $signed_data = ''; + foreach ($signed_headers as $h) { + if (array_key_exists($h, $headers)) { + $signed_data .= $h . ': ' . $headers[$h] . "\n"; + } + if ($h === '(created)') { + if ($sig_block['algorithm'] && (strpos($sig_block['algorithm'], 'rsa') !== false || strpos($sig_block['algorithm'], 'hmac') !== false || strpos($sig_block['algorithm'], 'ecdsa') !== false)) { + logger('created not allowed here'); + return $result; + } + if ((!isset($sig_block['(created)'])) || (!intval($sig_block['(created)'])) || intval($sig_block['(created)']) > time()) { + logger('created in future'); + return $result; + } + $signed_data .= '(created): ' . $sig_block['(created)'] . "\n"; + } + if ($h === '(expires)') { + if ($sig_block['algorithm'] && (strpos($sig_block['algorithm'], 'rsa') !== false || strpos($sig_block['algorithm'], 'hmac') !== false || strpos($sig_block['algorithm'], 'ecdsa') !== false)) { + logger('expires not allowed here'); + return $result; + } + if ((!isset($sig_block['(expires)'])) || (!intval($sig_block['(expires)'])) || intval($sig_block['(expires)']) < time()) { + logger('signature expired'); + return $result; + } + $signed_data .= '(expires): ' . $sig_block['(expires)'] . "\n"; + } + if ($h === 'date') { + $d = new DateTime($headers[$h]); + $d->setTimeZone(new DateTimeZone('UTC')); + $dplus = datetime_convert('UTC', 'UTC', 'now + 1 day'); + $dminus = datetime_convert('UTC', 'UTC', 'now - 1 day'); + $c = $d->format('Y-m-d H:i:s'); + if ($c > $dplus || $c < $dminus) { + logger('bad time: ' . $c); + return $result; + } + } + } + $signed_data = rtrim($signed_data, "\n"); + + $algorithm = null; + + if ($sig_block['algorithm'] === 'rsa-sha256') { + $algorithm = 'sha256'; + } + if ($sig_block['algorithm'] === 'rsa-sha512') { + $algorithm = 'sha512'; + } + + if (!array_key_exists('keyId', $sig_block)) { + return $result; + } + + $result['signer'] = $sig_block['keyId']; + + $fkey = self::get_key($key, $keytype, $result['signer']); + + if ($sig_block['algorithm'] === 'hs2019') { + if (isset($fkey['algorithm'])) { + if (strpos($fkey['algorithm'], 'rsa-sha256') !== false) { + $algorithm = 'sha256'; + } + if (strpos($fkey['algorithm'], 'rsa-sha512') !== false) { + $algorithm = 'sha512'; + } + } + } + + + if (!($fkey && $fkey['public_key'])) { + return $result; + } + + $x = Crypto::verify($signed_data, $sig_block['signature'], $fkey['public_key'], $algorithm); + + logger('verified: ' . $x, LOGGER_DEBUG); + + if (!$x) { + + // try again, ignoring the local actor (xchan) cache and refetching the key + // from its source + + $fkey = self::get_key($key, $keytype, $result['signer'], true); + + if ($fkey && $fkey['public_key']) { + $y = Crypto::verify($signed_data, $sig_block['signature'], $fkey['public_key'], $algorithm); + logger('verified: (cache reload) ' . $x, LOGGER_DEBUG); + } + + if (!$y) { + logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($fkey['public_key']) ? '' : ' no key')); + $sig_block['signature'] = base64_encode($sig_block['signature']); + logger('affected sigblock: ' . print_r($sig_block, true)); + logger('headers: ' . print_r($headers, true)); + logger('server: ' . print_r($_SERVER, true)); + return $result; + } + } + + $result['portable_id'] = $fkey['portable_id']; + $result['header_valid'] = true; + + if (in_array('digest', $signed_headers)) { + $result['content_signed'] = true; + $digest = explode('=', $headers['digest'], 2); + if ($digest[0] === 'SHA-256') { + $hashalg = 'sha256'; + } + if ($digest[0] === 'SHA-512') { + $hashalg = 'sha512'; + } + + if (base64_encode(hash($hashalg, $body, true)) === $digest[1]) { + $result['content_valid'] = true; + } + + logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false')); + if (!$result['content_valid']) { + logger('invalid content signature: data ' . print_r($data, true)); + logger('invalid content signature: headers ' . print_r($headers, true)); + logger('invalid content signature: body ' . print_r($body, true)); + } + } + + return $result; + } + + public static function get_key($key, $keytype, $id, $force = false) + { + + if ($key) { + if (function_exists($key)) { + return $key($id); + } + return ['public_key' => $key]; + } + + if ($keytype === 'zot6') { + $key = self::get_zotfinger_key($id, $force); + if ($key) { + return $key; + } + } + + + if (strpos($id, '#') === false) { + $key = self::get_webfinger_key($id, $force); + if ($key) { + return $key; + } + } -class HTTPSig { - - /** - * @brief RFC5843 - * - * @see https://tools.ietf.org/html/rfc5843 - * - * @param string $body The value to create the digest for - * @param string $alg hash algorithm (one of 'sha256','sha512') - * @return string The generated digest header string for $body - */ - - static function generate_digest_header($body,$alg = 'sha256') { - - $digest = base64_encode(hash($alg, $body, true)); - switch ($alg) { - case 'sha512': - return 'SHA-512=' . $digest; - case 'sha256': - default: - return 'SHA-256=' . $digest; - break; - } - } - - - - static function find_headers($data,&$body) { - - // decide if $data arrived via controller submission or curl - // changes $body for the caller - - if (is_array($data) && array_key_exists('header',$data)) { - if (! $data['success']) { - $body = EMPTY_STR; - return []; - } - - if (! $data['header']) { - $body = EMPTY_STR; - return []; - } - - $h = new HTTPHeaders($data['header']); - $headers = $h->fetcharr(); - $body = $data['body']; - $headers['(request-target)'] = $data['request_target']; - } - - else { - $headers = []; - $headers['(request-target)'] = strtolower($_SERVER['REQUEST_METHOD']) . ' ' . $_SERVER['REQUEST_URI']; - $headers['content-type'] = $_SERVER['CONTENT_TYPE']; - $headers['content-length'] = $_SERVER['CONTENT_LENGTH']; - - foreach ($_SERVER as $k => $v) { - if (strpos($k,'HTTP_') === 0) { - $field = str_replace('_','-',strtolower(substr($k,5))); - $headers[$field] = $v; - } - } - } - - //logger('SERVER: ' . print_r($_SERVER,true), LOGGER_ALL); - //logger('headers: ' . print_r($headers,true), LOGGER_ALL); - - return $headers; - } - - - // See draft-cavage-http-signatures-10 - - static function verify($data,$key = '', $keytype = '') { - - $body = $data; - $headers = null; - - $result = [ - 'signer' => '', - 'portable_id' => '', - 'header_signed' => false, - 'header_valid' => false, - 'content_signed' => false, - 'content_valid' => false - ]; - - - $headers = self::find_headers($data,$body); - - if (! $headers) { - return $result; - } - - if (is_array($body)) { - btlogger('body is array!' . print_r($body,true)); - } - - - $sig_block = null; - - if (array_key_exists('signature',$headers)) { - $sig_block = self::parse_sigheader($headers['signature']); - } - elseif (array_key_exists('authorization',$headers)) { - $sig_block = self::parse_sigheader($headers['authorization']); - } - - if (! $sig_block) { - logger('no signature provided.', LOGGER_DEBUG); - return $result; - } - - // Warning: This log statement includes binary data - // logger('sig_block: ' . print_r($sig_block,true), LOGGER_DATA); - - $result['header_signed'] = true; - - $signed_headers = $sig_block['headers']; - if (! $signed_headers) { - $signed_headers = [ 'date' ]; - } - $signed_data = ''; - foreach ($signed_headers as $h) { - if (array_key_exists($h,$headers)) { - $signed_data .= $h . ': ' . $headers[$h] . "\n"; - } - if ($h === '(created)') { - if ($sig_block['algorithm'] && (strpos($sig_block['algorithm'],'rsa') !== false || strpos($sig_block['algorithm'],'hmac') !== false || strpos($sig_block['algorithm'],'ecdsa') !== false)) { - logger('created not allowed here'); - return $result; - } - if ((! isset($sig_block['(created)'])) || (! intval($sig_block['(created)'])) || intval($sig_block['(created)']) > time()) { - logger('created in future'); - return $result; - } - $signed_data .= '(created): ' . $sig_block['(created)'] . "\n"; - } - if ($h === '(expires)') { - if ($sig_block['algorithm'] && (strpos($sig_block['algorithm'],'rsa') !== false || strpos($sig_block['algorithm'],'hmac') !== false || strpos($sig_block['algorithm'],'ecdsa') !== false)) { - logger('expires not allowed here'); - return $result; - } - if ((! isset($sig_block['(expires)'])) || (! intval($sig_block['(expires)'])) || intval($sig_block['(expires)']) < time()) { - logger('signature expired'); - return $result; - } - $signed_data .= '(expires): ' . $sig_block['(expires)'] . "\n"; - } - if ($h === 'date') { - $d = new DateTime($headers[$h]); - $d->setTimeZone(new DateTimeZone('UTC')); - $dplus = datetime_convert('UTC','UTC','now + 1 day'); - $dminus = datetime_convert('UTC','UTC','now - 1 day'); - $c = $d->format('Y-m-d H:i:s'); - if ($c > $dplus || $c < $dminus) { - logger('bad time: ' . $c); - return $result; - } - } - } - $signed_data = rtrim($signed_data,"\n"); - - $algorithm = null; - - if ($sig_block['algorithm'] === 'rsa-sha256') { - $algorithm = 'sha256'; - } - if ($sig_block['algorithm'] === 'rsa-sha512') { - $algorithm = 'sha512'; - } - - if (! array_key_exists('keyId',$sig_block)) { - return $result; - } - - $result['signer'] = $sig_block['keyId']; - - $fkey = self::get_key($key,$keytype,$result['signer']); - - if ($sig_block['algorithm'] === 'hs2019') { - if (isset($fkey['algorithm'])) { - if (strpos($fkey['algorithm'],'rsa-sha256') !== false) { - $algorithm = 'sha256'; - } - if (strpos($fkey['algorithm'],'rsa-sha512') !== false) { - $algorithm = 'sha512'; - } - } - } - - - if (! ($fkey && $fkey['public_key'])) { - return $result; - } - - $x = Crypto::verify($signed_data,$sig_block['signature'],$fkey['public_key'],$algorithm); - - logger('verified: ' . $x, LOGGER_DEBUG); - - if (! $x) { - - // try again, ignoring the local actor (xchan) cache and refetching the key - // from its source - - $fkey = self::get_key($key,$keytype,$result['signer'],true); - - if ($fkey && $fkey['public_key']) { - $y = Crypto::verify($signed_data,$sig_block['signature'],$fkey['public_key'],$algorithm); - logger('verified: (cache reload) ' . $x, LOGGER_DEBUG); - } - - if (! $y) { - logger('verify failed for ' . $result['signer'] . ' alg=' . $algorithm . (($fkey['public_key']) ? '' : ' no key')); - $sig_block['signature'] = base64_encode($sig_block['signature']); - logger('affected sigblock: ' . print_r($sig_block,true)); - logger('headers: ' . print_r($headers,true)); - logger('server: ' . print_r($_SERVER,true)); - return $result; - } - } - - $result['portable_id'] = $fkey['portable_id']; - $result['header_valid'] = true; - - if (in_array('digest',$signed_headers)) { - $result['content_signed'] = true; - $digest = explode('=', $headers['digest'], 2); - if ($digest[0] === 'SHA-256') { - $hashalg = 'sha256'; - } - if ($digest[0] === 'SHA-512') { - $hashalg = 'sha512'; - } - - if (base64_encode(hash($hashalg,$body,true)) === $digest[1]) { - $result['content_valid'] = true; - } - - logger('Content_Valid: ' . (($result['content_valid']) ? 'true' : 'false')); - if (! $result['content_valid']) { - logger('invalid content signature: data ' . print_r($data,true)); - logger('invalid content signature: headers ' . print_r($headers,true)); - logger('invalid content signature: body ' . print_r($body,true)); - } - } - - return $result; - } - - static function get_key($key,$keytype,$id,$force = false) { - - if ($key) { - if (function_exists($key)) { - return $key($id); - } - return [ 'public_key' => $key ]; - } - - if ($keytype === 'zot6') { - $key = self::get_zotfinger_key($id,$force); - if ($key) { - return $key; - } - } - - - if (strpos($id,'#') === false) { - $key = self::get_webfinger_key($id,$force); - if ($key) { - return $key; - } - } - - $key = self::get_activitystreams_key($id,$force); - return $key; - - } - - - static function convertKey($key) { - - if (strstr($key,'RSA ')) { - return Keyutils::rsatopem($key); - } - elseif (substr($key,0,5) === 'data:') { - return Keyutils::convertSalmonKey($key); - } - else { - return $key; - } - - } - - - /** - * @brief - * - * @param string $id - * @return boolean|string - * false if no pub key found, otherwise return the pub key - */ - - static function get_activitystreams_key($id,$force = false) { - - // Check the local cache first, but remove any fragments like #main-key since these won't be present in our cached data - - $cache_url = ((strpos($id,'#')) ? substr($id,0,strpos($id,'#')) : $id); - - // $force is used to ignore the local cache and only use the remote data; for instance the cached key might be stale - - if (! $force) { - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') order by hubloc_id desc", - dbesc(str_replace('acct:','',$cache_url)), - dbesc($cache_url), - dbesc($cache_url) - ); - - if ($x) { - $best = Libzot::zot_record_preferred($x); - } - - if ($best && $best['xchan_pubkey']) { - return [ 'portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'] , 'algorithm' => get_xconfig($best['xchan_hash'],'system','signing_algorithm'), 'hubloc' => $best ]; - } - } - - // The record wasn't in cache. Fetch it now. - - $r = Activity::fetch($id); - $signatureAlgorithm = EMPTY_STR; - - if ($r) { - if (array_key_exists('publicKey',$r) && array_key_exists('publicKeyPem',$r['publicKey']) && array_key_exists('id',$r['publicKey'])) { - if ($r['publicKey']['id'] === $id || $r['id'] === $id) { - $portable_id = ((array_key_exists('owner',$r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR); - - // the w3c sec context has conflicting names and no defined values for this property except - // "http://www.w3.org/2000/09/xmldsig#rsa-sha1" - - // Since the names conflict, it could mess up LD-signatures but we will accept both, and at this - // time we will only look for the substrings 'rsa-sha256' and 'rsa-sha512' within those properties. - // We will also accept a toplevel 'sigAlgorithm' regardless of namespace with the same constraints. - // Default to rsa-sha256 if we can't figure out. If they're sending 'hs2019' we have to - // look for something. - - if (isset($r['publicKey']['signingAlgorithm'])) { - $signatureAlgorithm = $r['publicKey']['signingAlgorithm']; - set_xconfig($portable_id,'system','signing_algorithm',$signatureAlgorithm); - } - if (isset($r['publicKey']['signatureAlgorithm'])) { - $signatureAlgorithm = $r['publicKey']['signatureAlgorithm']; - set_xconfig($portable_id,'system','signing_algorithm',$signatureAlgorithm); - } - - if (isset($r['sigAlgorithm'])) { - $signatureAlgorithm = $r['sigAlgorithm']; - set_xconfig($portable_id,'system','signing_algorithm',$signatureAlgorithm); - } - - return [ 'public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'algorithm' => (($signatureAlgorithm) ? $signatureAlgorithm : 'rsa-sha256'), 'hubloc' => [] ]; - } - } - } - - // No key was found - - return false; - } - - - static function get_webfinger_key($id,$force = false) { - - if (! $force) { - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') order by hubloc_id desc", - dbesc(str_replace('acct:','',$id)), - dbesc($id), - dbesc($id) - ); - - if ($x) { - $best = Libzot::zot_record_preferred($x); - } - - if ($best && $best['xchan_pubkey']) { - return [ 'portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'] , 'algorithm' => get_xconfig($best['xchan_hash'],'system','signing_algorithm'), 'hubloc' => $best ]; - } - } - - $wf = Webfinger::exec($id); - $key = [ 'portable_id' => '', 'public_key' => '', 'algorithm' => '', 'hubloc' => [] ]; - - if ($wf) { - if (array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) { - $key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']); - } - if (array_key_exists('links', $wf) && is_array($wf['links'])) { - foreach ($wf['links'] as $l) { - if (! (is_array($l) && array_key_exists('rel',$l))) { - continue; - } - if ($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) { - $key['public_key'] = self::convertKey($l['href']); - } - } - } - } - - return (($key['public_key']) ? $key : false); - } - - - static function get_zotfinger_key($id,$force = false) { - - if (! $force) { - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) and hubloc_network = 'zot6' order by hubloc_id desc", - dbesc(str_replace('acct:','',$id)), - dbesc($id) - ); - - if ($x) { - $best = Libzot::zot_record_preferred($x); - } - - if ($best && $best['xchan_pubkey']) { - return [ 'portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'] , 'algorithm' => get_xconfig($best['xchan_hash'],'system','signing_algorithm'), 'hubloc' => $best ]; - } - } - - $wf = Webfinger::exec($id); - $key = [ 'portable_id' => '', 'public_key' => '', 'algorithm' => '', 'hubloc' => [] ]; - - if ($wf) { - if (array_key_exists('properties',$wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem',$wf['properties'])) { - $key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']); - } - if (array_key_exists('links', $wf) && is_array($wf['links'])) { - foreach ($wf['links'] as $l) { - if (! (is_array($l) && array_key_exists('rel',$l))) { - continue; - } - if ($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href',$l) && $l['href'] !== EMPTY_STR) { - - // The third argument to Zotfinger::exec() tells it not to verify signatures - // Since we're inside a function that is fetching keys with which to verify signatures, - // this is necessary to prevent infinite loops. - - $z = Zotfinger::exec($l['href'], null, false); - if ($z) { - $i = Libzot::import_xchan($z['data']); - if ($i['success']) { - $key['portable_id'] = $i['hash']; - - $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' order by hubloc_id desc limit 1", - dbesc($l['href']) - ); - if ($x) { - $key['hubloc'] = $x[0]; - } - $key['algorithm'] = get_xconfig($i['hash'],'system','signing_algorithm'); - } - } - } - if ($l['rel'] === 'magic-public-key' && array_key_exists('href',$l) && $key['public_key'] === EMPTY_STR) { - $key['public_key'] = self::convertKey($l['href']); - } - } - } - } - - return (($key['public_key']) ? $key : false); - } - - - /** - * @brief - * - * @param array $head - * @param string $prvkey - * @param string $keyid (optional, default '') - * @param boolean $auth (optional, default false) - * @param string $alg (optional, default 'sha256') - * @param array $encryption [ 'key', 'algorithm' ] or false - * @return array - */ - static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false ) { - - $return_headers = []; - - if ($alg === 'sha256') { - $algorithm = 'rsa-sha256'; - } - if ($alg === 'sha512') { - $algorithm = 'rsa-sha512'; - } - - $x = self::sign($head,$prvkey,$alg); - - $headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"'; - - if ($encryption) { - $x = Crypto::encapsulate($headerval,$encryption['key'],$encryption['algorithm']); - if (is_array($x)) { - $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"'; - } - } - - if ($auth) { - $sighead = 'Authorization: Signature ' . $headerval; - } - else { - $sighead = 'Signature: ' . $headerval; - } - - if ($head) { - foreach ($head as $k => $v) { - // strip the request-target virtual header from the output headers - if ($k === '(request-target)') { - continue; - } - $return_headers[] = $k . ': ' . $v; - } - } - $return_headers[] = $sighead; - - return $return_headers; - } - - /** - * @brief set headers - * - * @param array $headers - * @return void - */ - - static function set_headers($headers) { - if ($headers && is_array($headers)) { - foreach ($headers as $h) { - header($h); - } - } - } - - - /** - * @brief - * - * @param array $head - * @param string $prvkey - * @param string $alg (optional) default 'sha256' - * @return array - */ - - static function sign($head, $prvkey, $alg = 'sha256') { - - $ret = []; - - $headers = ''; - $fields = ''; - - logger('signing: ' . print_r($head,true), LOGGER_DATA); - - if ($head) { - foreach ($head as $k => $v) { - $headers .= strtolower($k) . ': ' . trim($v) . "\n"; - if ($fields) { - $fields .= ' '; - } - $fields .= strtolower($k); - } - // strip the trailing linefeed - $headers = rtrim($headers,"\n"); - } - - $sig = base64_encode(Crypto::sign($headers,$prvkey,$alg)); - - $ret['headers'] = $fields; - $ret['signature'] = $sig; - - return $ret; - } - - /** - * @brief - * - * @param string $header - * @return array associate array with - * - \e string \b keyID - * - \e string \b algorithm - * - \e array \b headers - * - \e string \b signature - */ - - static function parse_sigheader($header) { - - $ret = []; - $matches = []; - - // if the header is encrypted, decrypt with (default) site private key and continue - - if (preg_match('/iv="(.*?)"/ism',$header,$matches)) { - $header = self::decrypt_sigheader($header); - } - - if (preg_match('/keyId="(.*?)"/ism',$header,$matches)) { - $ret['keyId'] = $matches[1]; - } - if (preg_match('/created=([0-9]*)/ism',$header,$matches)) { - $ret['(created)'] = $matches[1]; - } - if (preg_match('/expires=([0-9]*)/ism',$header,$matches)) { - $ret['(expires)'] = $matches[1]; - } - if (preg_match('/algorithm="(.*?)"/ism',$header,$matches)) { - $ret['algorithm'] = $matches[1]; - } - if (preg_match('/headers="(.*?)"/ism',$header,$matches)) { - $ret['headers'] = explode(' ', $matches[1]); - } - if (preg_match('/signature="(.*?)"/ism',$header,$matches)) { - $ret['signature'] = base64_decode(preg_replace('/\s+/','',$matches[1])); - } - - if (($ret['signature']) && ($ret['algorithm']) && (! $ret['headers'])) { - $ret['headers'] = [ 'date' ]; - } - - return $ret; - } - - - /** - * @brief - * - * @param string $header - * @param string $prvkey (optional), if not set use site private key - * @return array|string associative array, empty string if failue - * - \e string \b iv - * - \e string \b key - * - \e string \b alg - * - \e string \b data - */ - - static function decrypt_sigheader($header, $prvkey = null) { - - $iv = $key = $alg = $data = null; - - if (! $prvkey) { - $prvkey = get_config('system', 'prvkey'); - } - - $matches = []; - - if (preg_match('/iv="(.*?)"/ism',$header,$matches)) { - $iv = $matches[1]; - } - if (preg_match('/key="(.*?)"/ism',$header,$matches)) { - $key = $matches[1]; - } - if (preg_match('/alg="(.*?)"/ism',$header,$matches)) { - $alg = $matches[1]; - } - if (preg_match('/data="(.*?)"/ism',$header,$matches)) { - $data = $matches[1]; - } - - if ($iv && $key && $alg && $data) { - return Crypto::unencapsulate([ 'encrypted' => true, 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data ] , $prvkey); - } - - return ''; - } + $key = self::get_activitystreams_key($id, $force); + return $key; + + } + + + public static function convertKey($key) + { + + if (strstr($key, 'RSA ')) { + return Keyutils::rsatopem($key); + } elseif (substr($key, 0, 5) === 'data:') { + return Keyutils::convertSalmonKey($key); + } else { + return $key; + } + + } + + + /** + * @brief + * + * @param string $id + * @return bool|string + * false if no pub key found, otherwise return the pub key + */ + + public static function get_activitystreams_key($id, $force = false) + { + + // Check the local cache first, but remove any fragments like #main-key since these won't be present in our cached data + + $cache_url = ((strpos($id, '#')) ? substr($id, 0, strpos($id, '#')) : $id); + + // $force is used to ignore the local cache and only use the remote data; for instance the cached key might be stale + + if (!$force) { + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') order by hubloc_id desc", + dbesc(str_replace('acct:', '', $cache_url)), + dbesc($cache_url), + dbesc($cache_url) + ); + + if ($x) { + $best = Libzot::zot_record_preferred($x); + } + + if ($best && $best['xchan_pubkey']) { + return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best]; + } + } + + // The record wasn't in cache. Fetch it now. + + $r = Activity::fetch($id); + $signatureAlgorithm = EMPTY_STR; + + if ($r) { + if (array_key_exists('publicKey', $r) && array_key_exists('publicKeyPem', $r['publicKey']) && array_key_exists('id', $r['publicKey'])) { + if ($r['publicKey']['id'] === $id || $r['id'] === $id) { + $portable_id = ((array_key_exists('owner', $r['publicKey'])) ? $r['publicKey']['owner'] : EMPTY_STR); + + // the w3c sec context has conflicting names and no defined values for this property except + // "http://www.w3.org/2000/09/xmldsig#rsa-sha1" + + // Since the names conflict, it could mess up LD-signatures but we will accept both, and at this + // time we will only look for the substrings 'rsa-sha256' and 'rsa-sha512' within those properties. + // We will also accept a toplevel 'sigAlgorithm' regardless of namespace with the same constraints. + // Default to rsa-sha256 if we can't figure out. If they're sending 'hs2019' we have to + // look for something. + + if (isset($r['publicKey']['signingAlgorithm'])) { + $signatureAlgorithm = $r['publicKey']['signingAlgorithm']; + set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm); + } + if (isset($r['publicKey']['signatureAlgorithm'])) { + $signatureAlgorithm = $r['publicKey']['signatureAlgorithm']; + set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm); + } + + if (isset($r['sigAlgorithm'])) { + $signatureAlgorithm = $r['sigAlgorithm']; + set_xconfig($portable_id, 'system', 'signing_algorithm', $signatureAlgorithm); + } + + return ['public_key' => self::convertKey($r['publicKey']['publicKeyPem']), 'portable_id' => $portable_id, 'algorithm' => (($signatureAlgorithm) ? $signatureAlgorithm : 'rsa-sha256'), 'hubloc' => []]; + } + } + } + + // No key was found + + return false; + } + + + public static function get_webfinger_key($id, $force = false) + { + + if (!$force) { + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s') order by hubloc_id desc", + dbesc(str_replace('acct:', '', $id)), + dbesc($id), + dbesc($id) + ); + + if ($x) { + $best = Libzot::zot_record_preferred($x); + } + + if ($best && $best['xchan_pubkey']) { + return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best]; + } + } + + $wf = Webfinger::exec($id); + $key = ['portable_id' => '', 'public_key' => '', 'algorithm' => '', 'hubloc' => []]; + + if ($wf) { + if (array_key_exists('properties', $wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem', $wf['properties'])) { + $key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']); + } + if (array_key_exists('links', $wf) && is_array($wf['links'])) { + foreach ($wf['links'] as $l) { + if (!(is_array($l) && array_key_exists('rel', $l))) { + continue; + } + if ($l['rel'] === 'magic-public-key' && array_key_exists('href', $l) && $key['public_key'] === EMPTY_STR) { + $key['public_key'] = self::convertKey($l['href']); + } + } + } + } + + return (($key['public_key']) ? $key : false); + } + + + public static function get_zotfinger_key($id, $force = false) + { + + if (!$force) { + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where ( hubloc_addr = '%s' or hubloc_id_url = '%s' ) and hubloc_network = 'zot6' order by hubloc_id desc", + dbesc(str_replace('acct:', '', $id)), + dbesc($id) + ); + + if ($x) { + $best = Libzot::zot_record_preferred($x); + } + + if ($best && $best['xchan_pubkey']) { + return ['portable_id' => $best['xchan_hash'], 'public_key' => $best['xchan_pubkey'], 'algorithm' => get_xconfig($best['xchan_hash'], 'system', 'signing_algorithm'), 'hubloc' => $best]; + } + } + + $wf = Webfinger::exec($id); + $key = ['portable_id' => '', 'public_key' => '', 'algorithm' => '', 'hubloc' => []]; + + if ($wf) { + if (array_key_exists('properties', $wf) && array_key_exists('https://w3id.org/security/v1#publicKeyPem', $wf['properties'])) { + $key['public_key'] = self::convertKey($wf['properties']['https://w3id.org/security/v1#publicKeyPem']); + } + if (array_key_exists('links', $wf) && is_array($wf['links'])) { + foreach ($wf['links'] as $l) { + if (!(is_array($l) && array_key_exists('rel', $l))) { + continue; + } + if ($l['rel'] === 'http://purl.org/zot/protocol/6.0' && array_key_exists('href', $l) && $l['href'] !== EMPTY_STR) { + + // The third argument to Zotfinger::exec() tells it not to verify signatures + // Since we're inside a function that is fetching keys with which to verify signatures, + // this is necessary to prevent infinite loops. + + $z = Zotfinger::exec($l['href'], null, false); + if ($z) { + $i = Libzot::import_xchan($z['data']); + if ($i['success']) { + $key['portable_id'] = $i['hash']; + + $x = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_id_url = '%s' order by hubloc_id desc limit 1", + dbesc($l['href']) + ); + if ($x) { + $key['hubloc'] = $x[0]; + } + $key['algorithm'] = get_xconfig($i['hash'], 'system', 'signing_algorithm'); + } + } + } + if ($l['rel'] === 'magic-public-key' && array_key_exists('href', $l) && $key['public_key'] === EMPTY_STR) { + $key['public_key'] = self::convertKey($l['href']); + } + } + } + } + + return (($key['public_key']) ? $key : false); + } + + + /** + * @brief + * + * @param array $head + * @param string $prvkey + * @param string $keyid (optional, default '') + * @param bool $auth (optional, default false) + * @param string $alg (optional, default 'sha256') + * @param array $encryption [ 'key', 'algorithm' ] or false + * @return array + */ + public static function create_sig($head, $prvkey, $keyid = EMPTY_STR, $auth = false, $alg = 'sha256', $encryption = false) + { + + $return_headers = []; + + if ($alg === 'sha256') { + $algorithm = 'rsa-sha256'; + } + if ($alg === 'sha512') { + $algorithm = 'rsa-sha512'; + } + + $x = self::sign($head, $prvkey, $alg); + + $headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"'; + + if ($encryption) { + $x = Crypto::encapsulate($headerval, $encryption['key'], $encryption['algorithm']); + if (is_array($x)) { + $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'] . '"'; + } + } + + if ($auth) { + $sighead = 'Authorization: Signature ' . $headerval; + } else { + $sighead = 'Signature: ' . $headerval; + } + + if ($head) { + foreach ($head as $k => $v) { + // strip the request-target virtual header from the output headers + if ($k === '(request-target)') { + continue; + } + $return_headers[] = $k . ': ' . $v; + } + } + $return_headers[] = $sighead; + + return $return_headers; + } + + /** + * @brief set headers + * + * @param array $headers + * @return void + */ + + public static function set_headers($headers) + { + if ($headers && is_array($headers)) { + foreach ($headers as $h) { + header($h); + } + } + } + + + /** + * @brief + * + * @param array $head + * @param string $prvkey + * @param string $alg (optional) default 'sha256' + * @return array + */ + + public static function sign($head, $prvkey, $alg = 'sha256') + { + + $ret = []; + + $headers = ''; + $fields = ''; + + logger('signing: ' . print_r($head, true), LOGGER_DATA); + + if ($head) { + foreach ($head as $k => $v) { + $headers .= strtolower($k) . ': ' . trim($v) . "\n"; + if ($fields) { + $fields .= ' '; + } + $fields .= strtolower($k); + } + // strip the trailing linefeed + $headers = rtrim($headers, "\n"); + } + + $sig = base64_encode(Crypto::sign($headers, $prvkey, $alg)); + + $ret['headers'] = $fields; + $ret['signature'] = $sig; + + return $ret; + } + + /** + * @brief + * + * @param string $header + * @return array associate array with + * - \e string \b keyID + * - \e string \b algorithm + * - \e array \b headers + * - \e string \b signature + */ + + public static function parse_sigheader($header) + { + + $ret = []; + $matches = []; + + // if the header is encrypted, decrypt with (default) site private key and continue + + if (preg_match('/iv="(.*?)"/ism', $header, $matches)) { + $header = self::decrypt_sigheader($header); + } + + if (preg_match('/keyId="(.*?)"/ism', $header, $matches)) { + $ret['keyId'] = $matches[1]; + } + if (preg_match('/created=([0-9]*)/ism', $header, $matches)) { + $ret['(created)'] = $matches[1]; + } + if (preg_match('/expires=([0-9]*)/ism', $header, $matches)) { + $ret['(expires)'] = $matches[1]; + } + if (preg_match('/algorithm="(.*?)"/ism', $header, $matches)) { + $ret['algorithm'] = $matches[1]; + } + if (preg_match('/headers="(.*?)"/ism', $header, $matches)) { + $ret['headers'] = explode(' ', $matches[1]); + } + if (preg_match('/signature="(.*?)"/ism', $header, $matches)) { + $ret['signature'] = base64_decode(preg_replace('/\s+/', '', $matches[1])); + } + + if (($ret['signature']) && ($ret['algorithm']) && (!$ret['headers'])) { + $ret['headers'] = ['date']; + } + + return $ret; + } + + + /** + * @brief + * + * @param string $header + * @param string $prvkey (optional), if not set use site private key + * @return array|string associative array, empty string if failue + * - \e string \b iv + * - \e string \b key + * - \e string \b alg + * - \e string \b data + */ + + public static function decrypt_sigheader($header, $prvkey = null) + { + + $iv = $key = $alg = $data = null; + + if (!$prvkey) { + $prvkey = get_config('system', 'prvkey'); + } + + $matches = []; + + if (preg_match('/iv="(.*?)"/ism', $header, $matches)) { + $iv = $matches[1]; + } + if (preg_match('/key="(.*?)"/ism', $header, $matches)) { + $key = $matches[1]; + } + if (preg_match('/alg="(.*?)"/ism', $header, $matches)) { + $alg = $matches[1]; + } + if (preg_match('/data="(.*?)"/ism', $header, $matches)) { + $data = $matches[1]; + } + + if ($iv && $key && $alg && $data) { + return Crypto::unencapsulate(['encrypted' => true, 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data], $prvkey); + } + + return ''; + } } diff --git a/Zotlabs/Web/HttpMeta.php b/Zotlabs/Web/HttpMeta.php index 4afd5b81f..9b361c9c9 100644 --- a/Zotlabs/Web/HttpMeta.php +++ b/Zotlabs/Web/HttpMeta.php @@ -3,112 +3,114 @@ namespace Zotlabs\Web; -class HttpMeta { +class HttpMeta +{ - private $vars = null; - private $og = null; + private $vars = null; + private $og = null; - function __construct() { + public function __construct() + { - $this->vars = []; - $this->og = []; - $this->ogproperties = []; + $this->vars = []; + $this->og = []; + $this->ogproperties = []; - } + } - //Set Meta Value - // Mode: - // 0 = Default - set if no value currently exists - // 1 = Overwrite - replace existing value(s) - // 2 = Multi - append to the array of values - function set($property,$value,$mode=0) { - $ogallowsmulti = ['image','audio','video']; - if (strpos($property,'og:') === 0) { - $count = 0; - foreach ($this->og as $ogk => $ogdata) { - if (strpos($ogdata['property'],$property) === 0) { - if ($mode == 1) { - unset($this->og[$ogk]); - unset($this->ogproperties[$property]); - } - elseif ($mode == 0) { - return; - } - elseif ($value == $ogdata['value']) { - return; - } - else { - $count++; - } - } - } + //Set Meta Value + // Mode: + // 0 = Default - set if no value currently exists + // 1 = Overwrite - replace existing value(s) + // 2 = Multi - append to the array of values + public function set($property, $value, $mode = 0) + { + $ogallowsmulti = ['image', 'audio', 'video']; + if (strpos($property, 'og:') === 0) { + $count = 0; + foreach ($this->og as $ogk => $ogdata) { + if (strpos($ogdata['property'], $property) === 0) { + if ($mode == 1) { + unset($this->og[$ogk]); + unset($this->ogproperties[$property]); + } elseif ($mode == 0) { + return; + } elseif ($value == $ogdata['value']) { + return; + } else { + $count++; + } + } + } - if ($value !== null) { - //mode = 1 with value === null will delete the property entirely. - $components = explode(':',$property); - $ogp=$components[1]; + if ($value !== null) { + //mode = 1 with value === null will delete the property entirely. + $components = explode(':', $property); + $ogp = $components[1]; - if (!$count || in_array($ogp,$ogallowsmulti)) { - $this->og[]=['property'=>$property,'value'=>$value]; - $this->ogproperties[$property] = $property; - } - } - } else { - $this->vars[$property] = $value; - } - } + if (!$count || in_array($ogp, $ogallowsmulti)) { + $this->og[] = ['property' => $property, 'value' => $value]; + $this->ogproperties[$property] = $property; + } + } + } else { + $this->vars[$property] = $value; + } + } - function check_required() { - if ( - in_array('og:title',$this->ogproperties) - && in_array('og:type', $this->ogproperties) - && (in_array('og:image',$this->ogproperties) - || in_array('og:image:url',$this->ogproperties)) - && (array_key_exists('og:url', $this->ogproperties) - || array_key_exists('og:url:secure_url', $this->ogproperties)) - && array_key_exists('og:description', $this->ogproperties) - ) { - return true; - } - return false; - } + public function check_required() + { + if ( + in_array('og:title', $this->ogproperties) + && in_array('og:type', $this->ogproperties) + && (in_array('og:image', $this->ogproperties) + || in_array('og:image:url', $this->ogproperties)) + && (array_key_exists('og:url', $this->ogproperties) + || array_key_exists('og:url:secure_url', $this->ogproperties)) + && array_key_exists('og:description', $this->ogproperties) + ) { + return true; + } + return false; + } - function get_field($field) { - if (strpos($field,'og:') === 0) { - foreach ($this->og as $ogdata) { - if (strpos($ogdata['property'],$field) === 0) { - $arr[$field][] = $ogdata['value']; - } - } - } - else { - $arr = $this->vars; - } - - if (isset($arr) && is_array($arr) && array_key_exists($field,$arr) && $arr[$field]) { - return $arr[$field]; - } - return false; - } + public function get_field($field) + { + if (strpos($field, 'og:') === 0) { + foreach ($this->og as $ogdata) { + if (strpos($ogdata['property'], $field) === 0) { + $arr[$field][] = $ogdata['value']; + } + } + } else { + $arr = $this->vars; + } + + if (isset($arr) && is_array($arr) && array_key_exists($field, $arr) && $arr[$field]) { + return $arr[$field]; + } + return false; + } - function get() { - // use 'name' for most meta fields, and 'property' for opengraph properties - $o = ''; - if ($this->vars) { - foreach ($this->vars as $k => $v) { - $o .= '' . "\r\n" ; - } - } - if ($this->check_required()) { - foreach ($this->og as $ogdata) { - $o .= '' . "\r\n" ; - } - } - if ($o) { - return "\r\n" . $o; - } - return $o; - } + public function get() + { + // use 'name' for most meta fields, and 'property' for opengraph properties + $o = ''; + if ($this->vars) { + foreach ($this->vars as $k => $v) { + $o .= '' . "\r\n"; + } + } + if ($this->check_required()) { + foreach ($this->og as $ogdata) { + $o .= '' . "\r\n"; + } + } + if ($o) { + return "\r\n" . $o; + } + return $o; + } } diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php index 4f1f3c220..8c5f606e1 100644 --- a/Zotlabs/Web/Router.php +++ b/Zotlabs/Web/Router.php @@ -33,237 +33,237 @@ use Exception; * so within the module init and/or post functions and then invoke killme() to terminate * further processing. */ -class Router { +class Router +{ - private $modname = ''; - private $controller = null; + private $modname = ''; + private $controller = null; - /** - * @brief Router constructor. - * - * @throws Exception module not found - */ - function __construct() { + /** + * @brief Router constructor. + * + * @throws Exception module not found + */ + public function __construct() + { - $module = App::$module; - $modname = "Zotlabs\\Module\\" . ucfirst($module); + $module = App::$module; + $modname = "Zotlabs\\Module\\" . ucfirst($module); - if (strlen($module)) { + if (strlen($module)) { - /* - * We will always have a module name. - * First see if we have a plugin handling this route - */ + /* + * We will always have a module name. + * First see if we have a plugin handling this route + */ - $routes = Route::get(); - if ($routes) { - foreach ($routes as $route) { - if (is_array($route) && strtolower($route[1]) === $module) { - if (file_exists($route[0])) { - include_once($route[0]); - } - if (class_exists($modname)) { - $this->controller = new $modname; - App::$module_loaded = true; - } - } - } - } + $routes = Route::get(); + if ($routes) { + foreach ($routes as $route) { + if (is_array($route) && strtolower($route[1]) === $module) { + if (file_exists($route[0])) { + include_once($route[0]); + } + if (class_exists($modname)) { + $this->controller = new $modname(); + App::$module_loaded = true; + } + } + } + } - /* - * If the site has a custom module to over-ride the standard module, use it. - * Otherwise, look for the standard program module - */ + /* + * If the site has a custom module to over-ride the standard module, use it. + * Otherwise, look for the standard program module + */ - if(! (App::$module_loaded)) { - try { - $filename = 'Zotlabs/SiteModule/'. ucfirst($module). '.php'; - if (file_exists($filename)) { - // This won't be picked up by the autoloader, so load it explicitly - require_once($filename); - $this->controller = new $modname; - App::$module_loaded = true; - } - else { - $filename = 'Zotlabs/Module/'. ucfirst($module). '.php'; - if (file_exists($filename)) { - $this->controller = new $modname; - App::$module_loaded = true; - } - } - if (! App::$module_loaded) { - throw new Exception('Module not found'); - } - } - catch(Exception $e) { + if (!(App::$module_loaded)) { + try { + $filename = 'Zotlabs/SiteModule/' . ucfirst($module) . '.php'; + if (file_exists($filename)) { + // This won't be picked up by the autoloader, so load it explicitly + require_once($filename); + $this->controller = new $modname(); + App::$module_loaded = true; + } else { + $filename = 'Zotlabs/Module/' . ucfirst($module) . '.php'; + if (file_exists($filename)) { + $this->controller = new $modname(); + App::$module_loaded = true; + } + } + if (!App::$module_loaded) { + throw new Exception('Module not found'); + } + } catch (Exception $e) { - } - } + } + } - $x = [ - 'module' => $module, - 'installed' => App::$module_loaded, - 'controller' => $this->controller - ]; + $x = [ + 'module' => $module, + 'installed' => App::$module_loaded, + 'controller' => $this->controller + ]; - /** - * @hooks module_loaded - * Called when a module has been successfully locate to server a URL request. - * This provides a place for plugins to register module handlers which don't otherwise exist - * on the system, or to completely over-ride an existing module. - * If the plugin sets 'installed' to true we won't throw a 404 error for the specified module even if - * there is no specific module file or matching plugin name. - * The plugin should catch at least one of the module hooks for this URL. - * * \e string \b module - * * \e boolean \b installed - * * \e mixed \b controller - The initialized module object - */ - call_hooks('module_loaded', $x); - if ($x['installed']) { - App::$module_loaded = true; - $this->controller = $x['controller']; - } + /** + * @hooks module_loaded + * Called when a module has been successfully locate to server a URL request. + * This provides a place for plugins to register module handlers which don't otherwise exist + * on the system, or to completely over-ride an existing module. + * If the plugin sets 'installed' to true we won't throw a 404 error for the specified module even if + * there is no specific module file or matching plugin name. + * The plugin should catch at least one of the module hooks for this URL. + * * \e string \b module + * * \e boolean \b installed + * * \e mixed \b controller - The initialized module object + */ + call_hooks('module_loaded', $x); + if ($x['installed']) { + App::$module_loaded = true; + $this->controller = $x['controller']; + } - /* - * The URL provided does not resolve to a valid module. - */ + /* + * The URL provided does not resolve to a valid module. + */ - if (! (App::$module_loaded)) { + if (!(App::$module_loaded)) { - // undo the setting of a letsencrypt acme-challenge rewrite rule - // which blocks access to our .well-known routes. - // Also provide a config setting for sites that have a legitimate need - // for a custom .htaccess in the .well-known directory; but they should - // make the file read-only so letsencrypt doesn't modify it + // undo the setting of a letsencrypt acme-challenge rewrite rule + // which blocks access to our .well-known routes. + // Also provide a config setting for sites that have a legitimate need + // for a custom .htaccess in the .well-known directory; but they should + // make the file read-only so letsencrypt doesn't modify it - if (strpos($_SERVER['REQUEST_URI'],'/.well-known/') === 0) { - if (file_exists('.well-known/.htaccess') && get_config('system','fix_apache_acme',true)) { - rename('.well-known/.htaccess','.well-known/.htaccess.old'); - } - } + if (strpos($_SERVER['REQUEST_URI'], '/.well-known/') === 0) { + if (file_exists('.well-known/.htaccess') && get_config('system', 'fix_apache_acme', true)) { + rename('.well-known/.htaccess', '.well-known/.htaccess.old'); + } + } - $x = [ - 'module' => $module, - 'installed' => App::$module_loaded, - 'controller' => $this->controller - ]; - call_hooks('page_not_found',$x); + $x = [ + 'module' => $module, + 'installed' => App::$module_loaded, + 'controller' => $this->controller + ]; + call_hooks('page_not_found', $x); - // Stupid browser tried to pre-fetch our Javascript img template. - // Don't log the event or return anything - just quietly exit. + // Stupid browser tried to pre-fetch our Javascript img template. + // Don't log the event or return anything - just quietly exit. - if ((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) { - killme(); - } + if ((x($_SERVER, 'QUERY_STRING')) && preg_match('/{[0-9]}/', $_SERVER['QUERY_STRING']) !== 0) { + killme(); + } - if (get_config('system','log_404',true)) { - logger("Module {$module} not found.", LOGGER_DEBUG, LOG_WARNING); - logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] - . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' - . $_SERVER['QUERY_STRING'], LOGGER_DEBUG); - } + if (get_config('system', 'log_404', true)) { + logger("Module {$module} not found.", LOGGER_DEBUG, LOG_WARNING); + logger('index.php: page not found: ' . $_SERVER['REQUEST_URI'] + . ' ADDRESS: ' . $_SERVER['REMOTE_ADDR'] . ' QUERY: ' + . $_SERVER['QUERY_STRING'], LOGGER_DEBUG); + } - header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); - $tpl = get_markup_template('404.tpl'); - App::$page['content'] = replace_macros(get_markup_template('404.tpl'), [ '$message' => t('Page not found.') ]); + header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); + $tpl = get_markup_template('404.tpl'); + App::$page['content'] = replace_macros(get_markup_template('404.tpl'), ['$message' => t('Page not found.')]); - // pretend this is a module so it will initialise the theme - App::$module = '404'; - App::$module_loaded = true; - App::$error = true; - } - } - } + // pretend this is a module so it will initialise the theme + App::$module = '404'; + App::$module_loaded = true; + App::$error = true; + } + } + } - /** - * @brief - * - */ - function Dispatch() { + /** + * @brief + * + */ + public function Dispatch() + { - /** - * Call module functions - */ + /** + * Call module functions + */ - if (App::$module_loaded) { + if (App::$module_loaded) { - App::$page['page_title'] = App::$module; - $placeholder = ''; + App::$page['page_title'] = App::$module; + $placeholder = ''; - /* - * No theme has been specified when calling the module_init functions - * For this reason, please restrict the use of templates to those which - * do not provide any presentation details - as themes will not be able - * to over-ride them. - */ + /* + * No theme has been specified when calling the module_init functions + * For this reason, please restrict the use of templates to those which + * do not provide any presentation details - as themes will not be able + * to over-ride them. + */ - $arr = [ 'init' => true, 'replace' => false ]; - call_hooks(App::$module . '_mod_init', $arr); - if (! $arr['replace']) { - if ($this->controller && method_exists($this->controller,'init')) { - $this->controller->init(); - } - } + $arr = ['init' => true, 'replace' => false]; + call_hooks(App::$module . '_mod_init', $arr); + if (!$arr['replace']) { + if ($this->controller && method_exists($this->controller, 'init')) { + $this->controller->init(); + } + } - /* - * Do all theme initialisation here before calling any additional module functions. - * The module_init function may have changed the theme. - * Additionally any page with a Comanche template may alter the theme. - * So we'll check for those now. - */ + /* + * Do all theme initialisation here before calling any additional module functions. + * The module_init function may have changed the theme. + * Additionally any page with a Comanche template may alter the theme. + * So we'll check for those now. + */ - /* - * In case a page has overloaded a module, see if we already have a layout defined - * otherwise, if a PDL file exists for this module, use it - * The member may have also created a customised PDL that's stored in the config - */ + /* + * In case a page has overloaded a module, see if we already have a layout defined + * otherwise, if a PDL file exists for this module, use it + * The member may have also created a customised PDL that's stored in the config + */ - load_pdl(); + load_pdl(); - /* - * load current theme info - */ + /* + * load current theme info + */ - $current_theme = Theme::current(); + $current_theme = Theme::current(); - $theme_info_file = 'view/theme/' . $current_theme[0] . '/php/theme.php'; - if (file_exists($theme_info_file)) { - require_once($theme_info_file); - } + $theme_info_file = 'view/theme/' . $current_theme[0] . '/php/theme.php'; + if (file_exists($theme_info_file)) { + require_once($theme_info_file); + } - if (function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) { - $func = str_replace('-', '_', $current_theme[0]) . '_init'; - $func($a); - } - elseif (x(App::$theme_info, 'extends') && file_exists('view/theme/' . App::$theme_info['extends'] . '/php/theme.php')) { - require_once('view/theme/' . App::$theme_info['extends'] . '/php/theme.php'); - if (function_exists(str_replace('-', '_', App::$theme_info['extends']) . '_init')) { - $func = str_replace('-', '_', App::$theme_info['extends']) . '_init'; - $func($a); - } - } + if (function_exists(str_replace('-', '_', $current_theme[0]) . '_init')) { + $func = str_replace('-', '_', $current_theme[0]) . '_init'; + $func($a); + } elseif (x(App::$theme_info, 'extends') && file_exists('view/theme/' . App::$theme_info['extends'] . '/php/theme.php')) { + require_once('view/theme/' . App::$theme_info['extends'] . '/php/theme.php'); + if (function_exists(str_replace('-', '_', App::$theme_info['extends']) . '_init')) { + $func = str_replace('-', '_', App::$theme_info['extends']) . '_init'; + $func($a); + } + } - if (($_SERVER['REQUEST_METHOD'] === 'POST') && (! App::$error) && (! x($_POST, 'auth-params'))) { - call_hooks(App::$module . '_mod_post', $_POST); - if ($this->controller && method_exists($this->controller,'post')) { - $this->controller->post(); - } - } + if (($_SERVER['REQUEST_METHOD'] === 'POST') && (!App::$error) && (!x($_POST, 'auth-params'))) { + call_hooks(App::$module . '_mod_post', $_POST); + if ($this->controller && method_exists($this->controller, 'post')) { + $this->controller->post(); + } + } - if (! App::$error) { - $arr = [ 'content' => App::$page['content'], 'replace' => false ]; - call_hooks(App::$module . '_mod_content', $arr); + if (!App::$error) { + $arr = ['content' => App::$page['content'], 'replace' => false]; + call_hooks(App::$module . '_mod_content', $arr); - if (! $arr['replace']) { - if ($this->controller && method_exists($this->controller,'get')) { - $arr = [ 'content' => $this->controller->get(), 'replace' => false ]; - } - } - call_hooks(App::$module . '_mod_aftercontent', $arr); - App::$page['content'] = (($arr['replace']) ? $arr['content'] : App::$page['content'] . $arr['content']); - } - } - } + if (!$arr['replace']) { + if ($this->controller && method_exists($this->controller, 'get')) { + $arr = ['content' => $this->controller->get(), 'replace' => false]; + } + } + call_hooks(App::$module . '_mod_aftercontent', $arr); + App::$page['content'] = (($arr['replace']) ? $arr['content'] : App::$page['content'] . $arr['content']); + } + } + } } diff --git a/Zotlabs/Web/SessionHandler.php b/Zotlabs/Web/SessionHandler.php index 92753a166..4b0a9bbfd 100644 --- a/Zotlabs/Web/SessionHandler.php +++ b/Zotlabs/Web/SessionHandler.php @@ -4,90 +4,96 @@ namespace Zotlabs\Web; use SessionHandlerInterface; -class SessionHandler implements SessionHandlerInterface { +class SessionHandler implements SessionHandlerInterface +{ - function open ($s, $n) { - return true; - } + public function open($s, $n) + { + return true; + } - // IMPORTANT: if we read the session and it doesn't exist, create an empty record. - // We rely on this due to differing PHP implementation of session_regenerate_id() - // some which call read explicitly and some that do not. So we call it explicitly - // just after sid regeneration to force a record to exist. + // IMPORTANT: if we read the session and it doesn't exist, create an empty record. + // We rely on this due to differing PHP implementation of session_regenerate_id() + // some which call read explicitly and some that do not. So we call it explicitly + // just after sid regeneration to force a record to exist. - function read ($id) { + public function read($id) + { - if ($id) { - $r = q("SELECT sess_data FROM session WHERE sid= '%s'", dbesc($id)); + if ($id) { + $r = q("SELECT sess_data FROM session WHERE sid= '%s'", dbesc($id)); - if ($r) { - return $r[0]['sess_data']; - } - else { - q("INSERT INTO session (sess_data, sid, expire) values ('%s', '%s', '%s')", - dbesc(''), - dbesc($id), - dbesc(time() + 1800) - ); - } - } + if ($r) { + return $r[0]['sess_data']; + } else { + q("INSERT INTO session (sess_data, sid, expire) values ('%s', '%s', '%s')", + dbesc(''), + dbesc($id), + dbesc(time() + 1800) + ); + } + } - return ''; - } + return ''; + } - function write ($id, $data) { + public function write($id, $data) + { - // Pretend everything is hunky-dory, even though it isn't. There probably isn't anything - // we can do about it in any event. - - if (! $id) { - return true; - } + // Pretend everything is hunky-dory, even though it isn't. There probably isn't anything + // we can do about it in any event. - // Unless we authenticate somehow, only keep a session for 30 minutes - // The viewer can extend this by performing any web action using the - // original cookie, but this allows us to cleanup the hundreds or - // thousands of empty sessions left around from web crawlers which are - // assigned cookies on each page that they never use. + if (!$id) { + return true; + } - $expire = time() + 1800; + // Unless we authenticate somehow, only keep a session for 30 minutes + // The viewer can extend this by performing any web action using the + // original cookie, but this allows us to cleanup the hundreds or + // thousands of empty sessions left around from web crawlers which are + // assigned cookies on each page that they never use. - if ($_SESSION) { - if (array_key_exists('remember_me',$_SESSION) && intval($_SESSION['remember_me'])) - $expire = time() + (60 * 60 * 24 * 365); - elseif (local_channel()) - $expire = time() + (60 * 60 * 24 * 3); - elseif (remote_channel()) - $expire = time() + (60 * 60 * 24 * 1); - } + $expire = time() + 1800; - q("UPDATE session + if ($_SESSION) { + if (array_key_exists('remember_me', $_SESSION) && intval($_SESSION['remember_me'])) + $expire = time() + (60 * 60 * 24 * 365); + elseif (local_channel()) + $expire = time() + (60 * 60 * 24 * 3); + elseif (remote_channel()) + $expire = time() + (60 * 60 * 24 * 1); + } + + q("UPDATE session SET sess_data = '%s', expire = '%s' WHERE sid = '%s'", - dbesc($data), - dbesc($expire), - dbesc($id) - ); + dbesc($data), + dbesc($expire), + dbesc($id) + ); - return true; - } - - - function close() { - return true; - } + return true; + } - function destroy ($id) { - q("DELETE FROM session WHERE sid = '%s'", dbesc($id)); - return true; - } + public function close() + { + return true; + } - function gc($expire) { - q("DELETE FROM session WHERE expire < %d", dbesc(time())); - return true; - } + public function destroy($id) + { + q("DELETE FROM session WHERE sid = '%s'", dbesc($id)); + return true; + } + + + public function gc($expire) + { + q("DELETE FROM session WHERE expire < %d", dbesc(time())); + return true; + } } diff --git a/Zotlabs/Web/SubModule.php b/Zotlabs/Web/SubModule.php index af828b364..b304ba512 100644 --- a/Zotlabs/Web/SubModule.php +++ b/Zotlabs/Web/SubModule.php @@ -8,68 +8,72 @@ use Zotlabs\Extend\Route; * @brief * */ -class SubModule { - private $controller = false; +class SubModule +{ - /** - * @brief Submodule constructor. - * - * Initiate sub-modules. By default the submodule name is in argv(1), though this is configurable. - * Example: Given a URL path such as /admin/plugins, and the Admin module initiates sub-modules. - * This means we'll look for a class Plugins in Zotlabs/Module/Admin/Plugins.php - * The specific methods and calling parameters are up to the top level module controller logic. - * - * **If** you were to provide sub-module support on the photos module, you would probably use - * $whicharg = 2, as photos are typically called with a URL path of /photos/channel_address/submodule_name - * where submodule_name might be something like album or image. - * - * @param int $whicharg - */ - function __construct($whicharg = 1) { + private $controller = false; - if (argc() < ($whicharg + 1)) { - return; - } + /** + * @brief Submodule constructor. + * + * Initiate sub-modules. By default the submodule name is in argv(1), though this is configurable. + * Example: Given a URL path such as /admin/plugins, and the Admin module initiates sub-modules. + * This means we'll look for a class Plugins in Zotlabs/Module/Admin/Plugins.php + * The specific methods and calling parameters are up to the top level module controller logic. + * + * **If** you were to provide sub-module support on the photos module, you would probably use + * $whicharg = 2, as photos are typically called with a URL path of /photos/channel_address/submodule_name + * where submodule_name might be something like album or image. + * + * @param int $whicharg + */ + public function __construct($whicharg = 1) + { - $filename = 'Zotlabs/Module/' . ucfirst(argv(0)) . '/'. ucfirst(argv($whicharg)) . '.php'; - $modname = '\\Zotlabs\\Module\\' . ucfirst(argv(0)) . '\\' . ucfirst(argv($whicharg)); + if (argc() < ($whicharg + 1)) { + return; + } - if (file_exists($filename)) { - $this->controller = new $modname(); - } + $filename = 'Zotlabs/Module/' . ucfirst(argv(0)) . '/' . ucfirst(argv($whicharg)) . '.php'; + $modname = '\\Zotlabs\\Module\\' . ucfirst(argv(0)) . '\\' . ucfirst(argv($whicharg)); - $routes = Route::get(); + if (file_exists($filename)) { + $this->controller = new $modname(); + } - if ($routes) { - foreach ($routes as $route) { - if (is_array($route) && strtolower($route[1]) === strtolower(argv(0)) . '/' . strtolower(argv($whicharg))) { - include_once($route[0]); - if (class_exists($modname)) { - $this->controller = new $modname; - } - } - } - } - } + $routes = Route::get(); - /** - * @brief - * - * @param string $method - * @return boolean|mixed - */ - function call($method) { + if ($routes) { + foreach ($routes as $route) { + if (is_array($route) && strtolower($route[1]) === strtolower(argv(0)) . '/' . strtolower(argv($whicharg))) { + include_once($route[0]); + if (class_exists($modname)) { + $this->controller = new $modname(); + } + } + } + } + } - if (! $this->controller) { - return false; - } + /** + * @brief + * + * @param string $method + * @return bool|mixed + */ + public function call($method) + { - if (method_exists($this->controller, $method)) { - return $this->controller->$method(); - } + if (!$this->controller) { + return false; + } - return false; - } + if (method_exists($this->controller, $method)) { + return $this->controller->$method(); + } + + return false; + } } diff --git a/Zotlabs/Widget/Activity.php b/Zotlabs/Widget/Activity.php index b5421e2a7..2a84312e0 100644 --- a/Zotlabs/Widget/Activity.php +++ b/Zotlabs/Widget/Activity.php @@ -5,65 +5,65 @@ namespace Zotlabs\Widget; use Zotlabs\Lib\LibBlock; -class Activity { +class Activity +{ - function widget($arr) { + public function widget($arr) + { - if (! local_channel()) { - return ''; - } + if (!local_channel()) { + return ''; + } - $o = EMPTY_STR; + $o = EMPTY_STR; - if (is_array($arr) && array_key_exists('limit',$arr)) { - $limit = " limit " . intval($limit) . " "; - } - else { - $limit = EMPTY_STR; - } + if (is_array($arr) && array_key_exists('limit', $arr)) { + $limit = " limit " . intval($limit) . " "; + } else { + $limit = EMPTY_STR; + } - $perms_sql = item_permissions_sql(local_channel()) . item_normal(); + $perms_sql = item_permissions_sql(local_channel()) . item_normal(); - $r = q("select author_xchan from item where item_unseen = 1 and uid = %d $perms_sql", - intval(local_channel()) - ); + $r = q("select author_xchan from item where item_unseen = 1 and uid = %d $perms_sql", + intval(local_channel()) + ); - $contributors = []; - $arr = []; + $contributors = []; + $arr = []; - if ($r) { - foreach ($r as $rv) { - if (array_key_exists($rv['author_xchan'],$contributors)) { - $contributors[$rv['author_xchan']] ++; - } - else { - $contributors[$rv['author_xchan']] = 1; - } - } - foreach($contributors as $k => $v) { - if (! LibBlock::fetch_by_entity(local_channel(), $k)) { - $arr[] = [ 'author_xchan' => $k, 'total' => $v ]; - } - } - usort($arr,'total_sort'); - xchan_query($arr); - } + if ($r) { + foreach ($r as $rv) { + if (array_key_exists($rv['author_xchan'], $contributors)) { + $contributors[$rv['author_xchan']]++; + } else { + $contributors[$rv['author_xchan']] = 1; + } + } + foreach ($contributors as $k => $v) { + if (!LibBlock::fetch_by_entity(local_channel(), $k)) { + $arr[] = ['author_xchan' => $k, 'total' => $v]; + } + } + usort($arr, 'total_sort'); + xchan_query($arr); + } - $x = [ 'entries' => $arr ]; - call_hooks('activity_widget',$x); - $arr = $x['entries']; + $x = ['entries' => $arr]; + call_hooks('activity_widget', $x); + $arr = $x['entries']; - if($arr) { - $o .= '
      '; - $o .= '

      ' . t('Activity','widget') . '

      '; + } + return $o; + } } diff --git a/Zotlabs/Widget/Activity_filter.php b/Zotlabs/Widget/Activity_filter.php index 229f2a624..13403bd4d 100644 --- a/Zotlabs/Widget/Activity_filter.php +++ b/Zotlabs/Widget/Activity_filter.php @@ -5,273 +5,273 @@ namespace Zotlabs\Widget; use App; use Zotlabs\Lib\Apps; -class Activity_filter { +class Activity_filter +{ - function widget($arr) { + public function widget($arr) + { - if (! local_channel()) { - return EMPTY_STR; - } + if (!local_channel()) { + return EMPTY_STR; + } - $cmd = App::$cmd; + $cmd = App::$cmd; - $filter_active = false; - $events_active = false; - $video_active = false; - $polls_active = false; - $group_active = false; - $drafts_active = false; - $forum_active = false; - - $tabs = []; + $filter_active = false; + $events_active = false; + $video_active = false; + $polls_active = false; + $group_active = false; + $drafts_active = false; + $forum_active = false; - $dm_active = ((isset($_GET['dm']) && intval($_GET['dm'])) ? 'active' : ''); - if ($dm_active) { - $filter_active = 'dm'; - } + $tabs = []; - $tabs[] = [ - 'label' => t('Direct Messages'), - 'icon' => 'envelope-o', - 'url' => z_root() . '/' . $cmd . '/?dm=1', - 'sel' => $dm_active, - 'title' => t('Show direct (private) messages') - ]; + $dm_active = ((isset($_GET['dm']) && intval($_GET['dm'])) ? 'active' : ''); + if ($dm_active) { + $filter_active = 'dm'; + } + + $tabs[] = [ + 'label' => t('Direct Messages'), + 'icon' => 'envelope-o', + 'url' => z_root() . '/' . $cmd . '/?dm=1', + 'sel' => $dm_active, + 'title' => t('Show direct (private) messages') + ]; - $conv_active = ((isset($_GET['conv']) && intval($_GET['conv'])) ? 'active' : ''); - if ($conv_active) { - $filter_active = 'personal'; - } + $conv_active = ((isset($_GET['conv']) && intval($_GET['conv'])) ? 'active' : ''); + if ($conv_active) { + $filter_active = 'personal'; + } - $tabs[] = [ - 'label' => t('Personal Posts'), - 'icon' => 'user-circle', - 'url' => z_root() . '/' . $cmd . '/?conv=1', - 'sel' => $conv_active, - 'title' => t('Show posts that mention or involve me') - ]; + $tabs[] = [ + 'label' => t('Personal Posts'), + 'icon' => 'user-circle', + 'url' => z_root() . '/' . $cmd . '/?conv=1', + 'sel' => $conv_active, + 'title' => t('Show posts that mention or involve me') + ]; - $starred_active = ((isset($_GET['star']) && intval($_GET['star'])) ? 'active' : ''); - if ($starred_active) { - $filter_active = 'star'; - } + $starred_active = ((isset($_GET['star']) && intval($_GET['star'])) ? 'active' : ''); + if ($starred_active) { + $filter_active = 'star'; + } - $tabs[] = [ - 'label' => t('Saved Posts'), - 'icon' => 'star', - 'url' => z_root() . '/' . $cmd . '/?star=1', - 'sel' => $starred_active, - 'title' => t('Show posts that I have saved') - ]; + $tabs[] = [ + 'label' => t('Saved Posts'), + 'icon' => 'star', + 'url' => z_root() . '/' . $cmd . '/?star=1', + 'sel' => $starred_active, + 'title' => t('Show posts that I have saved') + ]; - if (local_channel() && Apps::system_app_installed(local_channel(),'Drafts')) { - $drafts_active = ((isset($_GET['draft']) && intval($_GET['draft'])) ? 'active' : ''); - if ($drafts_active) { - $filter_active = 'drafts'; - } + if (local_channel() && Apps::system_app_installed(local_channel(), 'Drafts')) { + $drafts_active = ((isset($_GET['draft']) && intval($_GET['draft'])) ? 'active' : ''); + if ($drafts_active) { + $filter_active = 'drafts'; + } - $tabs[] = [ - 'label' => t('Drafts'), - 'icon' => 'floppy-o', - 'url' => z_root() . '/' . $cmd . '/?draft=1', - 'sel' => $drafts_active, - 'title' => t('Show drafts that I have saved') - ]; - } + $tabs[] = [ + 'label' => t('Drafts'), + 'icon' => 'floppy-o', + 'url' => z_root() . '/' . $cmd . '/?draft=1', + 'sel' => $drafts_active, + 'title' => t('Show drafts that I have saved') + ]; + } - if(x($_GET,'search')) { - $video_active = (($_GET['search'] == 'video]') ? 'active' : ''); - $filter_active = (($events_active) ? 'videos' : 'search'); - } + if (x($_GET, 'search')) { + $video_active = (($_GET['search'] == 'video]') ? 'active' : ''); + $filter_active = (($events_active) ? 'videos' : 'search'); + } - $tabs[] = [ - 'label' => t('Videos'), - 'icon' => 'video', - 'url' => z_root() . '/' . $cmd . '/?search=video%5D', - 'sel' => $video_active, - 'title' => t('Show posts that include videos') - ]; + $tabs[] = [ + 'label' => t('Videos'), + 'icon' => 'video', + 'url' => z_root() . '/' . $cmd . '/?search=video%5D', + 'sel' => $video_active, + 'title' => t('Show posts that include videos') + ]; - if(x($_GET,'verb')) { - $events_active = (($_GET['verb'] == '.Event') ? 'active' : ''); - $polls_active = (($_GET['verb'] == '.Question') ? 'active' : ''); - $filter_active = (($events_active) ? 'events' : 'polls'); - } + if (x($_GET, 'verb')) { + $events_active = (($_GET['verb'] == '.Event') ? 'active' : ''); + $polls_active = (($_GET['verb'] == '.Question') ? 'active' : ''); + $filter_active = (($events_active) ? 'events' : 'polls'); + } - $tabs[] = [ - 'label' => t('Events'), - 'icon' => 'calendar', - 'url' => z_root() . '/' . $cmd . '/?verb=%2EEvent', - 'sel' => $events_active, - 'title' => t('Show posts that include events') - ]; + $tabs[] = [ + 'label' => t('Events'), + 'icon' => 'calendar', + 'url' => z_root() . '/' . $cmd . '/?verb=%2EEvent', + 'sel' => $events_active, + 'title' => t('Show posts that include events') + ]; - $tabs[] = [ - 'label' => t('Polls'), - 'icon' => 'bar-chart', - 'url' => z_root() . '/' . $cmd . '/?verb=%2EQuestion', - 'sel' => $polls_active, - 'title' => t('Show posts that include polls') - ]; + $tabs[] = [ + 'label' => t('Polls'), + 'icon' => 'bar-chart', + 'url' => z_root() . '/' . $cmd . '/?verb=%2EQuestion', + 'sel' => $polls_active, + 'title' => t('Show posts that include polls') + ]; + $groups = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", + intval(local_channel()) + ); - $groups = q("SELECT * FROM pgrp WHERE deleted = 0 AND uid = %d ORDER BY gname ASC", - intval(local_channel()) - ); + if ($groups || Apps::system_app_installed(local_channel(), 'Virtual Lists')) { + if ($groups) { + foreach ($groups as $g) { + if (x($_GET, 'gid')) { + $group_active = (($_GET['gid'] == $g['id']) ? 'active' : ''); + $filter_active = 'group'; + } + $gsub[] = [ + 'label' => $g['gname'], + 'icon' => '', + 'url' => z_root() . '/' . $cmd . '/?f=&gid=' . $g['id'], + 'sel' => $group_active, + 'title' => sprintf(t('Show posts related to the %s access list'), $g['gname']) + ]; + } + } + if (Apps::system_app_installed(local_channel(), 'Virtual Lists')) { + foreach ([':1', ':2', ':3'] as $l) { + switch ($l) { + case ':1': + $gname = t('Connections'); + break; + case ':2': + $gname = t('Nomad'); + break; + case ':3': + $gname = t('ActivityPub'); + break; + default: + break; + } - if($groups || Apps::system_app_installed(local_channel(),'Virtual Lists')) { - if ($groups) { - foreach($groups as $g) { - if(x($_GET,'gid')) { - $group_active = (($_GET['gid'] == $g['id']) ? 'active' : ''); - $filter_active = 'group'; - } - $gsub[] = [ - 'label' => $g['gname'], - 'icon' => '', - 'url' => z_root() . '/' . $cmd . '/?f=&gid=' . $g['id'], - 'sel' => $group_active, - 'title' => sprintf(t('Show posts related to the %s access list'), $g['gname']) - ]; - } - } - if (Apps::system_app_installed(local_channel(),'Virtual Lists')) { - foreach ([ ':1', ':2', ':3' ] as $l) { - switch ($l) { - case ':1': - $gname = t('Connections'); - break; - case ':2': - $gname = t('Nomad'); - break; - case ':3': - $gname = t('ActivityPub'); - break; - default: - break; - } + if (x($_GET, 'gid')) { + $group_active = (($_GET['gid'] == $l) ? 'active' : ''); + $filter_active = 'group'; + } - if(x($_GET,'gid')) { - $group_active = (($_GET['gid'] == $l) ? 'active' : ''); - $filter_active = 'group'; - } - - $gsub[] = [ - 'label' => $gname, - 'icon' => '', - 'url' => z_root() . '/' . $cmd . '/?f=&gid=' . $l, - 'sel' => $group_active, - 'title' => sprintf(t('Show posts related to the %s access list'), $gname) - ]; - } - } - $tabs[] = [ - 'id' => 'privacy_groups', - 'label' => t('Lists'), - 'icon' => 'users', - 'url' => '#', - 'sel' => (($filter_active == 'group') ? true : false), - 'title' => t('Show my access lists'), - 'sub' => $gsub - ]; - } + $gsub[] = [ + 'label' => $gname, + 'icon' => '', + 'url' => z_root() . '/' . $cmd . '/?f=&gid=' . $l, + 'sel' => $group_active, + 'title' => sprintf(t('Show posts related to the %s access list'), $gname) + ]; + } + } + $tabs[] = [ + 'id' => 'privacy_groups', + 'label' => t('Lists'), + 'icon' => 'users', + 'url' => '#', + 'sel' => (($filter_active == 'group') ? true : false), + 'title' => t('Show my access lists'), + 'sub' => $gsub + ]; + } - $forums = get_forum_channels(local_channel(),1); + $forums = get_forum_channels(local_channel(), 1); - if($forums) { - foreach($forums as $f) { - if(x($_GET,'pf') && x($_GET,'cid')) { - $forum_active = ((x($_GET,'pf') && $_GET['cid'] == $f['abook_id']) ? 'active' : ''); - $filter_active = 'forums'; - } - $fsub[] = [ - 'label' => $f['xchan_name'], - 'img' => $f['xchan_photo_s'], - 'url' => z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id'], - 'sel' => $forum_active, - 'title' => t('Show posts to this group'), - 'lock' => ((isset($f['private_forum']) && $f['private_forum']) ? 'lock' : ''), - 'edit' => t('New post'), - 'edit_url' => $f['xchan_url'] - ]; - } + if ($forums) { + foreach ($forums as $f) { + if (x($_GET, 'pf') && x($_GET, 'cid')) { + $forum_active = ((x($_GET, 'pf') && $_GET['cid'] == $f['abook_id']) ? 'active' : ''); + $filter_active = 'forums'; + } + $fsub[] = [ + 'label' => $f['xchan_name'], + 'img' => $f['xchan_photo_s'], + 'url' => z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id'], + 'sel' => $forum_active, + 'title' => t('Show posts to this group'), + 'lock' => ((isset($f['private_forum']) && $f['private_forum']) ? 'lock' : ''), + 'edit' => t('New post'), + 'edit_url' => $f['xchan_url'] + ]; + } - $tabs[] = [ - 'id' => 'forums', - 'label' => t('Groups'), - 'icon' => 'comments-o', - 'url' => '#', - 'sel' => (($filter_active == 'forums') ? true : false), - 'title' => t('Show groups'), - 'sub' => $fsub - ]; - } + $tabs[] = [ + 'id' => 'forums', + 'label' => t('Groups'), + 'icon' => 'comments-o', + 'url' => '#', + 'sel' => (($filter_active == 'forums') ? true : false), + 'title' => t('Show groups'), + 'sub' => $fsub + ]; + } - if(feature_enabled(local_channel(),'filing')) { - $terms = q("select distinct term from term where uid = %d and ttype = %d order by term asc", - intval(local_channel()), - intval(TERM_FILE) - ); + if (feature_enabled(local_channel(), 'filing')) { + $terms = q("select distinct term from term where uid = %d and ttype = %d order by term asc", + intval(local_channel()), + intval(TERM_FILE) + ); - if($terms) { - foreach($terms as $t) { - if(x($_GET,'file')) { - $file_active = (($_GET['file'] == $t['term']) ? 'active' : ''); - $filter_active = 'file'; - } - $tsub[] = [ - 'label' => $t['term'], - 'icon' => '', - 'url' => z_root() . '/' . $cmd . '/?f=&file=' . $t['term'], - 'sel' => $file_active, - 'title' => sprintf(t('Show posts that I have filed to %s'), $t['term']), - ]; - } + if ($terms) { + foreach ($terms as $t) { + if (x($_GET, 'file')) { + $file_active = (($_GET['file'] == $t['term']) ? 'active' : ''); + $filter_active = 'file'; + } + $tsub[] = [ + 'label' => $t['term'], + 'icon' => '', + 'url' => z_root() . '/' . $cmd . '/?f=&file=' . $t['term'], + 'sel' => $file_active, + 'title' => sprintf(t('Show posts that I have filed to %s'), $t['term']), + ]; + } - $tabs[] = [ - 'id' => 'saved_folders', - 'label' => t('Saved Folders'), - 'icon' => 'folder', - 'url' => '#', - 'sel' => (($filter_active == 'file') ? true : false), - 'title' => t('Show filed post categories'), - 'sub' => $tsub + $tabs[] = [ + 'id' => 'saved_folders', + 'label' => t('Saved Folders'), + 'icon' => 'folder', + 'url' => '#', + 'sel' => (($filter_active == 'file') ? true : false), + 'title' => t('Show filed post categories'), + 'sub' => $tsub - ]; - } - } + ]; + } + } - $ft = get_pconfig(local_channel(),'system','followed_tags', EMPTY_STR); - if (is_array($ft) && $ft) { - foreach($ft as $t) { - $tag_active = ((isset($_GET['netsearch']) && $_GET['netsearch'] === '#' . $t) ? 'active' : ''); - if ($tag_active) { - $filter_active = 'tags'; - } - - $tsub[] = [ - 'label' => '#' . $t, - 'icon' => '', - 'url' => z_root() . '/' . $cmd . '/?search=' . '%23' . $t, - 'sel' => $tag_active, - 'title' => sprintf(t('Show posts with hashtag %s'), '#' . $t), - ]; - } + $ft = get_pconfig(local_channel(), 'system', 'followed_tags', EMPTY_STR); + if (is_array($ft) && $ft) { + foreach ($ft as $t) { + $tag_active = ((isset($_GET['netsearch']) && $_GET['netsearch'] === '#' . $t) ? 'active' : ''); + if ($tag_active) { + $filter_active = 'tags'; + } - $tabs[] = [ - 'id' => 'followed_tags', - 'label' => t('Followed Hashtags'), - 'icon' => 'bookmark', - 'url' => '#', - 'sel' => (($filter_active == 'tags') ? true : false), - 'title' => t('Show followed hashtags'), - 'sub' => $tsub - ]; + $tsub[] = [ + 'label' => '#' . $t, + 'icon' => '', + 'url' => z_root() . '/' . $cmd . '/?search=' . '%23' . $t, + 'sel' => $tag_active, + 'title' => sprintf(t('Show posts with hashtag %s'), '#' . $t), + ]; + } - } + $tabs[] = [ + 'id' => 'followed_tags', + 'label' => t('Followed Hashtags'), + 'icon' => 'bookmark', + 'url' => '#', + 'sel' => (($filter_active == 'tags') ? true : false), + 'title' => t('Show followed hashtags'), + 'sub' => $tsub + ]; + } // if(x($_GET,'search')) { @@ -285,50 +285,50 @@ class Activity_filter { // ]; // } - $name = []; - if(isset($_GET['name']) && $_GET['name']) { - $filter_active = 'name'; - } - $name = [ - 'label' => x($_GET,'name') ? $_GET['name'] : t('Name'), - 'icon' => 'filter', - 'url'=> z_root() . '/' . $cmd . '/', - 'sel'=> $filter_active == 'name' ? 'is-valid' : '', - 'title' => '' - ]; + $name = []; + if (isset($_GET['name']) && $_GET['name']) { + $filter_active = 'name'; + } + $name = [ + 'label' => x($_GET, 'name') ? $_GET['name'] : t('Name'), + 'icon' => 'filter', + 'url' => z_root() . '/' . $cmd . '/', + 'sel' => $filter_active == 'name' ? 'is-valid' : '', + 'title' => '' + ]; - $reset = []; - if ($filter_active) { - $reset = [ - 'label' => '', - 'icon' => 'remove', - 'url'=> z_root() . '/' . $cmd, - 'sel'=> '', - 'title' => t('Remove active filter') - ]; - } + $reset = []; + if ($filter_active) { + $reset = [ + 'label' => '', + 'icon' => 'remove', + 'url' => z_root() . '/' . $cmd, + 'sel' => '', + 'title' => t('Remove active filter') + ]; + } - $arr = ['tabs' => $tabs]; + $arr = ['tabs' => $tabs]; - call_hooks('activity_filter', $arr); + call_hooks('activity_filter', $arr); - $o = ''; + $o = ''; - if($arr['tabs']) { - $content = replace_macros(get_markup_template('common_pills.tpl'), [ - '$pills' => $arr['tabs'] - ]); + if ($arr['tabs']) { + $content = replace_macros(get_markup_template('common_pills.tpl'), [ + '$pills' => $arr['tabs'] + ]); - $o .= replace_macros(get_markup_template('activity_filter_widget.tpl'), [ - '$title' => t('Stream Filters'), - '$reset' => $reset, - '$content' => $content, - '$name' => $name - ]); - } + $o .= replace_macros(get_markup_template('activity_filter_widget.tpl'), [ + '$title' => t('Stream Filters'), + '$reset' => $reset, + '$content' => $content, + '$name' => $name + ]); + } - return $o; + return $o; - } + } } diff --git a/Zotlabs/Widget/Admin.php b/Zotlabs/Widget/Admin.php index 90f049283..50af3b2b5 100644 --- a/Zotlabs/Widget/Admin.php +++ b/Zotlabs/Widget/Admin.php @@ -4,69 +4,71 @@ namespace Zotlabs\Widget; use App; -class Admin { +class Admin +{ - function widget($arr) { + public function widget($arr) + { - /* - * Side bar links - */ + /* + * Side bar links + */ - if(! is_site_admin()) { - return ''; - } + if (!is_site_admin()) { + return ''; + } - $o = ''; + $o = ''; - // array( url, name, extra css classes ) + // array( url, name, extra css classes ) - $aside = [ - 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'), + $aside = [ + 'site' => array(z_root() . '/admin/site/', t('Site'), 'site'), // 'profile_photo' => array(z_root() . '/admin/profile_photo', t('Site icon/logo'), 'profile_photo'), // 'cover_photo' => array(z_root() . '/admin/cover_photo', t('Site photo'), 'cover_photo'), - 'accounts' => array(z_root() . '/admin/accounts/', t('Accounts'), 'accounts', 'pending-update', t('Member registrations waiting for confirmation')), - 'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'), - 'security' => array(z_root() . '/admin/security/', t('Security'), 'security'), + 'accounts' => array(z_root() . '/admin/accounts/', t('Accounts'), 'accounts', 'pending-update', t('Member registrations waiting for confirmation')), + 'channels' => array(z_root() . '/admin/channels/', t('Channels'), 'channels'), + 'security' => array(z_root() . '/admin/security/', t('Security'), 'security'), // 'features' => array(z_root() . '/admin/features/', t('Features'), 'features'), - 'addons' => array(z_root() . '/admin/addons/', t('Addons'), 'addons'), - 'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'), - 'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'), + 'addons' => array(z_root() . '/admin/addons/', t('Addons'), 'addons'), + 'themes' => array(z_root() . '/admin/themes/', t('Themes'), 'themes'), + 'queue' => array(z_root() . '/admin/queue', t('Inspect queue'), 'queue'), // 'profs' => array(z_root() . '/admin/profs', t('Profile Fields'), 'profs'), - 'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync') - ]; + 'dbsync' => array(z_root() . '/admin/dbsync/', t('DB updates'), 'dbsync') + ]; - /* get plugins admin page */ + /* get plugins admin page */ - $r = q("SELECT * FROM addon WHERE plugin_admin = 1"); + $r = q("SELECT * FROM addon WHERE plugin_admin = 1"); - $plugins = []; - if($r) { - foreach ($r as $h){ - $plugin = $h['aname']; - $plugins[] = array(z_root() . '/admin/addons/' . $plugin, $plugin, 'plugin'); - // temp plugins with admin - App::$plugins_admin[] = $plugin; - } - } + $plugins = []; + if ($r) { + foreach ($r as $h) { + $plugin = $h['aname']; + $plugins[] = array(z_root() . '/admin/addons/' . $plugin, $plugin, 'plugin'); + // temp plugins with admin + App::$plugins_admin[] = $plugin; + } + } - $logs = array(z_root() . '/admin/logs/', t('Logs'), 'logs'); + $logs = array(z_root() . '/admin/logs/', t('Logs'), 'logs'); - $arr = array('links' => $aside,'plugins' => $plugins,'logs' => $logs); - call_hooks('admin_aside',$arr); + $arr = array('links' => $aside, 'plugins' => $plugins, 'logs' => $logs); + call_hooks('admin_aside', $arr); - $o .= replace_macros(get_markup_template('admin_aside.tpl'), array( - '$admin' => $aside, - '$admtxt' => t('Admin'), - '$plugadmtxt' => t('Addon Features'), - '$plugins' => $plugins, - '$logtxt' => t('Logs'), - '$logs' => $logs, - '$h_pending' => t('Member registrations waiting for confirmation'), - '$admurl'=> z_root() . '/admin/' - )); + $o .= replace_macros(get_markup_template('admin_aside.tpl'), array( + '$admin' => $aside, + '$admtxt' => t('Admin'), + '$plugadmtxt' => t('Addon Features'), + '$plugins' => $plugins, + '$logtxt' => t('Logs'), + '$logs' => $logs, + '$h_pending' => t('Member registrations waiting for confirmation'), + '$admurl' => z_root() . '/admin/' + )); - return $o; + return $o; - } + } } diff --git a/Zotlabs/Widget/Affinity.php b/Zotlabs/Widget/Affinity.php index bcd54f9cf..5dd7e4cc0 100644 --- a/Zotlabs/Widget/Affinity.php +++ b/Zotlabs/Widget/Affinity.php @@ -4,46 +4,48 @@ namespace Zotlabs\Widget; use Zotlabs\Lib\Apps; -class Affinity { +class Affinity +{ - function widget($arr) { + public function widget($arr) + { - if(! local_channel()) - return ''; - - $default_cmin = ((Apps::system_app_installed(local_channel(),'Friend Zoom')) ? get_pconfig(local_channel(),'affinity','cmin',0) : 0); - $default_cmax = ((Apps::system_app_installed(local_channel(),'Friend Zoom')) ? get_pconfig(local_channel(),'affinity','cmax',99) : 99); + if (!local_channel()) + return ''; - $cmin = ((x($_REQUEST,'cmin')) ? intval($_REQUEST['cmin']) : $default_cmin); - $cmax = ((x($_REQUEST,'cmax')) ? intval($_REQUEST['cmax']) : $default_cmax); + $default_cmin = ((Apps::system_app_installed(local_channel(), 'Friend Zoom')) ? get_pconfig(local_channel(), 'affinity', 'cmin', 0) : 0); + $default_cmax = ((Apps::system_app_installed(local_channel(), 'Friend Zoom')) ? get_pconfig(local_channel(), 'affinity', 'cmax', 99) : 99); + + $cmin = ((x($_REQUEST, 'cmin')) ? intval($_REQUEST['cmin']) : $default_cmin); + $cmax = ((x($_REQUEST, 'cmax')) ? intval($_REQUEST['cmax']) : $default_cmax); - if(Apps::system_app_installed(local_channel(),'Friend Zoom')) { + if (Apps::system_app_installed(local_channel(), 'Friend Zoom')) { - $labels = array( - 0 => t('Me'), - 20 => t('Family'), - 40 => t('Friends'), - 60 => t('Peers'), - 80 => t('Connections'), - 99 => t('All') - ); - call_hooks('affinity_labels',$labels); + $labels = array( + 0 => t('Me'), + 20 => t('Family'), + 40 => t('Friends'), + 60 => t('Peers'), + 80 => t('Connections'), + 99 => t('All') + ); + call_hooks('affinity_labels', $labels); - $tpl = get_markup_template('main_slider.tpl'); - $x = replace_macros($tpl, [ - '$cmin' => $cmin, - '$cmax' => $cmax, - '$lbl' => t('Friend zoom in/out'), - '$refresh' => t('Refresh'), - '$labels' => $labels, - ]); - - $arr = array('html' => $x); - call_hooks('main_slider',$arr); - return $arr['html']; - } - return ''; - } + $tpl = get_markup_template('main_slider.tpl'); + $x = replace_macros($tpl, [ + '$cmin' => $cmin, + '$cmax' => $cmax, + '$lbl' => t('Friend zoom in/out'), + '$refresh' => t('Refresh'), + '$labels' => $labels, + ]); + + $arr = array('html' => $x); + call_hooks('main_slider', $arr); + return $arr['html']; + } + return ''; + } } \ No newline at end of file diff --git a/Zotlabs/Widget/Album.php b/Zotlabs/Widget/Album.php index c690a0794..653112a01 100644 --- a/Zotlabs/Widget/Album.php +++ b/Zotlabs/Widget/Album.php @@ -5,106 +5,108 @@ namespace Zotlabs\Widget; use App; require_once('include/attach.php'); -class Album { +class Album +{ - function widget($args) { + public function widget($args) + { - $owner_uid = App::$profile_uid; - $sql_extra = permissions_sql($owner_uid); + $owner_uid = App::$profile_uid; + $sql_extra = permissions_sql($owner_uid); - if (! perm_is_allowed($owner_uid,get_observer_hash(),'view_storage')) { - return ''; - } + if (!perm_is_allowed($owner_uid, get_observer_hash(), 'view_storage')) { + return ''; + } - if ($args['album']) { - $album = $args['album']; - } - if ($args['title']) { - $title = $args['title']; - } - - /** - * This may return incorrect permissions if you have multiple directories of the same name. - * It is a limitation of the photo table using a name for a photo album instead of a folder hash - */ + if ($args['album']) { + $album = $args['album']; + } + if ($args['title']) { + $title = $args['title']; + } - if ($album) { - $x = q("select hash from attach where filename = '%s' and uid = %d limit 1", - dbesc($album), - intval($owner_uid) - ); - if($x) { - $y = attach_can_view_folder($owner_uid,get_observer_hash(),$x[0]['hash']); - if(! $y) - return ''; - } - } + /** + * This may return incorrect permissions if you have multiple directories of the same name. + * It is a limitation of the photo table using a name for a photo album instead of a folder hash + */ - $order = 'DESC'; + if ($album) { + $x = q("select hash from attach where filename = '%s' and uid = %d limit 1", + dbesc($album), + intval($owner_uid) + ); + if ($x) { + $y = attach_can_view_folder($owner_uid, get_observer_hash(), $x[0]['hash']); + if (!$y) + return ''; + } + } - $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN + $order = 'DESC'; + + $r = q("SELECT p.resource_id, p.id, p.filename, p.mimetype, p.imgscale, p.description, p.created FROM photo p INNER JOIN (SELECT resource_id, max(imgscale) imgscale FROM photo WHERE uid = %d AND album = '%s' AND imgscale <= 4 AND photo_usage IN ( %d, %d ) $sql_extra GROUP BY resource_id) ph ON (p.resource_id = ph.resource_id AND p.imgscale = ph.imgscale) ORDER BY created $order ", - intval($owner_uid), - dbesc($album), - intval(PHOTO_NORMAL), - intval(PHOTO_PROFILE) - ); + intval($owner_uid), + dbesc($album), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE) + ); - //edit album name - $album_edit = null; + //edit album name + $album_edit = null; - $photos = []; - if($r) { - $twist = 'rotright'; - foreach($r as $rr) { + $photos = []; + if ($r) { + $twist = 'rotright'; + foreach ($r as $rr) { - if($twist == 'rotright') - $twist = 'rotleft'; - else - $twist = 'rotright'; + if ($twist == 'rotright') + $twist = 'rotleft'; + else + $twist = 'rotright'; - $ext = $phototypes[$rr['mimetype']]; + $ext = $phototypes[$rr['mimetype']]; - $imgalt_e = $rr['filename']; - $desc_e = $rr['description']; + $imgalt_e = $rr['filename']; + $desc_e = $rr['description']; - $imagelink = (z_root() . '/photos/' . App::$profile['channel_address'] . '/image/' . $rr['resource_id']); + $imagelink = (z_root() . '/photos/' . App::$profile['channel_address'] . '/image/' . $rr['resource_id']); - $photos[] = array( - 'id' => $rr['id'], - 'twist' => ' ' . $twist . rand(2,4), - 'link' => $imagelink, - 'title' => t('View Photo'), - 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' .$ext, - 'alt' => $imgalt_e, - 'desc'=> $desc_e, - 'ext' => $ext, - 'hash'=> $rr['resource_id'], - 'unknown' => t('Unknown') - ); - } - } + $photos[] = array( + 'id' => $rr['id'], + 'twist' => ' ' . $twist . rand(2, 4), + 'link' => $imagelink, + 'title' => t('View Photo'), + 'src' => z_root() . '/photo/' . $rr['resource_id'] . '-' . $rr['imgscale'] . '.' . $ext, + 'alt' => $imgalt_e, + 'desc' => $desc_e, + 'ext' => $ext, + 'hash' => $rr['resource_id'], + 'unknown' => t('Unknown') + ); + } + } - $tpl = get_markup_template('photo_album.tpl'); - $o .= replace_macros($tpl, array( - '$photos' => $photos, - '$album' => (($title) ? $title : $album), - '$album_id' => rand(), - '$album_edit' => array(t('Edit Album'), $album_edit), - '$can_post' => false, - '$upload' => array(t('Upload'), z_root() . '/photos/' . App::$profile['channel_address'] . '/upload/' . bin2hex($album)), - '$order' => false, - '$upload_form' => $upload_form, - '$usage' => $usage_message - )); - - return $o; - } + $tpl = get_markup_template('photo_album.tpl'); + $o .= replace_macros($tpl, array( + '$photos' => $photos, + '$album' => (($title) ? $title : $album), + '$album_id' => rand(), + '$album_edit' => array(t('Edit Album'), $album_edit), + '$can_post' => false, + '$upload' => array(t('Upload'), z_root() . '/photos/' . App::$profile['channel_address'] . '/upload/' . bin2hex($album)), + '$order' => false, + '$upload_form' => $upload_form, + '$usage' => $usage_message + )); + + return $o; + } } diff --git a/Zotlabs/Widget/Appcategories.php b/Zotlabs/Widget/Appcategories.php index c698be069..2ec9c00bc 100644 --- a/Zotlabs/Widget/Appcategories.php +++ b/Zotlabs/Widget/Appcategories.php @@ -2,28 +2,30 @@ namespace Zotlabs\Widget; -class Appcategories { +class Appcategories +{ - function widget($arr) { + public function widget($arr) + { - if(! local_channel()) - return ''; + if (!local_channel()) + return ''; - $selected = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : ''); + $selected = ((x($_REQUEST, 'cat')) ? htmlspecialchars($_REQUEST['cat'], ENT_COMPAT, 'UTF-8') : ''); - // @FIXME ??? $srchurl undefined here - commented out until is reviewed - //$srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&'); - //$srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl); + // @FIXME ??? $srchurl undefined here - commented out until is reviewed + //$srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&'); + //$srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl); - // Leaving this line which negates the effect of the two invalid lines prior - $srchurl = z_root() . '/apps'; - if(argc() > 1 && argv(1) === 'available') - $srchurl .= '/available'; + // Leaving this line which negates the effect of the two invalid lines prior + $srchurl = z_root() . '/apps'; + if (argc() > 1 && argv(1) === 'available') + $srchurl .= '/available'; - $terms = []; + $terms = []; - $r = q("select distinct(term.term) + $r = q("select distinct(term.term) from term join app on term.oid = app.id where app_channel = %d and term.uid = app_channel @@ -31,23 +33,23 @@ class Appcategories { and term.term != 'nav_featured_app' and term.term != 'nav_pinned_app' order by term.term asc", - intval(local_channel()), - intval(TERM_OBJ_APP) - ); + intval(local_channel()), + intval(TERM_OBJ_APP) + ); - if($r) { - foreach($r as $rr) - $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); + if ($r) { + foreach ($r as $rr) + $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); - return replace_macros(get_markup_template('categories_widget.tpl'),array( - '$title' => t('Categories'), - '$desc' => '', - '$sel_all' => (($selected == '') ? 'selected' : ''), - '$all' => t('Everything'), - '$terms' => $terms, - '$base' => $srchurl, + return replace_macros(get_markup_template('categories_widget.tpl'), array( + '$title' => t('Categories'), + '$desc' => '', + '$sel_all' => (($selected == '') ? 'selected' : ''), + '$all' => t('Everything'), + '$terms' => $terms, + '$base' => $srchurl, - )); - } - } + )); + } + } } diff --git a/Zotlabs/Widget/Appcloud.php b/Zotlabs/Widget/Appcloud.php index 2a4671eee..e927ea980 100644 --- a/Zotlabs/Widget/Appcloud.php +++ b/Zotlabs/Widget/Appcloud.php @@ -2,12 +2,14 @@ namespace Zotlabs\Widget; -class Appcloud { +class Appcloud +{ - function widget($arr) { - if(! local_channel()) - return ''; - return app_tagblock(z_root() . '/apps'); - } + public function widget($arr) + { + if (!local_channel()) + return ''; + return app_tagblock(z_root() . '/apps'); + } } diff --git a/Zotlabs/Widget/Appstore.php b/Zotlabs/Widget/Appstore.php index 0f5d29ee7..ee55889aa 100644 --- a/Zotlabs/Widget/Appstore.php +++ b/Zotlabs/Widget/Appstore.php @@ -3,16 +3,18 @@ namespace Zotlabs\Widget; -class Appstore { +class Appstore +{ - function widget($arr) { - $store = ((argc() > 1 && argv(1) === 'available') ? 1 : 0); - return replace_macros(get_markup_template('appstore.tpl'), [ - '$title' => t('App Collections'), - '$options' => [ - [ z_root() . '/apps', t('Installed Apps'), 1 - $store ], - [ z_root() . '/apps/available', t('Available Apps'), $store ] - ] - ]); - } + public function widget($arr) + { + $store = ((argc() > 1 && argv(1) === 'available') ? 1 : 0); + return replace_macros(get_markup_template('appstore.tpl'), [ + '$title' => t('App Collections'), + '$options' => [ + [z_root() . '/apps', t('Installed Apps'), 1 - $store], + [z_root() . '/apps/available', t('Available Apps'), $store] + ] + ]); + } } diff --git a/Zotlabs/Widget/Archive.php b/Zotlabs/Widget/Archive.php index 8dd8c704f..c6b3f4687 100644 --- a/Zotlabs/Widget/Archive.php +++ b/Zotlabs/Widget/Archive.php @@ -5,53 +5,55 @@ namespace Zotlabs\Widget; use App; -class Archive { +class Archive +{ - function widget($arr) { + public function widget($arr) + { - $o = ''; + $o = ''; - if(! App::$profile_uid) { - return ''; - } + if (!App::$profile_uid) { + return ''; + } - $uid = App::$profile_uid; + $uid = App::$profile_uid; - if(! feature_enabled($uid,'archives')) - return ''; + if (!feature_enabled($uid, 'archives')) + return ''; - if(! perm_is_allowed($uid,get_observer_hash(),'view_stream')) - return ''; + if (!perm_is_allowed($uid, get_observer_hash(), 'view_stream')) + return ''; - $wall = ((array_key_exists('wall', $arr)) ? intval($arr['wall']) : 0); - $wall = ((array_key_exists('articles', $arr)) ? 2 : $wall); + $wall = ((array_key_exists('wall', $arr)) ? intval($arr['wall']) : 0); + $wall = ((array_key_exists('articles', $arr)) ? 2 : $wall); - $style = ((array_key_exists('style', $arr)) ? $arr['style'] : 'select'); - $showend = ((get_pconfig($uid,'system','archive_show_end_date')) ? true : false); - $mindate = get_pconfig($uid,'system','archive_mindate'); - $visible_years = get_pconfig($uid,'system','archive_visible_years',5); + $style = ((array_key_exists('style', $arr)) ? $arr['style'] : 'select'); + $showend = ((get_pconfig($uid, 'system', 'archive_show_end_date')) ? true : false); + $mindate = get_pconfig($uid, 'system', 'archive_mindate'); + $visible_years = get_pconfig($uid, 'system', 'archive_visible_years', 5); - $url = z_root() . '/' . App::$cmd; + $url = z_root() . '/' . App::$cmd; - $ret = list_post_dates($uid,$wall,$mindate); + $ret = list_post_dates($uid, $wall, $mindate); - if(! count($ret)) - return ''; + if (!count($ret)) + return ''; - $cutoff_year = intval(datetime_convert('',date_default_timezone_get(),'now','Y')) - $visible_years; - $cutoff = ((array_key_exists($cutoff_year,$ret))? true : false); + $cutoff_year = intval(datetime_convert('', date_default_timezone_get(), 'now', 'Y')) - $visible_years; + $cutoff = ((array_key_exists($cutoff_year, $ret)) ? true : false); - $o = replace_macros(get_markup_template('posted_date_widget.tpl'),array( - '$title' => t('Archives'), - '$size' => $visible_years, - '$cutoff_year' => $cutoff_year, - '$cutoff' => $cutoff, - '$url' => $url, - '$style' => $style, - '$showend' => $showend, - '$dates' => $ret - )); - return $o; - } + $o = replace_macros(get_markup_template('posted_date_widget.tpl'), array( + '$title' => t('Archives'), + '$size' => $visible_years, + '$cutoff_year' => $cutoff_year, + '$cutoff' => $cutoff, + '$url' => $url, + '$style' => $style, + '$showend' => $showend, + '$dates' => $ret + )); + return $o; + } } diff --git a/Zotlabs/Widget/Bookmarkedchats.php b/Zotlabs/Widget/Bookmarkedchats.php index b078f91d5..876727eea 100644 --- a/Zotlabs/Widget/Bookmarkedchats.php +++ b/Zotlabs/Widget/Bookmarkedchats.php @@ -4,27 +4,29 @@ namespace Zotlabs\Widget; use App; -class Bookmarkedchats { +class Bookmarkedchats +{ - function widget($arr) { + public function widget($arr) + { - if(! feature_enabled(App::$profile['profile_uid'],'ajaxchat')) - return ''; + if (!feature_enabled(App::$profile['profile_uid'], 'ajaxchat')) + return ''; - $h = get_observer_hash(); - if(! $h) - return; - $r = q("select xchat_url, xchat_desc from xchat where xchat_xchan = '%s' order by xchat_desc", - dbesc($h) - ); - if($r) { - for($x = 0; $x < count($r); $x ++) { - $r[$x]['xchat_url'] = zid($r[$x]['xchat_url']); - } - } - return replace_macros(get_markup_template('bookmarkedchats.tpl'),array( - '$header' => t('Bookmarked Chatrooms'), - '$rooms' => $r - )); - } + $h = get_observer_hash(); + if (!$h) + return; + $r = q("select xchat_url, xchat_desc from xchat where xchat_xchan = '%s' order by xchat_desc", + dbesc($h) + ); + if ($r) { + for ($x = 0; $x < count($r); $x++) { + $r[$x]['xchat_url'] = zid($r[$x]['xchat_url']); + } + } + return replace_macros(get_markup_template('bookmarkedchats.tpl'), array( + '$header' => t('Bookmarked Chatrooms'), + '$rooms' => $r + )); + } } diff --git a/Zotlabs/Widget/Catcloud.php b/Zotlabs/Widget/Catcloud.php index c8a32470d..05daf5330 100644 --- a/Zotlabs/Widget/Catcloud.php +++ b/Zotlabs/Widget/Catcloud.php @@ -4,45 +4,47 @@ namespace Zotlabs\Widget; use App; -class Catcloud { +class Catcloud +{ - function widget($arr) { + public function widget($arr) + { - if((! App::$profile['profile_uid']) || (! App::$profile['channel_hash'])) - return ''; + if ((!App::$profile['profile_uid']) || (!App::$profile['channel_hash'])) + return ''; - $limit = ((array_key_exists('limit',$arr)) ? intval($arr['limit']) : 50); + $limit = ((array_key_exists('limit', $arr)) ? intval($arr['limit']) : 50); - if(array_key_exists('type',$arr)) { - switch($arr['type']) { + if (array_key_exists('type', $arr)) { + switch ($arr['type']) { - case 'cards': + case 'cards': - if(! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_pages')) - return ''; + if (!perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_pages')) + return ''; - return card_catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash']); + return card_catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash']); - case 'articles': - - if(! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_articles')) - return ''; + case 'articles': - return article_catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash']); + if (!perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_articles')) + return ''; + + return article_catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash']); - default: - break; - } - } + default: + break; + } + } - if(! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_stream')) - return ''; + if (!perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_stream')) + return ''; - return catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash']); + return catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash']); - } + } } diff --git a/Zotlabs/Widget/Catcloud_wall.php b/Zotlabs/Widget/Catcloud_wall.php index 4e06a8e1c..32fe24ae8 100644 --- a/Zotlabs/Widget/Catcloud_wall.php +++ b/Zotlabs/Widget/Catcloud_wall.php @@ -4,18 +4,20 @@ namespace Zotlabs\Widget; use App; -class Catcloud_wall { +class Catcloud_wall +{ - function widget($arr) { + public function widget($arr) + { - if((! App::$profile['profile_uid']) || (! App::$profile['channel_hash'])) - return ''; - if(! perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_stream')) - return ''; + if ((!App::$profile['profile_uid']) || (!App::$profile['channel_hash'])) + return ''; + if (!perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), 'view_stream')) + return ''; - $limit = ((array_key_exists('limit',$arr)) ? intval($arr['limit']) : 50); + $limit = ((array_key_exists('limit', $arr)) ? intval($arr['limit']) : 50); - return catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash'], 'wall'); - } + return catblock(App::$profile['profile_uid'], $limit, '', App::$profile['channel_hash'], 'wall'); + } } diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php index 7170a3ded..86a24717f 100644 --- a/Zotlabs/Widget/Categories.php +++ b/Zotlabs/Widget/Categories.php @@ -5,54 +5,57 @@ namespace Zotlabs\Widget; use App; use Zotlabs\Lib\Apps; -class Categories { +class Categories +{ - function widget($arr) { + public function widget($arr) + { - $cards = ((array_key_exists('cards',$arr) && $arr['cards']) ? true : false); + $cards = ((array_key_exists('cards', $arr) && $arr['cards']) ? true : false); - if(($cards) && (! Apps::system_app_installed(App::$profile['profile_uid'], 'Cards'))) - return ''; + if (($cards) && (!Apps::system_app_installed(App::$profile['profile_uid'], 'Cards'))) + return ''; - $articles = ((array_key_exists('articles',$arr) && $arr['articles']) ? true : false); + $articles = ((array_key_exists('articles', $arr) && $arr['articles']) ? true : false); - if(($articles) && (! Apps::addon_app_installed(App::$profile['profile_uid'],'articles'))) - return ''; + if (($articles) && (!Apps::addon_app_installed(App::$profile['profile_uid'], 'articles'))) + return ''; - if((! App::$profile['profile_uid']) - || (! perm_is_allowed(App::$profile['profile_uid'],get_observer_hash(),(($cards || $articles) ? 'view_pages' : 'view_articles')))) { - return ''; - } + if ((!App::$profile['profile_uid']) + || (!perm_is_allowed(App::$profile['profile_uid'], get_observer_hash(), (($cards || $articles) ? 'view_pages' : 'view_articles')))) { + return ''; + } - $cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : ''); - $srchurl = (($cards) ? App::$argv[0] . '/' . App::$argv[1] : App::$query_string); - $srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&'); - $srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl); + $cat = ((x($_REQUEST, 'cat')) ? htmlspecialchars($_REQUEST['cat'], ENT_COMPAT, 'UTF-8') : ''); + $srchurl = (($cards) ? App::$argv[0] . '/' . App::$argv[1] : App::$query_string); + $srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is', '', $srchurl), '&'); + $srchurl = str_replace(array('?f=', '&f='), array('', ''), $srchurl); - if($cards) - return self::cardcategories_widget($srchurl, $cat); - elseif($articles) - return self::articlecategories_widget($srchurl, $cat); - else - return self::categories_widget($srchurl, $cat); + if ($cards) + return self::cardcategories_widget($srchurl, $cat); + elseif ($articles) + return self::articlecategories_widget($srchurl, $cat); + else + return self::categories_widget($srchurl, $cat); - } + } - static function articlecategories_widget($baseurl,$selected = '') { - - if(! Apps::system_app_installed(App::$profile['profile_uid'],'Categories')) - return ''; + public static function articlecategories_widget($baseurl, $selected = '') + { - $sql_extra = item_permissions_sql(App::$profile['profile_uid']); + if (!Apps::system_app_installed(App::$profile['profile_uid'], 'Categories')) + return ''; - $item_normal = "and item.item_hidden = 0 and item.item_type = 7 and item.item_deleted = 0 + $sql_extra = item_permissions_sql(App::$profile['profile_uid']); + + $item_normal = "and item.item_hidden = 0 and item.item_type = 7 and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 and item.item_blocked = 0 "; - $terms = []; - $r = q("select distinct(term.term) + $terms = []; + $r = q("select distinct(term.term) from term join item on term.oid = item.id where item.uid = %d and term.uid = item.uid @@ -62,41 +65,42 @@ class Categories { $item_normal $sql_extra order by term.term asc", - intval(App::$profile['profile_uid']), - intval(TERM_CATEGORY), - intval(TERM_OBJ_POST), - dbesc(App::$profile['channel_hash']) - ); - if($r && count($r)) { - foreach($r as $rr) - $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); + intval(App::$profile['profile_uid']), + intval(TERM_CATEGORY), + intval(TERM_OBJ_POST), + dbesc(App::$profile['channel_hash']) + ); + if ($r && count($r)) { + foreach ($r as $rr) + $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); - return replace_macros(get_markup_template('categories_widget.tpl'),array( - '$title' => t('Categories'), - '$desc' => '', - '$sel_all' => (($selected == '') ? 'selected' : ''), - '$all' => t('Everything'), - '$terms' => $terms, - '$base' => $baseurl, + return replace_macros(get_markup_template('categories_widget.tpl'), array( + '$title' => t('Categories'), + '$desc' => '', + '$sel_all' => (($selected == '') ? 'selected' : ''), + '$all' => t('Everything'), + '$terms' => $terms, + '$base' => $baseurl, - )); - } - return ''; - } + )); + } + return ''; + } - static function cardcategories_widget($baseurl,$selected = '') { - - if(! Apps::system_app_installed(App::$profile['profile_uid'],'Categories')) - return ''; + public static function cardcategories_widget($baseurl, $selected = '') + { - $sql_extra = item_permissions_sql(App::$profile['profile_uid']); + if (!Apps::system_app_installed(App::$profile['profile_uid'], 'Categories')) + return ''; - $item_normal = "and item.item_hidden = 0 and item.item_type = 6 and item.item_deleted = 0 + $sql_extra = item_permissions_sql(App::$profile['profile_uid']); + + $item_normal = "and item.item_hidden = 0 and item.item_type = 6 and item.item_deleted = 0 and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0 and item.item_blocked = 0 "; - $terms = []; - $r = q("select distinct(term.term) + $terms = []; + $r = q("select distinct(term.term) from term join item on term.oid = item.id where item.uid = %d and term.uid = item.uid @@ -106,42 +110,43 @@ class Categories { $item_normal $sql_extra order by term.term asc", - intval(App::$profile['profile_uid']), - intval(TERM_CATEGORY), - intval(TERM_OBJ_POST), - dbesc(App::$profile['channel_hash']) - ); - if($r && count($r)) { - foreach($r as $rr) - $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); + intval(App::$profile['profile_uid']), + intval(TERM_CATEGORY), + intval(TERM_OBJ_POST), + dbesc(App::$profile['channel_hash']) + ); + if ($r && count($r)) { + foreach ($r as $rr) + $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); - return replace_macros(get_markup_template('categories_widget.tpl'),array( - '$title' => t('Categories'), - '$desc' => '', - '$sel_all' => (($selected == '') ? 'selected' : ''), - '$all' => t('Everything'), - '$terms' => $terms, - '$base' => $baseurl, + return replace_macros(get_markup_template('categories_widget.tpl'), array( + '$title' => t('Categories'), + '$desc' => '', + '$sel_all' => (($selected == '') ? 'selected' : ''), + '$all' => t('Everything'), + '$terms' => $terms, + '$base' => $baseurl, - )); - } - return ''; - } + )); + } + return ''; + } - static function categories_widget($baseurl,$selected = '') { - - if(! Apps::system_app_installed(App::$profile['profile_uid'],'Categories')) - return ''; + public static function categories_widget($baseurl, $selected = '') + { - require_once('include/security.php'); + if (!Apps::system_app_installed(App::$profile['profile_uid'], 'Categories')) + return ''; - $sql_extra = item_permissions_sql(App::$profile['profile_uid']); - - $item_normal = item_normal(); + require_once('include/security.php'); - $terms = []; - $r = q("select distinct(term.term) from term join item on term.oid = item.id + $sql_extra = item_permissions_sql(App::$profile['profile_uid']); + + $item_normal = item_normal(); + + $terms = []; + $r = q("select distinct(term.term) from term join item on term.oid = item.id where item.uid = %d and term.uid = item.uid and term.ttype = %d @@ -152,27 +157,27 @@ class Categories { $item_normal $sql_extra order by term.term asc", - intval(App::$profile['profile_uid']), - intval(TERM_CATEGORY), - intval(TERM_OBJ_POST), - dbesc(App::$profile['channel_hash']), - dbesc(ACTIVITY_UPDATE) - ); - if($r && count($r)) { - foreach($r as $rr) - $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); + intval(App::$profile['profile_uid']), + intval(TERM_CATEGORY), + intval(TERM_OBJ_POST), + dbesc(App::$profile['channel_hash']), + dbesc(ACTIVITY_UPDATE) + ); + if ($r && count($r)) { + foreach ($r as $rr) + $terms[] = array('name' => $rr['term'], 'selected' => (($selected == $rr['term']) ? 'selected' : '')); - return replace_macros(get_markup_template('categories_widget.tpl'),array( - '$title' => t('Categories'), - '$desc' => '', - '$sel_all' => (($selected == '') ? 'selected' : ''), - '$all' => t('Everything'), - '$terms' => $terms, - '$base' => $baseurl, + return replace_macros(get_markup_template('categories_widget.tpl'), array( + '$title' => t('Categories'), + '$desc' => '', + '$sel_all' => (($selected == '') ? 'selected' : ''), + '$all' => t('Everything'), + '$terms' => $terms, + '$base' => $baseurl, - )); - } - return ''; - } + )); + } + return ''; + } } diff --git a/Zotlabs/Widget/Cdav.php b/Zotlabs/Widget/Cdav.php index 0e38d3d9f..550dc140a 100644 --- a/Zotlabs/Widget/Cdav.php +++ b/Zotlabs/Widget/Cdav.php @@ -8,187 +8,188 @@ use App; use DBA; use Sabre\CardDAV\Backend\PDO; -class Cdav { +class Cdav +{ - function widget() { - if(!local_channel()) - return; + public function widget() + { + if (!local_channel()) + return; - $channel = App::get_channel(); - $principalUri = 'principals/' . $channel['channel_address']; + $channel = App::get_channel(); + $principalUri = 'principals/' . $channel['channel_address']; - if(!cdav_principal($principalUri)) - return; + if (!cdav_principal($principalUri)) + return; - $pdo = DBA::$dba->db; + $pdo = DBA::$dba->db; - require_once 'vendor/autoload.php'; + require_once 'vendor/autoload.php'; - $o = ''; + $o = ''; - if(argc() <= 3 && argv(1) === 'calendar') { + if (argc() <= 3 && argv(1) === 'calendar') { - $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); + $caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo); - $sabrecals = $caldavBackend->getCalendarsForUser($principalUri); + $sabrecals = $caldavBackend->getCalendarsForUser($principalUri); - //TODO: we should probably also check for permission to send stream here - $local_channels = q("SELECT * FROM channel LEFT JOIN abook ON abook_xchan = channel_hash WHERE channel_system = 0 AND channel_removed = 0 AND channel_hash != '%s' AND abook_channel = %d", - dbesc($channel['channel_hash']), - intval($channel['channel_id']) - ); + //TODO: we should probably also check for permission to send stream here + $local_channels = q("SELECT * FROM channel LEFT JOIN abook ON abook_xchan = channel_hash WHERE channel_system = 0 AND channel_removed = 0 AND channel_hash != '%s' AND abook_channel = %d", + dbesc($channel['channel_hash']), + intval($channel['channel_id']) + ); - $sharee_options .= '' . "\r\n"; - foreach($local_channels as $local_channel) { - $sharee_options .= '' . "\r\n"; - } + $sharee_options .= '' . "\r\n"; + foreach ($local_channels as $local_channel) { + $sharee_options .= '' . "\r\n"; + } - $access_options = '' . "\r\n"; - $access_options .= '' . "\r\n"; + $access_options = '' . "\r\n"; + $access_options .= '' . "\r\n"; - //list calendars - foreach($sabrecals as $sabrecal) { - if($sabrecal['share-access'] == 1) - $access = ''; - if($sabrecal['share-access'] == 2) - $access = 'read'; - if($sabrecal['share-access'] == 3) - $access = 'read-write'; + //list calendars + foreach ($sabrecals as $sabrecal) { + if ($sabrecal['share-access'] == 1) + $access = ''; + if ($sabrecal['share-access'] == 2) + $access = 'read'; + if ($sabrecal['share-access'] == 3) + $access = 'read-write'; - $invites = $caldavBackend->getInvites($sabrecal['id']); + $invites = $caldavBackend->getInvites($sabrecal['id']); - $json_source = '/cdav/calendar/json/' . $sabrecal['id'][0] . '/' . $sabrecal['id'][1]; + $json_source = '/cdav/calendar/json/' . $sabrecal['id'][0] . '/' . $sabrecal['id'][1]; - $switch = get_pconfig(local_channel(), 'cdav_calendar', $sabrecal['id'][0]); + $switch = get_pconfig(local_channel(), 'cdav_calendar', $sabrecal['id'][0]); - $color = (($sabrecal['{http://apple.com/ns/ical/}calendar-color']) ? $sabrecal['{http://apple.com/ns/ical/}calendar-color'] : '#6cad39'); + $color = (($sabrecal['{http://apple.com/ns/ical/}calendar-color']) ? $sabrecal['{http://apple.com/ns/ical/}calendar-color'] : '#6cad39'); - $editable = (($sabrecal['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript + $editable = (($sabrecal['share-access'] == 2) ? 'false' : 'true'); // false/true must be string since we're passing it to javascript - $sharees = []; - $share_displayname = []; + $sharees = []; + $share_displayname = []; - foreach($invites as $invite) { - if(strpos($invite->href, 'mailto:') !== false) { - $sharee = channelx_by_nick(substr($invite->principal, 11)); - $sharees[] = [ - 'name' => $sharee['channel_name'], - 'access' => (($invite->access == 3) ? ' (RW)' : ' (R)'), - 'hash' => $sharee['channel_hash'] - ]; - } - } + foreach ($invites as $invite) { + if (strpos($invite->href, 'mailto:') !== false) { + $sharee = channelx_by_nick(substr($invite->principal, 11)); + $sharees[] = [ + 'name' => $sharee['channel_name'], + 'access' => (($invite->access == 3) ? ' (RW)' : ' (R)'), + 'hash' => $sharee['channel_hash'] + ]; + } + } - if(!$access) { - $my_calendars[] = [ - 'ownernick' => $channel['channel_address'], - 'uri' => $sabrecal['uri'], - 'displayname' => $sabrecal['{DAV:}displayname'], - 'calendarid' => $sabrecal['id'][0], - 'instanceid' => $sabrecal['id'][1], - 'json_source' => $json_source, - 'color' => $color, - 'editable' => $editable, - 'switch' => $switch, - 'sharees' => $sharees - ]; - } - else { - $shared_calendars[] = [ - 'ownernick' => $channel['channel_address'], - 'uri' => $sabrecal['uri'], - 'displayname' => $sabrecal['{DAV:}displayname'], - 'calendarid' => $sabrecal['id'][0], - 'instanceid' => $sabrecal['id'][1], - 'json_source' => $json_source, - 'color' => $color, - 'editable' => $editable, - 'switch' => $switch, - 'sharer' => $sabrecal['{urn:ietf:params:xml:ns:caldav}calendar-description'], - 'access' => $access - ]; - } + if (!$access) { + $my_calendars[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabrecal['uri'], + 'displayname' => $sabrecal['{DAV:}displayname'], + 'calendarid' => $sabrecal['id'][0], + 'instanceid' => $sabrecal['id'][1], + 'json_source' => $json_source, + 'color' => $color, + 'editable' => $editable, + 'switch' => $switch, + 'sharees' => $sharees + ]; + } else { + $shared_calendars[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabrecal['uri'], + 'displayname' => $sabrecal['{DAV:}displayname'], + 'calendarid' => $sabrecal['id'][0], + 'instanceid' => $sabrecal['id'][1], + 'json_source' => $json_source, + 'color' => $color, + 'editable' => $editable, + 'switch' => $switch, + 'sharer' => $sabrecal['{urn:ietf:params:xml:ns:caldav}calendar-description'], + 'access' => $access + ]; + } - if(!$access || $access === 'read-write') { - $writable_calendars[] = [ - 'displayname' => ((!$access) ? $sabrecal['{DAV:}displayname'] : $share_displayname[0]), - 'id' => $sabrecal['id'] - ]; - } - } + if (!$access || $access === 'read-write') { + $writable_calendars[] = [ + 'displayname' => ((!$access) ? $sabrecal['{DAV:}displayname'] : $share_displayname[0]), + 'id' => $sabrecal['id'] + ]; + } + } - $calendars[] = [ - 'ownernick' => $channel['channel_address'], - 'displayname' => $channel['channel_name'], - 'calendarid' => 'calendar', - 'json_source' => '/calendar/json', - 'color' => '#3a87ad', - 'editable' => true, - 'switch' => get_pconfig(local_channel(), 'cdav_calendar', 'calendar') - ]; + $calendars[] = [ + 'ownernick' => $channel['channel_address'], + 'displayname' => $channel['channel_name'], + 'calendarid' => 'calendar', + 'json_source' => '/calendar/json', + 'color' => '#3a87ad', + 'editable' => true, + 'switch' => get_pconfig(local_channel(), 'cdav_calendar', 'calendar') + ]; - $o .= replace_macros(get_markup_template('cdav_widget_calendar.tpl'), [ - '$calendars_label' => t('Channel Calendar'), - '$calendars' => $calendars, - '$my_calendars_label' => t('CalDAV Calendars'), - '$my_calendars' => $my_calendars, - '$shared_calendars_label' => t('Shared CalDAV Calendars'), - '$shared_calendars' => $shared_calendars, - '$sharee_options' => $sharee_options, - '$access_options' => $access_options, - '$share_label' => t('Share this calendar'), - '$share' => t('Share'), - '$edit_label' => t('Calendar name and color'), - '$edit' => t('Edit'), - '$create_label' => t('Create new CalDAV calendar'), - '$create' => t('Create'), - '$create_placeholder' => t('Calendar Name'), - '$tools_label' => t('Calendar Tools'), - '$tools_options_label' => [t('Channel Calendars'), t('CalDAV Calendars')], - '$import_label' => t('Import calendar'), - '$import_placeholder' => t('Select a calendar to import to'), - '$upload' => t('Upload'), - '$writable_calendars' => $writable_calendars - ]); + $o .= replace_macros(get_markup_template('cdav_widget_calendar.tpl'), [ + '$calendars_label' => t('Channel Calendar'), + '$calendars' => $calendars, + '$my_calendars_label' => t('CalDAV Calendars'), + '$my_calendars' => $my_calendars, + '$shared_calendars_label' => t('Shared CalDAV Calendars'), + '$shared_calendars' => $shared_calendars, + '$sharee_options' => $sharee_options, + '$access_options' => $access_options, + '$share_label' => t('Share this calendar'), + '$share' => t('Share'), + '$edit_label' => t('Calendar name and color'), + '$edit' => t('Edit'), + '$create_label' => t('Create new CalDAV calendar'), + '$create' => t('Create'), + '$create_placeholder' => t('Calendar Name'), + '$tools_label' => t('Calendar Tools'), + '$tools_options_label' => [t('Channel Calendars'), t('CalDAV Calendars')], + '$import_label' => t('Import calendar'), + '$import_placeholder' => t('Select a calendar to import to'), + '$upload' => t('Upload'), + '$writable_calendars' => $writable_calendars + ]); - return $o; + return $o; - } + } - if(argc() >= 2 && argv(1) === 'addressbook') { + if (argc() >= 2 && argv(1) === 'addressbook') { - $carddavBackend = new PDO($pdo); + $carddavBackend = new PDO($pdo); - $sabreabooks = $carddavBackend->getAddressBooksForUser($principalUri); + $sabreabooks = $carddavBackend->getAddressBooksForUser($principalUri); - //list addressbooks - foreach($sabreabooks as $sabreabook) { - $addressbooks[] = [ - 'ownernick' => $channel['channel_address'], - 'uri' => $sabreabook['uri'], - 'displayname' => $sabreabook['{DAV:}displayname'], - 'id' => $sabreabook['id'] - - ]; - } + //list addressbooks + foreach ($sabreabooks as $sabreabook) { + $addressbooks[] = [ + 'ownernick' => $channel['channel_address'], + 'uri' => $sabreabook['uri'], + 'displayname' => $sabreabook['{DAV:}displayname'], + 'id' => $sabreabook['id'] - $o .= replace_macros(get_markup_template('cdav_widget_addressbook.tpl'), [ - '$addressbooks_label' => t('Addressbooks'), - '$addressbooks' => $addressbooks, - '$edit_label' => t('Addressbook name'), - '$edit' => t('Edit'), - '$create_label' => t('Create new addressbook'), - '$create_placeholder' => t('Addressbook Name'), - '$create' => t('Create'), - '$tools_label' => t('Addressbook Tools'), - '$import_label' => t('Import addressbook'), - '$import_placeholder' => t('Select an addressbook to import to'), - '$upload' => t('Upload') - ]); + ]; + } - return $o; + $o .= replace_macros(get_markup_template('cdav_widget_addressbook.tpl'), [ + '$addressbooks_label' => t('Addressbooks'), + '$addressbooks' => $addressbooks, + '$edit_label' => t('Addressbook name'), + '$edit' => t('Edit'), + '$create_label' => t('Create new addressbook'), + '$create_placeholder' => t('Addressbook Name'), + '$create' => t('Create'), + '$tools_label' => t('Addressbook Tools'), + '$import_label' => t('Import addressbook'), + '$import_placeholder' => t('Select an addressbook to import to'), + '$upload' => t('Upload') + ]); - } + return $o; - } + } + + } } diff --git a/Zotlabs/Widget/Chatroom_list.php b/Zotlabs/Widget/Chatroom_list.php index 7a49edd94..8dbfd2f6b 100644 --- a/Zotlabs/Widget/Chatroom_list.php +++ b/Zotlabs/Widget/Chatroom_list.php @@ -5,23 +5,25 @@ namespace Zotlabs\Widget; use App; use Zotlabs\Lib\Chatroom; -class Chatroom_list { +class Chatroom_list +{ - function widget($arr) { + public function widget($arr) + { - if(! App::$profile) - return ''; + if (!App::$profile) + return ''; - $r = Chatroom::roomlist(App::$profile['profile_uid']); + $r = Chatroom::roomlist(App::$profile['profile_uid']); - if($r) { - return replace_macros(get_markup_template('chatroomlist.tpl'), array( - '$header' => t('Chatrooms'), - '$baseurl' => z_root(), - '$nickname' => App::$profile['channel_address'], - '$items' => $r, - '$overview' => t('Overview') - )); - } - } + if ($r) { + return replace_macros(get_markup_template('chatroomlist.tpl'), array( + '$header' => t('Chatrooms'), + '$baseurl' => z_root(), + '$nickname' => App::$profile['channel_address'], + '$items' => $r, + '$overview' => t('Overview') + )); + } + } } diff --git a/Zotlabs/Widget/Chatroom_members.php b/Zotlabs/Widget/Chatroom_members.php index 8ed77fb3c..619c23b73 100644 --- a/Zotlabs/Widget/Chatroom_members.php +++ b/Zotlabs/Widget/Chatroom_members.php @@ -2,14 +2,16 @@ namespace Zotlabs\Widget; -class Chatroom_members { +class Chatroom_members +{ - // The actual contents are filled in via AJAX + // The actual contents are filled in via AJAX - function widget() { - return replace_macros(get_markup_template('chatroom_members.tpl'), array( - '$header' => t('Chat Members') - )); - } + public function widget() + { + return replace_macros(get_markup_template('chatroom_members.tpl'), array( + '$header' => t('Chat Members') + )); + } } diff --git a/Zotlabs/Widget/Clock.php b/Zotlabs/Widget/Clock.php index 8dae200c0..65b34d9cc 100644 --- a/Zotlabs/Widget/Clock.php +++ b/Zotlabs/Widget/Clock.php @@ -2,13 +2,15 @@ namespace Zotlabs\Widget; -class Clock { +class Clock +{ - function widget($arr) { + public function widget($arr) + { - $miltime = ((isset($arr['military']) && $arr['military']) ? intval($arr['military']) : false); + $miltime = ((isset($arr['military']) && $arr['military']) ? intval($arr['military']) : false); - $o = <<< EOT + $o = <<< EOT

      '; - $o .= ''; + $o .= ''; - $o .= '
      ' . '

      ' . t('Tasks') . '

      '; - $o .= '
      '; - $o .= '
      '; - return $o; + $o .= '
      ' . '

      ' . t('Tasks') . '

      '; + $o .= '
      '; + $o .= '
      '; + return $o; - } + } } diff --git a/Zotlabs/Widget/Vcard.php b/Zotlabs/Widget/Vcard.php index 268a466b6..bf7bfc641 100644 --- a/Zotlabs/Widget/Vcard.php +++ b/Zotlabs/Widget/Vcard.php @@ -4,11 +4,13 @@ namespace Zotlabs\Widget; use App; -class Vcard { +class Vcard +{ - function widget($arr) { - return vcard_from_xchan('', App::get_observer()); - } + public function widget($arr) + { + return vcard_from_xchan('', App::get_observer()); + } } diff --git a/Zotlabs/Widget/Website_portation_tools.php b/Zotlabs/Widget/Website_portation_tools.php index e0cdc346b..dc97c7fcf 100644 --- a/Zotlabs/Widget/Website_portation_tools.php +++ b/Zotlabs/Widget/Website_portation_tools.php @@ -5,20 +5,22 @@ namespace Zotlabs\Widget; use App; -class Website_portation_tools { +class Website_portation_tools +{ - function widget($arr) { + public function widget($arr) + { - // mod menu doesn't load a profile. For any modules which load a profile, check it. - // otherwise local_channel() is sufficient for permissions. + // mod menu doesn't load a profile. For any modules which load a profile, check it. + // otherwise local_channel() is sufficient for permissions. - if(App::$profile['profile_uid']) - if((App::$profile['profile_uid'] != local_channel()) && (! App::$is_sys)) - return ''; + if (App::$profile['profile_uid']) + if ((App::$profile['profile_uid'] != local_channel()) && (!App::$is_sys)) + return ''; - if(! local_channel()) - return ''; + if (!local_channel()) + return ''; - return website_portation_tools(); - } + return website_portation_tools(); + } } diff --git a/Zotlabs/Widget/Zcard.php b/Zotlabs/Widget/Zcard.php index 13ffec510..22fed3bf6 100644 --- a/Zotlabs/Widget/Zcard.php +++ b/Zotlabs/Widget/Zcard.php @@ -4,10 +4,12 @@ namespace Zotlabs\Widget; use App; -class Zcard { +class Zcard +{ - function widget($args) { - $channel = channelx_by_n(App::$profile_uid); - return get_zcard($channel,get_observer_hash(),array('width' => 875)); - } + public function widget($args) + { + $channel = channelx_by_n(App::$profile_uid); + return get_zcard($channel, get_observer_hash(), array('width' => 875)); + } } diff --git a/Zotlabs/Zot6/IHandler.php b/Zotlabs/Zot6/IHandler.php index 0813b6ce0..69e115abb 100644 --- a/Zotlabs/Zot6/IHandler.php +++ b/Zotlabs/Zot6/IHandler.php @@ -2,15 +2,16 @@ namespace Zotlabs\Zot6; -interface IHandler { +interface IHandler +{ - function Notify($data,$hub); + public function Notify($data, $hub); - function Rekey($sender,$data,$hub); + public function Rekey($sender, $data, $hub); - function Refresh($sender,$recipients,$hub,$force); + public function Refresh($sender, $recipients, $hub, $force); - function Purge($sender,$recipients,$hub); + public function Purge($sender, $recipients, $hub); } diff --git a/Zotlabs/Zot6/Receiver.php b/Zotlabs/Zot6/Receiver.php index f70f926d2..704139622 100644 --- a/Zotlabs/Zot6/Receiver.php +++ b/Zotlabs/Zot6/Receiver.php @@ -7,224 +7,228 @@ use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Crypto; use Zotlabs\Web\HTTPSig; -class Receiver { +class Receiver +{ - protected $data; - protected $encrypted; - protected $error; - protected $messagetype; - protected $sender; - protected $site_id; - protected $validated; - protected $recipients; - protected $response; - protected $handler; - protected $prvkey; - protected $rawdata; - protected $sigdata; + protected $data; + protected $encrypted; + protected $error; + protected $messagetype; + protected $sender; + protected $site_id; + protected $validated; + protected $recipients; + protected $response; + protected $handler; + protected $prvkey; + protected $rawdata; + protected $sigdata; - function __construct($handler, $localdata = null) { + public function __construct($handler, $localdata = null) + { - $this->error = false; - $this->validated = false; - $this->messagetype = ''; - $this->response = [ 'success' => false ]; - $this->handler = $handler; - $this->data = null; - $this->rawdata = null; - $this->site_id = null; - $this->prvkey = Config::get('system','prvkey'); + $this->error = false; + $this->validated = false; + $this->messagetype = ''; + $this->response = ['success' => false]; + $this->handler = $handler; + $this->data = null; + $this->rawdata = null; + $this->site_id = null; + $this->prvkey = Config::get('system', 'prvkey'); - if($localdata) { - $this->rawdata = $localdata; - } - else { - $this->rawdata = file_get_contents('php://input'); + if ($localdata) { + $this->rawdata = $localdata; + } else { + $this->rawdata = file_get_contents('php://input'); - // All access to the zot endpoint must use http signatures + // All access to the zot endpoint must use http signatures - if (! $this->Valid_Httpsig()) { - logger('signature failed'); - $this->error = true; - $this->response['message'] = 'signature invalid'; - return; - } - } + if (!$this->Valid_Httpsig()) { + logger('signature failed'); + $this->error = true; + $this->response['message'] = 'signature invalid'; + return; + } + } - logger('received raw: ' . print_r($this->rawdata,true), LOGGER_DATA); + logger('received raw: ' . print_r($this->rawdata, true), LOGGER_DATA); - if ($this->rawdata) { - $this->data = json_decode($this->rawdata,true); - if(($this->data) && (! is_array($this->data)) && (substr($this->data,0,1) === "{")) { + if ($this->rawdata) { + $this->data = json_decode($this->rawdata, true); + if (($this->data) && (!is_array($this->data)) && (substr($this->data, 0, 1) === "{")) { - // Multiple json encoding has been seen in the wild and needs to be fixed on the sending side. - // Proceed anyway and log the event with a backtrace. + // Multiple json encoding has been seen in the wild and needs to be fixed on the sending side. + // Proceed anyway and log the event with a backtrace. - btlogger('multiple encoding detected'); - $this->data = json_decode($this->data,true); - } - } - else { - $this->error = true; - $this->response['message'] = 'no data'; - } + btlogger('multiple encoding detected'); + $this->data = json_decode($this->data, true); + } + } else { + $this->error = true; + $this->response['message'] = 'no data'; + } - logger('received_json: ' . json_encode($this->data,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES), LOGGER_DATA); + logger('received_json: ' . json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOGGER_DATA); - logger('received: ' . print_r($this->data,true), LOGGER_DATA); + logger('received: ' . print_r($this->data, true), LOGGER_DATA); - if ($this->data && is_array($this->data)) { - $this->encrypted = ((array_key_exists('encrypted',$this->data) && intval($this->data['encrypted'])) ? true : false); + if ($this->data && is_array($this->data)) { + $this->encrypted = ((array_key_exists('encrypted', $this->data) && intval($this->data['encrypted'])) ? true : false); - if ($this->encrypted && $this->prvkey) { - $uncrypted = Crypto::unencapsulate($this->data,$this->prvkey); - if ($uncrypted) { - $this->data = json_decode($uncrypted,true); - } - else { - $this->error = true; - $this->response['message'] = 'no data'; - } - } - } - } - - - function run() { - - if ($this->error) { - // make timing attacks on the decryption engine a bit more difficult - usleep(mt_rand(10000,100000)); - return($this->response); - } - - if ($this->data) { - if (array_key_exists('type',$this->data)) { - $this->messagetype = $this->data['type']; - } - - if (! $this->messagetype) { - $this->error = true; - $this->response['message'] = 'no datatype'; - return $this->response; - } - - $this->sender = ((array_key_exists('sender',$this->data)) ? $this->data['sender'] : null); - $this->recipients = ((array_key_exists('recipients',$this->data)) ? $this->data['recipients'] : null); - $this->site_id = ((array_key_exists('site_id',$this->data)) ? $this->data['site_id'] : null); - } - - if ($this->sender) { - $result = $this->ValidateSender(); - if (! $result) { - $this->error = true; - return $this->response; - } - } - - return $this->Dispatch(); - } - - function ValidateSender() { - - $hub = Libzot::valid_hub($this->sender,$this->site_id); - - if (! $hub) { - $x = Libzot::register_hub($this->sigdata['signer']); - if($x['success']) { - $hub = Libzot::valid_hub($this->sender,$this->site_id); - } - if(! $hub) { - $this->response['message'] = 'sender unknown'; - return false; - } - } - - if (! check_siteallowed($hub['hubloc_url'])) { - $this->response['message'] = 'forbidden'; - return false; - } - - if (! check_channelallowed($this->sender)) { - $this->response['message'] = 'forbidden'; - return false; - } - - Libzot::update_hub_connected($hub,$this->site_id); - - $this->validated = true; - $this->hub = $hub; - return true; + if ($this->encrypted && $this->prvkey) { + $uncrypted = Crypto::unencapsulate($this->data, $this->prvkey); + if ($uncrypted) { + $this->data = json_decode($uncrypted, true); + } else { + $this->error = true; + $this->response['message'] = 'no data'; + } + } + } } - function Valid_Httpsig() { + public function run() + { - $result = false; + if ($this->error) { + // make timing attacks on the decryption engine a bit more difficult + usleep(mt_rand(10000, 100000)); + return ($this->response); + } - $this->sigdata = HTTPSig::verify($this->rawdata, EMPTY_STR, 'zot6'); + if ($this->data) { + if (array_key_exists('type', $this->data)) { + $this->messagetype = $this->data['type']; + } - if ($this->sigdata && $this->sigdata['header_signed'] && $this->sigdata['header_valid']) { - $result = true; + if (!$this->messagetype) { + $this->error = true; + $this->response['message'] = 'no datatype'; + return $this->response; + } - // It is OK to not have signed content - not all messages provide content. - // But if it is signed, it has to be valid + $this->sender = ((array_key_exists('sender', $this->data)) ? $this->data['sender'] : null); + $this->recipients = ((array_key_exists('recipients', $this->data)) ? $this->data['recipients'] : null); + $this->site_id = ((array_key_exists('site_id', $this->data)) ? $this->data['site_id'] : null); + } - if (($this->sigdata['content_signed']) && (! $this->sigdata['content_valid'])) { - $result = false; - } - } - return $result; - } - - function Dispatch() { + if ($this->sender) { + $result = $this->ValidateSender(); + if (!$result) { + $this->error = true; + return $this->response; + } + } - switch ($this->messagetype) { + return $this->Dispatch(); + } - case 'purge': - $this->response = $this->handler->Purge($this->sender,$this->recipients,$this->hub); - break; + public function ValidateSender() + { - case 'refresh': - $this->response = $this->handler->Refresh($this->sender,$this->recipients,$this->hub,false); - break; - - case 'force_refresh': - $this->response = $this->handler->Refresh($this->sender,$this->recipients,$this->hub,true); - break; + $hub = Libzot::valid_hub($this->sender, $this->site_id); - case 'rekey': - $this->response = $this->handler->Rekey($this->sender, $this->data,$this->hub); - break; + if (!$hub) { + $x = Libzot::register_hub($this->sigdata['signer']); + if ($x['success']) { + $hub = Libzot::valid_hub($this->sender, $this->site_id); + } + if (!$hub) { + $this->response['message'] = 'sender unknown'; + return false; + } + } - case 'activity': - case 'response': // upstream message - case 'sync': - default: - // Only accept these message types with a valid sender - if ($this->sender) { - $this->response = $this->handler->Notify($this->data,$this->hub); - } - break; + if (!check_siteallowed($hub['hubloc_url'])) { + $this->response['message'] = 'forbidden'; + return false; + } - } + if (!check_channelallowed($this->sender)) { + $this->response['message'] = 'forbidden'; + return false; + } - logger('response_to_return: ' . print_r($this->response,true),LOGGER_DATA); + Libzot::update_hub_connected($hub, $this->site_id); - if ($this->encrypted) { - $this->EncryptResponse(); - } + $this->validated = true; + $this->hub = $hub; + return true; + } - return($this->response); - } - function EncryptResponse() { - $algorithm = Libzot::best_algorithm($this->hub['site_crypto']); - if ($algorithm) { - $this->response = Crypto::encapsulate(json_encode($this->response),$this->hub['hubloc_sitekey'], $algorithm); - } - } + public function Valid_Httpsig() + { + + $result = false; + + $this->sigdata = HTTPSig::verify($this->rawdata, EMPTY_STR, 'zot6'); + + if ($this->sigdata && $this->sigdata['header_signed'] && $this->sigdata['header_valid']) { + $result = true; + + // It is OK to not have signed content - not all messages provide content. + // But if it is signed, it has to be valid + + if (($this->sigdata['content_signed']) && (!$this->sigdata['content_valid'])) { + $result = false; + } + } + return $result; + } + + public function Dispatch() + { + + switch ($this->messagetype) { + + case 'purge': + $this->response = $this->handler->Purge($this->sender, $this->recipients, $this->hub); + break; + + case 'refresh': + $this->response = $this->handler->Refresh($this->sender, $this->recipients, $this->hub, false); + break; + + case 'force_refresh': + $this->response = $this->handler->Refresh($this->sender, $this->recipients, $this->hub, true); + break; + + case 'rekey': + $this->response = $this->handler->Rekey($this->sender, $this->data, $this->hub); + break; + + case 'activity': + case 'response': // upstream message + case 'sync': + default: + // Only accept these message types with a valid sender + if ($this->sender) { + $this->response = $this->handler->Notify($this->data, $this->hub); + } + break; + + } + + logger('response_to_return: ' . print_r($this->response, true), LOGGER_DATA); + + if ($this->encrypted) { + $this->EncryptResponse(); + } + + return ($this->response); + } + + public function EncryptResponse() + { + $algorithm = Libzot::best_algorithm($this->hub['site_crypto']); + if ($algorithm) { + $this->response = Crypto::encapsulate(json_encode($this->response), $this->hub['hubloc_sitekey'], $algorithm); + } + } } diff --git a/Zotlabs/Zot6/Zot6Handler.php b/Zotlabs/Zot6/Zot6Handler.php index 07e85cb12..24b23a020 100644 --- a/Zotlabs/Zot6/Zot6Handler.php +++ b/Zotlabs/Zot6/Zot6Handler.php @@ -5,188 +5,193 @@ namespace Zotlabs\Zot6; use Zotlabs\Lib\Libzot; use Zotlabs\Lib\Queue; -class Zot6Handler implements IHandler { +class Zot6Handler implements IHandler +{ - function Notify($data,$hub) { - return self::reply_notify($data,$hub); - } + public function Notify($data, $hub) + { + return self::reply_notify($data, $hub); + } - function Rekey($sender,$data,$hub) { - return self::reply_rekey_request($sender,$data,$hub); - } + public function Rekey($sender, $data, $hub) + { + return self::reply_rekey_request($sender, $data, $hub); + } - function Refresh($sender,$recipients,$hub,$force) { - return self::reply_refresh($sender,$recipients,$hub,$force); - } + public function Refresh($sender, $recipients, $hub, $force) + { + return self::reply_refresh($sender, $recipients, $hub, $force); + } - function Purge($sender,$recipients,$hub) { - return self::reply_purge($sender,$recipients,$hub); - } + public function Purge($sender, $recipients, $hub) + { + return self::reply_purge($sender, $recipients, $hub); + } - // Implementation of specific methods follows; - // These generally do a small amout of validation and call Libzot - // to do any heavy lifting + // Implementation of specific methods follows; + // These generally do a small amout of validation and call Libzot + // to do any heavy lifting - static function reply_notify($data,$hub) { + public static function reply_notify($data, $hub) + { - $ret = [ 'success' => false ]; + $ret = ['success' => false]; - logger('notify received from ' . $hub['hubloc_url']); + logger('notify received from ' . $hub['hubloc_url']); - $x = Libzot::fetch($data,$hub); - $ret['delivery_report'] = $x; - - - $ret['success'] = true; - return $ret; - } + $x = Libzot::fetch($data, $hub); + $ret['delivery_report'] = $x; + $ret['success'] = true; + return $ret; + } - /** - * @brief Remote channel info (such as permissions or photo or something) - * has been updated. Grab a fresh copy and sync it. - * - * The difference between refresh and force_refresh is that force_refresh - * unconditionally creates a directory update record, even if no changes were - * detected upon processing. - * - * @param array $sender - * @param array $recipients - * - * @return json_return_and_die() - */ - static function reply_refresh($sender, $recipients,$hub,$force) { - $ret = array('success' => false); + /** + * @brief Remote channel info (such as permissions or photo or something) + * has been updated. Grab a fresh copy and sync it. + * + * The difference between refresh and force_refresh is that force_refresh + * unconditionally creates a directory update record, even if no changes were + * detected upon processing. + * + * @param array $sender + * @param array $recipients + * + * @return json_return_and_die() + */ - if($recipients) { + public static function reply_refresh($sender, $recipients, $hub, $force) + { + $ret = array('success' => false); - // This would be a permissions update, typically for one connection + if ($recipients) { - foreach ($recipients as $recip) { - $r = q("select channel.*,xchan.* from channel + // This would be a permissions update, typically for one connection + + foreach ($recipients as $recip) { + $r = q("select channel.*,xchan.* from channel left join xchan on channel_hash = xchan_hash where channel_hash ='%s' limit 1", - dbesc($recip) - ); + dbesc($recip) + ); - $x = Libzot::refresh( [ 'hubloc_id_url' => $hub['hubloc_id_url'] ], $r[0], $force ); - } - } - else { + $x = Libzot::refresh(['hubloc_id_url' => $hub['hubloc_id_url']], $r[0], $force); + } + } else { - // system wide refresh - $x = Libzot::refresh( [ 'hubloc_id_url' => $hub['hubloc_id_url'] ], null, $force ); - } + // system wide refresh + $x = Libzot::refresh(['hubloc_id_url' => $hub['hubloc_id_url']], null, $force); + } - $ret['success'] = true; - return $ret; - } + $ret['success'] = true; + return $ret; + } - static function rekey_request($sender,$data,$hub) { + public static function rekey_request($sender, $data, $hub) + { - $ret = array('success' => false); + $ret = array('success' => false); - // newsig is newkey signed with oldkey + // newsig is newkey signed with oldkey - // The original xchan will remain. In Zot/Receiver we will have imported the new xchan and hubloc to verify - // the packet authenticity. What we will do now is verify that the keychange operation was signed by the - // oldkey, and if so change all the abook, abconfig, group, and permission elements which reference the - // old xchan_hash. + // The original xchan will remain. In Zot/Receiver we will have imported the new xchan and hubloc to verify + // the packet authenticity. What we will do now is verify that the keychange operation was signed by the + // oldkey, and if so change all the abook, abconfig, group, and permission elements which reference the + // old xchan_hash. - if((! $data['old_key']) && (! $data['new_key']) && (! $data['new_sig'])) - return $ret; + if ((!$data['old_key']) && (!$data['new_key']) && (!$data['new_sig'])) + return $ret; - $old = null; + $old = null; - if(Libzot::verify($data['old_guid'],$data['old_guid_sig'],$data['old_key'])) { - $oldhash = make_xchan_hash($data['old_guid'],$data['old_key']); - $old = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($oldhash) - ); - } - else - return $ret; + if (Libzot::verify($data['old_guid'], $data['old_guid_sig'], $data['old_key'])) { + $oldhash = make_xchan_hash($data['old_guid'], $data['old_key']); + $old = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($oldhash) + ); + } else + return $ret; - if(! $old) { - return $ret; - } + if (!$old) { + return $ret; + } - $xchan = $old[0]; + $xchan = $old[0]; - if(! Libzot::verify($data['new_key'],$data['new_sig'],$xchan['xchan_pubkey'])) { - return $ret; - } + if (!Libzot::verify($data['new_key'], $data['new_sig'], $xchan['xchan_pubkey'])) { + return $ret; + } - $r = q("select * from xchan where xchan_hash = '%s' limit 1", - dbesc($sender) - ); + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($sender) + ); - $newxchan = $r[0]; + $newxchan = $r[0]; - // @todo - // if ! $update create a linked identity + // @todo + // if ! $update create a linked identity - xchan_change_key($xchan,$newxchan,$data); + xchan_change_key($xchan, $newxchan, $data); - $ret['success'] = true; - return $ret; - } + $ret['success'] = true; + return $ret; + } - /** - * @brief - * - * @param array $sender - * @param array $recipients - * - * return json_return_and_die() - */ + /** + * @brief + * + * @param array $sender + * @param array $recipients + * + * return json_return_and_die() + */ - static function reply_purge($sender, $recipients, $hub) { + public static function reply_purge($sender, $recipients, $hub) + { - $ret = array('success' => false); + $ret = array('success' => false); - if (! $sender) { - return $ret; - } + if (!$sender) { + return $ret; + } - if ($recipients) { - // basically this means "unfriend" - foreach ($recipients as $recip) { - $channel = q("select channel.*,xchan.* from channel + if ($recipients) { + // basically this means "unfriend" + foreach ($recipients as $recip) { + $channel = q("select channel.*,xchan.* from channel left join xchan on channel_hash = xchan_hash where channel_hash = '%s' limit 1", - dbesc($recip) - ); - if ($channel) { - $abook = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1", - intval($channel[0]['channel_id']), - dbesc($sender) - ); - if ($abook) { - contact_remove($channel[0]['channel_id'],$abook[0]['abook_id']); - } - } - } - $ret['success'] = true; - } - else { + dbesc($recip) + ); + if ($channel) { + $abook = q("select abook_id from abook where abook_channel = %d and abook_xchan = '%s' limit 1", + intval($channel[0]['channel_id']), + dbesc($sender) + ); + if ($abook) { + contact_remove($channel[0]['channel_id'], $abook[0]['abook_id']); + } + } + } + $ret['success'] = true; + } else { - // Unfriend everybody - basically this means the channel has committed suicide + // Unfriend everybody - basically this means the channel has committed suicide - remove_all_xchan_resources($sender); + remove_all_xchan_resources($sender); - $ret['success'] = true; - } + $ret['success'] = true; + } - return $ret; - } + return $ret; + } } diff --git a/boot.php b/boot.php index fff184d4c..a5116761a 100755 --- a/boot.php +++ b/boot.php @@ -1007,7 +1007,7 @@ class App { * register template engines (probably just smarty, but this can be extended) */ - self::register_template_engine(get_class(new SmartyTemplate)); + self::register_template_engine(get_class(new SmartyTemplate())); } @@ -1287,7 +1287,7 @@ class App { } else { $class = self::$template_engines[$template_engine]; - $obj = new $class; + $obj = new $class(); self::$template_engine_instance[$template_engine] = $obj; return $obj; } @@ -1434,7 +1434,7 @@ function os_mkdir($path, $mode = 0777, $recursive = false) { * @brief Recursively delete a directory. * * @param string $path - * @return boolean + * @return bool */ function rrmdir($path) { if (is_dir($path) === true) { @@ -1455,7 +1455,7 @@ function rrmdir($path) { /** * @brief Function to check if request was an AJAX (xmlhttprequest) request. * - * @return boolean + * @return bool */ function is_ajax() { return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); @@ -1659,10 +1659,10 @@ function fix_system_urls($oldurl, $newurl) { * on the value of App::$config['system']['register_policy']. * Returns the complete html for inserting into the page * - * @param boolean $register (optional) default false + * @param bool $register (optional) default false * @param string $form_id (optional) default \e main-login - * @param boolean $hiddens (optional) default false - * @param boolean $login_page (optional) default true + * @param bool $hiddens (optional) default false + * @param bool $login_page (optional) default true * @return string Parsed HTML code. */ function login($register = false, $form_id = 'main-login', $hiddens = false, $login_page = true) { @@ -2603,8 +2603,8 @@ function check_cron_broken() { /** * @brief * - * @param boolean $allow_account (optional) default false - * @return boolean + * @param bool $allow_account (optional) default false + * @return bool */ function observer_prohibited($allow_account = false) { if($allow_account) { diff --git a/include/account.php b/include/account.php index 8f279a7b8..4b093f025 100644 --- a/include/account.php +++ b/include/account.php @@ -425,7 +425,7 @@ function send_register_success_email($email,$password) { * @brief Allows a user registration. * * @param string $hash - * @return array|boolean + * @return array|bool */ function account_allow($hash) { @@ -503,7 +503,7 @@ function account_allow($hash) { * allowed to have friends on this system * * @param string $hash - * @return boolean + * @return bool */ function account_deny($hash) { @@ -677,8 +677,8 @@ function downgrade_accounts() { * * @param int $uid The channel_id to check * @param string $property The service class property to check for - * @param string|boolean $usage (optional) The value to check against - * @return boolean + * @param string|bool $usage (optional) The value to check against + * @return bool */ function service_class_allows($uid, $property, $usage = false) { $limit = service_class_fetch($uid, $property); @@ -714,8 +714,8 @@ function service_class_allows($uid, $property, $usage = false) { * * @param int $aid The account_id to check * @param string $property The service class property to check for - * @param int|boolean $usage (optional) The value to check against - * @return boolean + * @param int|bool $usage (optional) The value to check against + * @return bool */ function account_service_class_allows($aid, $property, $usage = false) { @@ -748,7 +748,7 @@ function account_service_class_allows($aid, $property, $usage = false) { * * @param int $uid The channel_id to query * @param string $property The service property name to check for - * @return boolean|int + * @return bool|int * * @todo Should we merge this with account_service_class_fetch()? */ @@ -790,7 +790,7 @@ function service_class_fetch($uid, $property) { * * @param int $aid The account_id to query * @param string $property The service property name to check for - * @return boolean|int + * @return bool|int */ function account_service_class_fetch($aid, $property) { diff --git a/include/acl_selectors.php b/include/acl_selectors.php index e35cad577..e5988efe4 100644 --- a/include/acl_selectors.php +++ b/include/acl_selectors.php @@ -16,11 +16,11 @@ function fixacl(&$item) { * Builds a modal dialog for editing permissions, using acl_selector.tpl as the template. * * @param array $defaults Optional access control list for the initial state of the dialog. -* @param boolean $show_jotnets Whether plugins for federated networks should be included in the permissions dialog +* @param bool $show_jotnets Whether plugins for federated networks should be included in the permissions dialog * @param PermissionDescription $emptyACL_description - An optional description for the permission implied by selecting an empty ACL. Preferably an instance of PermissionDescription. * @param string $dialog_description Optional message to include at the top of the dialog. E.g. "Warning: Post permissions cannot be changed once sent". * @param string $context_help Allows the dialog to present a help icon. E.g. "acl_dialog_post" -* @param boolean $readonly Not implemented yet. When implemented, the dialog will use acl_readonly.tpl instead, so that permissions may be viewed for posts that can no longer have their permissions changed. +* @param bool $readonly Not implemented yet. When implemented, the dialog will use acl_readonly.tpl instead, so that permissions may be viewed for posts that can no longer have their permissions changed. * * @return string html modal dialog built from acl_selector.tpl */ diff --git a/include/addon.php b/include/addon.php index 189dc3e68..3f5173912 100644 --- a/include/addon.php +++ b/include/addon.php @@ -50,7 +50,7 @@ function unload_plugin($plugin){ * @brief Uninstalls an addon. * * @param string $plugin name of the addon - * @return boolean + * @return bool */ function uninstall_plugin($plugin) { @@ -168,7 +168,7 @@ function load_plugin($plugin) { * @brief Check if addon is installed (deprecated). * * @param string $name - * @return boolean + * @return bool */ function plugin_is_installed($name) { $r = q("select aname from addon where aname = '%s' and installed = 1 limit 1", @@ -184,7 +184,7 @@ function plugin_is_installed($name) { * @brief Check if addon is installed (use this one). * * @param string $name - * @return boolean + * @return bool */ function addon_is_installed($name) { @@ -1071,7 +1071,7 @@ function get_markup_template($s, $root = '') { * @brief * * @param string $folder - * @return boolean|string + * @return bool|string */ function folder_exists($folder) { // Get canonicalized absolute pathname diff --git a/include/attach.php b/include/attach.php index f894e0c50..9e78688e8 100644 --- a/include/attach.php +++ b/include/attach.php @@ -1065,7 +1065,7 @@ function attach_store($channel, $observer_hash, $options = '', $arr = null) { * * Also checking permissions of all parent components. * - * @param integer $channel_id + * @param int $channel_id * @param string $observer_hash hash of current observer * @param string $pathname * @param string $parent_hash (optional) @@ -1393,8 +1393,8 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) { * @param string $allow_gid * @param string $deny_cid * @param string $deny_gid - * @param boolean $recurse (optional) default false - * @param boolean $sync (optional) default false + * @param bool $recurse (optional) default false + * @param bool $sync (optional) default false */ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $recurse = false, $sync = false) { @@ -1703,7 +1703,7 @@ function get_cloud_url($channel_id, $channel_name, $attachHash) { * The id of the channel * @param string $attachHash * The hash of the attachment - * @param boolean $recurse + * @param bool $recurse * (optional) default false * @return string */ @@ -1817,7 +1817,7 @@ function pipe_streams($in, $out, $bufsize = 16384) { * @param string $deny_cid * @param string $deny_gid * @param string $verb - * @param boolean $notify + * @param bool $notify */ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid, $deny_gid, $verb, $notify) { @@ -2343,7 +2343,7 @@ function get_filename_by_cloudname($cloudname, $channel, $storepath) { * @param string $observer_hash * @param string $srcpath * @param string $cloudpath - * @return boolean + * @return bool */ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpath) { if (!is_dir($srcpath) || !is_readable($srcpath)) { @@ -2403,7 +2403,7 @@ function copy_folder_to_cloudfiles($channel, $observer_hash, $srcpath, $cloudpat * @param int $channel_id * @param int $resource_id * @param string $new_folder_hash - * @return void|boolean + * @return void|bool */ function attach_move($channel_id, $resource_id, $new_folder_hash, $newname = '') { diff --git a/include/channel.php b/include/channel.php index 1551e08c6..05d92ffe8 100644 --- a/include/channel.php +++ b/include/channel.php @@ -178,7 +178,7 @@ function create_sys_channel() { /** * @brief Returns the sys channel. * - * @return array|boolean + * @return array|bool */ function get_sys_channel() { @@ -202,7 +202,7 @@ function get_sys_channel() { * @brief Checks if $channel_id is sys channel. * * @param int $channel_id - * @return boolean + * @return bool */ function is_sys_channel($channel_id) { $s = get_sys_channel(); @@ -796,7 +796,7 @@ function channel_change_address($channel,$new_address) { * login account * @param int $channel_id * channel id to set as default for this account - * @param boolean $force (optional) default true + * @param bool $force (optional) default true * - if true, set this default unconditionally * - if $force is false only do this if there is no existing default */ @@ -1444,7 +1444,7 @@ function get_default_profile_photo($size = 300) { * * @param string $s * xchan_hash of the identity in question - * @return boolean true or false + * @return bool true or false */ function is_foreigner($s) { return((strpbrk($s, '.:@')) ? true : false); @@ -1455,7 +1455,7 @@ function is_foreigner($s) { * * @param string $s * xchan_hash of the identity in question - * @return boolean true or false + * @return bool true or false */ function is_member($s) { return((is_foreigner($s)) ? false : true); @@ -1500,7 +1500,7 @@ function get_online_status($nick) { * @brief * * @param string $webbie - * @return array|boolean|string + * @return array|bool|string */ function remote_online_status($webbie) { @@ -1900,7 +1900,7 @@ function get_zcard_embed($channel, $observer_hash = '', $args = []) { * @brief Get a channel array from a channel nickname. * * @param string $nick - A channel_address nickname - * @return array|boolean + * @return array|bool * - array with channel entry * - false if no channel with $nick was found */ @@ -1933,7 +1933,7 @@ function channelx_by_nick($nick,$include_removed = false) { * @brief Get a channel array by a channel_hash. * * @param string $hash - * @return array|boolean false if channel ID not found, otherwise the channel array + * @return array|bool false if channel ID not found, otherwise the channel array */ function channelx_by_hash($hash, $include_removed = false) { @@ -1957,7 +1957,7 @@ function channelx_by_hash($hash, $include_removed = false) { * @brief Get a channel array by a channel ID. * * @param int $id A channel ID - * @return array|boolean false if channel ID not found, otherwise the channel array + * @return array|bool false if channel ID not found, otherwise the channel array */ function channelx_by_n($id, $include_removed = false) { @@ -2124,9 +2124,9 @@ function profile_store_lowlevel($arr) { * authorisation to do this. * * @param int $account_id - * @param boolean $local (optional) default true - * @param boolean $unset_session (optional) default true - * @return boolean|array + * @param bool $local (optional) default true + * @param bool $unset_session (optional) default true + * @return bool|array */ function account_remove($account_id, $local = true, $unset_session = true) { @@ -2189,8 +2189,8 @@ function account_remove($account_id, $local = true, $unset_session = true) { * @brief Removes a channel. * * @param int $channel_id - * @param boolean $local default true - * @param boolean $unset_session default false + * @param bool $local default true + * @param bool $unset_session default false */ function channel_remove($channel_id, $local = true, $unset_session = false) { @@ -2357,7 +2357,7 @@ function channel_remove_final($channel_id) { * is in fact the resource owner whose channel_id is being checked. * * @param int $channel_id - * @return boolean + * @return bool */ function channel_codeallowed($channel_id) { if(! intval($channel_id)) diff --git a/include/conversation.php b/include/conversation.php index ebe5df568..c4eeb1398 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -327,7 +327,7 @@ function count_descendants($item) { * in the stream. * * @param array $item - * @return boolean + * @return bool */ function visible_activity($item) { $hidden_activities = [ ACTIVITY_LIKE, ACTIVITY_DISLIKE, 'Undo' ]; @@ -374,7 +374,7 @@ function visible_activity($item) { * * @param array $items * @param string $mode - * @param boolean $update + * @param bool $update * @param string $page_mode default traditional * @param string $prepared_item * @return string @@ -1879,7 +1879,7 @@ function prepare_page($item) { * @brief * * @param App $a - * @param boolean $is_owner default false + * @param bool $is_owner default false * @param string $nickname default null * @return void|string */ diff --git a/include/datetime.php b/include/datetime.php index 1a095976b..934f7ec90 100644 --- a/include/datetime.php +++ b/include/datetime.php @@ -160,15 +160,15 @@ function dob($dob) { * @param string $label * @param string $id * id and name of datetimepicker (defaults to "datetimepicker") - * @param boolean $pickdate + * @param bool $pickdate * true to show date picker (default) - * @param boolean $picktime + * @param bool $picktime * true to show time picker (default) * @param DateTime $minfrom * set minimum date from picker with id $minfrom (none by default) * @param DateTime $maxfrom * set maximum date from picker with id $maxfrom (none by default) - * @param boolean $required default false + * @param bool $required default false * @param int $first_day (optional) default 0 * @return string Parsed HTML output. * diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index 764ca976c..da5257f25 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -18,15 +18,15 @@ use Zotlabs\Lib\System; class DBA { - static public $dba = null; - static public $dbtype = null; - static public $scheme = 'mysql'; - static public $logging = false; + public static $dba = null; + public static $dbtype = null; + public static $scheme = 'mysql'; + public static $logging = false; - static public $install_script = 'schema_mysql.sql'; - static public $null_date = '0001-01-01 00:00:00'; - static public $utc_now = 'UTC_TIMESTAMP()'; - static public $tquot = "`"; + public static $install_script = 'schema_mysql.sql'; + public static $null_date = '0001-01-01 00:00:00'; + public static $utc_now = 'UTC_TIMESTAMP()'; + public static $tquot = "`"; /** @@ -41,7 +41,7 @@ class DBA { * @param bool $install Defaults to false * @return null|dba_driver A database driver object (dba_pdo) or null if no driver found. */ - static public function dba_factory($server,$port,$user,$pass,$db,$dbtype,$install = false) { + public static function dba_factory($server, $port, $user, $pass, $db, $dbtype, $install = false) { self::$dba = null; self::$dbtype = intval($dbtype); @@ -86,142 +86,156 @@ class DBA { * dba_mysql, dba_mysqli or dba_postgres, but we moved to PDO and the only * implemented driver is dba_pdo. */ -abstract class dba_driver { - // legacy behavior +abstract class dba_driver +{ + // legacy behavior - public $db; + public $db; - public $debug = 0; - public $connected = false; - public $error = false; + public $debug = 0; + public $connected = false; + public $error = false; - /** - * @brief Connect to the database. - * - * This abstract function needs to be implemented in the real driver. - * - * @param string $server DB server name - * @param string $scheme DB scheme - * @param string $port DB port - * @param string $user DB username - * @param string $pass DB password - * @param string $db database name - * @return bool - */ - abstract function connect($server, $scheme, $port, $user, $pass, $db); + /** + * @brief Connect to the database. + * + * This abstract function needs to be implemented in the real driver. + * + * @param string $server DB server name + * @param string $scheme DB scheme + * @param string $port DB port + * @param string $user DB username + * @param string $pass DB password + * @param string $db database name + * @return bool + */ + public abstract function connect($server, $scheme, $port, $user, $pass, $db); - /** - * @brief Perform a DB query with the SQL statement $sql. - * - * This abstract function needs to be implemented in the real driver. - * - * @param string $sql The SQL query to execute - */ - abstract function q($sql); + /** + * @brief Perform a DB query with the SQL statement $sql. + * + * This abstract function needs to be implemented in the real driver. + * + * @param string $sql The SQL query to execute + */ + public abstract function q($sql); - /** - * @brief Escape a string before being passed to a DB query. - * - * This abstract function needs to be implemented in the real driver. - * - * @param string $str The string to escape. - */ - abstract function escape($str); + /** + * @brief Escape a string before being passed to a DB query. + * + * This abstract function needs to be implemented in the real driver. + * + * @param string $str The string to escape. + */ + public abstract function escape($str); - /** - * @brief Close the database connection. - * - * This abstract function needs to be implemented in the real driver. - */ - abstract function close(); + /** + * @brief Close the database connection. + * + * This abstract function needs to be implemented in the real driver. + */ + public abstract function close(); - /** - * @brief Return text name for db driver - * - * This abstract function needs to be implemented in the real driver. - */ - abstract function getdriver(); + /** + * @brief Return text name for db driver + * + * This abstract function needs to be implemented in the real driver. + */ + public abstract function getdriver(); - function __construct($server, $scheme, $port, $user,$pass,$db,$install = false) { - if(($install) && (! $this->install($server, $scheme, $port, $user, $pass, $db))) { - return; - } - $this->connect($server, $scheme, $port, $user, $pass, $db); - } + public function __construct($server, $scheme, $port, $user, $pass, $db, $install = false) + { + if (($install) && (!$this->install($server, $scheme, $port, $user, $pass, $db))) { + return; + } + $this->connect($server, $scheme, $port, $user, $pass, $db); + } - function get_null_date() { - return DBA::$null_date; - } + public function get_null_date() + { + return DBA::$null_date; + } - function get_install_script() { - $platform_name = System::get_platform_name(); - if(file_exists('install/' . $platform_name . '/' . DBA::$install_script)) - return 'install/' . $platform_name . '/' . DBA::$install_script; + public function get_install_script() + { + $platform_name = System::get_platform_name(); + if (file_exists('install/' . $platform_name . '/' . DBA::$install_script)) + return 'install/' . $platform_name . '/' . DBA::$install_script; - return 'install/' . DBA::$install_script; - } + return 'install/' . DBA::$install_script; + } - function get_table_quote() { - return DBA::$tquot; - } + public function get_table_quote() + { + return DBA::$tquot; + } - function utcnow() { - return DBA::$utc_now; - } + public function utcnow() + { + return DBA::$utc_now; + } - function install($server,$scheme,$port,$user,$pass,$db) { - if (!(strlen($server) && strlen($user))){ - $this->connected = false; - $this->db = null; - return false; - } + public function install($server, $scheme, $port, $user, $pass, $db) + { + if (!(strlen($server) && strlen($user))) { + $this->connected = false; + $this->db = null; + return false; + } - if(strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1') && (! strpbrk($server,':;'))) { - if(! z_dns_check($server)) { - $this->error = sprintf( t('Cannot locate DNS info for database server \'%s\''), $server); - $this->connected = false; - $this->db = null; - return false; - } - } + if (strlen($server) && ($server !== 'localhost') && ($server !== '127.0.0.1') && (!strpbrk($server, ':;'))) { + if (!z_dns_check($server)) { + $this->error = sprintf(t('Cannot locate DNS info for database server \'%s\''), $server); + $this->connected = false; + $this->db = null; + return false; + } + } - return true; - } + return true; + } - /** - * @brief Sets the database driver's debugging state. - * - * @param int $dbg 0 to disable debugging - */ - function dbg($dbg) { - $this->debug = $dbg; - } + /** + * @brief Sets the database driver's debugging state. + * + * @param int $dbg 0 to disable debugging + */ + public function dbg($dbg) + { + $this->debug = $dbg; + } - function __destruct() { - if($this->db && $this->connected) { - $this->close(); - } - } + public function __destruct() + { + if ($this->db && $this->connected) { + $this->close(); + } + } - function quote_interval($txt) { - return $txt; - } + public function quote_interval($txt) + { + return $txt; + } - function optimize_table($table) { - q('OPTIMIZE TABLE '.$table); - } + public function optimize_table($table) + { + q('OPTIMIZE TABLE ' . $table); + } - function concat($fld, $sep) { - return 'GROUP_CONCAT(DISTINCT '.$fld.' SEPARATOR \''.$sep.'\')'; - } + public function concat($fld, $sep) + { + return 'GROUP_CONCAT(DISTINCT ' . $fld . ' SEPARATOR \'' . $sep . '\')'; + } - function escapebin($str) { - return $this->escape($str); - } + public function escapebin($str) + { + return $this->escape($str); + } - function unescapebin($str) { - return $str; - } + public function unescapebin($str) + { + return $str; + } } // end abstract dba_driver class diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php index de301a800..92955c3fe 100755 --- a/include/dba/dba_pdo.php +++ b/include/dba/dba_pdo.php @@ -6,180 +6,183 @@ require_once 'include/dba/dba_driver.php'; * @brief PDO based database driver. * */ -class dba_pdo extends dba_driver { +class dba_pdo extends dba_driver +{ - public $driver_dbtype = null; + public $driver_dbtype = null; - /** - * {@inheritDoc} - * @see dba_driver::connect() - */ - function connect($server, $scheme, $port, $user, $pass, $db) { + /** + * {@inheritDoc} + * @see dba_driver::connect() + */ + public function connect($server, $scheme, $port, $user, $pass, $db) + { - $this->driver_dbtype = $scheme; + $this->driver_dbtype = $scheme; - if(strpbrk($server,':;')) { - $dsn = $server; - } - else { - $dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? ';port=' . $port : ''); - } + if (strpbrk($server, ':;')) { + $dsn = $server; + } else { + $dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? ';port=' . $port : ''); + } - $dsn .= ';dbname=' . $db; + $dsn .= ';dbname=' . $db; - try { - $this->db = new PDO($dsn,$user,$pass); - $this->db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); - } - catch(PDOException $e) { - if(file_exists('dbfail.out')) { - file_put_contents('dbfail.out', datetime_convert() . "\nConnect: " . $e->getMessage() . "\n", FILE_APPEND); - } + try { + $this->db = new PDO($dsn, $user, $pass); + $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } catch (PDOException $e) { + if (file_exists('dbfail.out')) { + file_put_contents('dbfail.out', datetime_convert() . "\nConnect: " . $e->getMessage() . "\n", FILE_APPEND); + } - return false; - } + return false; + } - if($this->driver_dbtype === 'pgsql') - $this->q("SET standard_conforming_strings = 'off'; SET backslash_quote = 'on';"); + if ($this->driver_dbtype === 'pgsql') + $this->q("SET standard_conforming_strings = 'off'; SET backslash_quote = 'on';"); - $this->connected = true; + $this->connected = true; - return true; - } + return true; + } - /** - * {@inheritDoc} - * @see dba_driver::q() - * - * @return bool|array|PDOStatement - * - \b false if not connected or PDOException occured on query - * - \b array with results on a SELECT query - * - \b PDOStatement on a non SELECT SQL query - */ - function q($sql) { - if((! $this->db) || (! $this->connected)) - return false; + /** + * {@inheritDoc} + * @return bool|array|PDOStatement + * - \b false if not connected or PDOException occured on query + * - \b array with results on a SELECT query + * - \b PDOStatement on a non SELECT SQL query + * @see dba_driver::q() + * + */ + public function q($sql) + { + if ((!$this->db) || (!$this->connected)) + return false; - if($this->driver_dbtype === 'pgsql') { - if(substr(rtrim($sql),-1,1) !== ';') { - $sql .= ';'; - } - } + if ($this->driver_dbtype === 'pgsql') { + if (substr(rtrim($sql), -1, 1) !== ';') { + $sql .= ';'; + } + } - $result = null; - $this->error = ''; - $select = ((stripos($sql, 'select') === 0) ? true : false); + $result = null; + $this->error = ''; + $select = ((stripos($sql, 'select') === 0) ? true : false); - try { - $result = $this->db->query($sql, PDO::FETCH_ASSOC); - } - catch(PDOException $e) { + try { + $result = $this->db->query($sql, PDO::FETCH_ASSOC); + } catch (PDOException $e) { - $this->error = $e->getMessage(); - if($this->error) { - db_logger('dba_pdo: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR); - if(file_exists('dbfail.out')) { - file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . "\n" . $this->error . "\n", FILE_APPEND); - } - } - } + $this->error = $e->getMessage(); + if ($this->error) { + db_logger('dba_pdo: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR); + if (file_exists('dbfail.out')) { + file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . "\n" . $this->error . "\n", FILE_APPEND); + } + } + } - if(!($select)) { - if($this->debug) { - db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returns ' . (($result) ? 'true' : 'false'), LOGGER_NORMAL,(($result) ? LOG_INFO : LOG_ERR)); - } - return $result; - } + if (!($select)) { + if ($this->debug) { + db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returns ' . (($result) ? 'true' : 'false'), LOGGER_NORMAL, (($result) ? LOG_INFO : LOG_ERR)); + } + return $result; + } - $r = []; - if($result) { - foreach($result as $x) { - $r[] = $x; - } - } + $r = []; + if ($result) { + foreach ($result as $x) { + $r[] = $x; + } + } - if($this->debug) { - db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returned ' . count($r) . ' results.', LOGGER_NORMAL, LOG_INFO); - if(intval($this->debug) > 1) { - db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO); - } - } + if ($this->debug) { + db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returned ' . count($r) . ' results.', LOGGER_NORMAL, LOG_INFO); + if (intval($this->debug) > 1) { + db_logger('dba_pdo: ' . printable(print_r($r, true)), LOGGER_NORMAL, LOG_INFO); + } + } - return (($this->error) ? false : $r); - } + return (($this->error) ? false : $r); + } - function escape($str) { - if($this->db && $this->connected) { - return substr(substr(@$this->db->quote($str),1),0,-1); - } - } + public function escape($str) + { + if ($this->db && $this->connected) { + return substr(substr(@$this->db->quote($str), 1), 0, -1); + } + } - function close() { - if($this->db) - $this->db = null; + public function close() + { + if ($this->db) + $this->db = null; - $this->connected = false; - } + $this->connected = false; + } - function concat($fld,$sep) { - if($this->driver_dbtype === 'pgsql') { - return 'string_agg(' . $fld . ',\'' . $sep . '\')'; - } - else { - return 'GROUP_CONCAT(DISTINCT ' . $fld . ' SEPARATOR \'' . $sep . '\')'; - } - } + public function concat($fld, $sep) + { + if ($this->driver_dbtype === 'pgsql') { + return 'string_agg(' . $fld . ',\'' . $sep . '\')'; + } else { + return 'GROUP_CONCAT(DISTINCT ' . $fld . ' SEPARATOR \'' . $sep . '\')'; + } + } - function use_index($str) { - if($this->driver_dbtype === 'pgsql') { - return ''; - } - else { - return 'USE INDEX( ' . $str . ')'; - } - } + public function use_index($str) + { + if ($this->driver_dbtype === 'pgsql') { + return ''; + } else { + return 'USE INDEX( ' . $str . ')'; + } + } - function quote_interval($txt) { - if($this->driver_dbtype === 'pgsql') { - return "'$txt'"; - } - else { - return $txt; - } - } + public function quote_interval($txt) + { + if ($this->driver_dbtype === 'pgsql') { + return "'$txt'"; + } else { + return $txt; + } + } - // These two functions assume that postgres standard_conforming_strings is set to off; - // which we perform during DB open. + // These two functions assume that postgres standard_conforming_strings is set to off; + // which we perform during DB open. - function escapebin($str) { - if($this->driver_dbtype === 'pgsql') { - return "\\\\x" . bin2hex($str); - } - else { - return $this->escape($str); - } - } + public function escapebin($str) + { + if ($this->driver_dbtype === 'pgsql') { + return "\\\\x" . bin2hex($str); + } else { + return $this->escape($str); + } + } - function unescapebin($str) { - if(gettype($str) === 'resource') { - $x = ''; - while(! feof($str)) { - $x .= fread($str,8192); - } - if(substr($x,0,2) === '\\x') { - $x = hex2bin(substr($x,2)); - } - return $x; + public function unescapebin($str) + { + if (gettype($str) === 'resource') { + $x = ''; + while (!feof($str)) { + $x .= fread($str, 8192); + } + if (substr($x, 0, 2) === '\\x') { + $x = hex2bin(substr($x, 2)); + } + return $x; - } - else { - return $str; - } - } + } else { + return $str; + } + } - function getdriver() { - return 'pdo'; - } + public function getdriver() + { + return 'pdo'; + } } diff --git a/include/feedutils.php b/include/feedutils.php index cdc1aa187..f0e7bf243 100644 --- a/include/feedutils.php +++ b/include/feedutils.php @@ -282,7 +282,7 @@ function compat_photos_list($s) { * @param array $owner * @param string $comment default false * @param number $cid default 0 - * @param boolean $compat default false + * @param bool $compat default false * @return void|string */ function atom_entry($item, $type, $author, $owner, $comment = false, $cid = 0, $compat = false) { diff --git a/include/help.php b/include/help.php index a6d4a14a0..84ae9b6fa 100644 --- a/include/help.php +++ b/include/help.php @@ -91,7 +91,7 @@ function preg_callback_help_include($matches) { /** * @brief * - * @return boolean|array + * @return bool|array */ function determine_help_language() { @@ -135,7 +135,7 @@ function find_doc_file($s) { * @brief * * @param string $s - * @return number|mixed|unknown|boolean + * @return number|mixed|unknown|bool */ function search_doc_files($s) { @@ -227,7 +227,7 @@ function load_context_help() { * @brief * * @param string $s - * @return void|boolean[]|number[]|string[]|unknown[] + * @return void|bool|number[]|string[]|unknown[] */ function store_doc_file($s) { diff --git a/include/hubloc.php b/include/hubloc.php index 7a9a65708..1fe74a43e 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -12,7 +12,7 @@ use Zotlabs\Daemon\Run; * Creates an assoziative array which will be inserted into the hubloc table. * * @param array $arr An assoziative array with hubloc values - * @return boolean|PDOStatement + * @return bool|PDOStatement */ function hubloc_store_lowlevel($arr) { @@ -180,7 +180,7 @@ function remove_obsolete_hublocs() { * hubloc primary selection. * * @param array $hubloc - * @return boolean + * @return bool */ function hubloc_change_primary($hubloc) { diff --git a/include/import.php b/include/import.php index c07355a71..95f695291 100644 --- a/include/import.php +++ b/include/import.php @@ -20,7 +20,7 @@ require_once('include/menu.php'); * @param array $channel * @param int $account_id * @param int $seize - * @return boolean|array + * @return bool|array */ function import_channel($channel, $account_id, $seize, $newname = '') { @@ -367,8 +367,8 @@ function import_profiles($channel, $profiles) { * * @param array $channel * @param array $hublocs - * @param boolean $seize - * @param boolean $moving (optional) default false + * @param bool $seize + * @param bool $moving (optional) default false */ function import_hublocs($channel, $hublocs, $seize, $moving = false) { @@ -942,7 +942,7 @@ function sync_chatrooms($channel, $chatrooms) { * * @param array $channel where to import to * @param array $items - * @param boolean $sync default false + * @param bool $sync default false * @param array $relocate default null */ function import_items($channel, $items, $sync = false, $relocate = null) { @@ -1351,7 +1351,7 @@ function import_conv($channel,$convs) { * * @param array $channel * @param array $mails - * @param boolean $sync (optional) default false + * @param bool $sync (optional) default false */ function import_mail($channel, $mails, $sync = false) { if ($channel && $mails) { @@ -2128,8 +2128,8 @@ function get_webpage_elements($channel, $type = 'all') { * * @param array $files List of files to put in zip file * @param string $destination - * @param boolean $overwrite - * @return boolean Success status + * @param bool $overwrite + * @return bool Success status */ function create_zip_file($files = [], $destination = '', $overwrite = false) { // if the zip file already exists and overwrite is false, return false diff --git a/include/items.php b/include/items.php index 0103efe89..62bee009d 100644 --- a/include/items.php +++ b/include/items.php @@ -37,7 +37,7 @@ require_once('include/photo_factory.php'); * * @param array $item * @param[out] boolean $private_envelope - * @param boolean $include_groups + * @param bool $include_groups * @return array containing the recipients */ function collect_recipients($item, &$private_envelope,$include_groups = true) { @@ -289,7 +289,7 @@ function is_item_normal($item) { * * @param string $observer_xchan * @param array $item - * @return boolean + * @return bool */ function can_comment_on_post($observer_xchan, $item) { @@ -410,7 +410,7 @@ function absolutely_no_comments($item) { * * Modifies item in the database pointed to by $iid. * - * @param integer $iid + * @param int $iid * item['id'] of target item * @param string $hash * xchan_hash of the channel that sent the item @@ -443,8 +443,8 @@ function add_source_route($iid, $hash) { * or other processing is performed. * * @param array $arr - * @param boolean $allow_code (optional) default false - * @param boolean $deliver (optional) default true + * @param bool $allow_code (optional) default false + * @param bool $deliver (optional) default true * @returns array * * \e boolean \b success true or false * * \e array \b activity the resulting activity if successful @@ -1175,7 +1175,7 @@ function encode_item($item,$mirror = false) { * @brief * * @param int $scope - * @param boolean $strip (optional) default false + * @param bool $strip (optional) default false * @return string */ function map_scope($scope, $strip = false) { @@ -1563,8 +1563,8 @@ function item_json_encapsulate($arr,$k) { * @brief Stores an item type record. * * @param array $arr - * @param boolean $allow_exec (optional) default false - * @param boolean $deliver (optional) default true + * @param bool $allow_exec (optional) default false + * @param bool $deliver (optional) default true * * @return array * * \e boolean \b success @@ -2081,8 +2081,8 @@ function item_store($arr, $allow_exec = false, $deliver = true, $linkid = true) * @brief Update a stored item. * * @param array $arr an item - * @param boolean $allow_exec (optional) default false - * @param boolean $deliver (optional) default true + * @param bool $allow_exec (optional) default false + * @param bool $deliver (optional) default true * @return array */ function item_store_update($arr, $allow_exec = false, $deliver = true, $linkid = true) { @@ -2912,7 +2912,7 @@ function tag_deliver($uid, $item_id) { * * @param number $uid A chnnel_id * @param array $item - * @return boolean + * @return bool */ function tgroup_check($uid, $item) { @@ -3045,7 +3045,7 @@ function i_am_mentioned($channel,$item) { * @param array $channel * @param array $item * @param int $item_id - * @param boolean $parent + * @param bool $parent */ function start_delivery_chain($channel, $item, $item_id, $parent, $group = false, $edit = false) { @@ -3860,8 +3860,8 @@ function drop_item($id,$interactive = true,$stage = DROPITEM_NORMAL,$force = fal * * @param array $item * @param int $stage - * @param boolean $force - * @return boolean + * @param bool $force + * @return bool */ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { @@ -3946,8 +3946,8 @@ function delete_item_lowlevel($item, $stage = DROPITEM_NORMAL, $force = false) { * @brief Return the first post date. * * @param int $uid - * @param boolean $wall (optional) no longer used - * @return string|boolean date string, otherwise false + * @param bool $wall (optional) no longer used + * @return string|bool date string, otherwise false */ function first_post_date($uid, $wall = false) { @@ -3986,7 +3986,7 @@ function first_post_date($uid, $wall = false) { * current flat list of all representative dates. * * @param int $uid - * @param boolean $wall + * @param bool $wall * @param string $mindate * @return array */ @@ -4078,7 +4078,7 @@ function posted_dates($uid,$wall) { * @brief Extend an item array with the associated tags of the posts. * * @param array $items - * @param boolean $link (optional) default false + * @param bool $link (optional) default false * @return array Return the provided $items array after extended the posts with tags */ function fetch_post_tags($items, $link = false) { @@ -4720,7 +4720,7 @@ function set_linkified_perms($linkified, &$str_contact_allow, &$str_group_allow, * cause looping, so use this hackish but accurate method. * * @param array $item - * @return boolean + * @return bool */ function comment_local_origin($item) { if(stripos($item['mid'], App::get_hostname()) && ($item['parent'] != $item['id'])) diff --git a/include/language.php b/include/language.php index 35cfdd1af..c40189e2b 100644 --- a/include/language.php +++ b/include/language.php @@ -153,7 +153,7 @@ function pop_lang() { * @brief Load string translation table for alternate language. * * @param string $lang language code in 2-letter ISO 639-1 (en, de, fr) format - * @param boolean $install (optional) default false + * @param bool $install (optional) default false */ function load_translation_table($lang, $install = false) { @@ -251,7 +251,7 @@ function tt($singular, $plural, $count, $ctx = ''){ * any language file. * * @param int $n - * @return boolean + * @return bool */ function string_plural_select_default($n) { return ($n != 1); @@ -296,7 +296,7 @@ function detect_language($s) { return ''; } - $l = new Text_LanguageDetect; + $l = new Text_LanguageDetect(); try { // return 2-letter ISO 639-1 (en) language code $l->setNameMode(2); @@ -337,7 +337,7 @@ function get_language_name($s, $l = null) { if (strpos($s, '-') !== false) $s = substr($s, 0, 2) . strtoupper(substr($s, 2)); if ($l !== null && strpos($l, '-') !== false) $l = substr($l, 0, 2) . strtoupper(substr($l, 2)); - $languageRepository = new LanguageRepository; + $languageRepository = new LanguageRepository(); // Sometimes intl doesn't like the second part at all ... try { diff --git a/include/network.php b/include/network.php index 2412b69f9..6e0c1a252 100644 --- a/include/network.php +++ b/include/network.php @@ -33,7 +33,7 @@ function get_capath() { * * @param string $url * URL to fetch - * @param boolean $binary default false + * @param bool $binary default false * TRUE if asked to return binary results (file download) * @param int $redirects default 0 * internal use, recursion counter @@ -653,7 +653,7 @@ function z_dns_check($h,$check_mx = 0) { * @see z_dns_check() * * @param[in,out] string $url URL to check - * @return boolean Return true if it's OK, false if something is wrong with it + * @return bool Return true if it's OK, false if something is wrong with it */ function validate_url(&$url) { @@ -677,7 +677,7 @@ function validate_url(&$url) { * @brief Checks that email is an actual resolvable internet address. * * @param string $addr - * @return boolean + * @return bool */ function validate_email($addr) { @@ -702,7 +702,7 @@ function validate_email($addr) { * Compare against our list (wildcards allowed). * * @param string $email - * @return boolean Returns false if not allowed, true if allowed or if allowed list is + * @return bool Returns false if not allowed, true if allowed or if allowed list is * not configured. */ function allowed_email($email) { @@ -804,7 +804,7 @@ function sxml2array ( $xmlObject, $out = array () ) * $array = xml2array(file_get_contents('feed.xml', true, 1, 'attribute')); * * @param string $contents The XML text - * @param boolean $namespaces true or false include namespace information in the returned array as array elements + * @param bool $namespaces true or false include namespace information in the returned array as array elements * @param int $get_attributes 1 or 0. If this is 1 the function will get the attributes as well as the tag values - this results in a different array structure in the return value. * @param string $priority Can be 'tag' or 'attribute'. This will change the way the resulting array sturcture. For 'tag', the tags are given more importance. * @@ -1017,8 +1017,8 @@ function email_header_encode($in_str, $charset = 'UTF-8', $header = 'Subject') { * * @param string $webbie * @param string $protocol (optional) default empty - * @param boolean $verify (optional) default true, verify HTTP signatures on Zot discovery packets. - * @return boolean + * @param bool $verify (optional) default true, verify HTTP signatures on Zot discovery packets. + * @return bool */ function discover_by_webbie($webbie, $protocol = '', $verify = true) { @@ -1120,7 +1120,7 @@ function discover_by_webbie($webbie, $protocol = '', $verify = true) { * No longer used - see Zotlabs/Lib/Webfinger.php * * @param string $webbie - The resource - * @return boolean|string false or associative array from result JSON + * @return bool|string false or associative array from result JSON */ function webfinger_rfc7033($webbie) { @@ -1323,7 +1323,7 @@ function get_site_info() { * @brief * * @param string $url - * @return boolean + * @return bool */ function check_siteallowed($url) { @@ -1381,7 +1381,7 @@ function check_siteallowed($url) { * @brief * * @param string $url - * @return boolean + * @return bool */ function check_pubstream_siteallowed($url) { @@ -1441,7 +1441,7 @@ function check_pubstream_siteallowed($url) { * @brief * * @param string $hash - * @return boolean + * @return bool */ function check_channelallowed($hash) { @@ -1495,7 +1495,7 @@ function check_channelallowed($hash) { * @brief * * @param string $hash - * @return boolean + * @return bool */ function check_pubstream_channelallowed($hash) { @@ -1790,7 +1790,7 @@ function getBestSupportedMimeType($mimeTypes = null, $acceptedTypes = false) { * @brief Perform caching for jsonld normaliser. * * @param string $url - * @return mixed|boolean|array + * @return mixed|bool|array */ function jsonld_document_loader($url) { diff --git a/include/oauth.php b/include/oauth.php index e27e770b5..7f3f24fd1 100644 --- a/include/oauth.php +++ b/include/oauth.php @@ -11,167 +11,175 @@ define('ACCESS_TOKEN_DURATION', 31536000); require_once('library/OAuth1.php'); -class ZotOAuth1DataStore extends OAuth1DataStore { +class ZotOAuth1DataStore extends OAuth1DataStore +{ - function gen_token(){ - return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid()))); - } - - function lookup_consumer($consumer_key) { - logger('consumer_key: ' . $consumer_key, LOGGER_DEBUG); + public function gen_token() + { + return md5(base64_encode(pack('N6', mt_rand(), mt_rand(), mt_rand(), mt_rand(), mt_rand(), uniqid()))); + } - $r = q("SELECT client_id, pw, redirect_uri FROM clients WHERE client_id = '%s'", - dbesc($consumer_key) - ); + public function lookup_consumer($consumer_key) + { + logger('consumer_key: ' . $consumer_key, LOGGER_DEBUG); - if($r) { - App::set_oauth_key($consumer_key); - return new OAuth1Consumer($r[0]['client_id'],$r[0]['pw'],$r[0]['redirect_uri']); - } - return null; - } + $r = q("SELECT client_id, pw, redirect_uri FROM clients WHERE client_id = '%s'", + dbesc($consumer_key) + ); - function lookup_token($consumer, $token_type, $token) { + if ($r) { + App::set_oauth_key($consumer_key); + return new OAuth1Consumer($r[0]['client_id'], $r[0]['pw'], $r[0]['redirect_uri']); + } + return null; + } - logger(__function__ . ':' . $consumer . ', ' . $token_type . ', ' . $token, LOGGER_DEBUG); + public function lookup_token($consumer, $token_type, $token) + { - $r = q("SELECT id, secret, auth_scope, expires, uid FROM tokens WHERE client_id = '%s' AND auth_scope = '%s' AND id = '%s'", - dbesc($consumer->key), - dbesc($token_type), - dbesc($token) - ); + logger(__function__ . ':' . $consumer . ', ' . $token_type . ', ' . $token, LOGGER_DEBUG); - if ($r) { - $ot = new OAuth1Token($r[0]['id'],$r[0]['secret']); - $ot->scope = $r[0]['auth_scope']; - $ot->expires = $r[0]['expires']; - $ot->uid = $r[0]['uid']; - return $ot; - } - return null; - } + $r = q("SELECT id, secret, auth_scope, expires, uid FROM tokens WHERE client_id = '%s' AND auth_scope = '%s' AND id = '%s'", + dbesc($consumer->key), + dbesc($token_type), + dbesc($token) + ); - function lookup_nonce($consumer, $token, $nonce, $timestamp) { + if ($r) { + $ot = new OAuth1Token($r[0]['id'], $r[0]['secret']); + $ot->scope = $r[0]['auth_scope']; + $ot->expires = $r[0]['expires']; + $ot->uid = $r[0]['uid']; + return $ot; + } + return null; + } - $r = q("SELECT id, secret FROM tokens WHERE client_id = '%s' AND id = '%s' AND expires = %d", - dbesc($consumer->key), - dbesc($nonce), - intval($timestamp) - ); + public function lookup_nonce($consumer, $token, $nonce, $timestamp) + { - if ($r) { - return new OAuth1Token($r[0]['id'],$r[0]['secret']); - } - return null; - } + $r = q("SELECT id, secret FROM tokens WHERE client_id = '%s' AND id = '%s' AND expires = %d", + dbesc($consumer->key), + dbesc($nonce), + intval($timestamp) + ); - function new_request_token($consumer, $callback = null) { + if ($r) { + return new OAuth1Token($r[0]['id'], $r[0]['secret']); + } + return null; + } - logger(__function__ . ':' . $consumer . ', ' . $callback, LOGGER_DEBUG); + public function new_request_token($consumer, $callback = null) + { - $key = $this->gen_token(); - $sec = $this->gen_token(); - - if ($consumer->key){ - $k = $consumer->key; - } - else { - $k = $consumer; - } + logger(__function__ . ':' . $consumer . ', ' . $callback, LOGGER_DEBUG); - $r = q("INSERT INTO tokens (id, secret, client_id, auth_scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, 0)", - dbesc($key), - dbesc($sec), - dbesc($k), - 'request', - time()+intval(REQUEST_TOKEN_DURATION)); + $key = $this->gen_token(); + $sec = $this->gen_token(); - if (! $r) { - return null; - } - return new OAuth1Token($key,$sec); - } + if ($consumer->key) { + $k = $consumer->key; + } else { + $k = $consumer; + } - function new_access_token($token, $consumer, $verifier = null) { + $r = q("INSERT INTO tokens (id, secret, client_id, auth_scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, 0)", + dbesc($key), + dbesc($sec), + dbesc($k), + 'request', + time() + intval(REQUEST_TOKEN_DURATION)); - logger(__function__ . ':' . $token . ', ' . $consumer .', ' . $verifier, LOGGER_DEBUG); - - // return a new access token attached to this consumer - // for the user associated with this token if the request token - // is authorized - // should also invalidate the request token - - $ret = null; - - // get user for this verifier - $uverifier = get_config("oauth", $verifier); - logger(__function__ . ':' . $verifier . ', ' . $uverifier, LOGGER_DEBUG); - if (is_null($verifier) || ($uverifier !== false)) { - - $key = $this->gen_token(); - $sec = $this->gen_token(); + if (!$r) { + return null; + } + return new OAuth1Token($key, $sec); + } - $r = q("INSERT INTO tokens (id, secret, client_id, auth_scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, %d)", - dbesc($key), - dbesc($sec), - dbesc($consumer->key), - 'access', - time()+intval(ACCESS_TOKEN_DURATION), - intval($uverifier)); + public function new_access_token($token, $consumer, $verifier = null) + { - if ($r) { - $ret = new OAuth1Token($key,$sec); - } - } - - - q("DELETE FROM tokens WHERE id='%s'", $token->key); - - - if (! is_null($ret) && $uverifier !== false) { - del_config('oauth', $verifier); - } - return $ret; - } + logger(__function__ . ':' . $token . ', ' . $consumer . ', ' . $verifier, LOGGER_DEBUG); + + // return a new access token attached to this consumer + // for the user associated with this token if the request token + // is authorized + // should also invalidate the request token + + $ret = null; + + // get user for this verifier + $uverifier = get_config("oauth", $verifier); + logger(__function__ . ':' . $verifier . ', ' . $uverifier, LOGGER_DEBUG); + if (is_null($verifier) || ($uverifier !== false)) { + + $key = $this->gen_token(); + $sec = $this->gen_token(); + + $r = q("INSERT INTO tokens (id, secret, client_id, auth_scope, expires, uid) VALUES ('%s','%s','%s','%s', %d, %d)", + dbesc($key), + dbesc($sec), + dbesc($consumer->key), + 'access', + time() + intval(ACCESS_TOKEN_DURATION), + intval($uverifier)); + + if ($r) { + $ret = new OAuth1Token($key, $sec); + } + } + + + q("DELETE FROM tokens WHERE id='%s'", $token->key); + + + if (!is_null($ret) && $uverifier !== false) { + del_config('oauth', $verifier); + } + return $ret; + } } -class ZotOAuth1 extends OAuth1Server { +class ZotOAuth1 extends OAuth1Server +{ - function __construct() { - parent::__construct(new ZotOAuth1DataStore()); - $this->add_signature_method(new OAuth1SignatureMethod_PLAINTEXT()); - $this->add_signature_method(new OAuth1SignatureMethod_HMAC_SHA1()); - } - - function loginUser($uid) { + public function __construct() + { + parent::__construct(new ZotOAuth1DataStore()); + $this->add_signature_method(new OAuth1SignatureMethod_PLAINTEXT()); + $this->add_signature_method(new OAuth1SignatureMethod_HMAC_SHA1()); + } - logger("ZotOAuth1::loginUser $uid"); + public function loginUser($uid) + { - $r = q("SELECT * FROM channel WHERE channel_id = %d LIMIT 1", - intval($uid) - ); - if ($r) { - $record = $r[0]; - } - else { - logger('ZotOAuth1::loginUser failure: ' . print_r($_SERVER,true), LOGGER_DEBUG); - header('HTTP/1.0 401 Unauthorized'); - echo('This api requires login'); - killme(); - } + logger("ZotOAuth1::loginUser $uid"); - $_SESSION['uid'] = $record['channel_id']; - $_SESSION['addr'] = $_SERVER['REMOTE_ADDR']; + $r = q("SELECT * FROM channel WHERE channel_id = %d LIMIT 1", + intval($uid) + ); + if ($r) { + $record = $r[0]; + } else { + logger('ZotOAuth1::loginUser failure: ' . print_r($_SERVER, true), LOGGER_DEBUG); + header('HTTP/1.0 401 Unauthorized'); + echo('This api requires login'); + killme(); + } + + $_SESSION['uid'] = $record['channel_id']; + $_SESSION['addr'] = $_SERVER['REMOTE_ADDR']; + + $x = q("select * from account where account_id = %d limit 1", + intval($record['channel_account_id']) + ); + if ($x) { + require_once('include/security.php'); + authenticate_success($x[0], null, true, false, true, true); + $_SESSION['allow_api'] = true; + } + } - $x = q("select * from account where account_id = %d limit 1", - intval($record['channel_account_id']) - ); - if ($x) { - require_once('include/security.php'); - authenticate_success($x[0],null,true,false,true,true); - $_SESSION['allow_api'] = true; - } - } - } diff --git a/include/permissions.php b/include/permissions.php index 75a127720..e3a44ea18 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -244,7 +244,7 @@ function get_all_perms($uid, $observer_xchan, $check_siteblock = true, $default_ * @param int $uid The channel_id associated with the resource owner * @param string $observer_xchan The xchan_hash representing the observer * @param string $permission - * @param boolean $check_siteblock (default true) + * @param bool $check_siteblock (default true) * if false bypass check for "Block Public" at the site level * @return bool true if permission is allowed for observer on channel */ diff --git a/include/photo_factory.php b/include/photo_factory.php index f27d64998..3c51eab54 100644 --- a/include/photo_factory.php +++ b/include/photo_factory.php @@ -192,9 +192,9 @@ function delete_thing_photo($url, $ob_hash) { * external URL to fetch base image * @param string $xchan * channel unique hash - * @param boolean $thing + * @param bool $thing * TRUE if this is a thing URL - * @param boolean $force + * @param bool $force * TRUE if ignore image modification date check (force fetch) * * @return array of results @@ -519,7 +519,7 @@ function import_channel_photo_from_url($photo, $aid, $uid) { * @param string $type * @param int $aid * @param int $uid channel_id - * @return boolean|string false on failure, otherwise resource_id of photo + * @return bool|string false on failure, otherwise resource_id of photo */ function import_channel_photo($photo, $type, $aid, $uid) { diff --git a/include/photos.php b/include/photos.php index 1ccad80a1..f60e58688 100644 --- a/include/photos.php +++ b/include/photos.php @@ -760,7 +760,7 @@ function photos_album_widget($channelx,$observer,$sortkey = 'display_path',$dire * @param array $channel * @param array $observer * @param string $album (optional) default empty - * @return boolean|array + * @return bool|array */ function photos_list_photos($channel, $observer, $album = '') { @@ -802,7 +802,7 @@ function photos_list_photos($channel, $observer, $album = '') { * @param int $channel_id id of the channel * @param string $observer_hash * @param string $album name of the album - * @return boolean + * @return bool */ function photos_album_exists($channel_id, $observer_hash, $album) { @@ -842,7 +842,7 @@ function photos_album_rename($channel_id, $oldname, $newname) { * @param int $channel_id * @param string $album * @param string $remote_xchan (optional) default empty - * @return string|boolean + * @return string|bool */ function photos_album_get_db_idstr($channel_id, $album, $remote_xchan = '') { @@ -891,7 +891,7 @@ function photos_album_get_db_idstr_admin($channel_id, $album) { * @param array $channel * @param string $creator_hash * @param array $photo - * @param boolean $visible (optional) default false + * @param bool $visible (optional) default false * @return int item_id */ function photos_create_item($channel, $creator_hash, $photo, $visible = false) { diff --git a/include/security.php b/include/security.php index 8aa719398..49eb52441 100644 --- a/include/security.php +++ b/include/security.php @@ -180,7 +180,7 @@ function atoken_delete($atoken_id) { * @fixme we should set xchan_deleted if it's expired or removed * * @param array $xchan - * @return void|boolean + * @return void|bool */ function atoken_create_xchan($xchan) { diff --git a/include/text.php b/include/text.php index 165c21ea5..af3a5d398 100644 --- a/include/text.php +++ b/include/text.php @@ -145,7 +145,7 @@ function z_input_filter($s, $type = 'text/bbcode', $allow_code = false) { * @see HTMLPurifier * * @param string $s raw HTML - * @param boolean $allow_position allow CSS position + * @param bool $allow_position allow CSS position * @return string standards compliant filtered HTML */ function purify_html($s, $opts = []) { @@ -187,96 +187,96 @@ function purify_html($s, $opts = []) { // f6 navigation //dropdown menu - $def->info_global_attr['data-dropdown-menu'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-dropdown-menu'] = new HTMLPurifier_AttrDef_Text(); //drilldown menu - $def->info_global_attr['data-drilldown'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-drilldown'] = new HTMLPurifier_AttrDef_Text(); //accordion menu - $def->info_global_attr['data-accordion-menu'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-accordion-menu'] = new HTMLPurifier_AttrDef_Text(); //responsive navigation - $def->info_global_attr['data-responsive-menu'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-responsive-toggle'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-responsive-menu'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-responsive-toggle'] = new HTMLPurifier_AttrDef_Text(); //magellan - $def->info_global_attr['data-magellan'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-magellan-target'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-magellan'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-magellan-target'] = new HTMLPurifier_AttrDef_Text(); // f6 containers //accordion - $def->info_global_attr['data-accordion'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-accordion-item'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-tab-content'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-accordion'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-accordion-item'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-tab-content'] = new HTMLPurifier_AttrDef_Text(); //dropdown - $def->info_global_attr['data-dropdown'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-dropdown'] = new HTMLPurifier_AttrDef_Text(); //off-canvas - $def->info_global_attr['data-off-canvas-wrapper'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-off-canvas'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-off-canvas-content'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-off-canvas-wrapper'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-off-canvas'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-off-canvas-content'] = new HTMLPurifier_AttrDef_Text(); //reveal - $def->info_global_attr['data-reveal'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-reveal'] = new HTMLPurifier_AttrDef_Text(); //tabs - $def->info_global_attr['data-tabs'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-tabs-content'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-tabs'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-tabs-content'] = new HTMLPurifier_AttrDef_Text(); // f6 media //orbit - $def->info_global_attr['data-orbit'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-slide'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-orbit'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-slide'] = new HTMLPurifier_AttrDef_Text(); //tooltip - $def->info_global_attr['data-tooltip'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-tooltip'] = new HTMLPurifier_AttrDef_Text(); // f6 plugins //abide - the use is pointless since we can't do anything with forms //equalizer - $def->info_global_attr['data-equalizer'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-equalizer-watch'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-equalizer'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-equalizer-watch'] = new HTMLPurifier_AttrDef_Text(); //interchange - potentially dangerous since it can load content //toggler - $def->info_global_attr['data-toggler'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-toggler'] = new HTMLPurifier_AttrDef_Text(); //sticky - $def->info_global_attr['data-sticky'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-sticky-container'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-sticky'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-sticky-container'] = new HTMLPurifier_AttrDef_Text(); // f6 common - $def->info_global_attr['data-options'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-toggle'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-close'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-open'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-position'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-options'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-toggle'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-close'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-open'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-position'] = new HTMLPurifier_AttrDef_Text(); //data- attributes used by the bootstrap library - $def->info_global_attr['data-dismiss'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-target'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-toggle'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-backdrop'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-keyboard'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-show'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-spy'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-offset'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-animation'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-container'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-delay'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-placement'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-title'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-trigger'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-content'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-trigger'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-parent'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-ride'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-slide-to'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-slide'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-interval'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-pause'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-wrap'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-offset-top'] = new HTMLPurifier_AttrDef_Text; - $def->info_global_attr['data-offset-bottom'] = new HTMLPurifier_AttrDef_Text; + $def->info_global_attr['data-dismiss'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-target'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-toggle'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-backdrop'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-keyboard'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-show'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-spy'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-offset'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-animation'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-container'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-delay'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-placement'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-title'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-trigger'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-content'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-trigger'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-parent'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-ride'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-slide-to'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-slide'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-interval'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-pause'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-wrap'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-offset-top'] = new HTMLPurifier_AttrDef_Text(); + $def->info_global_attr['data-offset-bottom'] = new HTMLPurifier_AttrDef_Text(); //some html5 elements //Block @@ -657,7 +657,7 @@ function new_uuid() { * * @param string $attr attribute string * @param string $s attribute you are looking for - * @return boolean true if found + * @return bool true if found */ function attribute_contains($attr, $s) { // remove quotes @@ -1003,7 +1003,7 @@ function searchbox($s,$id='search-box',$url='/search',$save = false) { * @brief Replace naked text hyperlink with HTML formatted hyperlink. * * @param string $s - * @param boolean $me (optional) default false + * @param bool $me (optional) default false * @return string */ function linkify($s, $me = false) { @@ -1280,7 +1280,7 @@ function list_smilies($default_only = false) { * bbcode source for HTML display. * * @param string $s - * @param boolean $sample (optional) default false + * @param bool $sample (optional) default false * @return string */ function smilies($s, $sample = false) { @@ -1980,7 +1980,7 @@ function prepare_binary($item) { * * @param string $text * @param string $content_type (optional) default text/bbcode - * @param boolean $cache (optional) default false + * @param bool $cache (optional) default false * * @return string */ @@ -2483,7 +2483,7 @@ function trim_and_unpunify($s) { * save extra per item lookups there. * * @param[in,out] array &$items - * @param boolean $abook If true also include the abook info + * @param bool $abook If true also include the abook info * @param number $effective_uid */ function xchan_query(&$items, $abook = true, $effective_uid = 0) { @@ -2583,7 +2583,7 @@ function magic_link($s) { * @brief If $escape is true, dbesc() each element before adding quotes. * * @param[in,out] array &$arr - * @param boolean $escape (optional) default false + * @param bool $escape (optional) default false */ function stringify_array_elms(&$arr, $escape = false) { for($x = 0; $x < count($arr); $x ++) @@ -2595,7 +2595,7 @@ function stringify_array_elms(&$arr, $escape = false) { * @brief Similar to stringify_array_elms but returns a string. If $escape is true, dbesc() each element before adding quotes. * * @param array $arr - * @param boolean $escape (optional) default false + * @param bool $escape (optional) default false * @return string */ function stringify_array($arr, $escape = false) { @@ -2737,7 +2737,7 @@ function website_portation_tools() { * * @param string $needle * @param array $haystack - * @return boolean + * @return bool */ function in_arrayi($needle, $haystack) { return in_array(strtolower($needle), array_map('strtolower', $haystack)); @@ -2786,8 +2786,8 @@ function extra_query_args() { * @param[in,out] string &$str_tags string to add the tag to * @param int $profile_uid * @param string $tag the tag to replace - * @param boolean $in_network default true - * @return boolean true if replaced, false if not replaced + * @param bool $in_network default true + * @return bool true if replaced, false if not replaced */ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true) { @@ -3516,7 +3516,7 @@ function array2XML($obj, $array) { * @param string $table * @param array $arr * @param array $binary_fields - fields which will be cleansed with dbescbin rather than dbesc; this is critical for postgres - * @return boolean|PDOStatement + * @return bool|PDOStatement */ function create_table_from_array($table, $arr, $binary_fields = []) { diff --git a/include/zid.php b/include/zid.php index 3ebf1a3a4..bac5f2231 100644 --- a/include/zid.php +++ b/include/zid.php @@ -34,7 +34,7 @@ function is_matrix_url($url) { * * @param string $s * The url to accept the zid - * @param boolean $address + * @param bool $address * $address to use instead of session environment * @return string */ diff --git a/tests/unit/Access/PermissionsTest.php b/tests/unit/Access/PermissionsTest.php index b0dd35e83..461554ae4 100644 --- a/tests/unit/Access/PermissionsTest.php +++ b/tests/unit/Access/PermissionsTest.php @@ -280,7 +280,7 @@ class PermissionsTest extends UnitTestCase { * * @param array $p1 The first permission * @param array $p2 The second permission - * @param boolean $expectedresult The expected result of the tested method + * @param bool $expectedresult The expected result of the tested method */ public function testPermsCompare($p1, $p2, $expectedresult) { $this->assertEquals($expectedresult, Permissions::PermsCompare($p1, $p2)); diff --git a/tests/unit/DatabaseTestCase.php b/tests/unit/DatabaseTestCase.php index ced0375a4..3ed8862ea 100644 --- a/tests/unit/DatabaseTestCase.php +++ b/tests/unit/DatabaseTestCase.php @@ -45,7 +45,7 @@ abstract class DatabaseTestCase extends TestCase { * * @var PDO */ - static private $pdo = null; + private static $pdo = null; /** * Only instantiate \PHPUnit\DbUnit\Database\Connection once per test. diff --git a/tests/unit/Web/HttpSigTest.php b/tests/unit/Web/HttpSigTest.php index 18f2ce92b..1de250843 100644 --- a/tests/unit/Web/HttpSigTest.php +++ b/tests/unit/Web/HttpSigTest.php @@ -33,93 +33,104 @@ use Zotlabs\Web\HTTPSig; * * @covers Zotlabs\Web\HTTPSig */ -class PermissionDescriptionTest extends UnitTestCase { +class PermissionDescriptionTest extends UnitTestCase +{ - use PHPMock; + use PHPMock; - /** - * @dataProvider generate_digestProvider - */ - function testGenerate_digest($text, $digest) { - $this->assertSame( - $digest, - HTTPSig::generate_digest($text, false) - ); - } - public function generate_digestProvider() { - return [ - 'empty body text' => [ - '', - '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' - ], - 'sample body text' => [ - 'body text', - '2fu8kUkvuzuo5XyhWwORNOcJgDColXgxWkw1T5EXzPI=' - ], - 'NULL body text' => [ - null, - '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' - ], - ]; - } + /** + * @dataProvider generate_digestProvider + */ + public function testGenerate_digest($text, $digest) + { + $this->assertSame( + $digest, + HTTPSig::generate_digest($text, false) + ); + } - function testGeneratedDigestsOfDifferentTextShouldNotBeEqual() { - $this->assertNotSame( - HTTPSig::generate_digest('text1', false), - HTTPSig::generate_digest('text2', false) - ); - } + public function generate_digestProvider() + { + return [ + 'empty body text' => [ + '', + '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' + ], + 'sample body text' => [ + 'body text', + '2fu8kUkvuzuo5XyhWwORNOcJgDColXgxWkw1T5EXzPI=' + ], + 'NULL body text' => [ + null, + '47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=' + ], + ]; + } - /** - * Process separation needed for header() check. - * @runInSeparateProcess - */ - function testGenerate_digestSendsHttpHeader() { - $ret = HTTPSig::generate_digest('body text', true); + public function testGeneratedDigestsOfDifferentTextShouldNotBeEqual() + { + $this->assertNotSame( + HTTPSig::generate_digest('text1', false), + HTTPSig::generate_digest('text2', false) + ); + } - $this->assertSame('2fu8kUkvuzuo5XyhWwORNOcJgDColXgxWkw1T5EXzPI=', $ret); - $this->assertContains( - 'Digest: SHA-256=2fu8kUkvuzuo5XyhWwORNOcJgDColXgxWkw1T5EXzPI=', - xdebug_get_headers(), - 'HTTP header Digest does not match' - ); - } + /** + * Process separation needed for header() check. + * @runInSeparateProcess + */ + public function testGenerate_digestSendsHttpHeader() + { + $ret = HTTPSig::generate_digest('body text', true); - /** - * @uses ::crypto_unencapsulate - */ - function testDecrypt_sigheader() { - $header = 'Header: iv="value_iv" key="value_key" alg="value_alg" data="value_data"'; - $result = [ - 'iv' => 'value_iv', - 'key' => 'value_key', - 'alg' => 'value_alg', - 'data' => 'value_data' - ]; + $this->assertSame('2fu8kUkvuzuo5XyhWwORNOcJgDColXgxWkw1T5EXzPI=', $ret); + $this->assertContains( + 'Digest: SHA-256=2fu8kUkvuzuo5XyhWwORNOcJgDColXgxWkw1T5EXzPI=', + xdebug_get_headers(), + 'HTTP header Digest does not match' + ); + } - $this->assertSame($result, HTTPSig::decrypt_sigheader($header, 'site private key')); - } - /** - * @uses ::crypto_unencapsulate - */ - function testDecrypt_sigheaderUseSitePrivateKey() { - // Create a stub for global function get_config() with expectation - $t = $this->getFunctionMock('Zotlabs\Web', 'get_config'); - $t->expects($this->once())->willReturn('system.prvkey'); + /** + * @uses ::crypto_unencapsulate + */ + public function testDecrypt_sigheader() + { + $header = 'Header: iv="value_iv" key="value_key" alg="value_alg" data="value_data"'; + $result = [ + 'iv' => 'value_iv', + 'key' => 'value_key', + 'alg' => 'value_alg', + 'data' => 'value_data' + ]; - $header = 'Header: iv="value_iv" key="value_key" alg="value_alg" data="value_data"'; - $result = [ - 'iv' => 'value_iv', - 'key' => 'value_key', - 'alg' => 'value_alg', - 'data' => 'value_data' - ]; + $this->assertSame($result, HTTPSig::decrypt_sigheader($header, 'site private key')); + } - $this->assertSame($result, HTTPSig::decrypt_sigheader($header)); - } - function testDecrypt_sigheaderIncompleteHeaderShouldReturnEmptyString() { - $header = 'Header: iv="value_iv" key="value_key"'; + /** + * @uses ::crypto_unencapsulate + */ + public function testDecrypt_sigheaderUseSitePrivateKey() + { + // Create a stub for global function get_config() with expectation + $t = $this->getFunctionMock('Zotlabs\Web', 'get_config'); + $t->expects($this->once())->willReturn('system.prvkey'); - $this->assertEmpty(HTTPSig::decrypt_sigheader($header, 'site private key')); - } + $header = 'Header: iv="value_iv" key="value_key" alg="value_alg" data="value_data"'; + $result = [ + 'iv' => 'value_iv', + 'key' => 'value_key', + 'alg' => 'value_alg', + 'data' => 'value_data' + ]; + + $this->assertSame($result, HTTPSig::decrypt_sigheader($header)); + } + + public function testDecrypt_sigheaderIncompleteHeaderShouldReturnEmptyString() + { + $header = 'Header: iv="value_iv" key="value_key"'; + + $this->assertEmpty(HTTPSig::decrypt_sigheader($header, 'site private key')); + } } diff --git a/tests/unit/get_tags_test.php b/tests/unit/get_tags_test.php index e0e30e524..e7bfe0ec8 100644 --- a/tests/unit/get_tags_test.php +++ b/tests/unit/get_tags_test.php @@ -21,10 +21,12 @@ require_once 'mod/item.php'; * @author Alexander Kampmann * @package test.util */ -class MockApp { - function get_baseurl() { - return "baseurl"; - } +class MockApp +{ + public function get_baseurl() + { + return "baseurl"; + } } /** diff --git a/tests/unit/includes/LanguageTest.php b/tests/unit/includes/LanguageTest.php index 777b5ac14..ea3935ca5 100644 --- a/tests/unit/includes/LanguageTest.php +++ b/tests/unit/includes/LanguageTest.php @@ -55,7 +55,7 @@ class LanguageTest extends UnitTestCase { // Can not unit test detect_language(), therefore test the used library // only for now to find regressions on library updates. - $l = new Text_LanguageDetect; + $l = new Text_LanguageDetect(); // return 2-letter ISO 639-1 (en) language code $l->setNameMode(2); $lng = $l->detectConfidence($text); diff --git a/tests/unit/template_test.php b/tests/unit/template_test.php index fc354a9e4..929512773 100644 --- a/tests/unit/template_test.php +++ b/tests/unit/template_test.php @@ -1,4 +1,4 @@ -assertTrue(is_null($second)); - } - - public function testSimpleVariableString() { - $tpl='Hello $name!'; - - $text=replace_macros($tpl, array('$name'=>'Anna')); - - $this->assertEquals('Hello Anna!', $text); - } - +class TemplateTest extends PHPUnit_Framework_TestCase { + + public function setUp() { + global $t; + $t= new Template(); + } + + public function testListToShort() { + @list($first, $second)=array('first'); + + $this->assertTrue(is_null($second)); + } + + public function testSimpleVariableString() { + $tpl='Hello $name!'; + + $text=replace_macros($tpl, array('$name'=>'Anna')); + + $this->assertEquals('Hello Anna!', $text); + } + public function testSimpleVariableInt() { $tpl='There are $num new messages!'; $text=replace_macros($tpl, array('$num'=>172)); $this->assertEquals('There are 172 new messages!', $text); - } - + } + public function testConditionalElse() { $tpl='There{{ if $num!=1 }} are $num new messages{{ else }} is 1 new message{{ endif }}!'; - $text1=replace_macros($tpl, array('$num'=>1)); + $text1=replace_macros($tpl, array('$num'=>1)); $text22=replace_macros($tpl, array('$num'=>22)); - $this->assertEquals('There is 1 new message!', $text1); + $this->assertEquals('There is 1 new message!', $text1); $this->assertEquals('There are 22 new messages!', $text22); - } - + } + public function testConditionalNoElse() { $tpl='{{ if $num!=0 }}There are $num new messages!{{ endif }}'; @@ -78,98 +78,98 @@ class TemplateTest extends PHPUnit_Framework_TestCase { $this->assertEquals('', $text0); $this->assertEquals('There are 22 new messages!', $text22); - } - + } + public function testConditionalFail() { $tpl='There {{ if $num!=1 }} are $num new messages{{ else }} is 1 new message{{ endif }}!'; $text1=replace_macros($tpl, []); //$this->assertEquals('There is 1 new message!', $text1); - } - + } + public function testSimpleFor() { $tpl='{{ for $messages as $message }} $message {{ endfor }}'; $text=replace_macros($tpl, array('$messages'=>array('message 1', 'message 2'))); $this->assertEquals(' message 1 message 2 ', $text); - } - + } + public function testFor() { $tpl='{{ for $messages as $message }} from: $message.from to $message.to {{ endfor }}'; $text=replace_macros($tpl, array('$messages'=>array(array('from'=>'Mike', 'to'=>'Alex'), array('from'=>'Alex', 'to'=>'Mike')))); $this->assertEquals(' from: Mike to Alex from: Alex to Mike ', $text); - } - + } + public function testKeyedFor() { $tpl='{{ for $messages as $from=>$to }} from: $from to $to {{ endfor }}'; $text=replace_macros($tpl, array('$messages'=>array('Mike'=>'Alex', 'Sven'=>'Mike'))); $this->assertEquals(' from: Mike to Alex from: Sven to Mike ', $text); - } - + } + public function testForEmpty() { $tpl='messages: {{for $messages as $message}} from: $message.from to $message.to {{ endfor }}'; $text=replace_macros($tpl, array('$messages'=>[])); $this->assertEquals('messages: ', $text); - } - + } + public function testForWrongType() { $tpl='messages: {{for $messages as $message}} from: $message.from to $message.to {{ endfor }}'; $text=replace_macros($tpl, array('$messages'=>11)); $this->assertEquals('messages: ', $text); - } - + } + public function testForConditional() { $tpl='new messages: {{for $messages as $message}}{{ if $message.new }} $message.text{{endif}}{{ endfor }}'; - $text=replace_macros($tpl, array('$messages'=>array( - array('new'=>true, 'text'=>'new message'), + $text=replace_macros($tpl, array('$messages'=>array( + array('new'=>true, 'text'=>'new message'), array('new'=>false, 'text'=>'old message')))); $this->assertEquals('new messages: new message', $text); - } - + } + public function testConditionalFor() { $tpl='{{ if $enabled }}new messages:{{for $messages as $message}} $message.text{{ endfor }}{{endif}}'; - $text=replace_macros($tpl, array('$enabled'=>true, + $text=replace_macros($tpl, array('$enabled'=>true, '$messages'=>array( array('new'=>true, 'text'=>'new message'), array('new'=>false, 'text'=>'old message')))); $this->assertEquals('new messages: new message old message', $text); - } - + } + public function testFantasy() { $tpl='Fantasy: {{fantasy $messages}}'; $text=replace_macros($tpl, array('$messages'=>'no no')); $this->assertEquals('Fantasy: {{fantasy no no}}', $text); - } - + } + public function testInc() { $tpl='{{inc field_input.tpl with $field=$myvar}}{{ endinc }}'; $text=replace_macros($tpl, array('$myvar'=>array('myfield', 'label', 'value', 'help'))); - $this->assertEquals(" \n" - ."
      \n" - ." \n" - ." \n" - ." help\n" + $this->assertEquals(" \n" + ."
      \n" + ." \n" + ." \n" + ." help\n" ."
      \n", $text); - } - + } + public function testIncNoVar() { $tpl='{{inc field_input.tpl }}{{ endinc }}'; @@ -179,27 +179,27 @@ class TemplateTest extends PHPUnit_Framework_TestCase { ." \n" ." help\n" ."
      \n", $text); - } - + } + public function testDoubleUse() { $tpl='Hello $name! {{ if $enabled }} I love you! {{ endif }}'; $text=replace_macros($tpl, array('$name'=>'Anna', '$enabled'=>false)); - $this->assertEquals('Hello Anna! ', $text); - + $this->assertEquals('Hello Anna! ', $text); + $tpl='Hey $name! {{ if $enabled }} I hate you! {{ endif }}'; $text=replace_macros($tpl, array('$name'=>'Max', '$enabled'=>true)); $this->assertEquals('Hey Max! I hate you! ', $text); - } - + } + public function testIncDouble() { - $tpl='{{inc field_input.tpl with $field=$var1}}{{ endinc }}' + $tpl='{{inc field_input.tpl with $field=$var1}}{{ endinc }}' .'{{inc field_input.tpl with $field=$var2}}{{ endinc }}'; - $text=replace_macros($tpl, array('$var1'=>array('myfield', 'label', 'value', 'help'), + $text=replace_macros($tpl, array('$var1'=>array('myfield', 'label', 'value', 'help'), '$var2'=>array('myfield2', 'label2', 'value2', 'help2'))); $this->assertEquals(" \n" @@ -207,12 +207,12 @@ class TemplateTest extends PHPUnit_Framework_TestCase { ." \n" ." \n" ." help\n" - ."
      \n" - ." \n" - ."
      \n" - ." \n" - ." \n" - ." help2\n" + ."
      \n" + ." \n" + ."
      \n" + ." \n" + ." \n" + ." help2\n" ."
      \n", $text); - } + } } \ No newline at end of file diff --git a/util/addons b/util/addons index dadc29bb6..8100bbef3 100755 --- a/util/addons +++ b/util/addons @@ -41,7 +41,7 @@ cli_startup(); if ($idz !== false) { unset(App::$plugins[$idz]); uninstall_plugin($id); - set_config("system","addon", implode(", ",App::$plugins)); + set_config('system', 'addon', implode(', ',App::$plugins)); } } $info['disabled'] = 1-intval($x); @@ -92,7 +92,7 @@ if($argc == 3 && $argv[1] === 'install') { else { App::$plugins[] = $p[0]; install_plugin($p[0]); - set_config("system","addon", implode(", ",App::$plugins)); + set_config('system', 'addon', implode(', ',App::$plugins)); echo $p[0] . ' installed.' . "\n"; } } @@ -121,7 +121,7 @@ if($argc == 3 && $argv[1] === 'uninstall') { if ($idx !== false) unset(App::$plugins[$idx]); uninstall_plugin($p[0]); - set_config("system","addon", implode(", ",App::$plugins)); + set_config('system', 'addon', implode(', ',App::$plugins)); echo $p[0] . ' uninstalled.' . "\n"; } } @@ -135,7 +135,7 @@ if($argc == 3 && $argv[1] === 'uninstall') { if ($idx !== false) unset(App::$plugins[$idx]); uninstall_plugin($argv[2]); - set_config("system","addon", implode(", ",App::$plugins)); + set_config('system', 'addon', implode(', ',App::$plugins)); echo $argv[2] . ' uninstalled.' . "\n"; } diff --git a/util/admins b/util/admins index ecc672a78..8e0fd3f1d 100755 --- a/util/admins +++ b/util/admins @@ -26,7 +26,7 @@ EndOfOutput; } if($argc == 1) { - $r = q("select account_id, account_roles, account_email from account"); + $r = q('select account_id, account_roles, account_email from account'); if($r) { foreach($r as $rr) { echo sprintf('%4u %s %s', $rr['account_id'], $rr['account_email'],(($rr['account_roles'] & 4096) ? '*' : '')) . PHP_EOL; @@ -37,7 +37,7 @@ if($argc == 1) { if($argc > 1 && $argv[1] === 'list') { - $r = q("select account_id, account_roles, account_email from account where (account_roles & 4096) > 0"); + $r = q('select account_id, account_roles, account_email from account where (account_roles & 4096) > 0'); if($r) { foreach($r as $rr) { echo sprintf('%4u %s %s', $rr['account_id'], $rr['account_email'],(($rr['account_roles'] & 4096) ? '*' : '')) . PHP_EOL; @@ -47,13 +47,13 @@ if($argc > 1 && $argv[1] === 'list') { if($argc > 2 && $argv[1] === 'add' && intval($argv[2])) { - $r = q("update account set account_roles = (account_roles | 4096) where account_id = %d", + $r = q('update account set account_roles = (account_roles | 4096) where account_id = %d', intval($argv[2]) ); } if($argc > 2 && $argv[1] === 'remove' && intval($argv[2])) { - $r = q("update account set account_roles = (account_roles - 4096) where account_id = %d and (account_roles & 4096) > 0", + $r = q('update account set account_roles = (account_roles - 4096) where account_id = %d and (account_roles & 4096) > 0', intval($argv[2]) ); } diff --git a/util/config b/util/config index 328b294b4..26e797ce1 100755 --- a/util/config +++ b/util/config @@ -71,7 +71,7 @@ if($argc == 2) { } if($argc == 1) { - $r = q("select * from config where true"); + $r = q('select * from config where true'); if($r) { foreach($r as $rr) { echo "config[{$rr['cat']}][{$rr['k']}] = " . printable_config($rr['v']) . "\n"; diff --git a/util/db_update b/util/db_update index 46a98b4db..9862540be 100755 --- a/util/db_update +++ b/util/db_update @@ -12,12 +12,12 @@ require_once('include/cli_startup.php'); cli_startup(); $build = get_config('system','db_version'); -echo "Old DB VERSION: " . $build . "\n"; -echo "New DB VERSION: " . DB_UPDATE_VERSION . "\n"; +echo 'Old DB VERSION: ' . $build . "\n"; +echo 'New DB VERSION: ' . DB_UPDATE_VERSION . "\n"; if($build != DB_UPDATE_VERSION) { - echo "Updating database..."; + echo 'Updating database...'; check_config(); echo "Done\n"; } diff --git a/util/dcp b/util/dcp index a1ac0dd86..a78ac6d1b 100755 --- a/util/dcp +++ b/util/dcp @@ -17,7 +17,7 @@ cli_startup(); if($argc < 3) { - echo "Usage: " . $argv[0] . ' src dstdir' . "\n"; + echo 'Usage: ' . $argv[0] . ' src dstdir' . "\n"; echo 'Always run from the toplevel web directory.' . "\n"; echo 'destination should begin with store/$nickname/desired/path or $nickname/desired/path' . "\n"; echo 'Example: util/dcp /etc/motd store/joe/etc' . "\n"; diff --git a/util/dmkdir b/util/dmkdir index a476ca02f..92f01db62 100755 --- a/util/dmkdir +++ b/util/dmkdir @@ -19,7 +19,7 @@ cli_startup(); $dstfile = $argv[1]; if($argc != 2) { - echo "Usage: " . $argv[0] . ' directory' . "\n"; + echo 'Usage: ' . $argv[0] . ' directory' . "\n"; echo 'Always run from the toplevel web directory.' . "\n"; echo 'directory should begin with store/$nickname/desired/path or $nickname/desired/path' . "\n"; echo 'Example: util/dmkdir store/bob/photos/2017' . "\n"; diff --git a/util/docblox_errorchecker.php b/util/docblox_errorchecker.php index eaef0bbc4..81b7baf6d 100644 --- a/util/docblox_errorchecker.php +++ b/util/docblox_errorchecker.php @@ -32,9 +32,9 @@ * @return string comma-seperated list of the file names */ function namesList($fileset) { - $fsparam=""; + $fsparam= ''; foreach($fileset as $file) { - $fsparam=$fsparam.",".$file; + $fsparam=$fsparam. ',' .$file; } return $fsparam; } @@ -50,7 +50,7 @@ function namesList($fileset) { function runs($fileset) { $fsParam=namesList($fileset); exec('docblox -t phpdoc_out -f '.$fsParam); - if(file_exists("phpdoc_out/index.html")) { + if(file_exists('phpdoc_out/index.html')) { echo "\n Subset ".$fsParam." is okay. \n"; exec('rm -r phpdoc_out'); return true; @@ -77,10 +77,10 @@ function reduce($fileset, $ps) { //split array... $parts=array_chunk($fileset, $ps); //filter working subsets... - $parts=array_filter($parts, "runs"); + $parts=array_filter($parts, 'runs'); //melt remaining parts together if(is_array($parts)) { - return array_reduce($parts, "array_merge", []); + return array_reduce($parts, 'array_merge', []); } return []; } @@ -96,17 +96,17 @@ $filelist=[]; //loop over all files in $dir while($dh=opendir($dir)) { while($file=readdir($dh)) { - if(is_dir($dir."/".$file)) { + if(is_dir($dir. '/' .$file)) { //add to directory stack - if($file!=".." && $file!=".") { - array_push($dirstack, $dir."/".$file); - echo "dir ".$dir."/".$file."\n"; + if($file!= '..' && $file!= '.') { + array_push($dirstack, $dir. '/' .$file); + echo 'dir ' .$dir. '/' .$file."\n"; } } else { //test if it is a source file and add to filelist - if(substr($file, strlen($file)-4)==".php") { - array_push($filelist, $dir."/".$file); - echo $dir."/".$file."\n"; + if(substr($file, strlen($file)-4)== '.php') { + array_push($filelist, $dir. '/' .$file); + echo $dir. '/' .$file."\n"; } } } @@ -125,7 +125,7 @@ $res=$filelist; $i=0; do { $i=count($res); - echo $i."/".count($fileset)." elements remaining. \n"; + echo $i. '/' .count($fileset)." elements remaining. \n"; $res=reduce($res, count($res)/2); shuffle($res); } while(count($res)<$i); @@ -137,9 +137,9 @@ while(count($res)!=0) { $file=array_pop($res); if(runs(array_merge($res, $needed))) { - echo "needs: ".$file." and file count ".count($needed); + echo 'needs: ' .$file. ' and file count ' .count($needed); array_push($needed, $file); } } -echo "\nSmallest Set is: ".namesList($needed)." with ".count($needed)." files. "; +echo "\nSmallest Set is: ".namesList($needed). ' with ' .count($needed). ' files. '; diff --git a/util/pconfig b/util/pconfig index a30e69960..69192534f 100755 --- a/util/pconfig +++ b/util/pconfig @@ -82,7 +82,7 @@ if($argc == 3) { } if($argc == 2) { - $r = q("select * from pconfig where uid = " . intval($argv[1])); + $r = q('select * from pconfig where uid = ' . intval($argv[1])); if($r) { foreach($r as $rr) { echo "pconfig[{$rr['uid']}][{$rr['cat']}][{$rr['k']}] = " . printable_config($rr['v']) . "\n"; @@ -91,7 +91,7 @@ if($argc == 2) { } if($argc == 1) { - $r = q("select channel_id, channel_name from channel where channel_removed = 0"); + $r = q('select channel_id, channel_name from channel where channel_removed = 0'); if($r) { foreach($r as $rr) { echo sprintf('%4u %s', $rr['channel_id'], $rr['channel_name']) . PHP_EOL; diff --git a/util/php2po.php b/util/php2po.php index c68874661..83ace1180 100644 --- a/util/php2po.php +++ b/util/php2po.php @@ -2,18 +2,18 @@ if(! class_exists('App')) { class App { - static public $rtl; - static public $strings = Array(); + public static $rtl; + public static $strings = Array(); } } if ($argc!=2) { - print "Usage: ".$argv[0]." \n\n"; + print 'Usage: ' .$argv[0]." \n\n"; return; } $phpfile = $argv[1]; - $pofile = dirname($phpfile)."/messages.po"; + $pofile = dirname($phpfile). '/messages.po'; if (!file_exists($phpfile)){ print "Unable to find '$phpfile'\n"; @@ -24,34 +24,34 @@ print "Out to '$pofile'\n"; - $out = ""; + $out = ''; $infile = file($pofile); - $k = ""; - $c = ""; + $k = ''; + $c = ''; $ink = False; foreach ($infile as $l) { - $l = trim($l, " "); - if (!preg_match("/^msgstr\[[1-9]/",$l)) { - if ($k!="" && (substr($l,0,7)=="msgstr " || substr($l,0,8)=="msgstr[0")){ + $l = trim($l, ' '); + if (!preg_match('/^msgstr\[[1-9]/',$l)) { + if ($k!= '' && (substr($l,0,7)== 'msgstr ' || substr($l,0,8)== 'msgstr[0')){ $ink = False; $k = stripcslashes($k); - $v = ""; + $v = ''; if (isset(App::$strings[$k])) { $v = App::$strings[$k]; } else { - $k = "__ctx:".$c."__ ".$k; + $k = '__ctx:' .$c. '__ ' .$k; if (isset(App::$strings[$k])) { $v = App::$strings[$k]; - $c = ""; + $c = ''; } } if (!empty($v)) { if (is_array($v)) { - $l = ""; + $l = ''; $n = 0; foreach ($v as &$value) { - $l .= "msgstr[".$n."] \"".addcslashes($value,"\"\n")."\"\n"; + $l .= 'msgstr[' .$n."] \"".addcslashes($value,"\"\n")."\"\n"; $n++; } } else { @@ -60,20 +60,20 @@ } } - if (substr($l,0,6)=="msgid_" || substr($l,0,7)=="msgstr[") $ink = False; + if (substr($l,0,6)== 'msgid_' || substr($l,0,7)== 'msgstr[') $ink = False; if ($ink) { preg_match('/^"(.*)"$/',$l,$m); $k .= $m[1]; } - if (substr($l,0,6)=="msgid ") { + if (substr($l,0,6)== 'msgid ') { preg_match('/^msgid "(.*)"$/',$l,$m); $k = $m[1]; $ink = True; } - if (substr($l,0,8)=="msgctxt ") { + if (substr($l,0,8)== 'msgctxt ') { preg_match('/^msgctxt "(.*)"$/',$l,$m); $c = $m[1]; } diff --git a/util/phplogtime b/util/phplogtime index 0fb8a8e2b..d774ecaef 100755 --- a/util/phplogtime +++ b/util/phplogtime @@ -33,8 +33,8 @@ if (! $lines) { if ($lines) { foreach ($lines as $line) { - if (substr($line,0,1) === "[") { - $ts = rtrim(substr($line,1,strpos($line,"]")),"]"); + if (substr($line,0,1) === '[') { + $ts = rtrim(substr($line,1,strpos($line, ']')), ']'); if ($ts) { $arr = explode(' ', $ts); if (count($arr) === 3) { @@ -42,8 +42,8 @@ if ($lines) { $d = new DateTime($arr[1] . ' ' . $arr[2]); $to = new DateTimeZone($dest_tz); $d->setTimeZone($to); - $o = $d->format("Y-m-d H:i:s"); - echo "[" . $o . "]" . substr($line,strlen($ts) + 2); + $o = $d->format('Y-m-d H:i:s'); + echo '[' . $o . ']' . substr($line,strlen($ts) + 2); } } } diff --git a/util/po2php.php b/util/po2php.php index 6bb54f2e9..25cff5f29 100644 --- a/util/po2php.php +++ b/util/po2php.php @@ -3,14 +3,14 @@ function po2php_run($argc,$argv) { if ($argc < 2) { - print "Usage: ".$argv[0]." \n\n"; + print 'Usage: ' .$argv[0]." \n\n"; return; } $rtl = false; $pofile = $argv[1]; - $outfile = dirname($pofile)."/strings.php"; + $outfile = dirname($pofile). '/strings.php'; if($argc > 2) { if($argv[2] === 'rtl') @@ -34,9 +34,9 @@ function po2php_run($argc,$argv) { $out=" " + . ' => ' .preg_replace_callback($escape_s_exp,'escape_s',$match[2]) .",\n"; } - if (substr($l,0,6)=="msgid_") { + if (substr($l,0,6)== 'msgid_') { $ink = False; $out .= 'App::$strings["'.$k.'"] = '; } @@ -104,36 +104,36 @@ function po2php_run($argc,$argv) { //$out .= 'App::$strings['.$k.'] = '; } - if (substr($l,0,6)=="msgid "){ + if (substr($l,0,6)== 'msgid '){ if ($inv) { $inv = False; $out .= '"'.$v.'"'; } - if ($k!="") $out .= $arr?"];\n":";\n"; + if ($k!= '') $out .= $arr?"];\n":";\n"; $arr=False; - $k = str_replace("msgid ","",$l); + $k = str_replace('msgid ', '',$l); $k = trim_message($k); $k = $ctx.$k; // echo $ctx ? $ctx."\nX\n":""; $k = preg_replace_callback($escape_s_exp,'escape_s',$k); - $ctx = ""; + $ctx = ''; $ink = True; } - if ($inv && substr($l,0,6)!="msgstr" && substr($l,0,7)!="msgctxt") { + if ($inv && substr($l,0,6)!= 'msgstr' && substr($l,0,7)!= 'msgctxt') { $v .= trim_message($l); $v = preg_replace_callback($escape_s_exp,'escape_s',$v); //$out .= 'App::$strings['.$k.'] = '; } - if (substr($l,0,7)=="msgctxt") { - $ctx = str_replace("msgctxt ","",$l); + if (substr($l,0,7)== 'msgctxt') { + $ctx = str_replace('msgctxt ', '',$l); $ctx = trim_message($ctx); - $ctx = "__ctx:".$ctx."__ "; + $ctx = '__ctx:' .$ctx. '__ '; $ctx = preg_replace_callback($escape_s_exp,'escape_s',$ctx); } } if ($inv) { $inv = False; $out .= '"'.$v.'"'; } - if ($k!="") $out .= $arr?"];\n":";\n"; + if ($k!= '') $out .= $arr?"];\n":";\n"; file_put_contents($outfile, $out); diff --git a/util/precompile_smarty3.php b/util/precompile_smarty3.php index c977a9680..c5f9ddac6 100755 --- a/util/precompile_smarty3.php +++ b/util/precompile_smarty3.php @@ -7,7 +7,7 @@ #require_once('boot.php'); #require_once('include/cli_startup.php'); -require_once "library/Smarty/libs/Smarty.class.php"; +require_once 'library/Smarty/libs/Smarty.class.php'; #cli_startup(); @@ -21,7 +21,7 @@ $s->setCompileDir(TEMPLATE_BUILD_PATH . '/compiled/'); $s->setConfigDir(TEMPLATE_BUILD_PATH . '/config/'); $s->setCacheDir(TEMPLATE_BUILD_PATH . '/cache/'); -$s->left_delimiter = "{{"; -$s->right_delimiter = "}}"; +$s->left_delimiter = '{{'; +$s->right_delimiter = '}}'; $s->compileAllTemplates('.tpl',true); \ No newline at end of file diff --git a/util/schemaspy b/util/schemaspy index fdae74965..29a631300 100755 --- a/util/schemaspy +++ b/util/schemaspy @@ -2,7 +2,7 @@ 0"); + $x = q('SELECT COUNT(id) AS qty FROM photo WHERE resource_id IN (SELECT DISTINCT resource_id FROM photo WHERE photo_usage = 0 and os_storage = 1) AND imgscale > 0'); echo 'Thumbnails total: ' . $x[0]['qty'] . PHP_EOL; - $x = q("SELECT COUNT(id) AS qty FROM photo WHERE resource_id IN (SELECT DISTINCT resource_id FROM photo WHERE photo_usage = 0 and os_storage = 1) AND os_storage != %d AND imgscale > 0", + $x = q('SELECT COUNT(id) AS qty FROM photo WHERE resource_id IN (SELECT DISTINCT resource_id FROM photo WHERE photo_usage = 0 and os_storage = 1) AND os_storage != %d AND imgscale > 0', $storage ); echo 'Thumbnails to convert: ' . $x[0]['qty'] . PHP_EOL; @@ -45,7 +45,7 @@ if($argc == 2) { break; } - $x = q("SELECT resource_id, content FROM photo WHERE photo_usage = 0 AND os_storage = 1 AND imgscale = 0"); + $x = q('SELECT resource_id, content FROM photo WHERE photo_usage = 0 AND os_storage = 1 AND imgscale = 0'); if($x) { foreach($x as $xx) { @@ -88,7 +88,7 @@ if($argc == 2) { break; } - $x = q("SELECT resource_id FROM photo WHERE photo_usage = 0 AND os_storage = 1 AND imgscale = 0"); + $x = q('SELECT resource_id FROM photo WHERE photo_usage = 0 AND os_storage = 1 AND imgscale = 0'); if($x) { foreach($x as $xx) { diff --git a/util/strings.php b/util/strings.php index 84321f9c2..69fe5fadb 100644 --- a/util/strings.php +++ b/util/strings.php @@ -1,2742 +1,2742 @@ may apply to this list and any future members. If this is not what you intended, please create another list with a different name."] = ""; -App::$strings["Add new connections to this access list"] = ""; -App::$strings["edit"] = ""; -App::$strings["Edit list"] = ""; -App::$strings["Create new list"] = ""; -App::$strings["Channels not in any access list"] = ""; -App::$strings["add"] = ""; -App::$strings["Source code of failed update: "] = ""; -App::$strings["Update Error at %s"] = ""; -App::$strings["Update %s failed. See error logs."] = ""; -App::$strings["__ctx:permcat__ default"] = ""; -App::$strings["__ctx:permcat__ follower"] = ""; -App::$strings["__ctx:permcat__ contributor"] = ""; -App::$strings["__ctx:permcat__ publisher"] = ""; -App::$strings["%1\$s wrote the following %2\$s %3\$s"] = ""; -App::$strings["post"] = ""; -App::$strings["Private Message"] = ""; -App::$strings["Privacy conflict. Discretion advised."] = ""; -App::$strings["Admin Delete"] = ""; -App::$strings["Select"] = ""; -App::$strings["Save to Folder"] = ""; -App::$strings["I will attend"] = ""; -App::$strings["I will not attend"] = ""; -App::$strings["I might attend"] = ""; -App::$strings["I agree"] = ""; -App::$strings["I disagree"] = ""; -App::$strings["I abstain"] = ""; -App::$strings["View all"] = ""; -App::$strings["__ctx:noun__ Like"] = [ - 0 => "", - 1 => "", +App::$strings['Social Networking'] = ''; +App::$strings['Social - Normal'] = ''; +App::$strings['Social - Restricted'] = ''; +App::$strings['Community Group'] = ''; +App::$strings['Group - Normal'] = ''; +App::$strings['Group - Restricted'] = ''; +App::$strings['Group - Moderated'] = ''; +App::$strings['Collection'] = ''; +App::$strings['Collection - Normal'] = ''; +App::$strings['Collection - Restricted'] = ''; +App::$strings['Grant viewing access to and delivery of your channel stream and posts'] = ''; +App::$strings['Grant viewing access to your default channel profile'] = ''; +App::$strings['Grant viewing access to your address book (connections)'] = ''; +App::$strings['Grant viewing access to your file storage and photos'] = ''; +App::$strings['Grant permission to post on your channel (wall) page'] = ''; +App::$strings['Accept delivery of their posts and all comments to their posts'] = ''; +App::$strings['Accept delivery of comments and likes on your posts'] = ''; +App::$strings['Accept delivery of their likes of your profile'] = ''; +App::$strings['Grant upload permissions to your file storage and photos'] = ''; +App::$strings['Grant permission to republish/mirror your posts'] = ''; +App::$strings['Accept comments and wall posts only after approval (moderation)'] = ''; +App::$strings['Grant channel administration (delegation) permission'] = ''; +App::$strings['Missing room name'] = ''; +App::$strings['Duplicate room name'] = ''; +App::$strings['Invalid room specifier.'] = ''; +App::$strings['Room not found.'] = ''; +App::$strings['Permission denied.'] = ''; +App::$strings['Room is full'] = ''; +App::$strings['Apps'] = ''; +App::$strings['Friend Zoom'] = ''; +App::$strings['Articles'] = ''; +App::$strings['Cards'] = ''; +App::$strings['Calendar'] = ''; +App::$strings['Categories'] = ''; +App::$strings['Clients'] = ''; +App::$strings['Site Admin'] = ''; +App::$strings['Content Filter'] = ''; +App::$strings['Content Import'] = ''; +App::$strings['Report Bug'] = ''; +App::$strings['View Bookmarks'] = ''; +App::$strings['Chatrooms'] = ''; +App::$strings['Connections'] = ''; +App::$strings['Expire Posts'] = ''; +App::$strings['Future Posting'] = ''; +App::$strings['Remote Diagnostics'] = ''; +App::$strings['Suggest Channels'] = ''; +App::$strings['Login'] = ''; +App::$strings['Channel Manager'] = ''; +App::$strings['Notes'] = ''; +App::$strings['Stream'] = ''; +App::$strings['Settings'] = ''; +App::$strings['Files'] = ''; +App::$strings['Webpages'] = ''; +App::$strings['Wiki'] = ''; +App::$strings['Channel Home'] = ''; +App::$strings['View Profile'] = ''; +App::$strings['Photos'] = ''; +App::$strings['Photomap'] = ''; +App::$strings['Events'] = ''; +App::$strings['Tasks'] = ''; +App::$strings['No Comment'] = ''; +App::$strings['Directory'] = ''; +App::$strings['Help'] = ''; +App::$strings['Mail'] = ''; +App::$strings['Mood'] = ''; +App::$strings['Poke'] = ''; +App::$strings['Chat'] = ''; +App::$strings['Search'] = ''; +App::$strings['Stream Order'] = ''; +App::$strings['Probe'] = ''; +App::$strings['Suggest'] = ''; +App::$strings['Random Channel'] = ''; +App::$strings['Invite'] = ''; +App::$strings['Features'] = ''; +App::$strings['Language'] = ''; +App::$strings['Post'] = ''; +App::$strings['ZotPost'] = ''; +App::$strings['Profile Photo'] = ''; +App::$strings['Profile'] = ''; +App::$strings['Profiles'] = ''; +App::$strings['Lists'] = ''; +App::$strings['Notifications'] = ''; +App::$strings['Order Apps'] = ''; +App::$strings['CalDAV'] = ''; +App::$strings['CardDAV'] = ''; +App::$strings['Channel Sources'] = ''; +App::$strings['Gallery'] = ''; +App::$strings['Guest Access'] = ''; +App::$strings['OAuth Apps Manager'] = ''; +App::$strings['OAuth2 Apps Manager'] = ''; +App::$strings['PDL Editor'] = ''; +App::$strings['Permission Categories'] = ''; +App::$strings['Premium Channel'] = ''; +App::$strings['Public Stream'] = ''; +App::$strings['My Chatrooms'] = ''; +App::$strings['Update'] = ''; +App::$strings['Install'] = ''; +App::$strings['Purchase'] = ''; +App::$strings['Edit'] = ''; +App::$strings['Delete'] = ''; +App::$strings['Undelete'] = ''; +App::$strings['Add to app-tray'] = ''; +App::$strings['Remove from app-tray'] = ''; +App::$strings['Pin to navbar'] = ''; +App::$strings['Unpin from navbar'] = ''; +App::$strings['Unknown'] = ''; +App::$strings['Visible to your default audience'] = ''; +App::$strings['Only me'] = ''; +App::$strings['Public'] = ''; +App::$strings["Anybody in the \$Projectname network"] = ''; +App::$strings['Any account on %s'] = ''; +App::$strings['Any of my connections'] = ''; +App::$strings['Only connections I specifically allow'] = ''; +App::$strings['Anybody authenticated (could include visitors from other networks)'] = ''; +App::$strings["Any connections including those who haven't yet been approved"] = ''; +App::$strings['This is your default setting for the audience of your normal stream, and posts.'] = ''; +App::$strings['This is your default setting for who can view your default channel profile'] = ''; +App::$strings['This is your default setting for who can view your connections'] = ''; +App::$strings['This is your default setting for who can view your file storage and photos'] = ''; +App::$strings['This is your default setting for the audience of your webpages'] = ''; +App::$strings['Channel is blocked on this site.'] = ''; +App::$strings['Channel location missing.'] = ''; +App::$strings['Remote channel or protocol unavailable.'] = ''; +App::$strings['Channel discovery failed.'] = ''; +App::$strings['Protocol not supported'] = ''; +App::$strings['Cannot connect to yourself.'] = ''; +App::$strings['error saving data'] = ''; +App::$strings['A deleted list with this name was revived. Existing item permissions may apply to this list and any future members. If this is not what you intended, please create another list with a different name.'] = ''; +App::$strings['Add new connections to this access list'] = ''; +App::$strings['edit'] = ''; +App::$strings['Edit list'] = ''; +App::$strings['Create new list'] = ''; +App::$strings['Channels not in any access list'] = ''; +App::$strings['add'] = ''; +App::$strings['Source code of failed update: '] = ''; +App::$strings['Update Error at %s'] = ''; +App::$strings['Update %s failed. See error logs.'] = ''; +App::$strings['__ctx:permcat__ default'] = ''; +App::$strings['__ctx:permcat__ follower'] = ''; +App::$strings['__ctx:permcat__ contributor'] = ''; +App::$strings['__ctx:permcat__ publisher'] = ''; +App::$strings["%1\$s wrote the following %2\$s %3\$s"] = ''; +App::$strings['post'] = ''; +App::$strings['Private Message'] = ''; +App::$strings['Privacy conflict. Discretion advised.'] = ''; +App::$strings['Admin Delete'] = ''; +App::$strings['Select'] = ''; +App::$strings['Save to Folder'] = ''; +App::$strings['I will attend'] = ''; +App::$strings['I will not attend'] = ''; +App::$strings['I might attend'] = ''; +App::$strings['I agree'] = ''; +App::$strings['I disagree'] = ''; +App::$strings['I abstain'] = ''; +App::$strings['View all'] = ''; +App::$strings['__ctx:noun__ Like'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:noun__ Likes"] = ""; -App::$strings["__ctx:noun__ Dislike"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:noun__ Likes'] = ''; +App::$strings['__ctx:noun__ Dislike'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:noun__ Dislikes"] = ""; -App::$strings["Save"] = ""; -App::$strings["Message signature validated"] = ""; -App::$strings["Message signature incorrect"] = ""; -App::$strings["Add Tag"] = ""; -App::$strings["I like this (toggle)"] = ""; -App::$strings["like"] = ""; -App::$strings["I don't like this (toggle)"] = ""; -App::$strings["dislike"] = ""; -App::$strings["Repeat This"] = ""; -App::$strings["Share this"] = ""; -App::$strings["Delivery Report"] = ""; -App::$strings["%d comment"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:noun__ Dislikes'] = ''; +App::$strings['Save'] = ''; +App::$strings['Message signature validated'] = ''; +App::$strings['Message signature incorrect'] = ''; +App::$strings['Add Tag'] = ''; +App::$strings['I like this (toggle)'] = ''; +App::$strings['like'] = ''; +App::$strings["I don't like this (toggle)"] = ''; +App::$strings['dislike'] = ''; +App::$strings['Repeat This'] = ''; +App::$strings['Share this'] = ''; +App::$strings['Delivery Report'] = ''; +App::$strings['%d comment'] = [ + 0 => '', + 1 => '', ]; -App::$strings["%d unseen"] = ""; -App::$strings["View %s's profile - %s"] = ""; -App::$strings["to"] = ""; -App::$strings["via"] = ""; -App::$strings["Wall-to-Wall"] = ""; -App::$strings["via Wall-To-Wall:"] = ""; -App::$strings["from %s"] = ""; -App::$strings["last edited: %s"] = ""; -App::$strings["Expires: %s"] = ""; -App::$strings["Attend"] = ""; -App::$strings["Attendance Options"] = ""; -App::$strings["Vote"] = ""; -App::$strings["Voting Options"] = ""; -App::$strings["Reply"] = ""; -App::$strings["Pinned post"] = ""; -App::$strings["Unpin this post"] = ""; -App::$strings["Pin this post"] = ""; -App::$strings["Save Bookmarks"] = ""; -App::$strings["Add to Calendar"] = ""; -App::$strings["Mark all seen"] = ""; -App::$strings["Close"] = ""; -App::$strings["This is an unsaved preview"] = ""; -App::$strings["Please wait"] = ""; -App::$strings["%s show all"] = ""; -App::$strings["This is you"] = ""; -App::$strings["Comment"] = ""; -App::$strings["Submit"] = ""; -App::$strings["Bold"] = ""; -App::$strings["Italic"] = ""; -App::$strings["Underline"] = ""; -App::$strings["Quote"] = ""; -App::$strings["Code"] = ""; -App::$strings["Image"] = ""; -App::$strings["Attach/Upload file"] = ""; -App::$strings["Insert Link"] = ""; -App::$strings["Video"] = ""; -App::$strings["Preview"] = ""; -App::$strings["Reset"] = ""; -App::$strings["Encrypt text"] = ""; -App::$strings["Your full name (required)"] = ""; -App::$strings["Your email address (required)"] = ""; -App::$strings["Your website URL (optional)"] = ""; -App::$strings["Likes %1\$s's %2\$s"] = ""; -App::$strings["Doesn't like %1\$s's %2\$s"] = ""; -App::$strings["Will attend %s's event"] = ""; -App::$strings["Will not attend %s's event"] = ""; -App::$strings["May attend %s's event"] = ""; -App::$strings["May not attend %s's event"] = ""; -App::$strings["🔁 Repeated %1\$s's %2\$s"] = ""; -App::$strings["%1\$s (%2\$s)"] = ""; -App::$strings["\$Projectname Notification"] = ""; -App::$strings["\$projectname"] = ""; -App::$strings["Thank You,"] = ""; -App::$strings["%s Administrator"] = ""; -App::$strings["This email was sent by %1\$s at %2\$s."] = ""; -App::$strings["\$Projectname"] = ""; -App::$strings["To stop receiving these messages, please adjust your Notification Settings at %s"] = ""; -App::$strings["To stop receiving these messages, please adjust your %s."] = ""; -App::$strings["Notification Settings"] = ""; -App::$strings["%s "] = ""; -App::$strings["[\$Projectname:Notify] New mail received at %s"] = ""; -App::$strings["%1\$s sent you a new private message at %2\$s."] = ""; -App::$strings["%1\$s sent you %2\$s."] = ""; -App::$strings["a private message"] = ""; -App::$strings["Please visit %s to view and/or reply to your private messages."] = ""; -App::$strings["commented on"] = ""; -App::$strings["liked"] = ""; -App::$strings["disliked"] = ""; -App::$strings["%1\$s %2\$s [zrl=%3\$s]a %4\$s[/zrl]"] = ""; -App::$strings["%1\$s %2\$s [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = ""; -App::$strings["%1\$s %2\$s [zrl=%3\$s]your %4\$s[/zrl]"] = ""; -App::$strings["[\$Projectname:Notify] Moderated Comment to conversation #%1\$d by %2\$s"] = ""; -App::$strings["[\$Projectname:Notify] Comment to conversation #%1\$d by %2\$s"] = ""; -App::$strings["%1\$s commented on an item/conversation you have been following."] = ""; -App::$strings["(Moderated)"] = ""; -App::$strings["Please visit %s to view and/or reply to the conversation."] = ""; -App::$strings["Please visit %s to approve or reject this comment."] = ""; -App::$strings["%1\$s liked [zrl=%2\$s]your %3\$s[/zrl]"] = ""; -App::$strings["[\$Projectname:Notify] Like received to conversation #%1\$d by %2\$s"] = ""; -App::$strings["%1\$s liked an item/conversation you created."] = ""; -App::$strings["[\$Projectname:Notify] %s posted to your profile wall"] = ""; -App::$strings["%1\$s posted to your profile wall at %2\$s"] = ""; -App::$strings["%1\$s posted to [zrl=%2\$s]your wall[/zrl]"] = ""; -App::$strings[" - "] = ""; -App::$strings["Moderated"] = ""; -App::$strings["Please visit %s to approve or reject this post."] = ""; -App::$strings["[\$Projectname:Notify] %s tagged you"] = ""; -App::$strings["%1\$s tagged you at %2\$s"] = ""; -App::$strings["%1\$s [zrl=%2\$s]tagged you[/zrl]."] = ""; -App::$strings["[\$Projectname:Notify] %1\$s poked you"] = ""; -App::$strings["%1\$s poked you at %2\$s"] = ""; -App::$strings["%1\$s [zrl=%2\$s]poked you[/zrl]."] = ""; -App::$strings["[\$Projectname:Notify] %s tagged your post"] = ""; -App::$strings["%1\$s tagged your post at %2\$s"] = ""; -App::$strings["%1\$s tagged [zrl=%2\$s]your post[/zrl]"] = ""; -App::$strings["[\$Projectname:Notify] Introduction received"] = ""; -App::$strings["You've received an new connection request from '%1\$s' at %2\$s"] = ""; -App::$strings["You've received [zrl=%1\$s]a new connection request[/zrl] from %2\$s."] = ""; -App::$strings["You may visit their profile at %s"] = ""; -App::$strings["Please visit %s to approve or reject the connection request."] = ""; -App::$strings["[\$Projectname:Notify] Friend suggestion received"] = ""; -App::$strings["You've received a friend suggestion from '%1\$s' at %2\$s"] = ""; -App::$strings["You've received [zrl=%1\$s]a friend suggestion[/zrl] for %2\$s from %3\$s."] = ""; -App::$strings["Name:"] = ""; -App::$strings["Photo:"] = ""; -App::$strings["Please visit %s to approve or reject the suggestion."] = ""; -App::$strings["[\$Projectname:Notify]"] = ""; -App::$strings["created a new post"] = ""; -App::$strings["reacted to %s's conversation"] = ""; -App::$strings["shared %s's post"] = ""; -App::$strings["edited a post dated %s"] = ""; -App::$strings["edited a comment dated %s"] = ""; -App::$strings["Unable to verify site signature for %s"] = ""; -App::$strings["Requested channel is not available."] = ""; -App::$strings["Requested profile is not available."] = ""; -App::$strings["Change profile photo"] = ""; -App::$strings["Edit Profiles"] = ""; -App::$strings["Create New Profile"] = ""; -App::$strings["Edit Profile"] = ""; -App::$strings["Profile Image"] = ""; -App::$strings["Visible to everybody"] = ""; -App::$strings["Edit visibility"] = ""; -App::$strings["Connect"] = ""; -App::$strings["Location:"] = ""; -App::$strings["Gender:"] = ""; -App::$strings["Status:"] = ""; -App::$strings["Homepage:"] = ""; -App::$strings["Change your profile photo"] = ""; -App::$strings["Female"] = ""; -App::$strings["Male"] = ""; -App::$strings["Trans"] = ""; -App::$strings["Inter"] = ""; -App::$strings["Neuter"] = ""; -App::$strings["Non-specific"] = ""; -App::$strings["Full Name:"] = ""; -App::$strings["Like this channel"] = ""; -App::$strings["j F, Y"] = ""; -App::$strings["j F"] = ""; -App::$strings["Birthday:"] = ""; -App::$strings["Age:"] = ""; -App::$strings["for %1\$d %2\$s"] = ""; -App::$strings["Tags:"] = ""; -App::$strings["Sexual Preference:"] = ""; -App::$strings["Hometown:"] = ""; -App::$strings["Political Views:"] = ""; -App::$strings["Religion:"] = ""; -App::$strings["About:"] = ""; -App::$strings["Hobbies/Interests:"] = ""; -App::$strings["Likes:"] = ""; -App::$strings["Dislikes:"] = ""; -App::$strings["Contact information and Social Networks:"] = ""; -App::$strings["My other channels:"] = ""; -App::$strings["Musical interests:"] = ""; -App::$strings["Books, literature:"] = ""; -App::$strings["Television:"] = ""; -App::$strings["Film/dance/culture/entertainment:"] = ""; -App::$strings["Love/Romance:"] = ""; -App::$strings["Work/employment:"] = ""; -App::$strings["School/education:"] = ""; -App::$strings["Like this thing"] = ""; -App::$strings["Export"] = ""; -App::$strings["Unable to verify channel signature"] = ""; -App::$strings["default"] = ""; -App::$strings["Select an alternate language"] = ""; -App::$strings["Directory Options"] = ""; -App::$strings["Safe Mode"] = ""; -App::$strings["No"] = ""; -App::$strings["Yes"] = ""; -App::$strings["Public Groups Only"] = ""; -App::$strings["Collections Only"] = ""; -App::$strings["This Website Only"] = ""; -App::$strings["Remote privacy information not available."] = ""; -App::$strings["Visible to:"] = ""; -App::$strings["__ctx:acl__ Profile"] = ""; -App::$strings["Event can not end before it has started."] = ""; -App::$strings["Unable to generate preview."] = ""; -App::$strings["Event title and start time are required."] = ""; -App::$strings["Event not found."] = ""; -App::$strings["event"] = ""; -App::$strings["Edit event"] = ""; -App::$strings["Delete event"] = ""; -App::$strings["Link to source"] = ""; -App::$strings["calendar"] = ""; -App::$strings["Failed to remove event"] = ""; -App::$strings["sent you a private message"] = ""; -App::$strings["added your channel"] = ""; -App::$strings["requires approval"] = ""; -App::$strings["g A l F d"] = ""; -App::$strings["[today]"] = ""; -App::$strings["posted an event"] = ""; -App::$strings["shared a file with you"] = ""; -App::$strings["reported content"] = ""; -App::$strings["Private group"] = ""; -App::$strings["Public group"] = ""; -App::$strings["Off"] = ""; -App::$strings["On"] = ""; -App::$strings["Lock feature %s"] = ""; -App::$strings["Manage Additional Features"] = ""; -App::$strings["Log settings updated."] = ""; -App::$strings["Administration"] = ""; -App::$strings["Logs"] = ""; -App::$strings["Clear"] = ""; -App::$strings["Debugging"] = ""; -App::$strings["Log file"] = ""; -App::$strings["Must be writable by web server. Relative to your top-level webserver directory."] = ""; -App::$strings["Log level"] = ""; -App::$strings["New Profile Field"] = ""; -App::$strings["Field nickname"] = ""; -App::$strings["System name of field"] = ""; -App::$strings["Input type"] = ""; -App::$strings["Field Name"] = ""; -App::$strings["Label on profile pages"] = ""; -App::$strings["Help text"] = ""; -App::$strings["Additional info (optional)"] = ""; -App::$strings["Field definition not found"] = ""; -App::$strings["Edit Profile Field"] = ""; -App::$strings["Profile Fields"] = ""; -App::$strings["Basic Profile Fields"] = ""; -App::$strings["Advanced Profile Fields"] = ""; -App::$strings["(In addition to basic fields)"] = ""; -App::$strings["All available fields"] = ""; -App::$strings["Custom Fields"] = ""; -App::$strings["Create Custom Field"] = ""; -App::$strings["Queue Statistics"] = ""; -App::$strings["Total Entries"] = ""; -App::$strings["Priority"] = ""; -App::$strings["Destination URL"] = ""; -App::$strings["Mark hub permanently offline"] = ""; -App::$strings["Empty queue for this hub"] = ""; -App::$strings["Last known contact"] = ""; -App::$strings["Theme settings updated."] = ""; -App::$strings["No themes found."] = ""; -App::$strings["Item not found."] = ""; -App::$strings["Disable"] = ""; -App::$strings["Enable"] = ""; -App::$strings["Screenshot"] = ""; -App::$strings["Themes"] = ""; -App::$strings["Toggle"] = ""; -App::$strings["Author: "] = ""; -App::$strings["Maintainer: "] = ""; -App::$strings["[Experimental]"] = ""; -App::$strings["[Unsupported]"] = ""; -App::$strings["Update has been marked successful"] = ""; -App::$strings["Verification of update %s failed. Check system logs."] = ""; -App::$strings["Update %s was successfully applied."] = ""; -App::$strings["Verifying update %s did not return a status. Unknown if it succeeded."] = ""; -App::$strings["Update %s does not contain a verification function."] = ""; -App::$strings["Update function %s could not be found."] = ""; -App::$strings["Executing update procedure %s failed. Check system logs."] = ""; -App::$strings["Update %s did not return a status. It cannot be determined if it was successful."] = ""; -App::$strings["Failed Updates"] = ""; -App::$strings["Mark success (if update was manually applied)"] = ""; -App::$strings["Attempt to verify this update if a verification procedure exists"] = ""; -App::$strings["Attempt to execute this update step automatically"] = ""; -App::$strings["No failed updates."] = ""; -App::$strings["Password changed for account %d."] = ""; -App::$strings["Account settings updated."] = ""; -App::$strings["Account not found."] = ""; -App::$strings["Account Edit"] = ""; -App::$strings["New Password"] = ""; -App::$strings["New Password again"] = ""; -App::$strings["Account language (for emails)"] = ""; -App::$strings["Service class"] = ""; -App::$strings["%s account blocked/unblocked"] = [ - 0 => "", - 1 => "", +App::$strings['%d unseen'] = ''; +App::$strings["View %s's profile - %s"] = ''; +App::$strings['to'] = ''; +App::$strings['via'] = ''; +App::$strings['Wall-to-Wall'] = ''; +App::$strings['via Wall-To-Wall:'] = ''; +App::$strings['from %s'] = ''; +App::$strings['last edited: %s'] = ''; +App::$strings['Expires: %s'] = ''; +App::$strings['Attend'] = ''; +App::$strings['Attendance Options'] = ''; +App::$strings['Vote'] = ''; +App::$strings['Voting Options'] = ''; +App::$strings['Reply'] = ''; +App::$strings['Pinned post'] = ''; +App::$strings['Unpin this post'] = ''; +App::$strings['Pin this post'] = ''; +App::$strings['Save Bookmarks'] = ''; +App::$strings['Add to Calendar'] = ''; +App::$strings['Mark all seen'] = ''; +App::$strings['Close'] = ''; +App::$strings['This is an unsaved preview'] = ''; +App::$strings['Please wait'] = ''; +App::$strings['%s show all'] = ''; +App::$strings['This is you'] = ''; +App::$strings['Comment'] = ''; +App::$strings['Submit'] = ''; +App::$strings['Bold'] = ''; +App::$strings['Italic'] = ''; +App::$strings['Underline'] = ''; +App::$strings['Quote'] = ''; +App::$strings['Code'] = ''; +App::$strings['Image'] = ''; +App::$strings['Attach/Upload file'] = ''; +App::$strings['Insert Link'] = ''; +App::$strings['Video'] = ''; +App::$strings['Preview'] = ''; +App::$strings['Reset'] = ''; +App::$strings['Encrypt text'] = ''; +App::$strings['Your full name (required)'] = ''; +App::$strings['Your email address (required)'] = ''; +App::$strings['Your website URL (optional)'] = ''; +App::$strings["Likes %1\$s's %2\$s"] = ''; +App::$strings["Doesn't like %1\$s's %2\$s"] = ''; +App::$strings["Will attend %s's event"] = ''; +App::$strings["Will not attend %s's event"] = ''; +App::$strings["May attend %s's event"] = ''; +App::$strings["May not attend %s's event"] = ''; +App::$strings["🔁 Repeated %1\$s's %2\$s"] = ''; +App::$strings["%1\$s (%2\$s)"] = ''; +App::$strings["\$Projectname Notification"] = ''; +App::$strings["\$projectname"] = ''; +App::$strings['Thank You,'] = ''; +App::$strings['%s Administrator'] = ''; +App::$strings["This email was sent by %1\$s at %2\$s."] = ''; +App::$strings["\$Projectname"] = ''; +App::$strings['To stop receiving these messages, please adjust your Notification Settings at %s'] = ''; +App::$strings['To stop receiving these messages, please adjust your %s.'] = ''; +App::$strings['Notification Settings'] = ''; +App::$strings['%s '] = ''; +App::$strings["[\$Projectname:Notify] New mail received at %s"] = ''; +App::$strings["%1\$s sent you a new private message at %2\$s."] = ''; +App::$strings["%1\$s sent you %2\$s."] = ''; +App::$strings['a private message'] = ''; +App::$strings['Please visit %s to view and/or reply to your private messages.'] = ''; +App::$strings['commented on'] = ''; +App::$strings['liked'] = ''; +App::$strings['disliked'] = ''; +App::$strings["%1\$s %2\$s [zrl=%3\$s]a %4\$s[/zrl]"] = ''; +App::$strings["%1\$s %2\$s [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = ''; +App::$strings["%1\$s %2\$s [zrl=%3\$s]your %4\$s[/zrl]"] = ''; +App::$strings["[\$Projectname:Notify] Moderated Comment to conversation #%1\$d by %2\$s"] = ''; +App::$strings["[\$Projectname:Notify] Comment to conversation #%1\$d by %2\$s"] = ''; +App::$strings["%1\$s commented on an item/conversation you have been following."] = ''; +App::$strings['(Moderated)'] = ''; +App::$strings['Please visit %s to view and/or reply to the conversation.'] = ''; +App::$strings['Please visit %s to approve or reject this comment.'] = ''; +App::$strings["%1\$s liked [zrl=%2\$s]your %3\$s[/zrl]"] = ''; +App::$strings["[\$Projectname:Notify] Like received to conversation #%1\$d by %2\$s"] = ''; +App::$strings["%1\$s liked an item/conversation you created."] = ''; +App::$strings["[\$Projectname:Notify] %s posted to your profile wall"] = ''; +App::$strings["%1\$s posted to your profile wall at %2\$s"] = ''; +App::$strings["%1\$s posted to [zrl=%2\$s]your wall[/zrl]"] = ''; +App::$strings[' - '] = ''; +App::$strings['Moderated'] = ''; +App::$strings['Please visit %s to approve or reject this post.'] = ''; +App::$strings["[\$Projectname:Notify] %s tagged you"] = ''; +App::$strings["%1\$s tagged you at %2\$s"] = ''; +App::$strings["%1\$s [zrl=%2\$s]tagged you[/zrl]."] = ''; +App::$strings["[\$Projectname:Notify] %1\$s poked you"] = ''; +App::$strings["%1\$s poked you at %2\$s"] = ''; +App::$strings["%1\$s [zrl=%2\$s]poked you[/zrl]."] = ''; +App::$strings["[\$Projectname:Notify] %s tagged your post"] = ''; +App::$strings["%1\$s tagged your post at %2\$s"] = ''; +App::$strings["%1\$s tagged [zrl=%2\$s]your post[/zrl]"] = ''; +App::$strings["[\$Projectname:Notify] Introduction received"] = ''; +App::$strings["You've received an new connection request from '%1\$s' at %2\$s"] = ''; +App::$strings["You've received [zrl=%1\$s]a new connection request[/zrl] from %2\$s."] = ''; +App::$strings['You may visit their profile at %s'] = ''; +App::$strings['Please visit %s to approve or reject the connection request.'] = ''; +App::$strings["[\$Projectname:Notify] Friend suggestion received"] = ''; +App::$strings["You've received a friend suggestion from '%1\$s' at %2\$s"] = ''; +App::$strings["You've received [zrl=%1\$s]a friend suggestion[/zrl] for %2\$s from %3\$s."] = ''; +App::$strings['Name:'] = ''; +App::$strings['Photo:'] = ''; +App::$strings['Please visit %s to approve or reject the suggestion.'] = ''; +App::$strings["[\$Projectname:Notify]"] = ''; +App::$strings['created a new post'] = ''; +App::$strings["reacted to %s's conversation"] = ''; +App::$strings["shared %s's post"] = ''; +App::$strings['edited a post dated %s'] = ''; +App::$strings['edited a comment dated %s'] = ''; +App::$strings['Unable to verify site signature for %s'] = ''; +App::$strings['Requested channel is not available.'] = ''; +App::$strings['Requested profile is not available.'] = ''; +App::$strings['Change profile photo'] = ''; +App::$strings['Edit Profiles'] = ''; +App::$strings['Create New Profile'] = ''; +App::$strings['Edit Profile'] = ''; +App::$strings['Profile Image'] = ''; +App::$strings['Visible to everybody'] = ''; +App::$strings['Edit visibility'] = ''; +App::$strings['Connect'] = ''; +App::$strings['Location:'] = ''; +App::$strings['Gender:'] = ''; +App::$strings['Status:'] = ''; +App::$strings['Homepage:'] = ''; +App::$strings['Change your profile photo'] = ''; +App::$strings['Female'] = ''; +App::$strings['Male'] = ''; +App::$strings['Trans'] = ''; +App::$strings['Inter'] = ''; +App::$strings['Neuter'] = ''; +App::$strings['Non-specific'] = ''; +App::$strings['Full Name:'] = ''; +App::$strings['Like this channel'] = ''; +App::$strings['j F, Y'] = ''; +App::$strings['j F'] = ''; +App::$strings['Birthday:'] = ''; +App::$strings['Age:'] = ''; +App::$strings["for %1\$d %2\$s"] = ''; +App::$strings['Tags:'] = ''; +App::$strings['Sexual Preference:'] = ''; +App::$strings['Hometown:'] = ''; +App::$strings['Political Views:'] = ''; +App::$strings['Religion:'] = ''; +App::$strings['About:'] = ''; +App::$strings['Hobbies/Interests:'] = ''; +App::$strings['Likes:'] = ''; +App::$strings['Dislikes:'] = ''; +App::$strings['Contact information and Social Networks:'] = ''; +App::$strings['My other channels:'] = ''; +App::$strings['Musical interests:'] = ''; +App::$strings['Books, literature:'] = ''; +App::$strings['Television:'] = ''; +App::$strings['Film/dance/culture/entertainment:'] = ''; +App::$strings['Love/Romance:'] = ''; +App::$strings['Work/employment:'] = ''; +App::$strings['School/education:'] = ''; +App::$strings['Like this thing'] = ''; +App::$strings['Export'] = ''; +App::$strings['Unable to verify channel signature'] = ''; +App::$strings['default'] = ''; +App::$strings['Select an alternate language'] = ''; +App::$strings['Directory Options'] = ''; +App::$strings['Safe Mode'] = ''; +App::$strings['No'] = ''; +App::$strings['Yes'] = ''; +App::$strings['Public Groups Only'] = ''; +App::$strings['Collections Only'] = ''; +App::$strings['This Website Only'] = ''; +App::$strings['Remote privacy information not available.'] = ''; +App::$strings['Visible to:'] = ''; +App::$strings['__ctx:acl__ Profile'] = ''; +App::$strings['Event can not end before it has started.'] = ''; +App::$strings['Unable to generate preview.'] = ''; +App::$strings['Event title and start time are required.'] = ''; +App::$strings['Event not found.'] = ''; +App::$strings['event'] = ''; +App::$strings['Edit event'] = ''; +App::$strings['Delete event'] = ''; +App::$strings['Link to source'] = ''; +App::$strings['calendar'] = ''; +App::$strings['Failed to remove event'] = ''; +App::$strings['sent you a private message'] = ''; +App::$strings['added your channel'] = ''; +App::$strings['requires approval'] = ''; +App::$strings['g A l F d'] = ''; +App::$strings['[today]'] = ''; +App::$strings['posted an event'] = ''; +App::$strings['shared a file with you'] = ''; +App::$strings['reported content'] = ''; +App::$strings['Private group'] = ''; +App::$strings['Public group'] = ''; +App::$strings['Off'] = ''; +App::$strings['On'] = ''; +App::$strings['Lock feature %s'] = ''; +App::$strings['Manage Additional Features'] = ''; +App::$strings['Log settings updated.'] = ''; +App::$strings['Administration'] = ''; +App::$strings['Logs'] = ''; +App::$strings['Clear'] = ''; +App::$strings['Debugging'] = ''; +App::$strings['Log file'] = ''; +App::$strings['Must be writable by web server. Relative to your top-level webserver directory.'] = ''; +App::$strings['Log level'] = ''; +App::$strings['New Profile Field'] = ''; +App::$strings['Field nickname'] = ''; +App::$strings['System name of field'] = ''; +App::$strings['Input type'] = ''; +App::$strings['Field Name'] = ''; +App::$strings['Label on profile pages'] = ''; +App::$strings['Help text'] = ''; +App::$strings['Additional info (optional)'] = ''; +App::$strings['Field definition not found'] = ''; +App::$strings['Edit Profile Field'] = ''; +App::$strings['Profile Fields'] = ''; +App::$strings['Basic Profile Fields'] = ''; +App::$strings['Advanced Profile Fields'] = ''; +App::$strings['(In addition to basic fields)'] = ''; +App::$strings['All available fields'] = ''; +App::$strings['Custom Fields'] = ''; +App::$strings['Create Custom Field'] = ''; +App::$strings['Queue Statistics'] = ''; +App::$strings['Total Entries'] = ''; +App::$strings['Priority'] = ''; +App::$strings['Destination URL'] = ''; +App::$strings['Mark hub permanently offline'] = ''; +App::$strings['Empty queue for this hub'] = ''; +App::$strings['Last known contact'] = ''; +App::$strings['Theme settings updated.'] = ''; +App::$strings['No themes found.'] = ''; +App::$strings['Item not found.'] = ''; +App::$strings['Disable'] = ''; +App::$strings['Enable'] = ''; +App::$strings['Screenshot'] = ''; +App::$strings['Themes'] = ''; +App::$strings['Toggle'] = ''; +App::$strings['Author: '] = ''; +App::$strings['Maintainer: '] = ''; +App::$strings['[Experimental]'] = ''; +App::$strings['[Unsupported]'] = ''; +App::$strings['Update has been marked successful'] = ''; +App::$strings['Verification of update %s failed. Check system logs.'] = ''; +App::$strings['Update %s was successfully applied.'] = ''; +App::$strings['Verifying update %s did not return a status. Unknown if it succeeded.'] = ''; +App::$strings['Update %s does not contain a verification function.'] = ''; +App::$strings['Update function %s could not be found.'] = ''; +App::$strings['Executing update procedure %s failed. Check system logs.'] = ''; +App::$strings['Update %s did not return a status. It cannot be determined if it was successful.'] = ''; +App::$strings['Failed Updates'] = ''; +App::$strings['Mark success (if update was manually applied)'] = ''; +App::$strings['Attempt to verify this update if a verification procedure exists'] = ''; +App::$strings['Attempt to execute this update step automatically'] = ''; +App::$strings['No failed updates.'] = ''; +App::$strings['Password changed for account %d.'] = ''; +App::$strings['Account settings updated.'] = ''; +App::$strings['Account not found.'] = ''; +App::$strings['Account Edit'] = ''; +App::$strings['New Password'] = ''; +App::$strings['New Password again'] = ''; +App::$strings['Account language (for emails)'] = ''; +App::$strings['Service class'] = ''; +App::$strings['%s account blocked/unblocked'] = [ + 0 => '', + 1 => '', ]; -App::$strings["%s account deleted"] = [ - 0 => "", - 1 => "", +App::$strings['%s account deleted'] = [ + 0 => '', + 1 => '', ]; -App::$strings["Account not found"] = ""; -App::$strings["Account '%s' deleted"] = ""; -App::$strings["Account '%s' blocked"] = ""; -App::$strings["Account '%s' unblocked"] = ""; -App::$strings["Accounts"] = ""; -App::$strings["select all"] = ""; -App::$strings["Registrations waiting for confirm"] = ""; -App::$strings["Request date"] = ""; -App::$strings["Email"] = ""; -App::$strings["No registrations."] = ""; -App::$strings["Approve"] = ""; -App::$strings["Deny"] = ""; -App::$strings["Block"] = ""; -App::$strings["Unblock"] = ""; -App::$strings["ID"] = ""; -App::$strings["All Channels"] = ""; -App::$strings["Register date"] = ""; -App::$strings["Last login"] = ""; -App::$strings["Expires"] = ""; -App::$strings["Service Class"] = ""; -App::$strings["Selected accounts will be deleted!\\n\\nEverything these accounts had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; -App::$strings["The account {0} will be deleted!\\n\\nEverything this account has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; -App::$strings["Plugin %s disabled."] = ""; -App::$strings["Plugin %s enabled."] = ""; -App::$strings["Addons"] = ""; -App::$strings["Minimum project version: "] = ""; -App::$strings["Maximum project version: "] = ""; -App::$strings["Minimum PHP version: "] = ""; -App::$strings["Compatible Server Roles: "] = ""; -App::$strings["Requires: "] = ""; -App::$strings["Disabled - version incompatibility"] = ""; -App::$strings["Enter the public git repository URL of the addon repo."] = ""; -App::$strings["Addon repo git URL"] = ""; -App::$strings["Custom repo name"] = ""; -App::$strings["(optional)"] = ""; -App::$strings["Download Addon Repo"] = ""; -App::$strings["Install new repo"] = ""; -App::$strings["Cancel"] = ""; -App::$strings["Manage Repos"] = ""; -App::$strings["Installed Addon Repositories"] = ""; -App::$strings["Install a New Addon Repository"] = ""; -App::$strings["Switch branch"] = ""; -App::$strings["Remove"] = ""; -App::$strings["Site settings updated."] = ""; -App::$strings["Default"] = ""; -App::$strings["%s - (Incompatible)"] = ""; -App::$strings["mobile"] = ""; -App::$strings["experimental"] = ""; -App::$strings["unsupported"] = ""; -App::$strings["Yes - with approval"] = ""; -App::$strings["My site is not a public server"] = ""; -App::$strings["My site provides free public access"] = ""; -App::$strings["My site provides paid public access"] = ""; -App::$strings["My site provides free public access and premium paid plans"] = ""; -App::$strings["Default permission role for new accounts"] = ""; -App::$strings["This role will be used for the first channel created after registration."] = ""; -App::$strings["Site"] = ""; -App::$strings["Site Configuration"] = ""; -App::$strings["Registration"] = ""; -App::$strings["File upload"] = ""; -App::$strings["Policies"] = ""; -App::$strings["Advanced"] = ""; -App::$strings["Site name"] = ""; -App::$strings["Banner/Logo"] = ""; -App::$strings["Unfiltered HTML/CSS/JS is allowed"] = ""; -App::$strings["Administrator Information"] = ""; -App::$strings["Contact information for site administrators. Displayed on siteinfo page. BBCode may be used here."] = ""; -App::$strings["Site Information"] = ""; -App::$strings["Publicly visible description of this site. Displayed on siteinfo page. BBCode may be used here."] = ""; -App::$strings["System language"] = ""; -App::$strings["System theme"] = ""; -App::$strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = ""; -App::$strings["Allow ActivityPub Connections"] = ""; -App::$strings["Provides access to software supporting the ActivityPub protocol."] = ""; -App::$strings["Maximum image size"] = ""; -App::$strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = ""; -App::$strings["Cache all public images"] = ""; -App::$strings["By default proxy non-SSL images, but do not cache"] = ""; -App::$strings["Does this site allow new member registration?"] = ""; -App::$strings["Invitation only"] = ""; -App::$strings["Only allow new member registrations with an invitation code. New member registration must be allowed for this to work."] = ""; -App::$strings["Minimum age"] = ""; -App::$strings["Minimum age (in years) for who may register on this site."] = ""; -App::$strings["Which best describes the types of account offered by this hub?"] = ""; -App::$strings["If a public server policy is selected, this information may be displayed on the public server site list."] = ""; -App::$strings["Register text"] = ""; -App::$strings["Will be displayed prominently on the registration page."] = ""; -App::$strings["Site homepage to show visitors (default: login box)"] = ""; -App::$strings["example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file."] = ""; -App::$strings["Preserve site homepage URL"] = ""; -App::$strings["Present the site homepage in a frame at the original location instead of redirecting"] = ""; -App::$strings["Accounts abandoned after x days"] = ""; -App::$strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = ""; -App::$strings["Verify Email Addresses"] = ""; -App::$strings["Check to verify email addresses used in account registration (recommended)."] = ""; -App::$strings["Force publish"] = ""; -App::$strings["Check to force all profiles on this site to be listed in the site directory."] = ""; -App::$strings["Import Public Streams"] = ""; -App::$strings["Import and allow access to public content pulled from other sites. Warning: this content is unmoderated."] = ""; -App::$strings["Site only Public Streams"] = ""; -App::$strings["Allow access to public content originating only from this site if Imported Public Streams are disabled."] = ""; -App::$strings["Allow anybody on the internet to access the Public streams"] = ""; -App::$strings["Default is to only allow viewing by site members. Warning: this content is unmoderated."] = ""; -App::$strings["Show numbers of likes and dislikes in conversations"] = ""; -App::$strings["If disabled, the presence of likes and dislikes will be shown, but without totals."] = ""; -App::$strings["Only import Public stream posts with this text"] = ""; -App::$strings["words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts"] = ""; -App::$strings["Do not import Public stream posts with this text"] = ""; -App::$strings["Login on Homepage"] = ""; -App::$strings["Present a login box to visitors on the home page if no other content has been configured."] = ""; -App::$strings["Enable context help"] = ""; -App::$strings["Display contextual help for the current page when the help button is pressed."] = ""; -App::$strings["Reply-to email address for system generated email."] = ""; -App::$strings["Sender (From) email address for system generated email."] = ""; -App::$strings["Name of email sender for system generated email."] = ""; -App::$strings["Directory Server URL"] = ""; -App::$strings["Default directory server"] = ""; -App::$strings["Proxy user"] = ""; -App::$strings["Proxy URL"] = ""; -App::$strings["Network timeout"] = ""; -App::$strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = ""; -App::$strings["Delivery interval"] = ""; -App::$strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = ""; -App::$strings["Deliveries per process"] = ""; -App::$strings["Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5."] = ""; -App::$strings["Queue Threshold"] = ""; -App::$strings["Always defer immediate delivery if queue contains more than this number of entries."] = ""; -App::$strings["Poll interval"] = ""; -App::$strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = ""; -App::$strings["Path to ImageMagick convert program"] = ""; -App::$strings["If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert"] = ""; -App::$strings["Maximum Load Average"] = ""; -App::$strings["Maximum system load before delivery and poll processes are deferred - default 50."] = ""; -App::$strings["Expiration period in days for imported streams and cached images"] = ""; -App::$strings["0 for no expiration of imported content"] = ""; -App::$strings["Do not expire any posts which have comments less than this many days ago"] = ""; -App::$strings["Public servers: Optional landing (marketing) webpage for new registrants"] = ""; -App::$strings["Create this page first. Default is %s/register"] = ""; -App::$strings["Page to display after creating a new channel"] = ""; -App::$strings["Default: profiles"] = ""; -App::$strings["Optional: site location"] = ""; -App::$strings["Region or country"] = ""; -App::$strings["%s channel censored/uncensored"] = [ - 0 => "", - 1 => "", +App::$strings['Account not found'] = ''; +App::$strings["Account '%s' deleted"] = ''; +App::$strings["Account '%s' blocked"] = ''; +App::$strings["Account '%s' unblocked"] = ''; +App::$strings['Accounts'] = ''; +App::$strings['select all'] = ''; +App::$strings['Registrations waiting for confirm'] = ''; +App::$strings['Request date'] = ''; +App::$strings['Email'] = ''; +App::$strings['No registrations.'] = ''; +App::$strings['Approve'] = ''; +App::$strings['Deny'] = ''; +App::$strings['Block'] = ''; +App::$strings['Unblock'] = ''; +App::$strings['ID'] = ''; +App::$strings['All Channels'] = ''; +App::$strings['Register date'] = ''; +App::$strings['Last login'] = ''; +App::$strings['Expires'] = ''; +App::$strings['Service Class'] = ''; +App::$strings["Selected accounts will be deleted!\\n\\nEverything these accounts had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = ''; +App::$strings["The account {0} will be deleted!\\n\\nEverything this account has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = ''; +App::$strings['Plugin %s disabled.'] = ''; +App::$strings['Plugin %s enabled.'] = ''; +App::$strings['Addons'] = ''; +App::$strings['Minimum project version: '] = ''; +App::$strings['Maximum project version: '] = ''; +App::$strings['Minimum PHP version: '] = ''; +App::$strings['Compatible Server Roles: '] = ''; +App::$strings['Requires: '] = ''; +App::$strings['Disabled - version incompatibility'] = ''; +App::$strings['Enter the public git repository URL of the addon repo.'] = ''; +App::$strings['Addon repo git URL'] = ''; +App::$strings['Custom repo name'] = ''; +App::$strings['(optional)'] = ''; +App::$strings['Download Addon Repo'] = ''; +App::$strings['Install new repo'] = ''; +App::$strings['Cancel'] = ''; +App::$strings['Manage Repos'] = ''; +App::$strings['Installed Addon Repositories'] = ''; +App::$strings['Install a New Addon Repository'] = ''; +App::$strings['Switch branch'] = ''; +App::$strings['Remove'] = ''; +App::$strings['Site settings updated.'] = ''; +App::$strings['Default'] = ''; +App::$strings['%s - (Incompatible)'] = ''; +App::$strings['mobile'] = ''; +App::$strings['experimental'] = ''; +App::$strings['unsupported'] = ''; +App::$strings['Yes - with approval'] = ''; +App::$strings['My site is not a public server'] = ''; +App::$strings['My site provides free public access'] = ''; +App::$strings['My site provides paid public access'] = ''; +App::$strings['My site provides free public access and premium paid plans'] = ''; +App::$strings['Default permission role for new accounts'] = ''; +App::$strings['This role will be used for the first channel created after registration.'] = ''; +App::$strings['Site'] = ''; +App::$strings['Site Configuration'] = ''; +App::$strings['Registration'] = ''; +App::$strings['File upload'] = ''; +App::$strings['Policies'] = ''; +App::$strings['Advanced'] = ''; +App::$strings['Site name'] = ''; +App::$strings['Banner/Logo'] = ''; +App::$strings['Unfiltered HTML/CSS/JS is allowed'] = ''; +App::$strings['Administrator Information'] = ''; +App::$strings['Contact information for site administrators. Displayed on siteinfo page. BBCode may be used here.'] = ''; +App::$strings['Site Information'] = ''; +App::$strings['Publicly visible description of this site. Displayed on siteinfo page. BBCode may be used here.'] = ''; +App::$strings['System language'] = ''; +App::$strings['System theme'] = ''; +App::$strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = ''; +App::$strings['Allow ActivityPub Connections'] = ''; +App::$strings['Provides access to software supporting the ActivityPub protocol.'] = ''; +App::$strings['Maximum image size'] = ''; +App::$strings['Maximum size in bytes of uploaded images. Default is 0, which means no limits.'] = ''; +App::$strings['Cache all public images'] = ''; +App::$strings['By default proxy non-SSL images, but do not cache'] = ''; +App::$strings['Does this site allow new member registration?'] = ''; +App::$strings['Invitation only'] = ''; +App::$strings['Only allow new member registrations with an invitation code. New member registration must be allowed for this to work.'] = ''; +App::$strings['Minimum age'] = ''; +App::$strings['Minimum age (in years) for who may register on this site.'] = ''; +App::$strings['Which best describes the types of account offered by this hub?'] = ''; +App::$strings['If a public server policy is selected, this information may be displayed on the public server site list.'] = ''; +App::$strings['Register text'] = ''; +App::$strings['Will be displayed prominently on the registration page.'] = ''; +App::$strings['Site homepage to show visitors (default: login box)'] = ''; +App::$strings["example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file."] = ''; +App::$strings['Preserve site homepage URL'] = ''; +App::$strings['Present the site homepage in a frame at the original location instead of redirecting'] = ''; +App::$strings['Accounts abandoned after x days'] = ''; +App::$strings['Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.'] = ''; +App::$strings['Verify Email Addresses'] = ''; +App::$strings['Check to verify email addresses used in account registration (recommended).'] = ''; +App::$strings['Force publish'] = ''; +App::$strings['Check to force all profiles on this site to be listed in the site directory.'] = ''; +App::$strings['Import Public Streams'] = ''; +App::$strings['Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.'] = ''; +App::$strings['Site only Public Streams'] = ''; +App::$strings['Allow access to public content originating only from this site if Imported Public Streams are disabled.'] = ''; +App::$strings['Allow anybody on the internet to access the Public streams'] = ''; +App::$strings['Default is to only allow viewing by site members. Warning: this content is unmoderated.'] = ''; +App::$strings['Show numbers of likes and dislikes in conversations'] = ''; +App::$strings['If disabled, the presence of likes and dislikes will be shown, but without totals.'] = ''; +App::$strings['Only import Public stream posts with this text'] = ''; +App::$strings['words one per line or #tags or /patterns/ or lang=xx, leave blank to import all posts'] = ''; +App::$strings['Do not import Public stream posts with this text'] = ''; +App::$strings['Login on Homepage'] = ''; +App::$strings['Present a login box to visitors on the home page if no other content has been configured.'] = ''; +App::$strings['Enable context help'] = ''; +App::$strings['Display contextual help for the current page when the help button is pressed.'] = ''; +App::$strings['Reply-to email address for system generated email.'] = ''; +App::$strings['Sender (From) email address for system generated email.'] = ''; +App::$strings['Name of email sender for system generated email.'] = ''; +App::$strings['Directory Server URL'] = ''; +App::$strings['Default directory server'] = ''; +App::$strings['Proxy user'] = ''; +App::$strings['Proxy URL'] = ''; +App::$strings['Network timeout'] = ''; +App::$strings['Value is in seconds. Set to 0 for unlimited (not recommended).'] = ''; +App::$strings['Delivery interval'] = ''; +App::$strings['Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.'] = ''; +App::$strings['Deliveries per process'] = ''; +App::$strings['Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.'] = ''; +App::$strings['Queue Threshold'] = ''; +App::$strings['Always defer immediate delivery if queue contains more than this number of entries.'] = ''; +App::$strings['Poll interval'] = ''; +App::$strings['Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.'] = ''; +App::$strings['Path to ImageMagick convert program'] = ''; +App::$strings['If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert'] = ''; +App::$strings['Maximum Load Average'] = ''; +App::$strings['Maximum system load before delivery and poll processes are deferred - default 50.'] = ''; +App::$strings['Expiration period in days for imported streams and cached images'] = ''; +App::$strings['0 for no expiration of imported content'] = ''; +App::$strings['Do not expire any posts which have comments less than this many days ago'] = ''; +App::$strings['Public servers: Optional landing (marketing) webpage for new registrants'] = ''; +App::$strings['Create this page first. Default is %s/register'] = ''; +App::$strings['Page to display after creating a new channel'] = ''; +App::$strings['Default: profiles'] = ''; +App::$strings['Optional: site location'] = ''; +App::$strings['Region or country'] = ''; +App::$strings['%s channel censored/uncensored'] = [ + 0 => '', + 1 => '', ]; -App::$strings["%s channel code allowed/disallowed"] = [ - 0 => "", - 1 => "", +App::$strings['%s channel code allowed/disallowed'] = [ + 0 => '', + 1 => '', ]; -App::$strings["%s channel deleted"] = [ - 0 => "", - 1 => "", +App::$strings['%s channel deleted'] = [ + 0 => '', + 1 => '', ]; -App::$strings["Channel not found"] = ""; -App::$strings["Channel '%s' deleted"] = ""; -App::$strings["Channel '%s' censored"] = ""; -App::$strings["Channel '%s' uncensored"] = ""; -App::$strings["Channel '%s' code allowed"] = ""; -App::$strings["Channel '%s' code disallowed"] = ""; -App::$strings["Channels"] = ""; -App::$strings["Censor"] = ""; -App::$strings["Uncensor"] = ""; -App::$strings["Allow Code"] = ""; -App::$strings["Disallow Code"] = ""; -App::$strings["Channel"] = ""; -App::$strings["UID"] = ""; -App::$strings["Name"] = ""; -App::$strings["Address"] = ""; -App::$strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; -App::$strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; -App::$strings["By default, unfiltered HTML is allowed in embedded media. This is inherently insecure."] = ""; -App::$strings["The recommended setting is to only allow unfiltered HTML from the following sites:"] = ""; -App::$strings["https://youtube.com/
      https://www.youtube.com/
      https://youtu.be/
      https://vimeo.com/
      https://soundcloud.com/
      "] = ""; -App::$strings["All other embedded content will be filtered, unless embedded content from that site is explicitly blocked."] = ""; -App::$strings["Security"] = ""; -App::$strings["Block public"] = ""; -App::$strings["Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated."] = ""; -App::$strings["Block public search"] = ""; -App::$strings["Prevent access to search content unless you are currently authenticated."] = ""; -App::$strings["Hide local directory"] = ""; -App::$strings["Only use the global directory"] = ""; -App::$strings["Provide a cloud root directory"] = ""; -App::$strings["The cloud root directory lists all channel names which provide public files"] = ""; -App::$strings["Show total disk space available to cloud uploads"] = ""; -App::$strings["Allow SVG thumbnails in file browser"] = ""; -App::$strings["WARNING: SVG images may contain malicious code."] = ""; -App::$strings["Allow embedded (inline) PDF files"] = ""; -App::$strings["Set \"Transport Security\" HTTP header"] = ""; -App::$strings["Set \"Content Security Policy\" HTTP header"] = ""; -App::$strings["Allowed email domains"] = ""; -App::$strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = ""; -App::$strings["Not allowed email domains"] = ""; -App::$strings["Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined."] = ""; -App::$strings["Allow communications only from these sites"] = ""; -App::$strings["One site per line. Leave empty to allow communication from anywhere by default"] = ""; -App::$strings["Block communications from these sites"] = ""; -App::$strings["Allow communications only from these channels"] = ""; -App::$strings["One channel (hash) per line. Leave empty to allow from any channel by default"] = ""; -App::$strings["Block communications from these channels"] = ""; -App::$strings["Allow public stream communications only from these sites"] = ""; -App::$strings["Block public stream communications from these sites"] = ""; -App::$strings["Allow public stream communications only from these channels"] = ""; -App::$strings["Block public stream communications from these channels"] = ""; -App::$strings["Only allow embeds from secure (SSL) websites and links."] = ""; -App::$strings["Allow unfiltered embedded HTML content only from these domains"] = ""; -App::$strings["One site per line. By default embedded content is filtered."] = ""; -App::$strings["Block embedded HTML from these domains"] = ""; -App::$strings["You must be logged in to see this page."] = ""; -App::$strings["Posts and comments"] = ""; -App::$strings["Only posts"] = ""; -App::$strings["This is the home page of %s."] = ""; -App::$strings["Insufficient permissions. Request redirected to profile page."] = ""; -App::$strings["Search Results For:"] = ""; -App::$strings["Reset form"] = ""; -App::$strings["You must enable javascript for your browser to be able to view this content."] = ""; -App::$strings["Authorize application connection"] = ""; -App::$strings["Return to your app and insert this Security Code:"] = ""; -App::$strings["Please login to continue."] = ""; -App::$strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = ""; -App::$strings["Change Order of Pinned Navbar Apps"] = ""; -App::$strings["Change Order of App Tray Apps"] = ""; -App::$strings["Use arrows to move the corresponding app left (top) or right (bottom) in the navbar"] = ""; -App::$strings["Use arrows to move the corresponding app up or down in the app tray"] = ""; -App::$strings["Available Apps"] = ""; -App::$strings["Installed Apps"] = ""; -App::$strings["Manage apps"] = ""; -App::$strings["Create Custom App"] = ""; -App::$strings["No channel."] = ""; -App::$strings["No connections in common."] = ""; -App::$strings["View Common Connections"] = ""; -App::$strings["Item not available."] = ""; -App::$strings["Unknown App"] = ""; -App::$strings["Authorize"] = ""; -App::$strings["Do you authorize the app %s to access your channel data?"] = ""; -App::$strings["Allow"] = ""; -App::$strings["Channel not found."] = ""; -App::$strings["Permissions denied."] = ""; -App::$strings["l, F j"] = ""; -App::$strings["Link to Source"] = ""; -App::$strings["Edit Event"] = ""; -App::$strings["Create Event"] = ""; -App::$strings["Previous"] = ""; -App::$strings["Next"] = ""; -App::$strings["Import"] = ""; -App::$strings["Today"] = ""; -App::$strings["Expiration settings updated."] = ""; -App::$strings["This app allows you to set an optional expiration date/time for posts, after which they will be deleted. This must be at least fifteen minutes into the future. You may also choose to automatically delete all your posts after a set number of days"] = ""; -App::$strings["Expire and delete all my posts after this many days"] = ""; -App::$strings["Leave at 0 if you wish to manually control expiration of specific posts."] = ""; -App::$strings["Automatic Expiration Settings"] = ""; -App::$strings["Blocked accounts"] = ""; -App::$strings["Expired accounts"] = ""; -App::$strings["Expiring accounts"] = ""; -App::$strings["Primary"] = ""; -App::$strings["Clones"] = ""; -App::$strings["Message queues"] = ""; -App::$strings["Your software should be updated"] = ""; -App::$strings["Summary"] = ""; -App::$strings["Registered accounts"] = ""; -App::$strings["Pending registrations"] = ""; -App::$strings["Registered channels"] = ""; -App::$strings["Active addons"] = ""; -App::$strings["Version"] = ""; -App::$strings["Repository version (release)"] = ""; -App::$strings["Repository version (dev)"] = ""; -App::$strings["Invalid item."] = ""; -App::$strings["Page not found."] = ""; -App::$strings["Create personal planning cards"] = ""; -App::$strings["Add Card"] = ""; -App::$strings["Create"] = ""; -App::$strings["Block Name"] = ""; -App::$strings["Blocks"] = ""; -App::$strings["Block Title"] = ""; -App::$strings["Created"] = ""; -App::$strings["Edited"] = ""; -App::$strings["Share"] = ""; -App::$strings["View"] = ""; -App::$strings["Calendar entries imported."] = ""; -App::$strings["No calendar entries found."] = ""; -App::$strings["INVALID EVENT DISMISSED!"] = ""; -App::$strings["Summary: "] = ""; -App::$strings["Date: "] = ""; -App::$strings["Reason: "] = ""; -App::$strings["INVALID CARD DISMISSED!"] = ""; -App::$strings["Name: "] = ""; -App::$strings["CardDAV App"] = ""; -App::$strings["Not Installed"] = ""; -App::$strings["CalDAV capable addressbook"] = ""; -App::$strings["Event title"] = ""; -App::$strings["Start date and time"] = ""; -App::$strings["End date and time"] = ""; -App::$strings["Description"] = ""; -App::$strings["Location"] = ""; -App::$strings["Month"] = ""; -App::$strings["Week"] = ""; -App::$strings["Day"] = ""; -App::$strings["List month"] = ""; -App::$strings["List week"] = ""; -App::$strings["List day"] = ""; -App::$strings["More"] = ""; -App::$strings["Less"] = ""; -App::$strings["Select calendar"] = ""; -App::$strings["Channel Calendars"] = ""; -App::$strings["CalDAV Calendars"] = ""; -App::$strings["Delete all"] = ""; -App::$strings["Sorry! Editing of recurrent events is not yet implemented."] = ""; -App::$strings["Organisation"] = ""; -App::$strings["Title"] = ""; -App::$strings["Phone"] = ""; -App::$strings["Instant messenger"] = ""; -App::$strings["Website"] = ""; -App::$strings["Note"] = ""; -App::$strings["Mobile"] = ""; -App::$strings["Home"] = ""; -App::$strings["Work"] = ""; -App::$strings["Other"] = ""; -App::$strings["Add Contact"] = ""; -App::$strings["Add Field"] = ""; -App::$strings["P.O. Box"] = ""; -App::$strings["Additional"] = ""; -App::$strings["Street"] = ""; -App::$strings["Locality"] = ""; -App::$strings["Region"] = ""; -App::$strings["ZIP Code"] = ""; -App::$strings["Country"] = ""; -App::$strings["Default Calendar"] = ""; -App::$strings["Default Addressbook"] = ""; -App::$strings["Channel name changes are not allowed within 48 hours of changing the account password."] = ""; -App::$strings["Reserved nickname. Please choose another."] = ""; -App::$strings["Nickname has unsupported characters or is already being used on this site."] = ""; -App::$strings["Feature has been disabled"] = ""; -App::$strings["Change channel nickname/address"] = ""; -App::$strings["WARNING: "] = ""; -App::$strings["Any/all connections on other networks will be lost!"] = ""; -App::$strings["Please enter your password for verification:"] = ""; -App::$strings["New channel address"] = ""; -App::$strings["Rename Channel"] = ""; -App::$strings["toggle full screen mode"] = ""; -App::$strings["Documentation Search"] = ""; -App::$strings["\$Projectname Documentation"] = ""; -App::$strings["Contents"] = ""; -App::$strings["Away"] = ""; -App::$strings["Online"] = ""; -App::$strings["Could not access contact record."] = ""; -App::$strings["Could not locate selected profile."] = ""; -App::$strings["Connection updated."] = ""; -App::$strings["Failed to update connection record."] = ""; -App::$strings["is now connected to"] = ""; -App::$strings["Could not access address book record."] = ""; -App::$strings["Refresh failed - channel is currently unavailable."] = ""; -App::$strings["Added by Connedit"] = ""; -App::$strings["Unable to set address book parameters."] = ""; -App::$strings["Connection has been removed."] = ""; -App::$strings["View %s's profile"] = ""; -App::$strings["Refresh Permissions"] = ""; -App::$strings["Fetch updated permissions"] = ""; -App::$strings["Refresh Photo"] = ""; -App::$strings["Fetch updated photo"] = ""; -App::$strings["Recent Activity"] = ""; -App::$strings["View recent posts and comments"] = ""; -App::$strings["Block (or Unblock) all communications with this connection"] = ""; -App::$strings["This connection is blocked!"] = ""; -App::$strings["Unignore"] = ""; -App::$strings["Ignore"] = ""; -App::$strings["Ignore (or Unignore) all inbound communications from this connection"] = ""; -App::$strings["This connection is ignored!"] = ""; -App::$strings["Censor (or Uncensor) images from this connection"] = ""; -App::$strings["This connection is censored!"] = ""; -App::$strings["Unarchive"] = ""; -App::$strings["Archive"] = ""; -App::$strings["Archive (or Unarchive) this connection - mark channel dead but keep content"] = ""; -App::$strings["This connection is archived!"] = ""; -App::$strings["Unhide"] = ""; -App::$strings["Hide"] = ""; -App::$strings["Hide or Unhide this connection from your other connections"] = ""; -App::$strings["This connection is hidden!"] = ""; -App::$strings["Delete this connection"] = ""; -App::$strings["Fetch Vcard"] = ""; -App::$strings["Fetch electronic calling card for this connection"] = ""; -App::$strings["Permissions"] = ""; -App::$strings["Open Individual Permissions section by default"] = ""; -App::$strings["Open Friend Zoom section by default"] = ""; -App::$strings["Me"] = ""; -App::$strings["Family"] = ""; -App::$strings["Friends"] = ""; -App::$strings["Peers"] = ""; -App::$strings["All"] = ""; -App::$strings["Filter"] = ""; -App::$strings["Open Custom Filter section by default"] = ""; -App::$strings["Approve this connection"] = ""; -App::$strings["Accept connection to allow communication"] = ""; -App::$strings["Set Friend Zoom"] = ""; -App::$strings["Set Profile"] = ""; -App::$strings["Set Friend Zoom & Profile"] = ""; -App::$strings["This connection is unreachable from this location."] = ""; -App::$strings["This connection may be unreachable from other channel locations."] = ""; -App::$strings["Location independence is not supported by their network."] = ""; -App::$strings["This connection is unreachable from this location. Location independence is not supported by their network."] = ""; -App::$strings["Connection Default Permissions"] = ""; -App::$strings["Connection: %s"] = ""; -App::$strings["Apply these permissions automatically"] = ""; -App::$strings["Connection requests will be approved without your interaction"] = ""; -App::$strings["Permission role"] = ""; -App::$strings["Loading"] = ""; -App::$strings["Add permission role"] = ""; -App::$strings["This connection's primary address is"] = ""; -App::$strings["Available locations:"] = ""; -App::$strings["The permissions indicated on this page will be applied to all new connections."] = ""; -App::$strings["Connection Tools"] = ""; -App::$strings["Slide to adjust your degree of friendship"] = ""; -App::$strings["Rating"] = ""; -App::$strings["Slide to adjust your rating"] = ""; -App::$strings["Optionally explain your rating"] = ""; -App::$strings["Custom Filter"] = ""; -App::$strings["Only import posts with this text"] = ""; -App::$strings["words one per line or #tags, \$categories, /patterns/, or lang=xx, leave blank to import all posts"] = ""; -App::$strings["Do not import posts with this text"] = ""; -App::$strings["Nickname"] = ""; -App::$strings["optional - allows you to search by a name that you have chosen"] = ""; -App::$strings["This information is public!"] = ""; -App::$strings["Connection Pending Approval"] = ""; -App::$strings["inherited"] = ""; -App::$strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = ""; -App::$strings["Their Settings"] = ""; -App::$strings["My Settings"] = ""; -App::$strings["Individual Permissions"] = ""; -App::$strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can not change those settings here."] = ""; -App::$strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes."] = ""; -App::$strings["Last update:"] = ""; -App::$strings["Details"] = ""; -App::$strings["Active"] = ""; -App::$strings["Blocked"] = ""; -App::$strings["Ignored"] = ""; -App::$strings["Hidden"] = ""; -App::$strings["Archived/Unreachable"] = ""; -App::$strings["New"] = ""; -App::$strings["Active Connections"] = ""; -App::$strings["Show active connections"] = ""; -App::$strings["New Connections"] = ""; -App::$strings["Show pending (new) connections"] = ""; -App::$strings["Only show blocked connections"] = ""; -App::$strings["Only show ignored connections"] = ""; -App::$strings["Only show archived/unreachable connections"] = ""; -App::$strings["Only show hidden connections"] = ""; -App::$strings["All Connections"] = ""; -App::$strings["Show all connections"] = ""; -App::$strings["Order by name"] = ""; -App::$strings["Recent"] = ""; -App::$strings["Order by recent"] = ""; -App::$strings["Order by date"] = ""; -App::$strings["Pending approval"] = ""; -App::$strings["Archived"] = ""; -App::$strings["Not connected at this location"] = ""; -App::$strings["%1\$s [%2\$s]"] = ""; -App::$strings["Edit connection"] = ""; -App::$strings["Delete connection"] = ""; -App::$strings["Channel address"] = ""; -App::$strings["Network"] = ""; -App::$strings["Call"] = ""; -App::$strings["Status"] = ""; -App::$strings["Connected"] = ""; -App::$strings["Approve connection"] = ""; -App::$strings["Ignore connection"] = ""; -App::$strings["Recent activity"] = ""; -App::$strings["Filter by"] = ""; -App::$strings["Sort by"] = ""; -App::$strings["Search your connections"] = ""; -App::$strings["Connections search"] = ""; -App::$strings["Find"] = ""; -App::$strings["network"] = ""; -App::$strings["App installed."] = ""; -App::$strings["Malformed app."] = ""; -App::$strings["Embed code"] = ""; -App::$strings["Edit App"] = ""; -App::$strings["Create App"] = ""; -App::$strings["Name of app"] = ""; -App::$strings["Required"] = ""; -App::$strings["Location (URL) of app"] = ""; -App::$strings["Photo icon URL"] = ""; -App::$strings["80 x 80 pixels - optional"] = ""; -App::$strings["Categories (optional, comma separated list)"] = ""; -App::$strings["Version ID"] = ""; -App::$strings["Price of app"] = ""; -App::$strings["Location (URL) to purchase app"] = ""; -App::$strings["Image uploaded but image cropping failed."] = ""; -App::$strings["Cover Photos"] = ""; -App::$strings["Image resize failed."] = ""; -App::$strings["Unable to process image"] = ""; -App::$strings["female"] = ""; -App::$strings["%1\$s updated her %2\$s"] = ""; -App::$strings["male"] = ""; -App::$strings["%1\$s updated his %2\$s"] = ""; -App::$strings["%1\$s updated their %2\$s"] = ""; -App::$strings["cover photo"] = ""; -App::$strings["Photo not available."] = ""; -App::$strings["Your cover photo may be visible to anybody on the internet"] = ""; -App::$strings["Upload File:"] = ""; -App::$strings["Select a profile:"] = ""; -App::$strings["Change Cover Photo"] = ""; -App::$strings["Upload"] = ""; -App::$strings["Use a photo from your albums"] = ""; -App::$strings["OK"] = ""; -App::$strings["Choose images to embed"] = ""; -App::$strings["Choose an album"] = ""; -App::$strings["Choose a different album"] = ""; -App::$strings["Error getting album list"] = ""; -App::$strings["Error getting photo link"] = ""; -App::$strings["Error getting album"] = ""; -App::$strings["Select previously uploaded photo"] = ""; -App::$strings["Crop Image"] = ""; -App::$strings["Please adjust the image cropping for optimum viewing."] = ""; -App::$strings["Done Editing"] = ""; -App::$strings["Settings updated."] = ""; -App::$strings["If enabled, connection requests will be approved without your interaction"] = ""; -App::$strings["Automatic approval settings"] = ""; -App::$strings["Some individual permissions may have been preset or locked based on your channel type and privacy settings."] = ""; -App::$strings["Invalid request."] = ""; -App::$strings["channel"] = ""; -App::$strings["thing"] = ""; -App::$strings["Permission denied"] = ""; -App::$strings["photo"] = ""; -App::$strings["status"] = ""; -App::$strings["%1\$s likes %2\$s's %3\$s"] = ""; -App::$strings["%1\$s doesn't like %2\$s's %3\$s"] = ""; -App::$strings["%1\$s is attending %2\$s's %3\$s"] = ""; -App::$strings["%1\$s is not attending %2\$s's %3\$s"] = ""; -App::$strings["%1\$s may attend %2\$s's %3\$s"] = ""; -App::$strings["Item not found"] = ""; -App::$strings["Item is not editable"] = ""; -App::$strings["Edit post"] = ""; -App::$strings["day(s)"] = ""; -App::$strings["week(s)"] = ""; -App::$strings["month(s)"] = ""; -App::$strings["year(s)"] = ""; -App::$strings["Edit event title"] = ""; -App::$strings["Categories (comma-separated list)"] = ""; -App::$strings["Edit Category"] = ""; -App::$strings["Category"] = ""; -App::$strings["Edit start date and time"] = ""; -App::$strings["Finish date and time are not known or not relevant"] = ""; -App::$strings["Edit finish date and time"] = ""; -App::$strings["Finish date and time"] = ""; -App::$strings["Adjust for viewer timezone"] = ""; -App::$strings["Important for events that happen in a particular place. Not practical for global holidays."] = ""; -App::$strings["Edit Description"] = ""; -App::$strings["Edit Location"] = ""; -App::$strings["Permission settings"] = ""; -App::$strings["Timezone:"] = ""; -App::$strings["Advanced Options"] = ""; -App::$strings["Event repeat"] = ""; -App::$strings["Repeat frequency"] = ""; -App::$strings["Repeat every"] = ""; -App::$strings["Number of total repeats"] = ""; -App::$strings["Event removed"] = ""; -App::$strings["Layout Name"] = ""; -App::$strings["Layout Description (Optional)"] = ""; -App::$strings["Edit Layout"] = ""; -App::$strings["This app allows you to create private notes for your personal use."] = ""; -App::$strings["This app is installed. The Notes tool can be found on your stream page."] = ""; -App::$strings["Page link"] = ""; -App::$strings["Insert web link"] = ""; -App::$strings["Edit Webpage"] = ""; -App::$strings["Token verification failed."] = ""; -App::$strings["Email verification resent"] = ""; -App::$strings["Unable to resend email verification message."] = ""; -App::$strings["Email Verification Required"] = ""; -App::$strings["A verification token was sent to your email address [%s]. Enter that token here to complete the account verification step. Please allow a few minutes for delivery, and check your spam folder if you do not see the message."] = ""; -App::$strings["Resend Email"] = ""; -App::$strings["Validation token"] = ""; -App::$strings["Image/photo"] = ""; -App::$strings["View Photo"] = ""; -App::$strings["Edit Album"] = ""; -App::$strings["Nothing to import."] = ""; -App::$strings["Unable to download data from old server"] = ""; -App::$strings["Imported file is empty."] = ""; -App::$strings["Your service plan only allows %d channels."] = ""; -App::$strings["No channel. Import failed."] = ""; -App::$strings["Import completed."] = ""; -App::$strings["You must be logged in to use this feature."] = ""; -App::$strings["Import Channel"] = ""; -App::$strings["Use this form to import an existing channel from a different server. You may retrieve the channel identity from the old server via the network or provide an export file."] = ""; -App::$strings["File to Upload"] = ""; -App::$strings["Or provide the old server details"] = ""; -App::$strings["Your old identity address (xyz@example.com)"] = ""; -App::$strings["Your old login email address"] = ""; -App::$strings["Your old login password"] = ""; -App::$strings["Import a few months of posts if possible (limited by available memory"] = ""; -App::$strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = ""; -App::$strings["Make this hub my primary location"] = ""; -App::$strings["Move this channel (disable all previous locations)"] = ""; -App::$strings["Use this channel nickname instead of the one provided"] = ""; -App::$strings["Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site."] = ""; -App::$strings["This process may take several minutes to complete. Please submit the form only once and leave this page open until finished."] = ""; -App::$strings["Total invitation limit exceeded."] = ""; -App::$strings["%s : Not a valid email address."] = ""; -App::$strings["Please join us on \$Projectname"] = ""; -App::$strings["Invitation limit exceeded. Please contact your site administrator."] = ""; -App::$strings["%s : Message delivery failed."] = ""; -App::$strings["%d message sent."] = [ - 0 => "", - 1 => "", +App::$strings['Channel not found'] = ''; +App::$strings["Channel '%s' deleted"] = ''; +App::$strings["Channel '%s' censored"] = ''; +App::$strings["Channel '%s' uncensored"] = ''; +App::$strings["Channel '%s' code allowed"] = ''; +App::$strings["Channel '%s' code disallowed"] = ''; +App::$strings['Channels'] = ''; +App::$strings['Censor'] = ''; +App::$strings['Uncensor'] = ''; +App::$strings['Allow Code'] = ''; +App::$strings['Disallow Code'] = ''; +App::$strings['Channel'] = ''; +App::$strings['UID'] = ''; +App::$strings['Name'] = ''; +App::$strings['Address'] = ''; +App::$strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = ''; +App::$strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = ''; +App::$strings['By default, unfiltered HTML is allowed in embedded media. This is inherently insecure.'] = ''; +App::$strings['The recommended setting is to only allow unfiltered HTML from the following sites:'] = ''; +App::$strings['https://youtube.com/
      https://www.youtube.com/
      https://youtu.be/
      https://vimeo.com/
      https://soundcloud.com/
      '] = ''; +App::$strings['All other embedded content will be filtered, unless embedded content from that site is explicitly blocked.'] = ''; +App::$strings['Security'] = ''; +App::$strings['Block public'] = ''; +App::$strings['Check to block public access to all otherwise public personal pages on this site unless you are currently authenticated.'] = ''; +App::$strings['Block public search'] = ''; +App::$strings['Prevent access to search content unless you are currently authenticated.'] = ''; +App::$strings['Hide local directory'] = ''; +App::$strings['Only use the global directory'] = ''; +App::$strings['Provide a cloud root directory'] = ''; +App::$strings['The cloud root directory lists all channel names which provide public files'] = ''; +App::$strings['Show total disk space available to cloud uploads'] = ''; +App::$strings['Allow SVG thumbnails in file browser'] = ''; +App::$strings['WARNING: SVG images may contain malicious code.'] = ''; +App::$strings['Allow embedded (inline) PDF files'] = ''; +App::$strings["Set \"Transport Security\" HTTP header"] = ''; +App::$strings["Set \"Content Security Policy\" HTTP header"] = ''; +App::$strings['Allowed email domains'] = ''; +App::$strings['Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains'] = ''; +App::$strings['Not allowed email domains'] = ''; +App::$strings['Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined.'] = ''; +App::$strings['Allow communications only from these sites'] = ''; +App::$strings['One site per line. Leave empty to allow communication from anywhere by default'] = ''; +App::$strings['Block communications from these sites'] = ''; +App::$strings['Allow communications only from these channels'] = ''; +App::$strings['One channel (hash) per line. Leave empty to allow from any channel by default'] = ''; +App::$strings['Block communications from these channels'] = ''; +App::$strings['Allow public stream communications only from these sites'] = ''; +App::$strings['Block public stream communications from these sites'] = ''; +App::$strings['Allow public stream communications only from these channels'] = ''; +App::$strings['Block public stream communications from these channels'] = ''; +App::$strings['Only allow embeds from secure (SSL) websites and links.'] = ''; +App::$strings['Allow unfiltered embedded HTML content only from these domains'] = ''; +App::$strings['One site per line. By default embedded content is filtered.'] = ''; +App::$strings['Block embedded HTML from these domains'] = ''; +App::$strings['You must be logged in to see this page.'] = ''; +App::$strings['Posts and comments'] = ''; +App::$strings['Only posts'] = ''; +App::$strings['This is the home page of %s.'] = ''; +App::$strings['Insufficient permissions. Request redirected to profile page.'] = ''; +App::$strings['Search Results For:'] = ''; +App::$strings['Reset form'] = ''; +App::$strings['You must enable javascript for your browser to be able to view this content.'] = ''; +App::$strings['Authorize application connection'] = ''; +App::$strings['Return to your app and insert this Security Code:'] = ''; +App::$strings['Please login to continue.'] = ''; +App::$strings['Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'] = ''; +App::$strings['Change Order of Pinned Navbar Apps'] = ''; +App::$strings['Change Order of App Tray Apps'] = ''; +App::$strings['Use arrows to move the corresponding app left (top) or right (bottom) in the navbar'] = ''; +App::$strings['Use arrows to move the corresponding app up or down in the app tray'] = ''; +App::$strings['Available Apps'] = ''; +App::$strings['Installed Apps'] = ''; +App::$strings['Manage apps'] = ''; +App::$strings['Create Custom App'] = ''; +App::$strings['No channel.'] = ''; +App::$strings['No connections in common.'] = ''; +App::$strings['View Common Connections'] = ''; +App::$strings['Item not available.'] = ''; +App::$strings['Unknown App'] = ''; +App::$strings['Authorize'] = ''; +App::$strings['Do you authorize the app %s to access your channel data?'] = ''; +App::$strings['Allow'] = ''; +App::$strings['Channel not found.'] = ''; +App::$strings['Permissions denied.'] = ''; +App::$strings['l, F j'] = ''; +App::$strings['Link to Source'] = ''; +App::$strings['Edit Event'] = ''; +App::$strings['Create Event'] = ''; +App::$strings['Previous'] = ''; +App::$strings['Next'] = ''; +App::$strings['Import'] = ''; +App::$strings['Today'] = ''; +App::$strings['Expiration settings updated.'] = ''; +App::$strings['This app allows you to set an optional expiration date/time for posts, after which they will be deleted. This must be at least fifteen minutes into the future. You may also choose to automatically delete all your posts after a set number of days'] = ''; +App::$strings['Expire and delete all my posts after this many days'] = ''; +App::$strings['Leave at 0 if you wish to manually control expiration of specific posts.'] = ''; +App::$strings['Automatic Expiration Settings'] = ''; +App::$strings['Blocked accounts'] = ''; +App::$strings['Expired accounts'] = ''; +App::$strings['Expiring accounts'] = ''; +App::$strings['Primary'] = ''; +App::$strings['Clones'] = ''; +App::$strings['Message queues'] = ''; +App::$strings['Your software should be updated'] = ''; +App::$strings['Summary'] = ''; +App::$strings['Registered accounts'] = ''; +App::$strings['Pending registrations'] = ''; +App::$strings['Registered channels'] = ''; +App::$strings['Active addons'] = ''; +App::$strings['Version'] = ''; +App::$strings['Repository version (release)'] = ''; +App::$strings['Repository version (dev)'] = ''; +App::$strings['Invalid item.'] = ''; +App::$strings['Page not found.'] = ''; +App::$strings['Create personal planning cards'] = ''; +App::$strings['Add Card'] = ''; +App::$strings['Create'] = ''; +App::$strings['Block Name'] = ''; +App::$strings['Blocks'] = ''; +App::$strings['Block Title'] = ''; +App::$strings['Created'] = ''; +App::$strings['Edited'] = ''; +App::$strings['Share'] = ''; +App::$strings['View'] = ''; +App::$strings['Calendar entries imported.'] = ''; +App::$strings['No calendar entries found.'] = ''; +App::$strings['INVALID EVENT DISMISSED!'] = ''; +App::$strings['Summary: '] = ''; +App::$strings['Date: '] = ''; +App::$strings['Reason: '] = ''; +App::$strings['INVALID CARD DISMISSED!'] = ''; +App::$strings['Name: '] = ''; +App::$strings['CardDAV App'] = ''; +App::$strings['Not Installed'] = ''; +App::$strings['CalDAV capable addressbook'] = ''; +App::$strings['Event title'] = ''; +App::$strings['Start date and time'] = ''; +App::$strings['End date and time'] = ''; +App::$strings['Description'] = ''; +App::$strings['Location'] = ''; +App::$strings['Month'] = ''; +App::$strings['Week'] = ''; +App::$strings['Day'] = ''; +App::$strings['List month'] = ''; +App::$strings['List week'] = ''; +App::$strings['List day'] = ''; +App::$strings['More'] = ''; +App::$strings['Less'] = ''; +App::$strings['Select calendar'] = ''; +App::$strings['Channel Calendars'] = ''; +App::$strings['CalDAV Calendars'] = ''; +App::$strings['Delete all'] = ''; +App::$strings['Sorry! Editing of recurrent events is not yet implemented.'] = ''; +App::$strings['Organisation'] = ''; +App::$strings['Title'] = ''; +App::$strings['Phone'] = ''; +App::$strings['Instant messenger'] = ''; +App::$strings['Website'] = ''; +App::$strings['Note'] = ''; +App::$strings['Mobile'] = ''; +App::$strings['Home'] = ''; +App::$strings['Work'] = ''; +App::$strings['Other'] = ''; +App::$strings['Add Contact'] = ''; +App::$strings['Add Field'] = ''; +App::$strings['P.O. Box'] = ''; +App::$strings['Additional'] = ''; +App::$strings['Street'] = ''; +App::$strings['Locality'] = ''; +App::$strings['Region'] = ''; +App::$strings['ZIP Code'] = ''; +App::$strings['Country'] = ''; +App::$strings['Default Calendar'] = ''; +App::$strings['Default Addressbook'] = ''; +App::$strings['Channel name changes are not allowed within 48 hours of changing the account password.'] = ''; +App::$strings['Reserved nickname. Please choose another.'] = ''; +App::$strings['Nickname has unsupported characters or is already being used on this site.'] = ''; +App::$strings['Feature has been disabled'] = ''; +App::$strings['Change channel nickname/address'] = ''; +App::$strings['WARNING: '] = ''; +App::$strings['Any/all connections on other networks will be lost!'] = ''; +App::$strings['Please enter your password for verification:'] = ''; +App::$strings['New channel address'] = ''; +App::$strings['Rename Channel'] = ''; +App::$strings['toggle full screen mode'] = ''; +App::$strings['Documentation Search'] = ''; +App::$strings["\$Projectname Documentation"] = ''; +App::$strings['Contents'] = ''; +App::$strings['Away'] = ''; +App::$strings['Online'] = ''; +App::$strings['Could not access contact record.'] = ''; +App::$strings['Could not locate selected profile.'] = ''; +App::$strings['Connection updated.'] = ''; +App::$strings['Failed to update connection record.'] = ''; +App::$strings['is now connected to'] = ''; +App::$strings['Could not access address book record.'] = ''; +App::$strings['Refresh failed - channel is currently unavailable.'] = ''; +App::$strings['Added by Connedit'] = ''; +App::$strings['Unable to set address book parameters.'] = ''; +App::$strings['Connection has been removed.'] = ''; +App::$strings["View %s's profile"] = ''; +App::$strings['Refresh Permissions'] = ''; +App::$strings['Fetch updated permissions'] = ''; +App::$strings['Refresh Photo'] = ''; +App::$strings['Fetch updated photo'] = ''; +App::$strings['Recent Activity'] = ''; +App::$strings['View recent posts and comments'] = ''; +App::$strings['Block (or Unblock) all communications with this connection'] = ''; +App::$strings['This connection is blocked!'] = ''; +App::$strings['Unignore'] = ''; +App::$strings['Ignore'] = ''; +App::$strings['Ignore (or Unignore) all inbound communications from this connection'] = ''; +App::$strings['This connection is ignored!'] = ''; +App::$strings['Censor (or Uncensor) images from this connection'] = ''; +App::$strings['This connection is censored!'] = ''; +App::$strings['Unarchive'] = ''; +App::$strings['Archive'] = ''; +App::$strings['Archive (or Unarchive) this connection - mark channel dead but keep content'] = ''; +App::$strings['This connection is archived!'] = ''; +App::$strings['Unhide'] = ''; +App::$strings['Hide'] = ''; +App::$strings['Hide or Unhide this connection from your other connections'] = ''; +App::$strings['This connection is hidden!'] = ''; +App::$strings['Delete this connection'] = ''; +App::$strings['Fetch Vcard'] = ''; +App::$strings['Fetch electronic calling card for this connection'] = ''; +App::$strings['Permissions'] = ''; +App::$strings['Open Individual Permissions section by default'] = ''; +App::$strings['Open Friend Zoom section by default'] = ''; +App::$strings['Me'] = ''; +App::$strings['Family'] = ''; +App::$strings['Friends'] = ''; +App::$strings['Peers'] = ''; +App::$strings['All'] = ''; +App::$strings['Filter'] = ''; +App::$strings['Open Custom Filter section by default'] = ''; +App::$strings['Approve this connection'] = ''; +App::$strings['Accept connection to allow communication'] = ''; +App::$strings['Set Friend Zoom'] = ''; +App::$strings['Set Profile'] = ''; +App::$strings['Set Friend Zoom & Profile'] = ''; +App::$strings['This connection is unreachable from this location.'] = ''; +App::$strings['This connection may be unreachable from other channel locations.'] = ''; +App::$strings['Location independence is not supported by their network.'] = ''; +App::$strings['This connection is unreachable from this location. Location independence is not supported by their network.'] = ''; +App::$strings['Connection Default Permissions'] = ''; +App::$strings['Connection: %s'] = ''; +App::$strings['Apply these permissions automatically'] = ''; +App::$strings['Connection requests will be approved without your interaction'] = ''; +App::$strings['Permission role'] = ''; +App::$strings['Loading'] = ''; +App::$strings['Add permission role'] = ''; +App::$strings["This connection's primary address is"] = ''; +App::$strings['Available locations:'] = ''; +App::$strings['The permissions indicated on this page will be applied to all new connections.'] = ''; +App::$strings['Connection Tools'] = ''; +App::$strings['Slide to adjust your degree of friendship'] = ''; +App::$strings['Rating'] = ''; +App::$strings['Slide to adjust your rating'] = ''; +App::$strings['Optionally explain your rating'] = ''; +App::$strings['Custom Filter'] = ''; +App::$strings['Only import posts with this text'] = ''; +App::$strings["words one per line or #tags, \$categories, /patterns/, or lang=xx, leave blank to import all posts"] = ''; +App::$strings['Do not import posts with this text'] = ''; +App::$strings['Nickname'] = ''; +App::$strings['optional - allows you to search by a name that you have chosen'] = ''; +App::$strings['This information is public!'] = ''; +App::$strings['Connection Pending Approval'] = ''; +App::$strings['inherited'] = ''; +App::$strings['Please choose the profile you would like to display to %s when viewing your profile securely.'] = ''; +App::$strings['Their Settings'] = ''; +App::$strings['My Settings'] = ''; +App::$strings['Individual Permissions'] = ''; +App::$strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can not change those settings here."] = ''; +App::$strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes."] = ''; +App::$strings['Last update:'] = ''; +App::$strings['Details'] = ''; +App::$strings['Active'] = ''; +App::$strings['Blocked'] = ''; +App::$strings['Ignored'] = ''; +App::$strings['Hidden'] = ''; +App::$strings['Archived/Unreachable'] = ''; +App::$strings['New'] = ''; +App::$strings['Active Connections'] = ''; +App::$strings['Show active connections'] = ''; +App::$strings['New Connections'] = ''; +App::$strings['Show pending (new) connections'] = ''; +App::$strings['Only show blocked connections'] = ''; +App::$strings['Only show ignored connections'] = ''; +App::$strings['Only show archived/unreachable connections'] = ''; +App::$strings['Only show hidden connections'] = ''; +App::$strings['All Connections'] = ''; +App::$strings['Show all connections'] = ''; +App::$strings['Order by name'] = ''; +App::$strings['Recent'] = ''; +App::$strings['Order by recent'] = ''; +App::$strings['Order by date'] = ''; +App::$strings['Pending approval'] = ''; +App::$strings['Archived'] = ''; +App::$strings['Not connected at this location'] = ''; +App::$strings["%1\$s [%2\$s]"] = ''; +App::$strings['Edit connection'] = ''; +App::$strings['Delete connection'] = ''; +App::$strings['Channel address'] = ''; +App::$strings['Network'] = ''; +App::$strings['Call'] = ''; +App::$strings['Status'] = ''; +App::$strings['Connected'] = ''; +App::$strings['Approve connection'] = ''; +App::$strings['Ignore connection'] = ''; +App::$strings['Recent activity'] = ''; +App::$strings['Filter by'] = ''; +App::$strings['Sort by'] = ''; +App::$strings['Search your connections'] = ''; +App::$strings['Connections search'] = ''; +App::$strings['Find'] = ''; +App::$strings['network'] = ''; +App::$strings['App installed.'] = ''; +App::$strings['Malformed app.'] = ''; +App::$strings['Embed code'] = ''; +App::$strings['Edit App'] = ''; +App::$strings['Create App'] = ''; +App::$strings['Name of app'] = ''; +App::$strings['Required'] = ''; +App::$strings['Location (URL) of app'] = ''; +App::$strings['Photo icon URL'] = ''; +App::$strings['80 x 80 pixels - optional'] = ''; +App::$strings['Categories (optional, comma separated list)'] = ''; +App::$strings['Version ID'] = ''; +App::$strings['Price of app'] = ''; +App::$strings['Location (URL) to purchase app'] = ''; +App::$strings['Image uploaded but image cropping failed.'] = ''; +App::$strings['Cover Photos'] = ''; +App::$strings['Image resize failed.'] = ''; +App::$strings['Unable to process image'] = ''; +App::$strings['female'] = ''; +App::$strings["%1\$s updated her %2\$s"] = ''; +App::$strings['male'] = ''; +App::$strings["%1\$s updated his %2\$s"] = ''; +App::$strings["%1\$s updated their %2\$s"] = ''; +App::$strings['cover photo'] = ''; +App::$strings['Photo not available.'] = ''; +App::$strings['Your cover photo may be visible to anybody on the internet'] = ''; +App::$strings['Upload File:'] = ''; +App::$strings['Select a profile:'] = ''; +App::$strings['Change Cover Photo'] = ''; +App::$strings['Upload'] = ''; +App::$strings['Use a photo from your albums'] = ''; +App::$strings['OK'] = ''; +App::$strings['Choose images to embed'] = ''; +App::$strings['Choose an album'] = ''; +App::$strings['Choose a different album'] = ''; +App::$strings['Error getting album list'] = ''; +App::$strings['Error getting photo link'] = ''; +App::$strings['Error getting album'] = ''; +App::$strings['Select previously uploaded photo'] = ''; +App::$strings['Crop Image'] = ''; +App::$strings['Please adjust the image cropping for optimum viewing.'] = ''; +App::$strings['Done Editing'] = ''; +App::$strings['Settings updated.'] = ''; +App::$strings['If enabled, connection requests will be approved without your interaction'] = ''; +App::$strings['Automatic approval settings'] = ''; +App::$strings['Some individual permissions may have been preset or locked based on your channel type and privacy settings.'] = ''; +App::$strings['Invalid request.'] = ''; +App::$strings['channel'] = ''; +App::$strings['thing'] = ''; +App::$strings['Permission denied'] = ''; +App::$strings['photo'] = ''; +App::$strings['status'] = ''; +App::$strings["%1\$s likes %2\$s's %3\$s"] = ''; +App::$strings["%1\$s doesn't like %2\$s's %3\$s"] = ''; +App::$strings["%1\$s is attending %2\$s's %3\$s"] = ''; +App::$strings["%1\$s is not attending %2\$s's %3\$s"] = ''; +App::$strings["%1\$s may attend %2\$s's %3\$s"] = ''; +App::$strings['Item not found'] = ''; +App::$strings['Item is not editable'] = ''; +App::$strings['Edit post'] = ''; +App::$strings['day(s)'] = ''; +App::$strings['week(s)'] = ''; +App::$strings['month(s)'] = ''; +App::$strings['year(s)'] = ''; +App::$strings['Edit event title'] = ''; +App::$strings['Categories (comma-separated list)'] = ''; +App::$strings['Edit Category'] = ''; +App::$strings['Category'] = ''; +App::$strings['Edit start date and time'] = ''; +App::$strings['Finish date and time are not known or not relevant'] = ''; +App::$strings['Edit finish date and time'] = ''; +App::$strings['Finish date and time'] = ''; +App::$strings['Adjust for viewer timezone'] = ''; +App::$strings['Important for events that happen in a particular place. Not practical for global holidays.'] = ''; +App::$strings['Edit Description'] = ''; +App::$strings['Edit Location'] = ''; +App::$strings['Permission settings'] = ''; +App::$strings['Timezone:'] = ''; +App::$strings['Advanced Options'] = ''; +App::$strings['Event repeat'] = ''; +App::$strings['Repeat frequency'] = ''; +App::$strings['Repeat every'] = ''; +App::$strings['Number of total repeats'] = ''; +App::$strings['Event removed'] = ''; +App::$strings['Layout Name'] = ''; +App::$strings['Layout Description (Optional)'] = ''; +App::$strings['Edit Layout'] = ''; +App::$strings['This app allows you to create private notes for your personal use.'] = ''; +App::$strings['This app is installed. The Notes tool can be found on your stream page.'] = ''; +App::$strings['Page link'] = ''; +App::$strings['Insert web link'] = ''; +App::$strings['Edit Webpage'] = ''; +App::$strings['Token verification failed.'] = ''; +App::$strings['Email verification resent'] = ''; +App::$strings['Unable to resend email verification message.'] = ''; +App::$strings['Email Verification Required'] = ''; +App::$strings['A verification token was sent to your email address [%s]. Enter that token here to complete the account verification step. Please allow a few minutes for delivery, and check your spam folder if you do not see the message.'] = ''; +App::$strings['Resend Email'] = ''; +App::$strings['Validation token'] = ''; +App::$strings['Image/photo'] = ''; +App::$strings['View Photo'] = ''; +App::$strings['Edit Album'] = ''; +App::$strings['Nothing to import.'] = ''; +App::$strings['Unable to download data from old server'] = ''; +App::$strings['Imported file is empty.'] = ''; +App::$strings['Your service plan only allows %d channels.'] = ''; +App::$strings['No channel. Import failed.'] = ''; +App::$strings['Import completed.'] = ''; +App::$strings['You must be logged in to use this feature.'] = ''; +App::$strings['Import Channel'] = ''; +App::$strings['Use this form to import an existing channel from a different server. You may retrieve the channel identity from the old server via the network or provide an export file.'] = ''; +App::$strings['File to Upload'] = ''; +App::$strings['Or provide the old server details'] = ''; +App::$strings['Your old identity address (xyz@example.com)'] = ''; +App::$strings['Your old login email address'] = ''; +App::$strings['Your old login password'] = ''; +App::$strings['Import a few months of posts if possible (limited by available memory'] = ''; +App::$strings['For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media.'] = ''; +App::$strings['Make this hub my primary location'] = ''; +App::$strings['Move this channel (disable all previous locations)'] = ''; +App::$strings['Use this channel nickname instead of the one provided'] = ''; +App::$strings['Leave blank to keep your existing channel nickname. You will be randomly assigned a similar nickname if either name is already allocated on this site.'] = ''; +App::$strings['This process may take several minutes to complete. Please submit the form only once and leave this page open until finished.'] = ''; +App::$strings['Total invitation limit exceeded.'] = ''; +App::$strings['%s : Not a valid email address.'] = ''; +App::$strings["Please join us on \$Projectname"] = ''; +App::$strings['Invitation limit exceeded. Please contact your site administrator.'] = ''; +App::$strings['%s : Message delivery failed.'] = ''; +App::$strings['%d message sent.'] = [ + 0 => '', + 1 => '', ]; -App::$strings["Send email invitations to join this network"] = ""; -App::$strings["You have no more invitations available"] = ""; -App::$strings["Send invitations"] = ""; -App::$strings["Enter email addresses, one per line:"] = ""; -App::$strings["Your message:"] = ""; -App::$strings["Please join my community on \$Projectname."] = ""; -App::$strings["You will need to supply this invitation code:"] = ""; -App::$strings["1. Register at any \$Projectname location (they are all inter-connected)"] = ""; -App::$strings["2. Enter my \$Projectname network address into the site searchbar."] = ""; -App::$strings["or visit"] = ""; -App::$strings["3. Click [Connect]"] = ""; -App::$strings["This app allows you to disable comments on individual posts."] = ""; -App::$strings["This app is installed. A button to control the ability to comment may be found below the post editor."] = ""; -App::$strings["Enter a folder name"] = ""; -App::$strings["or select an existing folder (doubleclick)"] = ""; -App::$strings["File not found."] = ""; -App::$strings["Permission Denied."] = ""; -App::$strings["Edit file permissions"] = ""; -App::$strings["Set/edit permissions"] = ""; -App::$strings["Include all files and sub folders"] = ""; -App::$strings["Return to file list"] = ""; -App::$strings["Copy/paste this code to attach file to a post"] = ""; -App::$strings["Copy/paste this URL to link file from a web page"] = ""; -App::$strings["Share this file"] = ""; -App::$strings["Show URL to this file"] = ""; -App::$strings["Show in your contacts shared folder"] = ""; -App::$strings["Entry censored"] = ""; -App::$strings["Entry uncensored"] = ""; -App::$strings["webpage"] = ""; -App::$strings["block"] = ""; -App::$strings["layout"] = ""; -App::$strings["menu"] = ""; -App::$strings["%s element installed"] = ""; -App::$strings["%s element installation failed"] = ""; -App::$strings["Thing updated"] = ""; -App::$strings["Object store: failed"] = ""; -App::$strings["Thing added"] = ""; -App::$strings["OBJ: %1\$s %2\$s %3\$s"] = ""; -App::$strings["Show Thing"] = ""; -App::$strings["item not found."] = ""; -App::$strings["Edit Thing"] = ""; -App::$strings["Select a profile"] = ""; -App::$strings["Post an activity"] = ""; -App::$strings["Only sends to viewers of the applicable profile"] = ""; -App::$strings["Name of thing e.g. something"] = ""; -App::$strings["URL of thing (optional)"] = ""; -App::$strings["URL for photo of thing (optional)"] = ""; -App::$strings["Add Thing to your Profile"] = ""; -App::$strings["Room not found"] = ""; -App::$strings["Leave Room"] = ""; -App::$strings["Delete Room"] = ""; -App::$strings["I am away right now"] = ""; -App::$strings["I am online"] = ""; -App::$strings["Please enter a link URL:"] = ""; -App::$strings["New Chatroom"] = ""; -App::$strings["Chatroom name"] = ""; -App::$strings["Expiration of chats (minutes)"] = ""; -App::$strings["%1\$s's Chatrooms"] = ""; -App::$strings["No chatrooms available"] = ""; -App::$strings["Create New"] = ""; -App::$strings["Expiration"] = ""; -App::$strings["min"] = ""; -App::$strings["No entries."] = ""; -App::$strings["Comment approved"] = ""; -App::$strings["Comment deleted"] = ""; -App::$strings["Welcome to Hubzilla!"] = ""; -App::$strings["You have got no unseen posts..."] = ""; -App::$strings["Access list created."] = ""; -App::$strings["Could not create access list."] = ""; -App::$strings["Access list not found."] = ""; -App::$strings["Access list updated."] = ""; -App::$strings["List members"] = ""; -App::$strings["List not found"] = ""; -App::$strings["Access Lists"] = ""; -App::$strings["Create access list"] = ""; -App::$strings["Access list name"] = ""; -App::$strings["Members are visible to other channels"] = ""; -App::$strings["Members"] = ""; -App::$strings["Access list removed."] = ""; -App::$strings["Unable to remove access list."] = ""; -App::$strings["Access List: %s"] = ""; -App::$strings["Access list name: "] = ""; -App::$strings["Delete access list"] = ""; -App::$strings["Not in this list"] = ""; -App::$strings["Select a channel to toggle membership"] = ""; -App::$strings["Layouts"] = ""; -App::$strings["Layout Description"] = ""; -App::$strings["Download PDL file"] = ""; -App::$strings["No such group"] = ""; -App::$strings["No such channel"] = ""; -App::$strings["Access list is empty"] = ""; -App::$strings["Access list: "] = ""; -App::$strings["Invalid channel."] = ""; -App::$strings["Title (optional)"] = ""; -App::$strings["Edit Card"] = ""; -App::$strings["Warning: Database versions differ by %1\$d updates."] = ""; -App::$strings["Import completed"] = ""; -App::$strings["Import Items"] = ""; -App::$strings["Use this form to import existing posts and content from an export file."] = ""; -App::$strings["Not found"] = ""; -App::$strings["Please refresh page"] = ""; -App::$strings["Unknown error"] = ""; -App::$strings["Group"] = ""; -App::$strings["You have created %1$.0f of %2$.0f allowed channels."] = ""; -App::$strings["Create a new channel"] = ""; -App::$strings["Current Channel"] = ""; -App::$strings["Switch to one of your channels by selecting it."] = ""; -App::$strings["Default Login Channel"] = ""; -App::$strings["Make Default"] = ""; -App::$strings["Add to menu"] = ""; -App::$strings["%d new messages"] = ""; -App::$strings["%d new introductions"] = ""; -App::$strings["Delegated Channel"] = ""; -App::$strings["Change UI language"] = ""; -App::$strings["Menu not found."] = ""; -App::$strings["Unable to create element."] = ""; -App::$strings["Unable to update menu element."] = ""; -App::$strings["Unable to add menu element."] = ""; -App::$strings["Not found."] = ""; -App::$strings["Menu Item Permissions"] = ""; -App::$strings["(click to open/close)"] = ""; -App::$strings["Link Name"] = ""; -App::$strings["Link or Submenu Target"] = ""; -App::$strings["Enter URL of the link or select a menu name to create a submenu"] = ""; -App::$strings["Use magic-auth if available"] = ""; -App::$strings["Open link in new window"] = ""; -App::$strings["Order in list"] = ""; -App::$strings["Higher numbers will sink to bottom of listing"] = ""; -App::$strings["Submit and finish"] = ""; -App::$strings["Submit and continue"] = ""; -App::$strings["Menu:"] = ""; -App::$strings["Link Target"] = ""; -App::$strings["Edit menu"] = ""; -App::$strings["Edit element"] = ""; -App::$strings["Drop element"] = ""; -App::$strings["New element"] = ""; -App::$strings["Edit this menu container"] = ""; -App::$strings["Add menu element"] = ""; -App::$strings["Delete this menu item"] = ""; -App::$strings["Edit this menu item"] = ""; -App::$strings["Menu item not found."] = ""; -App::$strings["Menu item deleted."] = ""; -App::$strings["Menu item could not be deleted."] = ""; -App::$strings["Edit Menu Element"] = ""; -App::$strings["Link text"] = ""; -App::$strings["Webfinger Diagnostic"] = ""; -App::$strings["Lookup address or URL"] = ""; -App::$strings["Edit Block"] = ""; -App::$strings["Invalid message"] = ""; -App::$strings["no results"] = ""; -App::$strings["channel sync processed"] = ""; -App::$strings["queued"] = ""; -App::$strings["posted"] = ""; -App::$strings["accepted for delivery"] = ""; -App::$strings["updated"] = ""; -App::$strings["update ignored"] = ""; -App::$strings["permission denied"] = ""; -App::$strings["recipient not found"] = ""; -App::$strings["mail recalled"] = ""; -App::$strings["duplicate mail received"] = ""; -App::$strings["mail delivered"] = ""; -App::$strings["Delivery report for %1\$s"] = ""; -App::$strings["Options"] = ""; -App::$strings["Redeliver"] = ""; -App::$strings["Post repeated"] = ""; -App::$strings["No valid account found."] = ""; -App::$strings["Password reset request issued. Check your email."] = ""; -App::$strings["Site Member (%s)"] = ""; -App::$strings["Password reset requested at %s"] = ""; -App::$strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = ""; -App::$strings["Password Reset"] = ""; -App::$strings["Your password has been reset as requested."] = ""; -App::$strings["Your new password is"] = ""; -App::$strings["Save or copy your new password - and then"] = ""; -App::$strings["click here to login"] = ""; -App::$strings["Your password may be changed from the Settings page after successful login."] = ""; -App::$strings["Your password has changed at %s"] = ""; -App::$strings["Forgot your Password?"] = ""; -App::$strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = ""; -App::$strings["Email Address"] = ""; -App::$strings["Unable to update menu."] = ""; -App::$strings["Unable to create menu."] = ""; -App::$strings["Menu Name"] = ""; -App::$strings["Unique name (not visible on webpage) - required"] = ""; -App::$strings["Menu Title"] = ""; -App::$strings["Visible on webpage - leave empty for no title"] = ""; -App::$strings["Allow Bookmarks"] = ""; -App::$strings["Menu may be used to store saved bookmarks"] = ""; -App::$strings["Submit and proceed"] = ""; -App::$strings["Menus"] = ""; -App::$strings["Drop"] = ""; -App::$strings["Bookmarks allowed"] = ""; -App::$strings["Delete this menu"] = ""; -App::$strings["Edit menu contents"] = ""; -App::$strings["Edit this menu"] = ""; -App::$strings["Menu could not be deleted."] = ""; -App::$strings["Edit Menu"] = ""; -App::$strings["Add or remove entries to this menu"] = ""; -App::$strings["Menu name"] = ""; -App::$strings["Must be unique, only seen by you"] = ""; -App::$strings["Menu title"] = ""; -App::$strings["Menu title as seen by others"] = ""; -App::$strings["Allow bookmarks"] = ""; -App::$strings["This setting requires special processing and editing has been blocked."] = ""; -App::$strings["Configuration Editor"] = ""; -App::$strings["Warning: Changing some settings could render your channel inoperable. Please leave this page unless you are comfortable with and knowledgeable about how to correctly use this feature."] = ""; -App::$strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = ""; -App::$strings["Please indicate acceptance of the Terms of Service. Registration failed."] = ""; -App::$strings["Passwords do not match."] = ""; -App::$strings["Registration successful. Continue to create your first channel..."] = ""; -App::$strings["Registration successful. Please check your email for validation instructions."] = ""; -App::$strings["Your registration is pending approval by the site owner."] = ""; -App::$strings["Your registration can not be processed."] = ""; -App::$strings["Registration on this hub is disabled."] = ""; -App::$strings["Registration on this hub is by approval only."] = ""; -App::$strings["Register at another affiliated hub."] = ""; -App::$strings["Registration on this hub is by invitation only."] = ""; -App::$strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = ""; -App::$strings["Terms of Service"] = ""; -App::$strings["I accept the %s for this website"] = ""; -App::$strings["I am over %s years of age and accept the %s for this website"] = ""; -App::$strings["Your email address"] = ""; -App::$strings["Choose a password"] = ""; -App::$strings["Please re-enter your password"] = ""; -App::$strings["Please enter your invitation code"] = ""; -App::$strings["Your Name"] = ""; -App::$strings["Real names are preferred."] = ""; -App::$strings["Choose a short nickname"] = ""; -App::$strings["Your nickname will be used to create an easy to remember channel address e.g. nickname%s"] = ""; -App::$strings["Channel role and privacy"] = ""; -App::$strings["Select a channel permission role for your usage needs and privacy requirements."] = ""; -App::$strings["no"] = ""; -App::$strings["yes"] = ""; -App::$strings["Register"] = ""; -App::$strings["This site requires email verification. After completing this form, please check your email for further instructions."] = ""; -App::$strings["Poll not found."] = ""; -App::$strings["Invalid response."] = ""; -App::$strings["Response submitted. Updates may not appear instantly."] = ""; -App::$strings["Location not found."] = ""; -App::$strings["Location lookup failed."] = ""; -App::$strings["Please select another location to become primary before removing the primary location."] = ""; -App::$strings["Pushing location info"] = ""; -App::$strings["No locations found."] = ""; -App::$strings["Manage Channel Locations"] = ""; -App::$strings["Publish these settings"] = ""; -App::$strings["Please wait several minutes between consecutive operations."] = ""; -App::$strings["When possible, drop a location by logging into that website/hub and removing your channel."] = ""; -App::$strings["Use this form to drop the location if the hub is no longer operating."] = ""; -App::$strings["item"] = ""; -App::$strings["inspect"] = ""; -App::$strings["Your real name is recommended."] = ""; -App::$strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\""] = ""; -App::$strings["This will be used to create a unique network address (like an email address)."] = ""; -App::$strings["Allowed characters are a-z 0-9, - and _"] = ""; -App::$strings["Channel name"] = ""; -App::$strings["Select a channel permission role compatible with your usage needs and privacy requirements."] = ""; -App::$strings["Create a Channel"] = ""; -App::$strings["A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things."] = ""; -App::$strings["or import an existing channel from another location."] = ""; -App::$strings["Validate"] = ""; -App::$strings["Continue"] = ""; -App::$strings["Premium Channel Setup"] = ""; -App::$strings["Enable premium channel connection restrictions"] = ""; -App::$strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = ""; -App::$strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = ""; -App::$strings["Potential connections will then see the following text before proceeding:"] = ""; -App::$strings["By continuing, I certify that I have complied with any instructions provided on this page."] = ""; -App::$strings["(No specific instructions have been provided by the channel owner.)"] = ""; -App::$strings["Restricted or Premium Channel"] = ""; -App::$strings["No more system notifications."] = ""; -App::$strings["System Notifications"] = ""; -App::$strings["Unable to locate original post."] = ""; -App::$strings["Comment may be moderated."] = ""; -App::$strings["Empty post discarded."] = ""; -App::$strings["Duplicate post suppressed."] = ""; -App::$strings["System error. Post not saved."] = ""; -App::$strings["Your post/comment is awaiting approval."] = ""; -App::$strings["Unable to obtain post information from database."] = ""; -App::$strings["You have reached your limit of %1$.0f top level posts."] = ""; -App::$strings["You have reached your limit of %1$.0f webpages."] = ""; -App::$strings["__ctx:mood__ %1\$s is %2\$s"] = ""; -App::$strings["Set your current mood and tell your friends"] = ""; -App::$strings["Unable to find your hub."] = ""; -App::$strings["Post successful."] = ""; -App::$strings["Public Hubs"] = ""; -App::$strings["The listed hubs allow public registration for the \$Projectname network. All hubs in the network are interlinked so membership on any of them conveys membership in the network as a whole. Some hubs may require subscription or provide tiered service plans. The hub itself may provide additional details."] = ""; -App::$strings["Hub URL"] = ""; -App::$strings["Access Type"] = ""; -App::$strings["Registration Policy"] = ""; -App::$strings["Software"] = ""; -App::$strings["Provide managed web pages on your channel"] = ""; -App::$strings["Import Webpage Elements"] = ""; -App::$strings["Import selected"] = ""; -App::$strings["Export Webpage Elements"] = ""; -App::$strings["Export selected"] = ""; -App::$strings["Actions"] = ""; -App::$strings["Page Link"] = ""; -App::$strings["Page Title"] = ""; -App::$strings["Invalid file type."] = ""; -App::$strings["Error opening zip file"] = ""; -App::$strings["Invalid folder path."] = ""; -App::$strings["No webpage elements detected."] = ""; -App::$strings["Import complete."] = ""; -App::$strings["Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."] = ""; -App::$strings["vcard"] = ""; -App::$strings["Layout updated."] = ""; -App::$strings["Edit System Page Description"] = ""; -App::$strings["(modified)"] = ""; -App::$strings["Layout not found."] = ""; -App::$strings["Module Name:"] = ""; -App::$strings["Layout Help"] = ""; -App::$strings["Edit another layout"] = ""; -App::$strings["System layout"] = ""; -App::$strings["Zap Server - Setup"] = ""; -App::$strings["Could not connect to database."] = ""; -App::$strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = ""; -App::$strings["Could not create table."] = ""; -App::$strings["Your site database has been installed."] = ""; -App::$strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = ""; -App::$strings["Please see the file \"install/INSTALL.txt\"."] = ""; -App::$strings["System check"] = ""; -App::$strings["Check again"] = ""; -App::$strings["Database connection"] = ""; -App::$strings["In order to install this software we need to know how to connect to your database."] = ""; -App::$strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = ""; -App::$strings["The database you specify below should already exist. If it does not, please create it before continuing."] = ""; -App::$strings["Database Server Name"] = ""; -App::$strings["Default is 127.0.0.1"] = ""; -App::$strings["Database Port"] = ""; -App::$strings["Communication port number - use 0 for default"] = ""; -App::$strings["Database Login Name"] = ""; -App::$strings["Database Login Password"] = ""; -App::$strings["Database Name"] = ""; -App::$strings["Database Type"] = ""; -App::$strings["Site administrator email address"] = ""; -App::$strings["Your account email address must match this in order to use the web admin panel."] = ""; -App::$strings["Website URL"] = ""; -App::$strings["Please use SSL (https) URL if available."] = ""; -App::$strings["Please select a default timezone for your website"] = ""; -App::$strings["Site settings"] = ""; -App::$strings["PHP version 7.1 or greater is required."] = ""; -App::$strings["PHP version"] = ""; -App::$strings["Could not find a command line version of PHP in the web server PATH."] = ""; -App::$strings["If you do not have a command line version of PHP installed on server, you will not be able to run background tasks - including message delivery."] = ""; -App::$strings["PHP executable path"] = ""; -App::$strings["Enter full path to php executable. You can leave this blank to continue the installation."] = ""; -App::$strings["Command line PHP"] = ""; -App::$strings["Unable to check command line PHP, as shell_exec() is disabled. This is required."] = ""; -App::$strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = ""; -App::$strings["This is required for message delivery to work."] = ""; -App::$strings["PHP register_argc_argv"] = ""; -App::$strings["This is not sufficient to upload larger images or files. You should be able to upload at least 2MB (2097152 bytes) at once."] = ""; -App::$strings["Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once."] = ""; -App::$strings["You can adjust these settings in the server php.ini file."] = ""; -App::$strings["PHP upload limits"] = ""; -App::$strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = ""; -App::$strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = ""; -App::$strings["Generate encryption keys"] = ""; -App::$strings["libCurl PHP module"] = ""; -App::$strings["GD graphics PHP module"] = ""; -App::$strings["OpenSSL PHP module"] = ""; -App::$strings["PDO database PHP module"] = ""; -App::$strings["mb_string PHP module"] = ""; -App::$strings["xml PHP module"] = ""; -App::$strings["zip PHP module"] = ""; -App::$strings["Apache mod_rewrite module"] = ""; -App::$strings["Error: Apache webserver mod-rewrite module is required but not installed."] = ""; -App::$strings["exec"] = ""; -App::$strings["Error: exec is required but is either not installed or has been disabled in php.ini"] = ""; -App::$strings["shell_exec"] = ""; -App::$strings["Error: shell_exec is required but is either not installed or has been disabled in php.ini"] = ""; -App::$strings["Error: libCURL PHP module required but not installed."] = ""; -App::$strings["Error: GD PHP module with JPEG support or ImageMagick graphics library required but not installed."] = ""; -App::$strings["Error: openssl PHP module required but not installed."] = ""; -App::$strings["Error: PDO database PHP module missing a driver for either mysql or pgsql."] = ""; -App::$strings["Error: PDO database PHP module required but not installed."] = ""; -App::$strings["Error: mb_string PHP module required but not installed."] = ""; -App::$strings["Error: xml PHP module required for DAV but not installed."] = ""; -App::$strings["Error: zip PHP module required but not installed."] = ""; -App::$strings[".htconfig.php is writable"] = ""; -App::$strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = ""; -App::$strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = ""; -App::$strings["Please see install/INSTALL.txt for additional information."] = ""; -App::$strings["This software uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = ""; -App::$strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the top level web folder."] = ""; -App::$strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = ""; -App::$strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = ""; -App::$strings["%s is writable"] = ""; -App::$strings["This software uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the top level web folder"] = ""; -App::$strings["store is writable"] = ""; -App::$strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = ""; -App::$strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = ""; -App::$strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = ""; -App::$strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = ""; -App::$strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = ""; -App::$strings["Providers are available that issue free certificates which are browser-valid."] = ""; -App::$strings["If you are confident that the certificate is valid and signed by a trusted authority, check to see if you have failed to install an intermediate cert. These are not normally required by browsers, but are required for server-to-server communications."] = ""; -App::$strings["SSL certificate validation"] = ""; -App::$strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = ""; -App::$strings["Url rewrite is working"] = ""; -App::$strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = ""; -App::$strings["Errors encountered creating database tables."] = ""; -App::$strings["

      What next?

      "] = ""; -App::$strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = ""; -App::$strings["Profile not found."] = ""; -App::$strings["Profile deleted."] = ""; -App::$strings["Profile-"] = ""; -App::$strings["New profile created."] = ""; -App::$strings["Profile unavailable to clone."] = ""; -App::$strings["Profile unavailable to export."] = ""; -App::$strings["Profile Name is required."] = ""; -App::$strings["Marital Status"] = ""; -App::$strings["Romantic Partner"] = ""; -App::$strings["Likes"] = ""; -App::$strings["Dislikes"] = ""; -App::$strings["Work/Employment"] = ""; -App::$strings["Religion"] = ""; -App::$strings["Political Views"] = ""; -App::$strings["Gender"] = ""; -App::$strings["Sexual Preference"] = ""; -App::$strings["Homepage"] = ""; -App::$strings["Interests"] = ""; -App::$strings["Profile updated."] = ""; -App::$strings["Hide your connections list from viewers of this profile"] = ""; -App::$strings["Edit Profile Details"] = ""; -App::$strings["View this profile"] = ""; -App::$strings["Profile Tools"] = ""; -App::$strings["Change cover photo"] = ""; -App::$strings["Create a new profile using these settings"] = ""; -App::$strings["Clone this profile"] = ""; -App::$strings["Delete this profile"] = ""; -App::$strings["Add profile things"] = ""; -App::$strings["Personal"] = ""; -App::$strings["Relationship"] = ""; -App::$strings["Miscellaneous"] = ""; -App::$strings["Import profile from file"] = ""; -App::$strings["Export profile to file"] = ""; -App::$strings["Your gender"] = ""; -App::$strings["Marital status"] = ""; -App::$strings["Sexual preference"] = ""; -App::$strings["Profile name"] = ""; -App::$strings["Your full name"] = ""; -App::$strings["Title/Description"] = ""; -App::$strings["Street address"] = ""; -App::$strings["Locality/City"] = ""; -App::$strings["Region/State"] = ""; -App::$strings["Postal/Zip code"] = ""; -App::$strings["Who (if applicable)"] = ""; -App::$strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = ""; -App::$strings["Since (date)"] = ""; -App::$strings["Tell us about yourself"] = ""; -App::$strings["Homepage URL"] = ""; -App::$strings["Hometown"] = ""; -App::$strings["Political views"] = ""; -App::$strings["Religious views"] = ""; -App::$strings["Keywords used in directory listings"] = ""; -App::$strings["Example: fishing photography software"] = ""; -App::$strings["Musical interests"] = ""; -App::$strings["Books, literature"] = ""; -App::$strings["Television"] = ""; -App::$strings["Film/Dance/Culture/Entertainment"] = ""; -App::$strings["Hobbies/Interests"] = ""; -App::$strings["Love/Romance"] = ""; -App::$strings["School/Education"] = ""; -App::$strings["Contact information and social networks"] = ""; -App::$strings["My other channels"] = ""; -App::$strings["Communications"] = ""; -App::$strings[" and "] = ""; -App::$strings[", "] = ""; -App::$strings["public profile"] = ""; -App::$strings["%1\$s changed %2\$s to “%3\$s”"] = ""; -App::$strings["Visit %1\$s's %2\$s"] = ""; -App::$strings["%1\$s has an updated %2\$s, changing %3\$s."] = ""; -App::$strings["Currently Male"] = ""; -App::$strings["Currently Female"] = ""; -App::$strings["Mostly Male"] = ""; -App::$strings["Mostly Female"] = ""; -App::$strings["Transgender"] = ""; -App::$strings["Intersex"] = ""; -App::$strings["Transsexual"] = ""; -App::$strings["Hermaphrodite"] = ""; -App::$strings["Undecided"] = ""; -App::$strings["Males"] = ""; -App::$strings["Females"] = ""; -App::$strings["Gay"] = ""; -App::$strings["Lesbian"] = ""; -App::$strings["No Preference"] = ""; -App::$strings["Bisexual"] = ""; -App::$strings["Autosexual"] = ""; -App::$strings["Abstinent"] = ""; -App::$strings["Virgin"] = ""; -App::$strings["Deviant"] = ""; -App::$strings["Fetish"] = ""; -App::$strings["Oodles"] = ""; -App::$strings["Nonsexual"] = ""; -App::$strings["Single"] = ""; -App::$strings["Lonely"] = ""; -App::$strings["Available"] = ""; -App::$strings["Unavailable"] = ""; -App::$strings["Has crush"] = ""; -App::$strings["Infatuated"] = ""; -App::$strings["Dating"] = ""; -App::$strings["Unfaithful"] = ""; -App::$strings["Sex Addict"] = ""; -App::$strings["Friends/Benefits"] = ""; -App::$strings["Casual"] = ""; -App::$strings["Engaged"] = ""; -App::$strings["Married"] = ""; -App::$strings["Imaginarily married"] = ""; -App::$strings["Partners"] = ""; -App::$strings["Cohabiting"] = ""; -App::$strings["Common law"] = ""; -App::$strings["Happy"] = ""; -App::$strings["Not looking"] = ""; -App::$strings["Swinger"] = ""; -App::$strings["Betrayed"] = ""; -App::$strings["Separated"] = ""; -App::$strings["Unstable"] = ""; -App::$strings["Divorced"] = ""; -App::$strings["Imaginarily divorced"] = ""; -App::$strings["Widowed"] = ""; -App::$strings["Uncertain"] = ""; -App::$strings["It's complicated"] = ""; -App::$strings["Don't care"] = ""; -App::$strings["Ask me"] = ""; -App::$strings["Poke somebody in your addressbook"] = ""; -App::$strings["Poke somebody"] = ""; -App::$strings["Poke/Prod"] = ""; -App::$strings["Poke, prod or do other things to somebody"] = ""; -App::$strings["Recipient"] = ""; -App::$strings["Choose what you wish to do to recipient"] = ""; -App::$strings["Make this post private"] = ""; -App::$strings["Profile Photos"] = ""; -App::$strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = ""; -App::$strings["Image upload failed."] = ""; -App::$strings["Unable to process image."] = ""; -App::$strings["Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile"] = ""; -App::$strings["Your profile photo is visible to anybody on the internet and may be distributed to other websites."] = ""; -App::$strings["Use Photo for Profile"] = ""; -App::$strings["Change Profile Photo"] = ""; -App::$strings["Use"] = ""; -App::$strings["Page owner information could not be retrieved."] = ""; -App::$strings["Album not found."] = ""; -App::$strings["Delete Album"] = ""; -App::$strings["Delete Photo"] = ""; -App::$strings["Public access denied."] = ""; -App::$strings["No photos selected"] = ""; -App::$strings["Access to this item is restricted."] = ""; -App::$strings["%1$.2f MB of %2$.2f MB photo storage used."] = ""; -App::$strings["%1$.2f MB photo storage used."] = ""; -App::$strings["Upload Photos"] = ""; -App::$strings["Enter an album name"] = ""; -App::$strings["or select an existing album (doubleclick)"] = ""; -App::$strings["Create a status post for this upload"] = ""; -App::$strings["Description (optional)"] = ""; -App::$strings["Date descending"] = ""; -App::$strings["Date ascending"] = ""; -App::$strings["Name ascending"] = ""; -App::$strings["Add Photos"] = ""; -App::$strings["Sort"] = ""; -App::$strings["Permission denied. Access to this item may be restricted."] = ""; -App::$strings["Photo not available"] = ""; -App::$strings["Use as profile photo"] = ""; -App::$strings["Use as cover photo"] = ""; -App::$strings["Private Photo"] = ""; -App::$strings["View Full Size"] = ""; -App::$strings["Edit photo"] = ""; -App::$strings["Move photo to album"] = ""; -App::$strings["Enter a new album name"] = ""; -App::$strings["or select an existing one (doubleclick)"] = ""; -App::$strings["Add a Tag"] = ""; -App::$strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = ""; -App::$strings["Flag as adult in album view"] = ""; -App::$strings["__ctx:title__ Likes"] = ""; -App::$strings["__ctx:title__ Dislikes"] = ""; -App::$strings["__ctx:title__ Attending"] = ""; -App::$strings["__ctx:title__ Not attending"] = ""; -App::$strings["__ctx:title__ Might attend"] = ""; -App::$strings["Photo Tools"] = ""; -App::$strings["In This Photo:"] = ""; -App::$strings["Map"] = ""; -App::$strings["Recent Photos"] = ""; -App::$strings["Invalid profile identifier."] = ""; -App::$strings["Profile Visibility Editor"] = ""; -App::$strings["Click on a contact to add or remove."] = ""; -App::$strings["Visible To"] = ""; -App::$strings["Channel removals are not allowed within 48 hours of changing the account password."] = ""; -App::$strings["Remove This Channel"] = ""; -App::$strings["This channel will be completely removed from this server. "] = ""; -App::$strings["This action is permanent and can not be undone!"] = ""; -App::$strings["Remove Channel"] = ""; -App::$strings["Friend Zoom settings updated."] = ""; -App::$strings["This app (when installed) presents a slider control in your connection editor and also on your stream page. The slider represents your degree of friendship with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream."] = ""; -App::$strings["The number below represents the default maximum slider position for your stream page as a percentage."] = ""; -App::$strings["Default friend zoom in/out"] = ""; -App::$strings["Refresh"] = ""; -App::$strings["Friend Zoom Settings"] = ""; -App::$strings["Connection added."] = ""; -App::$strings["Welcome to %s"] = ""; -App::$strings["This site is not a directory server"] = ""; -App::$strings["Please login."] = ""; -App::$strings["Account removals are not allowed within 48 hours of changing the account password."] = ""; -App::$strings["Remove This Account"] = ""; -App::$strings["This account and all its channels will be completely removed from this server. "] = ""; -App::$strings["Remove Account"] = ""; -App::$strings["Authentication failed."] = ""; -App::$strings["Remote Authentication"] = ""; -App::$strings["Enter your channel address (e.g. channel@example.com)"] = ""; -App::$strings["Authenticate"] = ""; -App::$strings["ActivityPub Probe Diagnostic"] = ""; -App::$strings["Object URL"] = ""; -App::$strings["Authenticated fetch"] = ""; -App::$strings["This app provides a simple personal and task list."] = ""; -App::$strings["No service class restrictions found."] = ""; -App::$strings["Not valid email."] = ""; -App::$strings["Protected email address. Cannot change to that email."] = ""; -App::$strings["System failure storing new email. Please try again."] = ""; -App::$strings["Password verification failed."] = ""; -App::$strings["Passwords do not match. Password unchanged."] = ""; -App::$strings["Empty passwords are not allowed. Password unchanged."] = ""; -App::$strings["Password changed."] = ""; -App::$strings["Password update failed. Please try again."] = ""; -App::$strings["Account Settings"] = ""; -App::$strings["Current Password"] = ""; -App::$strings["Enter New Password"] = ""; -App::$strings["Confirm New Password"] = ""; -App::$strings["Leave password fields blank unless changing"] = ""; -App::$strings["Email Address:"] = ""; -App::$strings["Remove this account including all its channels"] = ""; -App::$strings["Affinity Slider settings updated."] = ""; -App::$strings["No feature settings configured"] = ""; -App::$strings["Default maximum affinity level"] = ""; -App::$strings["0-99 default 99"] = ""; -App::$strings["Default minimum affinity level"] = ""; -App::$strings["0-99 - default 0"] = ""; -App::$strings["Affinity Slider Settings"] = ""; -App::$strings["Addon Settings"] = ""; -App::$strings["Please save/submit changes to any panel before opening another."] = ""; -App::$strings["Activity Settings"] = ""; -App::$strings["Search by Date"] = ""; -App::$strings["Ability to select posts by date ranges"] = ""; -App::$strings["Saved Searches"] = ""; -App::$strings["Save search terms for re-use"] = ""; -App::$strings["Alternate Stream Order"] = ""; -App::$strings["Ability to order the stream by last post date, last comment date or unthreaded activities"] = ""; -App::$strings["Contact Filter"] = ""; -App::$strings["Ability to display only posts of a selected contact"] = ""; -App::$strings["Forum Filter"] = ""; -App::$strings["Ability to display only posts of a specific forum"] = ""; -App::$strings["Personal Posts Filter"] = ""; -App::$strings["Ability to display only posts that you've interacted on"] = ""; -App::$strings["Affinity Tool"] = ""; -App::$strings["Filter stream activity by depth of relationships"] = ""; -App::$strings["Show friend and connection suggestions"] = ""; -App::$strings["Connection Filtering"] = ""; -App::$strings["Filter incoming posts from connections based on keywords/content"] = ""; -App::$strings["Name is required"] = ""; -App::$strings["Key and Secret are required"] = ""; -App::$strings["Add application"] = ""; -App::$strings["Name of application"] = ""; -App::$strings["Consumer Key"] = ""; -App::$strings["Automatically generated - change if desired. Max length 20"] = ""; -App::$strings["Consumer Secret"] = ""; -App::$strings["Redirect"] = ""; -App::$strings["Redirect URI - leave blank unless your application specifically requires this"] = ""; -App::$strings["Icon url"] = ""; -App::$strings["Optional"] = ""; -App::$strings["Application not found."] = ""; -App::$strings["Connected Apps"] = ""; -App::$strings["Client key starts with"] = ""; -App::$strings["No name"] = ""; -App::$strings["Remove authorization"] = ""; -App::$strings["Permission Name is required."] = ""; -App::$strings["Permission category saved."] = ""; -App::$strings["Use this form to create permission rules for various classes of people or connections."] = ""; -App::$strings["Permission Name"] = ""; -App::$strings["This channel is limited to %d tokens"] = ""; -App::$strings["Name and Password are required."] = ""; -App::$strings["Token saved."] = ""; -App::$strings["Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content."] = ""; -App::$strings["You may also provide dropbox style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:"] = ""; -App::$strings["Guest Access Tokens"] = ""; -App::$strings["Login Name"] = ""; -App::$strings["Login Password"] = ""; -App::$strings["Expires (yyyy-mm-dd)"] = ""; -App::$strings["Additional Features"] = ""; -App::$strings["ID and Secret are required"] = ""; -App::$strings["Add OAuth2 application"] = ""; -App::$strings["Consumer ID"] = ""; -App::$strings["Grant Types"] = ""; -App::$strings["leave blank unless your application specifically requires this"] = ""; -App::$strings["Authorization scope"] = ""; -App::$strings["OAuth2 Application not found."] = ""; -App::$strings["Connected OAuth2 Apps"] = ""; -App::$strings["%s - (Experimental)"] = ""; -App::$strings["Display Settings"] = ""; -App::$strings["Theme Settings"] = ""; -App::$strings["Custom Theme Settings"] = ""; -App::$strings["Content Settings"] = ""; -App::$strings["Display Theme:"] = ""; -App::$strings["Select scheme"] = ""; -App::$strings["Preload images before rendering the page"] = ""; -App::$strings["The subjective page load time will be longer but the page will be ready when displayed"] = ""; -App::$strings["Enable user zoom on mobile devices"] = ""; -App::$strings["Update browser every xx seconds"] = ""; -App::$strings["Minimum of 10 seconds, no maximum"] = ""; -App::$strings["Maximum number of conversations to load at any time:"] = ""; -App::$strings["Maximum of 100 items"] = ""; -App::$strings["Show emoticons (smilies) as images"] = ""; -App::$strings["Provide channel menu in navigation bar"] = ""; -App::$strings["Default: channel menu located in app menu"] = ""; -App::$strings["System Page Layout Editor - (advanced)"] = ""; -App::$strings["Channel page max height of content (in pixels)"] = ""; -App::$strings["click to expand content exceeding this height"] = ""; -App::$strings["Stream page max height of content (in pixels)"] = ""; -App::$strings["Nobody except yourself"] = ""; -App::$strings["Only those you specifically allow"] = ""; -App::$strings["Approved connections"] = ""; -App::$strings["Any connections"] = ""; -App::$strings["Anybody on this website"] = ""; -App::$strings["Anybody in this network"] = ""; -App::$strings["Anybody authenticated"] = ""; -App::$strings["Anybody on the internet"] = ""; -App::$strings["Publish your profile in the network directory"] = ""; -App::$strings["Allow us to suggest you as a potential friend to new members?"] = ""; -App::$strings["or"] = ""; -App::$strings["Your channel address is"] = ""; -App::$strings["Friends using compatible applications can use this address to connect with you."] = ""; -App::$strings["Your files/photos are accessible as a network drive at"] = ""; -App::$strings["(Windows)"] = ""; -App::$strings["(other platforms)"] = ""; -App::$strings["Automatic membership approval"] = ""; -App::$strings["Friend-of-friend conversations"] = ""; -App::$strings["Import public third-party conversations in which your connections participate."] = ""; -App::$strings["Enable ActivityPub protocol"] = ""; -App::$strings["ActivityPub"] = ""; -App::$strings["ActivityPub is an emerging internet standard for social communications. "] = ""; -App::$strings["It provides access to a large and growing number of existing users and supported software applications, however it is still evolving. If this is enabled you will obtain much greater social reach, however it is likely you will also encounter compatibility issues. "] = ""; -App::$strings["Channel Settings"] = ""; -App::$strings["Basic Settings"] = ""; -App::$strings["Full name"] = ""; -App::$strings["Your timezone"] = ""; -App::$strings["This is important for showing the correct time on shared events"] = ""; -App::$strings["Default post location"] = ""; -App::$strings["Optional geographical location to display on your posts"] = ""; -App::$strings["Obtain post location from your web browser or device"] = ""; -App::$strings["Adult content"] = ""; -App::$strings["Enable to indicate if this channel frequently or regularly publishes adult content. (Please also tag any adult material and/or nudity with #NSFW)"] = ""; -App::$strings["Security and Privacy"] = ""; -App::$strings["Your permissions are already configured. Click to view/adjust"] = ""; -App::$strings["Hide my online presence"] = ""; -App::$strings["Prevents displaying in your profile that you are online"] = ""; -App::$strings["Allow others to view your friends and connections"] = ""; -App::$strings["Allow others to tag your posts"] = ""; -App::$strings["Often used by the community to retro-actively flag inappropriate content"] = ""; -App::$strings["Channel Permission Limits"] = ""; -App::$strings["Expire other channel content after this many days"] = ""; -App::$strings["0 or blank to use the website limit."] = ""; -App::$strings["This website expires after %d days."] = ""; -App::$strings["This website does not expire imported content."] = ""; -App::$strings["The website limit takes precedence if lower than your limit."] = ""; -App::$strings["Maximum Friend Requests/Day:"] = ""; -App::$strings["May reduce spam activity"] = ""; -App::$strings["Default Access List"] = ""; -App::$strings["Use my default audience setting for the type of object published"] = ""; -App::$strings["Profile to assign new connections"] = ""; -App::$strings["Default Permissions Group"] = ""; -App::$strings["Maximum private messages per day from unknown people:"] = ""; -App::$strings["Useful to reduce spamming"] = ""; -App::$strings["By default post a status message when:"] = ""; -App::$strings["accepting a friend request"] = ""; -App::$strings["joining a forum/community"] = ""; -App::$strings["making an interesting profile change"] = ""; -App::$strings["Send a notification email when:"] = ""; -App::$strings["You receive a connection request"] = ""; -App::$strings["Someone writes on your profile wall"] = ""; -App::$strings["Someone writes a followup comment"] = ""; -App::$strings["You are tagged in a post"] = ""; -App::$strings["Someone likes your post/comment"] = ""; -App::$strings["Show visual notifications including:"] = ""; -App::$strings["Unseen stream activity"] = ""; -App::$strings["Unseen channel activity"] = ""; -App::$strings["Upcoming events"] = ""; -App::$strings["Events today"] = ""; -App::$strings["Upcoming birthdays"] = ""; -App::$strings["Not available in all themes"] = ""; -App::$strings["System (personal) notifications"] = ""; -App::$strings["System info messages"] = ""; -App::$strings["Recommended"] = ""; -App::$strings["System critical alerts"] = ""; -App::$strings["New connections"] = ""; -App::$strings["System Registrations"] = ""; -App::$strings["Unseen public activity"] = ""; -App::$strings["Unseen likes and dislikes"] = ""; -App::$strings["Unseen forum posts"] = ""; -App::$strings["Reported content"] = ""; -App::$strings["Email notification hub (hostname)"] = ""; -App::$strings["If your channel is mirrored to multiple locations, set this to your preferred location. This will prevent duplicate email notifications. Example: %s"] = ""; -App::$strings["Show new wall posts, private messages and connections under Notices"] = ""; -App::$strings["Accept messages from strangers which mention me"] = ""; -App::$strings["This setting supercedes normal permissions"] = ""; -App::$strings["Accept messages from strangers which include any of the following hashtags"] = ""; -App::$strings["comma separated, do not include the #"] = ""; -App::$strings["Notify me of events this many days in advance"] = ""; -App::$strings["Must be greater than 0"] = ""; -App::$strings["Date and time"] = ""; -App::$strings["This section is reserved for use by optional addons and apps to provide additional settings."] = ""; -App::$strings["Advanced Account/Page Type Settings"] = ""; -App::$strings["Change the behaviour of this account for special situations"] = ""; -App::$strings["Default photo upload folder name"] = ""; -App::$strings["%Y - current year, %m - current month"] = ""; -App::$strings["Default file upload folder name"] = ""; -App::$strings["Personal menu to display in your channel pages"] = ""; -App::$strings["Remove this channel."] = ""; -App::$strings["Mentions should display"] = ""; -App::$strings["Changes to this setting are applied to new posts/comments only. It is not retroactive."] = ""; -App::$strings["the channel display name [example: @Barbara Jenkins]"] = ""; -App::$strings["the channel nickname [example: @barbara1976]"] = ""; -App::$strings["combined [example: @Barbara Jenkins (barbara1976)]"] = ""; -App::$strings["no preference, use the system default"] = ""; -App::$strings["Calendar week begins on"] = ""; -App::$strings["This varies by country/culture"] = ""; -App::$strings["Sunday"] = ""; -App::$strings["Monday"] = ""; -App::$strings["Tuesday"] = ""; -App::$strings["Wednesday"] = ""; -App::$strings["Thursday"] = ""; -App::$strings["Friday"] = ""; -App::$strings["Saturday"] = ""; -App::$strings["Items tagged with: %s"] = ""; -App::$strings["Search results for: %s"] = ""; -App::$strings["%1\$s is following %2\$s's %3\$s"] = ""; -App::$strings["%1\$s stopped following %2\$s's %3\$s"] = ""; -App::$strings["Files: shared with me"] = ""; -App::$strings["NEW"] = ""; -App::$strings["Size"] = ""; -App::$strings["Last Modified"] = ""; -App::$strings["Remove all files"] = ""; -App::$strings["Remove this file"] = ""; -App::$strings["About this site"] = ""; -App::$strings["Site Name"] = ""; -App::$strings["Administrator"] = ""; -App::$strings["Software and Project information"] = ""; -App::$strings["This site is powered by \$Projectname"] = ""; -App::$strings["Federated and decentralised networking and identity services provided by Zot"] = ""; -App::$strings["Federated transport protocols:"] = ""; -App::$strings["Version %s"] = ""; -App::$strings["Project homepage"] = ""; -App::$strings["Developer homepage"] = ""; -App::$strings["Export Channel"] = ""; -App::$strings["Export your basic channel information to a file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new server hub, but does not contain your content."] = ""; -App::$strings["Export Content"] = ""; -App::$strings["Export your channel information and recent content to a JSON backup that can be restored or imported to another server hub. This backs up all of your connections, permissions, profile data and several months of posts. This file may be VERY large. Please be patient - it may take several minutes for this download to begin."] = ""; -App::$strings["Export your posts from a given year."] = ""; -App::$strings["You may also export your posts and conversations for a particular year or month. Adjust the date in your browser location bar to select other dates. If the export fails (possibly due to memory exhaustion on your server hub), please try again selecting a more limited date range."] = ""; -App::$strings["To select all posts for a given year, such as this year, visit %2\$s"] = ""; -App::$strings["To select all posts for a given month, such as January of this year, visit %2\$s"] = ""; -App::$strings["These content files may be imported or restored by visiting %2\$s on any site containing your channel. For best results please import or restore these in date order (oldest first)."] = ""; -App::$strings["Failed to create source. No channel selected."] = ""; -App::$strings["Source created."] = ""; -App::$strings["Source updated."] = ""; -App::$strings["*"] = ""; -App::$strings["Manage remote sources of content for your channel."] = ""; -App::$strings["New Source"] = ""; -App::$strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = ""; -App::$strings["Only import content with these words (one per line)"] = ""; -App::$strings["Leave blank to import all public content"] = ""; -App::$strings["Channel Name"] = ""; -App::$strings["Add the following categories to posts imported from this source (comma separated)"] = ""; -App::$strings["Resend posts with this channel as author"] = ""; -App::$strings["Copyrights may apply"] = ""; -App::$strings["Source not found."] = ""; -App::$strings["Edit Source"] = ""; -App::$strings["Delete Source"] = ""; -App::$strings["Source removed"] = ""; -App::$strings["Unable to remove source."] = ""; -App::$strings["Article"] = ""; -App::$strings["Item has been removed."] = ""; -App::$strings["Post not found."] = ""; -App::$strings["comment"] = ""; -App::$strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = ""; -App::$strings["Tag removed"] = ""; -App::$strings["Remove Item Tag"] = ""; -App::$strings["Select a tag to remove: "] = ""; -App::$strings["No default suggestions were found."] = ""; -App::$strings["%d rating"] = [ - 0 => "", - 1 => "", +App::$strings['Send email invitations to join this network'] = ''; +App::$strings['You have no more invitations available'] = ''; +App::$strings['Send invitations'] = ''; +App::$strings['Enter email addresses, one per line:'] = ''; +App::$strings['Your message:'] = ''; +App::$strings["Please join my community on \$Projectname."] = ''; +App::$strings['You will need to supply this invitation code:'] = ''; +App::$strings["1. Register at any \$Projectname location (they are all inter-connected)"] = ''; +App::$strings["2. Enter my \$Projectname network address into the site searchbar."] = ''; +App::$strings['or visit'] = ''; +App::$strings['3. Click [Connect]'] = ''; +App::$strings['This app allows you to disable comments on individual posts.'] = ''; +App::$strings['This app is installed. A button to control the ability to comment may be found below the post editor.'] = ''; +App::$strings['Enter a folder name'] = ''; +App::$strings['or select an existing folder (doubleclick)'] = ''; +App::$strings['File not found.'] = ''; +App::$strings['Permission Denied.'] = ''; +App::$strings['Edit file permissions'] = ''; +App::$strings['Set/edit permissions'] = ''; +App::$strings['Include all files and sub folders'] = ''; +App::$strings['Return to file list'] = ''; +App::$strings['Copy/paste this code to attach file to a post'] = ''; +App::$strings['Copy/paste this URL to link file from a web page'] = ''; +App::$strings['Share this file'] = ''; +App::$strings['Show URL to this file'] = ''; +App::$strings['Show in your contacts shared folder'] = ''; +App::$strings['Entry censored'] = ''; +App::$strings['Entry uncensored'] = ''; +App::$strings['webpage'] = ''; +App::$strings['block'] = ''; +App::$strings['layout'] = ''; +App::$strings['menu'] = ''; +App::$strings['%s element installed'] = ''; +App::$strings['%s element installation failed'] = ''; +App::$strings['Thing updated'] = ''; +App::$strings['Object store: failed'] = ''; +App::$strings['Thing added'] = ''; +App::$strings["OBJ: %1\$s %2\$s %3\$s"] = ''; +App::$strings['Show Thing'] = ''; +App::$strings['item not found.'] = ''; +App::$strings['Edit Thing'] = ''; +App::$strings['Select a profile'] = ''; +App::$strings['Post an activity'] = ''; +App::$strings['Only sends to viewers of the applicable profile'] = ''; +App::$strings['Name of thing e.g. something'] = ''; +App::$strings['URL of thing (optional)'] = ''; +App::$strings['URL for photo of thing (optional)'] = ''; +App::$strings['Add Thing to your Profile'] = ''; +App::$strings['Room not found'] = ''; +App::$strings['Leave Room'] = ''; +App::$strings['Delete Room'] = ''; +App::$strings['I am away right now'] = ''; +App::$strings['I am online'] = ''; +App::$strings['Please enter a link URL:'] = ''; +App::$strings['New Chatroom'] = ''; +App::$strings['Chatroom name'] = ''; +App::$strings['Expiration of chats (minutes)'] = ''; +App::$strings["%1\$s's Chatrooms"] = ''; +App::$strings['No chatrooms available'] = ''; +App::$strings['Create New'] = ''; +App::$strings['Expiration'] = ''; +App::$strings['min'] = ''; +App::$strings['No entries.'] = ''; +App::$strings['Comment approved'] = ''; +App::$strings['Comment deleted'] = ''; +App::$strings['Welcome to Hubzilla!'] = ''; +App::$strings['You have got no unseen posts...'] = ''; +App::$strings['Access list created.'] = ''; +App::$strings['Could not create access list.'] = ''; +App::$strings['Access list not found.'] = ''; +App::$strings['Access list updated.'] = ''; +App::$strings['List members'] = ''; +App::$strings['List not found'] = ''; +App::$strings['Access Lists'] = ''; +App::$strings['Create access list'] = ''; +App::$strings['Access list name'] = ''; +App::$strings['Members are visible to other channels'] = ''; +App::$strings['Members'] = ''; +App::$strings['Access list removed.'] = ''; +App::$strings['Unable to remove access list.'] = ''; +App::$strings['Access List: %s'] = ''; +App::$strings['Access list name: '] = ''; +App::$strings['Delete access list'] = ''; +App::$strings['Not in this list'] = ''; +App::$strings['Select a channel to toggle membership'] = ''; +App::$strings['Layouts'] = ''; +App::$strings['Layout Description'] = ''; +App::$strings['Download PDL file'] = ''; +App::$strings['No such group'] = ''; +App::$strings['No such channel'] = ''; +App::$strings['Access list is empty'] = ''; +App::$strings['Access list: '] = ''; +App::$strings['Invalid channel.'] = ''; +App::$strings['Title (optional)'] = ''; +App::$strings['Edit Card'] = ''; +App::$strings["Warning: Database versions differ by %1\$d updates."] = ''; +App::$strings['Import completed'] = ''; +App::$strings['Import Items'] = ''; +App::$strings['Use this form to import existing posts and content from an export file.'] = ''; +App::$strings['Not found'] = ''; +App::$strings['Please refresh page'] = ''; +App::$strings['Unknown error'] = ''; +App::$strings['Group'] = ''; +App::$strings['You have created %1$.0f of %2$.0f allowed channels.'] = ''; +App::$strings['Create a new channel'] = ''; +App::$strings['Current Channel'] = ''; +App::$strings['Switch to one of your channels by selecting it.'] = ''; +App::$strings['Default Login Channel'] = ''; +App::$strings['Make Default'] = ''; +App::$strings['Add to menu'] = ''; +App::$strings['%d new messages'] = ''; +App::$strings['%d new introductions'] = ''; +App::$strings['Delegated Channel'] = ''; +App::$strings['Change UI language'] = ''; +App::$strings['Menu not found.'] = ''; +App::$strings['Unable to create element.'] = ''; +App::$strings['Unable to update menu element.'] = ''; +App::$strings['Unable to add menu element.'] = ''; +App::$strings['Not found.'] = ''; +App::$strings['Menu Item Permissions'] = ''; +App::$strings['(click to open/close)'] = ''; +App::$strings['Link Name'] = ''; +App::$strings['Link or Submenu Target'] = ''; +App::$strings['Enter URL of the link or select a menu name to create a submenu'] = ''; +App::$strings['Use magic-auth if available'] = ''; +App::$strings['Open link in new window'] = ''; +App::$strings['Order in list'] = ''; +App::$strings['Higher numbers will sink to bottom of listing'] = ''; +App::$strings['Submit and finish'] = ''; +App::$strings['Submit and continue'] = ''; +App::$strings['Menu:'] = ''; +App::$strings['Link Target'] = ''; +App::$strings['Edit menu'] = ''; +App::$strings['Edit element'] = ''; +App::$strings['Drop element'] = ''; +App::$strings['New element'] = ''; +App::$strings['Edit this menu container'] = ''; +App::$strings['Add menu element'] = ''; +App::$strings['Delete this menu item'] = ''; +App::$strings['Edit this menu item'] = ''; +App::$strings['Menu item not found.'] = ''; +App::$strings['Menu item deleted.'] = ''; +App::$strings['Menu item could not be deleted.'] = ''; +App::$strings['Edit Menu Element'] = ''; +App::$strings['Link text'] = ''; +App::$strings['Webfinger Diagnostic'] = ''; +App::$strings['Lookup address or URL'] = ''; +App::$strings['Edit Block'] = ''; +App::$strings['Invalid message'] = ''; +App::$strings['no results'] = ''; +App::$strings['channel sync processed'] = ''; +App::$strings['queued'] = ''; +App::$strings['posted'] = ''; +App::$strings['accepted for delivery'] = ''; +App::$strings['updated'] = ''; +App::$strings['update ignored'] = ''; +App::$strings['permission denied'] = ''; +App::$strings['recipient not found'] = ''; +App::$strings['mail recalled'] = ''; +App::$strings['duplicate mail received'] = ''; +App::$strings['mail delivered'] = ''; +App::$strings["Delivery report for %1\$s"] = ''; +App::$strings['Options'] = ''; +App::$strings['Redeliver'] = ''; +App::$strings['Post repeated'] = ''; +App::$strings['No valid account found.'] = ''; +App::$strings['Password reset request issued. Check your email.'] = ''; +App::$strings['Site Member (%s)'] = ''; +App::$strings['Password reset requested at %s'] = ''; +App::$strings['Request could not be verified. (You may have previously submitted it.) Password reset failed.'] = ''; +App::$strings['Password Reset'] = ''; +App::$strings['Your password has been reset as requested.'] = ''; +App::$strings['Your new password is'] = ''; +App::$strings['Save or copy your new password - and then'] = ''; +App::$strings['click here to login'] = ''; +App::$strings['Your password may be changed from the Settings page after successful login.'] = ''; +App::$strings['Your password has changed at %s'] = ''; +App::$strings['Forgot your Password?'] = ''; +App::$strings['Enter your email address and submit to have your password reset. Then check your email for further instructions.'] = ''; +App::$strings['Email Address'] = ''; +App::$strings['Unable to update menu.'] = ''; +App::$strings['Unable to create menu.'] = ''; +App::$strings['Menu Name'] = ''; +App::$strings['Unique name (not visible on webpage) - required'] = ''; +App::$strings['Menu Title'] = ''; +App::$strings['Visible on webpage - leave empty for no title'] = ''; +App::$strings['Allow Bookmarks'] = ''; +App::$strings['Menu may be used to store saved bookmarks'] = ''; +App::$strings['Submit and proceed'] = ''; +App::$strings['Menus'] = ''; +App::$strings['Drop'] = ''; +App::$strings['Bookmarks allowed'] = ''; +App::$strings['Delete this menu'] = ''; +App::$strings['Edit menu contents'] = ''; +App::$strings['Edit this menu'] = ''; +App::$strings['Menu could not be deleted.'] = ''; +App::$strings['Edit Menu'] = ''; +App::$strings['Add or remove entries to this menu'] = ''; +App::$strings['Menu name'] = ''; +App::$strings['Must be unique, only seen by you'] = ''; +App::$strings['Menu title'] = ''; +App::$strings['Menu title as seen by others'] = ''; +App::$strings['Allow bookmarks'] = ''; +App::$strings['This setting requires special processing and editing has been blocked.'] = ''; +App::$strings['Configuration Editor'] = ''; +App::$strings['Warning: Changing some settings could render your channel inoperable. Please leave this page unless you are comfortable with and knowledgeable about how to correctly use this feature.'] = ''; +App::$strings['Maximum daily site registrations exceeded. Please try again tomorrow.'] = ''; +App::$strings['Please indicate acceptance of the Terms of Service. Registration failed.'] = ''; +App::$strings['Passwords do not match.'] = ''; +App::$strings['Registration successful. Continue to create your first channel...'] = ''; +App::$strings['Registration successful. Please check your email for validation instructions.'] = ''; +App::$strings['Your registration is pending approval by the site owner.'] = ''; +App::$strings['Your registration can not be processed.'] = ''; +App::$strings['Registration on this hub is disabled.'] = ''; +App::$strings['Registration on this hub is by approval only.'] = ''; +App::$strings["Register at another affiliated hub."] = ''; +App::$strings['Registration on this hub is by invitation only.'] = ''; +App::$strings['This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.'] = ''; +App::$strings['Terms of Service'] = ''; +App::$strings['I accept the %s for this website'] = ''; +App::$strings['I am over %s years of age and accept the %s for this website'] = ''; +App::$strings['Your email address'] = ''; +App::$strings['Choose a password'] = ''; +App::$strings['Please re-enter your password'] = ''; +App::$strings['Please enter your invitation code'] = ''; +App::$strings['Your Name'] = ''; +App::$strings['Real names are preferred.'] = ''; +App::$strings['Choose a short nickname'] = ''; +App::$strings['Your nickname will be used to create an easy to remember channel address e.g. nickname%s'] = ''; +App::$strings['Channel role and privacy'] = ''; +App::$strings['Select a channel permission role for your usage needs and privacy requirements.'] = ''; +App::$strings['no'] = ''; +App::$strings['yes'] = ''; +App::$strings['Register'] = ''; +App::$strings['This site requires email verification. After completing this form, please check your email for further instructions.'] = ''; +App::$strings['Poll not found.'] = ''; +App::$strings['Invalid response.'] = ''; +App::$strings['Response submitted. Updates may not appear instantly.'] = ''; +App::$strings['Location not found.'] = ''; +App::$strings['Location lookup failed.'] = ''; +App::$strings['Please select another location to become primary before removing the primary location.'] = ''; +App::$strings['Pushing location info'] = ''; +App::$strings['No locations found.'] = ''; +App::$strings['Manage Channel Locations'] = ''; +App::$strings['Publish these settings'] = ''; +App::$strings['Please wait several minutes between consecutive operations.'] = ''; +App::$strings['When possible, drop a location by logging into that website/hub and removing your channel.'] = ''; +App::$strings['Use this form to drop the location if the hub is no longer operating.'] = ''; +App::$strings['item'] = ''; +App::$strings['inspect'] = ''; +App::$strings['Your real name is recommended.'] = ''; +App::$strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\""] = ''; +App::$strings['This will be used to create a unique network address (like an email address).'] = ''; +App::$strings['Allowed characters are a-z 0-9, - and _'] = ''; +App::$strings['Channel name'] = ''; +App::$strings['Select a channel permission role compatible with your usage needs and privacy requirements.'] = ''; +App::$strings['Create a Channel'] = ''; +App::$strings['A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things.'] = ''; +App::$strings["or import an existing channel from another location."] = ''; +App::$strings['Validate'] = ''; +App::$strings['Continue'] = ''; +App::$strings['Premium Channel Setup'] = ''; +App::$strings['Enable premium channel connection restrictions'] = ''; +App::$strings['Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc.'] = ''; +App::$strings['This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'] = ''; +App::$strings['Potential connections will then see the following text before proceeding:'] = ''; +App::$strings['By continuing, I certify that I have complied with any instructions provided on this page.'] = ''; +App::$strings['(No specific instructions have been provided by the channel owner.)'] = ''; +App::$strings['Restricted or Premium Channel'] = ''; +App::$strings['No more system notifications.'] = ''; +App::$strings['System Notifications'] = ''; +App::$strings['Unable to locate original post.'] = ''; +App::$strings['Comment may be moderated.'] = ''; +App::$strings['Empty post discarded.'] = ''; +App::$strings['Duplicate post suppressed.'] = ''; +App::$strings['System error. Post not saved.'] = ''; +App::$strings['Your post/comment is awaiting approval.'] = ''; +App::$strings['Unable to obtain post information from database.'] = ''; +App::$strings['You have reached your limit of %1$.0f top level posts.'] = ''; +App::$strings['You have reached your limit of %1$.0f webpages.'] = ''; +App::$strings["__ctx:mood__ %1\$s is %2\$s"] = ''; +App::$strings['Set your current mood and tell your friends'] = ''; +App::$strings['Unable to find your hub.'] = ''; +App::$strings['Post successful.'] = ''; +App::$strings['Public Hubs'] = ''; +App::$strings["The listed hubs allow public registration for the \$Projectname network. All hubs in the network are interlinked so membership on any of them conveys membership in the network as a whole. Some hubs may require subscription or provide tiered service plans. The hub itself may provide additional details."] = ''; +App::$strings['Hub URL'] = ''; +App::$strings['Access Type'] = ''; +App::$strings['Registration Policy'] = ''; +App::$strings['Software'] = ''; +App::$strings['Provide managed web pages on your channel'] = ''; +App::$strings['Import Webpage Elements'] = ''; +App::$strings['Import selected'] = ''; +App::$strings['Export Webpage Elements'] = ''; +App::$strings['Export selected'] = ''; +App::$strings['Actions'] = ''; +App::$strings['Page Link'] = ''; +App::$strings['Page Title'] = ''; +App::$strings['Invalid file type.'] = ''; +App::$strings['Error opening zip file'] = ''; +App::$strings['Invalid folder path.'] = ''; +App::$strings['No webpage elements detected.'] = ''; +App::$strings['Import complete.'] = ''; +App::$strings['Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'] = ''; +App::$strings['vcard'] = ''; +App::$strings['Layout updated.'] = ''; +App::$strings['Edit System Page Description'] = ''; +App::$strings['(modified)'] = ''; +App::$strings['Layout not found.'] = ''; +App::$strings['Module Name:'] = ''; +App::$strings['Layout Help'] = ''; +App::$strings['Edit another layout'] = ''; +App::$strings['System layout'] = ''; +App::$strings['Zap Server - Setup'] = ''; +App::$strings['Could not connect to database.'] = ''; +App::$strings['Could not connect to specified site URL. Possible SSL certificate or DNS issue.'] = ''; +App::$strings['Could not create table.'] = ''; +App::$strings['Your site database has been installed.'] = ''; +App::$strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = ''; +App::$strings["Please see the file \"install/INSTALL.txt\"."] = ''; +App::$strings['System check'] = ''; +App::$strings['Check again'] = ''; +App::$strings['Database connection'] = ''; +App::$strings['In order to install this software we need to know how to connect to your database.'] = ''; +App::$strings['Please contact your hosting provider or site administrator if you have questions about these settings.'] = ''; +App::$strings['The database you specify below should already exist. If it does not, please create it before continuing.'] = ''; +App::$strings['Database Server Name'] = ''; +App::$strings['Default is 127.0.0.1'] = ''; +App::$strings['Database Port'] = ''; +App::$strings['Communication port number - use 0 for default'] = ''; +App::$strings['Database Login Name'] = ''; +App::$strings['Database Login Password'] = ''; +App::$strings['Database Name'] = ''; +App::$strings['Database Type'] = ''; +App::$strings['Site administrator email address'] = ''; +App::$strings['Your account email address must match this in order to use the web admin panel.'] = ''; +App::$strings['Website URL'] = ''; +App::$strings['Please use SSL (https) URL if available.'] = ''; +App::$strings['Please select a default timezone for your website'] = ''; +App::$strings['Site settings'] = ''; +App::$strings['PHP version 7.1 or greater is required.'] = ''; +App::$strings['PHP version'] = ''; +App::$strings['Could not find a command line version of PHP in the web server PATH.'] = ''; +App::$strings['If you do not have a command line version of PHP installed on server, you will not be able to run background tasks - including message delivery.'] = ''; +App::$strings['PHP executable path'] = ''; +App::$strings['Enter full path to php executable. You can leave this blank to continue the installation.'] = ''; +App::$strings['Command line PHP'] = ''; +App::$strings['Unable to check command line PHP, as shell_exec() is disabled. This is required.'] = ''; +App::$strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = ''; +App::$strings['This is required for message delivery to work.'] = ''; +App::$strings['PHP register_argc_argv'] = ''; +App::$strings['This is not sufficient to upload larger images or files. You should be able to upload at least 2MB (2097152 bytes) at once.'] = ''; +App::$strings['Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once.'] = ''; +App::$strings['You can adjust these settings in the server php.ini file.'] = ''; +App::$strings['PHP upload limits'] = ''; +App::$strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = ''; +App::$strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = ''; +App::$strings['Generate encryption keys'] = ''; +App::$strings['libCurl PHP module'] = ''; +App::$strings['GD graphics PHP module'] = ''; +App::$strings['OpenSSL PHP module'] = ''; +App::$strings['PDO database PHP module'] = ''; +App::$strings['mb_string PHP module'] = ''; +App::$strings['xml PHP module'] = ''; +App::$strings['zip PHP module'] = ''; +App::$strings['Apache mod_rewrite module'] = ''; +App::$strings['Error: Apache webserver mod-rewrite module is required but not installed.'] = ''; +App::$strings['exec'] = ''; +App::$strings['Error: exec is required but is either not installed or has been disabled in php.ini'] = ''; +App::$strings['shell_exec'] = ''; +App::$strings['Error: shell_exec is required but is either not installed or has been disabled in php.ini'] = ''; +App::$strings['Error: libCURL PHP module required but not installed.'] = ''; +App::$strings['Error: GD PHP module with JPEG support or ImageMagick graphics library required but not installed.'] = ''; +App::$strings['Error: openssl PHP module required but not installed.'] = ''; +App::$strings['Error: PDO database PHP module missing a driver for either mysql or pgsql.'] = ''; +App::$strings['Error: PDO database PHP module required but not installed.'] = ''; +App::$strings['Error: mb_string PHP module required but not installed.'] = ''; +App::$strings['Error: xml PHP module required for DAV but not installed.'] = ''; +App::$strings['Error: zip PHP module required but not installed.'] = ''; +App::$strings['.htconfig.php is writable'] = ''; +App::$strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = ''; +App::$strings['This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.'] = ''; +App::$strings['Please see install/INSTALL.txt for additional information.'] = ''; +App::$strings['This software uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.'] = ''; +App::$strings['In order to store these compiled templates, the web server needs to have write access to the directory %s under the top level web folder.'] = ''; +App::$strings['Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.'] = ''; +App::$strings['Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains.'] = ''; +App::$strings['%s is writable'] = ''; +App::$strings['This software uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the top level web folder'] = ''; +App::$strings['store is writable'] = ''; +App::$strings['SSL certificate cannot be validated. Fix certificate or disable https access to this site.'] = ''; +App::$strings['If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!'] = ''; +App::$strings['This restriction is incorporated because public posts from you may for example contain references to images on your own hub.'] = ''; +App::$strings['If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues.'] = ''; +App::$strings['This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement.'] = ''; +App::$strings['Providers are available that issue free certificates which are browser-valid.'] = ''; +App::$strings['If you are confident that the certificate is valid and signed by a trusted authority, check to see if you have failed to install an intermediate cert. These are not normally required by browsers, but are required for server-to-server communications.'] = ''; +App::$strings['SSL certificate validation'] = ''; +App::$strings['Url rewrite in .htaccess is not working. Check your server configuration.Test: '] = ''; +App::$strings['Url rewrite is working'] = ''; +App::$strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = ''; +App::$strings['Errors encountered creating database tables.'] = ''; +App::$strings['

      What next?

      '] = ''; +App::$strings['IMPORTANT: You will need to [manually] setup a scheduled task for the poller.'] = ''; +App::$strings['Profile not found.'] = ''; +App::$strings['Profile deleted.'] = ''; +App::$strings['Profile-'] = ''; +App::$strings['New profile created.'] = ''; +App::$strings['Profile unavailable to clone.'] = ''; +App::$strings['Profile unavailable to export.'] = ''; +App::$strings['Profile Name is required.'] = ''; +App::$strings['Marital Status'] = ''; +App::$strings['Romantic Partner'] = ''; +App::$strings['Likes'] = ''; +App::$strings['Dislikes'] = ''; +App::$strings['Work/Employment'] = ''; +App::$strings['Religion'] = ''; +App::$strings['Political Views'] = ''; +App::$strings['Gender'] = ''; +App::$strings['Sexual Preference'] = ''; +App::$strings['Homepage'] = ''; +App::$strings['Interests'] = ''; +App::$strings['Profile updated.'] = ''; +App::$strings['Hide your connections list from viewers of this profile'] = ''; +App::$strings['Edit Profile Details'] = ''; +App::$strings['View this profile'] = ''; +App::$strings['Profile Tools'] = ''; +App::$strings['Change cover photo'] = ''; +App::$strings['Create a new profile using these settings'] = ''; +App::$strings['Clone this profile'] = ''; +App::$strings['Delete this profile'] = ''; +App::$strings['Add profile things'] = ''; +App::$strings['Personal'] = ''; +App::$strings['Relationship'] = ''; +App::$strings['Miscellaneous'] = ''; +App::$strings['Import profile from file'] = ''; +App::$strings['Export profile to file'] = ''; +App::$strings['Your gender'] = ''; +App::$strings['Marital status'] = ''; +App::$strings['Sexual preference'] = ''; +App::$strings['Profile name'] = ''; +App::$strings['Your full name'] = ''; +App::$strings['Title/Description'] = ''; +App::$strings['Street address'] = ''; +App::$strings['Locality/City'] = ''; +App::$strings['Region/State'] = ''; +App::$strings['Postal/Zip code'] = ''; +App::$strings['Who (if applicable)'] = ''; +App::$strings['Examples: cathy123, Cathy Williams, cathy@example.com'] = ''; +App::$strings['Since (date)'] = ''; +App::$strings['Tell us about yourself'] = ''; +App::$strings['Homepage URL'] = ''; +App::$strings['Hometown'] = ''; +App::$strings['Political views'] = ''; +App::$strings['Religious views'] = ''; +App::$strings['Keywords used in directory listings'] = ''; +App::$strings['Example: fishing photography software'] = ''; +App::$strings['Musical interests'] = ''; +App::$strings['Books, literature'] = ''; +App::$strings['Television'] = ''; +App::$strings['Film/Dance/Culture/Entertainment'] = ''; +App::$strings['Hobbies/Interests'] = ''; +App::$strings['Love/Romance'] = ''; +App::$strings['School/Education'] = ''; +App::$strings['Contact information and social networks'] = ''; +App::$strings['My other channels'] = ''; +App::$strings['Communications'] = ''; +App::$strings[' and '] = ''; +App::$strings[', '] = ''; +App::$strings['public profile'] = ''; +App::$strings["%1\$s changed %2\$s to “%3\$s”"] = ''; +App::$strings["Visit %1\$s's %2\$s"] = ''; +App::$strings["%1\$s has an updated %2\$s, changing %3\$s."] = ''; +App::$strings['Currently Male'] = ''; +App::$strings['Currently Female'] = ''; +App::$strings['Mostly Male'] = ''; +App::$strings['Mostly Female'] = ''; +App::$strings['Transgender'] = ''; +App::$strings['Intersex'] = ''; +App::$strings['Transsexual'] = ''; +App::$strings['Hermaphrodite'] = ''; +App::$strings['Undecided'] = ''; +App::$strings['Males'] = ''; +App::$strings['Females'] = ''; +App::$strings['Gay'] = ''; +App::$strings['Lesbian'] = ''; +App::$strings['No Preference'] = ''; +App::$strings['Bisexual'] = ''; +App::$strings['Autosexual'] = ''; +App::$strings['Abstinent'] = ''; +App::$strings['Virgin'] = ''; +App::$strings['Deviant'] = ''; +App::$strings['Fetish'] = ''; +App::$strings['Oodles'] = ''; +App::$strings['Nonsexual'] = ''; +App::$strings['Single'] = ''; +App::$strings['Lonely'] = ''; +App::$strings['Available'] = ''; +App::$strings['Unavailable'] = ''; +App::$strings['Has crush'] = ''; +App::$strings['Infatuated'] = ''; +App::$strings['Dating'] = ''; +App::$strings['Unfaithful'] = ''; +App::$strings['Sex Addict'] = ''; +App::$strings['Friends/Benefits'] = ''; +App::$strings['Casual'] = ''; +App::$strings['Engaged'] = ''; +App::$strings['Married'] = ''; +App::$strings['Imaginarily married'] = ''; +App::$strings['Partners'] = ''; +App::$strings['Cohabiting'] = ''; +App::$strings['Common law'] = ''; +App::$strings['Happy'] = ''; +App::$strings['Not looking'] = ''; +App::$strings['Swinger'] = ''; +App::$strings['Betrayed'] = ''; +App::$strings['Separated'] = ''; +App::$strings['Unstable'] = ''; +App::$strings['Divorced'] = ''; +App::$strings['Imaginarily divorced'] = ''; +App::$strings['Widowed'] = ''; +App::$strings['Uncertain'] = ''; +App::$strings["It's complicated"] = ''; +App::$strings["Don't care"] = ''; +App::$strings['Ask me'] = ''; +App::$strings['Poke somebody in your addressbook'] = ''; +App::$strings['Poke somebody'] = ''; +App::$strings['Poke/Prod'] = ''; +App::$strings['Poke, prod or do other things to somebody'] = ''; +App::$strings['Recipient'] = ''; +App::$strings['Choose what you wish to do to recipient'] = ''; +App::$strings['Make this post private'] = ''; +App::$strings['Profile Photos'] = ''; +App::$strings['Shift-reload the page or clear browser cache if the new photo does not display immediately.'] = ''; +App::$strings['Image upload failed.'] = ''; +App::$strings['Unable to process image.'] = ''; +App::$strings['Your default profile photo is visible to anybody on the internet. Profile photos for alternate profiles will inherit the permissions of the profile'] = ''; +App::$strings['Your profile photo is visible to anybody on the internet and may be distributed to other websites.'] = ''; +App::$strings['Use Photo for Profile'] = ''; +App::$strings['Change Profile Photo'] = ''; +App::$strings['Use'] = ''; +App::$strings['Page owner information could not be retrieved.'] = ''; +App::$strings['Album not found.'] = ''; +App::$strings['Delete Album'] = ''; +App::$strings['Delete Photo'] = ''; +App::$strings['Public access denied.'] = ''; +App::$strings['No photos selected'] = ''; +App::$strings['Access to this item is restricted.'] = ''; +App::$strings['%1$.2f MB of %2$.2f MB photo storage used.'] = ''; +App::$strings['%1$.2f MB photo storage used.'] = ''; +App::$strings['Upload Photos'] = ''; +App::$strings['Enter an album name'] = ''; +App::$strings['or select an existing album (doubleclick)'] = ''; +App::$strings['Create a status post for this upload'] = ''; +App::$strings['Description (optional)'] = ''; +App::$strings['Date descending'] = ''; +App::$strings['Date ascending'] = ''; +App::$strings['Name ascending'] = ''; +App::$strings['Add Photos'] = ''; +App::$strings['Sort'] = ''; +App::$strings['Permission denied. Access to this item may be restricted.'] = ''; +App::$strings['Photo not available'] = ''; +App::$strings['Use as profile photo'] = ''; +App::$strings['Use as cover photo'] = ''; +App::$strings['Private Photo'] = ''; +App::$strings['View Full Size'] = ''; +App::$strings['Edit photo'] = ''; +App::$strings['Move photo to album'] = ''; +App::$strings['Enter a new album name'] = ''; +App::$strings['or select an existing one (doubleclick)'] = ''; +App::$strings['Add a Tag'] = ''; +App::$strings['Example: @bob, @Barbara_Jensen, @jim@example.com'] = ''; +App::$strings['Flag as adult in album view'] = ''; +App::$strings['__ctx:title__ Likes'] = ''; +App::$strings['__ctx:title__ Dislikes'] = ''; +App::$strings['__ctx:title__ Attending'] = ''; +App::$strings['__ctx:title__ Not attending'] = ''; +App::$strings['__ctx:title__ Might attend'] = ''; +App::$strings['Photo Tools'] = ''; +App::$strings['In This Photo:'] = ''; +App::$strings['Map'] = ''; +App::$strings['Recent Photos'] = ''; +App::$strings['Invalid profile identifier.'] = ''; +App::$strings['Profile Visibility Editor'] = ''; +App::$strings['Click on a contact to add or remove.'] = ''; +App::$strings['Visible To'] = ''; +App::$strings['Channel removals are not allowed within 48 hours of changing the account password.'] = ''; +App::$strings['Remove This Channel'] = ''; +App::$strings['This channel will be completely removed from this server. '] = ''; +App::$strings['This action is permanent and can not be undone!'] = ''; +App::$strings['Remove Channel'] = ''; +App::$strings['Friend Zoom settings updated.'] = ''; +App::$strings['This app (when installed) presents a slider control in your connection editor and also on your stream page. The slider represents your degree of friendship with each connection. It allows you to zoom in or out and display conversations from only your closest friends or everybody in your stream.'] = ''; +App::$strings['The number below represents the default maximum slider position for your stream page as a percentage.'] = ''; +App::$strings['Default friend zoom in/out'] = ''; +App::$strings['Refresh'] = ''; +App::$strings['Friend Zoom Settings'] = ''; +App::$strings['Connection added.'] = ''; +App::$strings['Welcome to %s'] = ''; +App::$strings['This site is not a directory server'] = ''; +App::$strings['Please login.'] = ''; +App::$strings['Account removals are not allowed within 48 hours of changing the account password.'] = ''; +App::$strings['Remove This Account'] = ''; +App::$strings['This account and all its channels will be completely removed from this server. '] = ''; +App::$strings['Remove Account'] = ''; +App::$strings['Authentication failed.'] = ''; +App::$strings['Remote Authentication'] = ''; +App::$strings['Enter your channel address (e.g. channel@example.com)'] = ''; +App::$strings['Authenticate'] = ''; +App::$strings['ActivityPub Probe Diagnostic'] = ''; +App::$strings['Object URL'] = ''; +App::$strings['Authenticated fetch'] = ''; +App::$strings['This app provides a simple personal and task list.'] = ''; +App::$strings['No service class restrictions found.'] = ''; +App::$strings['Not valid email.'] = ''; +App::$strings['Protected email address. Cannot change to that email.'] = ''; +App::$strings['System failure storing new email. Please try again.'] = ''; +App::$strings['Password verification failed.'] = ''; +App::$strings['Passwords do not match. Password unchanged.'] = ''; +App::$strings['Empty passwords are not allowed. Password unchanged.'] = ''; +App::$strings['Password changed.'] = ''; +App::$strings['Password update failed. Please try again.'] = ''; +App::$strings['Account Settings'] = ''; +App::$strings['Current Password'] = ''; +App::$strings['Enter New Password'] = ''; +App::$strings['Confirm New Password'] = ''; +App::$strings['Leave password fields blank unless changing'] = ''; +App::$strings['Email Address:'] = ''; +App::$strings['Remove this account including all its channels'] = ''; +App::$strings['Affinity Slider settings updated.'] = ''; +App::$strings['No feature settings configured'] = ''; +App::$strings['Default maximum affinity level'] = ''; +App::$strings['0-99 default 99'] = ''; +App::$strings['Default minimum affinity level'] = ''; +App::$strings['0-99 - default 0'] = ''; +App::$strings['Affinity Slider Settings'] = ''; +App::$strings['Addon Settings'] = ''; +App::$strings['Please save/submit changes to any panel before opening another.'] = ''; +App::$strings['Activity Settings'] = ''; +App::$strings['Search by Date'] = ''; +App::$strings['Ability to select posts by date ranges'] = ''; +App::$strings['Saved Searches'] = ''; +App::$strings['Save search terms for re-use'] = ''; +App::$strings['Alternate Stream Order'] = ''; +App::$strings['Ability to order the stream by last post date, last comment date or unthreaded activities'] = ''; +App::$strings['Contact Filter'] = ''; +App::$strings['Ability to display only posts of a selected contact'] = ''; +App::$strings['Forum Filter'] = ''; +App::$strings['Ability to display only posts of a specific forum'] = ''; +App::$strings['Personal Posts Filter'] = ''; +App::$strings["Ability to display only posts that you've interacted on"] = ''; +App::$strings['Affinity Tool'] = ''; +App::$strings['Filter stream activity by depth of relationships'] = ''; +App::$strings['Show friend and connection suggestions'] = ''; +App::$strings['Connection Filtering'] = ''; +App::$strings['Filter incoming posts from connections based on keywords/content'] = ''; +App::$strings['Name is required'] = ''; +App::$strings['Key and Secret are required'] = ''; +App::$strings['Add application'] = ''; +App::$strings['Name of application'] = ''; +App::$strings['Consumer Key'] = ''; +App::$strings['Automatically generated - change if desired. Max length 20'] = ''; +App::$strings['Consumer Secret'] = ''; +App::$strings['Redirect'] = ''; +App::$strings['Redirect URI - leave blank unless your application specifically requires this'] = ''; +App::$strings['Icon url'] = ''; +App::$strings['Optional'] = ''; +App::$strings['Application not found.'] = ''; +App::$strings['Connected Apps'] = ''; +App::$strings['Client key starts with'] = ''; +App::$strings['No name'] = ''; +App::$strings['Remove authorization'] = ''; +App::$strings['Permission Name is required.'] = ''; +App::$strings['Permission category saved.'] = ''; +App::$strings['Use this form to create permission rules for various classes of people or connections.'] = ''; +App::$strings['Permission Name'] = ''; +App::$strings['This channel is limited to %d tokens'] = ''; +App::$strings['Name and Password are required.'] = ''; +App::$strings['Token saved.'] = ''; +App::$strings['Use this form to create temporary access identifiers to share things with non-members. These identities may be used in Access Control Lists and visitors may login using these credentials to access private content.'] = ''; +App::$strings['You may also provide dropbox style access links to friends and associates by adding the Login Password to any specific site URL as shown. Examples:'] = ''; +App::$strings['Guest Access Tokens'] = ''; +App::$strings['Login Name'] = ''; +App::$strings['Login Password'] = ''; +App::$strings['Expires (yyyy-mm-dd)'] = ''; +App::$strings['Additional Features'] = ''; +App::$strings['ID and Secret are required'] = ''; +App::$strings['Add OAuth2 application'] = ''; +App::$strings['Consumer ID'] = ''; +App::$strings['Grant Types'] = ''; +App::$strings['leave blank unless your application specifically requires this'] = ''; +App::$strings['Authorization scope'] = ''; +App::$strings['OAuth2 Application not found.'] = ''; +App::$strings['Connected OAuth2 Apps'] = ''; +App::$strings['%s - (Experimental)'] = ''; +App::$strings['Display Settings'] = ''; +App::$strings['Theme Settings'] = ''; +App::$strings['Custom Theme Settings'] = ''; +App::$strings['Content Settings'] = ''; +App::$strings['Display Theme:'] = ''; +App::$strings['Select scheme'] = ''; +App::$strings['Preload images before rendering the page'] = ''; +App::$strings['The subjective page load time will be longer but the page will be ready when displayed'] = ''; +App::$strings['Enable user zoom on mobile devices'] = ''; +App::$strings['Update browser every xx seconds'] = ''; +App::$strings['Minimum of 10 seconds, no maximum'] = ''; +App::$strings['Maximum number of conversations to load at any time:'] = ''; +App::$strings['Maximum of 100 items'] = ''; +App::$strings['Show emoticons (smilies) as images'] = ''; +App::$strings['Provide channel menu in navigation bar'] = ''; +App::$strings['Default: channel menu located in app menu'] = ''; +App::$strings['System Page Layout Editor - (advanced)'] = ''; +App::$strings['Channel page max height of content (in pixels)'] = ''; +App::$strings['click to expand content exceeding this height'] = ''; +App::$strings['Stream page max height of content (in pixels)'] = ''; +App::$strings['Nobody except yourself'] = ''; +App::$strings['Only those you specifically allow'] = ''; +App::$strings['Approved connections'] = ''; +App::$strings['Any connections'] = ''; +App::$strings['Anybody on this website'] = ''; +App::$strings['Anybody in this network'] = ''; +App::$strings['Anybody authenticated'] = ''; +App::$strings['Anybody on the internet'] = ''; +App::$strings['Publish your profile in the network directory'] = ''; +App::$strings['Allow us to suggest you as a potential friend to new members?'] = ''; +App::$strings['or'] = ''; +App::$strings['Your channel address is'] = ''; +App::$strings['Friends using compatible applications can use this address to connect with you.'] = ''; +App::$strings['Your files/photos are accessible as a network drive at'] = ''; +App::$strings['(Windows)'] = ''; +App::$strings['(other platforms)'] = ''; +App::$strings['Automatic membership approval'] = ''; +App::$strings['Friend-of-friend conversations'] = ''; +App::$strings['Import public third-party conversations in which your connections participate.'] = ''; +App::$strings['Enable ActivityPub protocol'] = ''; +App::$strings['ActivityPub'] = ''; +App::$strings['ActivityPub is an emerging internet standard for social communications. '] = ''; +App::$strings['It provides access to a large and growing number of existing users and supported software applications, however it is still evolving. If this is enabled you will obtain much greater social reach, however it is likely you will also encounter compatibility issues. '] = ''; +App::$strings['Channel Settings'] = ''; +App::$strings['Basic Settings'] = ''; +App::$strings['Full name'] = ''; +App::$strings['Your timezone'] = ''; +App::$strings['This is important for showing the correct time on shared events'] = ''; +App::$strings['Default post location'] = ''; +App::$strings['Optional geographical location to display on your posts'] = ''; +App::$strings['Obtain post location from your web browser or device'] = ''; +App::$strings['Adult content'] = ''; +App::$strings['Enable to indicate if this channel frequently or regularly publishes adult content. (Please also tag any adult material and/or nudity with #NSFW)'] = ''; +App::$strings['Security and Privacy'] = ''; +App::$strings['Your permissions are already configured. Click to view/adjust'] = ''; +App::$strings['Hide my online presence'] = ''; +App::$strings['Prevents displaying in your profile that you are online'] = ''; +App::$strings['Allow others to view your friends and connections'] = ''; +App::$strings['Allow others to tag your posts'] = ''; +App::$strings['Often used by the community to retro-actively flag inappropriate content'] = ''; +App::$strings['Channel Permission Limits'] = ''; +App::$strings['Expire other channel content after this many days'] = ''; +App::$strings['0 or blank to use the website limit.'] = ''; +App::$strings['This website expires after %d days.'] = ''; +App::$strings['This website does not expire imported content.'] = ''; +App::$strings['The website limit takes precedence if lower than your limit.'] = ''; +App::$strings['Maximum Friend Requests/Day:'] = ''; +App::$strings['May reduce spam activity'] = ''; +App::$strings['Default Access List'] = ''; +App::$strings['Use my default audience setting for the type of object published'] = ''; +App::$strings['Profile to assign new connections'] = ''; +App::$strings['Default Permissions Group'] = ''; +App::$strings['Maximum private messages per day from unknown people:'] = ''; +App::$strings['Useful to reduce spamming'] = ''; +App::$strings['By default post a status message when:'] = ''; +App::$strings['accepting a friend request'] = ''; +App::$strings['joining a forum/community'] = ''; +App::$strings['making an interesting profile change'] = ''; +App::$strings['Send a notification email when:'] = ''; +App::$strings['You receive a connection request'] = ''; +App::$strings['Someone writes on your profile wall'] = ''; +App::$strings['Someone writes a followup comment'] = ''; +App::$strings['You are tagged in a post'] = ''; +App::$strings['Someone likes your post/comment'] = ''; +App::$strings['Show visual notifications including:'] = ''; +App::$strings['Unseen stream activity'] = ''; +App::$strings['Unseen channel activity'] = ''; +App::$strings['Upcoming events'] = ''; +App::$strings['Events today'] = ''; +App::$strings['Upcoming birthdays'] = ''; +App::$strings['Not available in all themes'] = ''; +App::$strings['System (personal) notifications'] = ''; +App::$strings['System info messages'] = ''; +App::$strings['Recommended'] = ''; +App::$strings['System critical alerts'] = ''; +App::$strings['New connections'] = ''; +App::$strings['System Registrations'] = ''; +App::$strings['Unseen public activity'] = ''; +App::$strings['Unseen likes and dislikes'] = ''; +App::$strings['Unseen forum posts'] = ''; +App::$strings['Reported content'] = ''; +App::$strings['Email notification hub (hostname)'] = ''; +App::$strings['If your channel is mirrored to multiple locations, set this to your preferred location. This will prevent duplicate email notifications. Example: %s'] = ''; +App::$strings['Show new wall posts, private messages and connections under Notices'] = ''; +App::$strings['Accept messages from strangers which mention me'] = ''; +App::$strings['This setting supercedes normal permissions'] = ''; +App::$strings['Accept messages from strangers which include any of the following hashtags'] = ''; +App::$strings['comma separated, do not include the #'] = ''; +App::$strings['Notify me of events this many days in advance'] = ''; +App::$strings['Must be greater than 0'] = ''; +App::$strings['Date and time'] = ''; +App::$strings['This section is reserved for use by optional addons and apps to provide additional settings.'] = ''; +App::$strings['Advanced Account/Page Type Settings'] = ''; +App::$strings['Change the behaviour of this account for special situations'] = ''; +App::$strings['Default photo upload folder name'] = ''; +App::$strings['%Y - current year, %m - current month'] = ''; +App::$strings['Default file upload folder name'] = ''; +App::$strings['Personal menu to display in your channel pages'] = ''; +App::$strings['Remove this channel.'] = ''; +App::$strings['Mentions should display'] = ''; +App::$strings['Changes to this setting are applied to new posts/comments only. It is not retroactive.'] = ''; +App::$strings['the channel display name [example: @Barbara Jenkins]'] = ''; +App::$strings['the channel nickname [example: @barbara1976]'] = ''; +App::$strings['combined [example: @Barbara Jenkins (barbara1976)]'] = ''; +App::$strings['no preference, use the system default'] = ''; +App::$strings['Calendar week begins on'] = ''; +App::$strings['This varies by country/culture'] = ''; +App::$strings['Sunday'] = ''; +App::$strings['Monday'] = ''; +App::$strings['Tuesday'] = ''; +App::$strings['Wednesday'] = ''; +App::$strings['Thursday'] = ''; +App::$strings['Friday'] = ''; +App::$strings['Saturday'] = ''; +App::$strings['Items tagged with: %s'] = ''; +App::$strings['Search results for: %s'] = ''; +App::$strings["%1\$s is following %2\$s's %3\$s"] = ''; +App::$strings["%1\$s stopped following %2\$s's %3\$s"] = ''; +App::$strings['Files: shared with me'] = ''; +App::$strings['NEW'] = ''; +App::$strings['Size'] = ''; +App::$strings['Last Modified'] = ''; +App::$strings['Remove all files'] = ''; +App::$strings['Remove this file'] = ''; +App::$strings['About this site'] = ''; +App::$strings['Site Name'] = ''; +App::$strings['Administrator'] = ''; +App::$strings['Software and Project information'] = ''; +App::$strings["This site is powered by \$Projectname"] = ''; +App::$strings['Federated and decentralised networking and identity services provided by Zot'] = ''; +App::$strings['Federated transport protocols:'] = ''; +App::$strings['Version %s'] = ''; +App::$strings['Project homepage'] = ''; +App::$strings['Developer homepage'] = ''; +App::$strings['Export Channel'] = ''; +App::$strings['Export your basic channel information to a file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new server hub, but does not contain your content.'] = ''; +App::$strings['Export Content'] = ''; +App::$strings['Export your channel information and recent content to a JSON backup that can be restored or imported to another server hub. This backs up all of your connections, permissions, profile data and several months of posts. This file may be VERY large. Please be patient - it may take several minutes for this download to begin.'] = ''; +App::$strings['Export your posts from a given year.'] = ''; +App::$strings['You may also export your posts and conversations for a particular year or month. Adjust the date in your browser location bar to select other dates. If the export fails (possibly due to memory exhaustion on your server hub), please try again selecting a more limited date range.'] = ''; +App::$strings["To select all posts for a given year, such as this year, visit %2\$s"] = ''; +App::$strings["To select all posts for a given month, such as January of this year, visit %2\$s"] = ''; +App::$strings["These content files may be imported or restored by visiting %2\$s on any site containing your channel. For best results please import or restore these in date order (oldest first)."] = ''; +App::$strings['Failed to create source. No channel selected.'] = ''; +App::$strings['Source created.'] = ''; +App::$strings['Source updated.'] = ''; +App::$strings['*'] = ''; +App::$strings['Manage remote sources of content for your channel.'] = ''; +App::$strings['New Source'] = ''; +App::$strings['Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'] = ''; +App::$strings['Only import content with these words (one per line)'] = ''; +App::$strings['Leave blank to import all public content'] = ''; +App::$strings['Channel Name'] = ''; +App::$strings['Add the following categories to posts imported from this source (comma separated)'] = ''; +App::$strings['Resend posts with this channel as author'] = ''; +App::$strings['Copyrights may apply'] = ''; +App::$strings['Source not found.'] = ''; +App::$strings['Edit Source'] = ''; +App::$strings['Delete Source'] = ''; +App::$strings['Source removed'] = ''; +App::$strings['Unable to remove source.'] = ''; +App::$strings['Article'] = ''; +App::$strings['Item has been removed.'] = ''; +App::$strings['Post not found.'] = ''; +App::$strings['comment'] = ''; +App::$strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = ''; +App::$strings['Tag removed'] = ''; +App::$strings['Remove Item Tag'] = ''; +App::$strings['Select a tag to remove: '] = ''; +App::$strings['No default suggestions were found.'] = ''; +App::$strings['%d rating'] = [ + 0 => '', + 1 => '', ]; -App::$strings["Gender: "] = ""; -App::$strings["Status: "] = ""; -App::$strings["Homepage: "] = ""; -App::$strings["Description:"] = ""; -App::$strings["Keywords: "] = ""; -App::$strings["Don't suggest"] = ""; -App::$strings["Common connections (estimated):"] = ""; -App::$strings["Global Directory"] = ""; -App::$strings["Local Directory"] = ""; -App::$strings["Finding:"] = ""; -App::$strings["Channel Suggestions"] = ""; -App::$strings["next page"] = ""; -App::$strings["previous page"] = ""; -App::$strings["Sort options"] = ""; -App::$strings["Alphabetic"] = ""; -App::$strings["Reverse Alphabetic"] = ""; -App::$strings["Newest to Oldest"] = ""; -App::$strings["Oldest to Newest"] = ""; -App::$strings["No entries (some entries may be hidden)."] = ""; -App::$strings["This directory server requires an access token"] = ""; -App::$strings["Xchan Lookup"] = ""; -App::$strings["Lookup xchan beginning with (or webbie): "] = ""; -App::$strings["This app allows you to add categories to posts and events."] = ""; -App::$strings["Zotfinger Diagnostic"] = ""; -App::$strings["Lookup URL"] = ""; -App::$strings["This app provides a displayable map when viewing detail of photos that contain location information."] = ""; -App::$strings["This app is currently installed."] = ""; -App::$strings["No connections."] = ""; -App::$strings["Visit %1\$s's profile [%2\$s]"] = ""; -App::$strings["View Connections"] = ""; -App::$strings["This app (when installed) displays a small number of friend suggestions on selected pages or you can run the app to display a full list of channel suggestions."] = ""; -App::$strings["This app allows you to authorize mobile apps using OAuth and OpenID to access your channel."] = ""; -App::$strings["Content Filter settings updated."] = ""; -App::$strings["This app (when installed) allows you to filter incoming content from all sources or from specific connections. The filtering may be based on words, tags, regular expressions, or language"] = ""; -App::$strings["The settings on this page apply to all incoming content. To edit the settings for individual connetions, see the similar settings on the Connection Edit page for that connection."] = ""; -App::$strings["words one per line or #tags, \$categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts"] = ""; -App::$strings["Content Filter Settings"] = ""; -App::$strings["This app allows you to set an optional publish date/time for posts, which may be in the future. This must be at least ten minutes into the future to initiate delayed publishing. The posts will be published automatically after that time has passed. Once installed, a new button will appear in the post editor to set the date/time."] = ""; -App::$strings["Added by Superblock"] = ""; -App::$strings["superblock settings updated"] = ""; -App::$strings["Blocked channels"] = ""; -App::$strings["No channels currently blocked"] = ""; -App::$strings["Blocked servers"] = ""; -App::$strings["No servers currently blocked"] = ""; -App::$strings["Manage Blocks"] = ""; -App::$strings["parent"] = ""; -App::$strings["Principal"] = ""; -App::$strings["Addressbook"] = ""; -App::$strings["Schedule Inbox"] = ""; -App::$strings["Schedule Outbox"] = ""; -App::$strings["Total"] = ""; -App::$strings["Shared"] = ""; -App::$strings["Add Files"] = ""; -App::$strings["Type"] = ""; -App::$strings["You are using %1\$s of your available file storage."] = ""; -App::$strings["You are using %1\$s of %2\$s available file storage. (%3\$s%)"] = ""; -App::$strings["WARNING:"] = ""; -App::$strings["Create new folder"] = ""; -App::$strings["Upload file"] = ""; -App::$strings["Drop files here to immediately upload"] = ""; -App::$strings["Added by superblock"] = ""; -App::$strings["Member registrations waiting for confirmation"] = ""; -App::$strings["Inspect queue"] = ""; -App::$strings["DB updates"] = ""; -App::$strings["Admin"] = ""; -App::$strings["Addon Features"] = ""; -App::$strings["Everything"] = ""; -App::$strings["App Collections"] = ""; -App::$strings["Installed apps"] = ""; -App::$strings["Archives"] = ""; -App::$strings["Bookmarked Chatrooms"] = ""; -App::$strings["Overview"] = ""; -App::$strings["Chat Members"] = ""; -App::$strings["Click to show more"] = ""; -App::$strings["Events Tools"] = ""; -App::$strings["Export Calendar"] = ""; -App::$strings["Import Calendar"] = ""; -App::$strings["You have %1$.0f of %2$.0f allowed connections."] = ""; -App::$strings["Add New Connection"] = ""; -App::$strings["Enter channel address"] = ""; -App::$strings["Examples: bob@example.com, https://example.com/barbara"] = ""; -App::$strings["Account settings"] = ""; -App::$strings["Channel settings"] = ""; -App::$strings["Display settings"] = ""; -App::$strings["Manage locations"] = ""; -App::$strings["Export channel"] = ""; -App::$strings["OAuth1 apps"] = ""; -App::$strings["Client apps"] = ""; -App::$strings["HQ Control Panel"] = ""; -App::$strings["Create a new post"] = ""; -App::$strings["Private Mail Menu"] = ""; -App::$strings["Combined View"] = ""; -App::$strings["Inbox"] = ""; -App::$strings["Outbox"] = ""; -App::$strings["New Message"] = ""; -App::$strings["photo/image"] = ""; -App::$strings["Rating Tools"] = ""; -App::$strings["Rate Me"] = ""; -App::$strings["View Ratings"] = ""; -App::$strings["Remove term"] = ""; -App::$strings["Commented Date"] = ""; -App::$strings["Order by last commented date"] = ""; -App::$strings["Posted Date"] = ""; -App::$strings["Order by last posted date"] = ""; -App::$strings["Date Unthreaded"] = ""; -App::$strings["Order unthreaded by date"] = ""; -App::$strings["Suggested Chatrooms"] = ""; -App::$strings["Tags"] = ""; -App::$strings["Common Connections"] = ""; -App::$strings["View all %d common connections"] = ""; -App::$strings["Saved Folders"] = ""; -App::$strings["%d invitation available"] = [ - 0 => "", - 1 => "", +App::$strings['Gender: '] = ''; +App::$strings['Status: '] = ''; +App::$strings['Homepage: '] = ''; +App::$strings['Description:'] = ''; +App::$strings['Keywords: '] = ''; +App::$strings["Don't suggest"] = ''; +App::$strings['Common connections (estimated):'] = ''; +App::$strings['Global Directory'] = ''; +App::$strings['Local Directory'] = ''; +App::$strings['Finding:'] = ''; +App::$strings['Channel Suggestions'] = ''; +App::$strings['next page'] = ''; +App::$strings['previous page'] = ''; +App::$strings['Sort options'] = ''; +App::$strings['Alphabetic'] = ''; +App::$strings['Reverse Alphabetic'] = ''; +App::$strings['Newest to Oldest'] = ''; +App::$strings['Oldest to Newest'] = ''; +App::$strings['No entries (some entries may be hidden).'] = ''; +App::$strings['This directory server requires an access token'] = ''; +App::$strings['Xchan Lookup'] = ''; +App::$strings['Lookup xchan beginning with (or webbie): '] = ''; +App::$strings['This app allows you to add categories to posts and events.'] = ''; +App::$strings['Zotfinger Diagnostic'] = ''; +App::$strings['Lookup URL'] = ''; +App::$strings['This app provides a displayable map when viewing detail of photos that contain location information.'] = ''; +App::$strings['This app is currently installed.'] = ''; +App::$strings['No connections.'] = ''; +App::$strings["Visit %1\$s's profile [%2\$s]"] = ''; +App::$strings['View Connections'] = ''; +App::$strings['This app (when installed) displays a small number of friend suggestions on selected pages or you can run the app to display a full list of channel suggestions.'] = ''; +App::$strings['This app allows you to authorize mobile apps using OAuth and OpenID to access your channel.'] = ''; +App::$strings['Content Filter settings updated.'] = ''; +App::$strings['This app (when installed) allows you to filter incoming content from all sources or from specific connections. The filtering may be based on words, tags, regular expressions, or language'] = ''; +App::$strings['The settings on this page apply to all incoming content. To edit the settings for individual connetions, see the similar settings on the Connection Edit page for that connection.'] = ''; +App::$strings["words one per line or #tags, \$categories, /patterns/, lang=xx, lang!=xx - leave blank to import all posts"] = ''; +App::$strings['Content Filter Settings'] = ''; +App::$strings['This app allows you to set an optional publish date/time for posts, which may be in the future. This must be at least ten minutes into the future to initiate delayed publishing. The posts will be published automatically after that time has passed. Once installed, a new button will appear in the post editor to set the date/time.'] = ''; +App::$strings['Added by Superblock'] = ''; +App::$strings['superblock settings updated'] = ''; +App::$strings['Blocked channels'] = ''; +App::$strings['No channels currently blocked'] = ''; +App::$strings['Blocked servers'] = ''; +App::$strings['No servers currently blocked'] = ''; +App::$strings['Manage Blocks'] = ''; +App::$strings['parent'] = ''; +App::$strings['Principal'] = ''; +App::$strings['Addressbook'] = ''; +App::$strings['Schedule Inbox'] = ''; +App::$strings['Schedule Outbox'] = ''; +App::$strings['Total'] = ''; +App::$strings['Shared'] = ''; +App::$strings['Add Files'] = ''; +App::$strings['Type'] = ''; +App::$strings["You are using %1\$s of your available file storage."] = ''; +App::$strings["You are using %1\$s of %2\$s available file storage. (%3\$s%)"] = ''; +App::$strings['WARNING:'] = ''; +App::$strings['Create new folder'] = ''; +App::$strings['Upload file'] = ''; +App::$strings['Drop files here to immediately upload'] = ''; +App::$strings['Added by superblock'] = ''; +App::$strings['Member registrations waiting for confirmation'] = ''; +App::$strings['Inspect queue'] = ''; +App::$strings['DB updates'] = ''; +App::$strings['Admin'] = ''; +App::$strings['Addon Features'] = ''; +App::$strings['Everything'] = ''; +App::$strings['App Collections'] = ''; +App::$strings['Installed apps'] = ''; +App::$strings['Archives'] = ''; +App::$strings['Bookmarked Chatrooms'] = ''; +App::$strings['Overview'] = ''; +App::$strings['Chat Members'] = ''; +App::$strings['Click to show more'] = ''; +App::$strings['Events Tools'] = ''; +App::$strings['Export Calendar'] = ''; +App::$strings['Import Calendar'] = ''; +App::$strings['You have %1$.0f of %2$.0f allowed connections.'] = ''; +App::$strings['Add New Connection'] = ''; +App::$strings['Enter channel address'] = ''; +App::$strings['Examples: bob@example.com, https://example.com/barbara'] = ''; +App::$strings['Account settings'] = ''; +App::$strings['Channel settings'] = ''; +App::$strings['Display settings'] = ''; +App::$strings['Manage locations'] = ''; +App::$strings['Export channel'] = ''; +App::$strings['OAuth1 apps'] = ''; +App::$strings['Client apps'] = ''; +App::$strings['HQ Control Panel'] = ''; +App::$strings['Create a new post'] = ''; +App::$strings['Private Mail Menu'] = ''; +App::$strings['Combined View'] = ''; +App::$strings['Inbox'] = ''; +App::$strings['Outbox'] = ''; +App::$strings['New Message'] = ''; +App::$strings['photo/image'] = ''; +App::$strings['Rating Tools'] = ''; +App::$strings['Rate Me'] = ''; +App::$strings['View Ratings'] = ''; +App::$strings['Remove term'] = ''; +App::$strings['Commented Date'] = ''; +App::$strings['Order by last commented date'] = ''; +App::$strings['Posted Date'] = ''; +App::$strings['Order by last posted date'] = ''; +App::$strings['Date Unthreaded'] = ''; +App::$strings['Order unthreaded by date'] = ''; +App::$strings['Suggested Chatrooms'] = ''; +App::$strings['Tags'] = ''; +App::$strings['Common Connections'] = ''; +App::$strings['View all %d common connections'] = ''; +App::$strings['Saved Folders'] = ''; +App::$strings['%d invitation available'] = [ + 0 => '', + 1 => '', ]; -App::$strings["Find Channels"] = ""; -App::$strings["Enter name or interest"] = ""; -App::$strings["Connect/Follow"] = ""; -App::$strings["Examples: Robert Morgenstein, Fishing"] = ""; -App::$strings["Advanced example: name=fred and country=iceland"] = ""; -App::$strings["Friend zoom in/out"] = ""; -App::$strings["Ignore/Hide"] = ""; -App::$strings["Suggestions"] = ""; -App::$strings["See more..."] = ""; -App::$strings["New Stream Activity"] = ""; -App::$strings["New Stream Activity Notifications"] = ""; -App::$strings["View your stream activity"] = ""; -App::$strings["Mark all notifications read"] = ""; -App::$strings["Show new posts only"] = ""; -App::$strings["Filter by name"] = ""; -App::$strings["New Home Activity"] = ""; -App::$strings["New Home Activity Notifications"] = ""; -App::$strings["View your home activity"] = ""; -App::$strings["Mark all notifications seen"] = ""; -App::$strings["New Mails"] = ""; -App::$strings["New Mails Notifications"] = ""; -App::$strings["View your private mails"] = ""; -App::$strings["Mark all messages seen"] = ""; -App::$strings["New Events"] = ""; -App::$strings["New Events Notifications"] = ""; -App::$strings["View events"] = ""; -App::$strings["Mark all events seen"] = ""; -App::$strings["New Connections Notifications"] = ""; -App::$strings["View all connections"] = ""; -App::$strings["New Files"] = ""; -App::$strings["New Files Notifications"] = ""; -App::$strings["Notices"] = ""; -App::$strings["View all notices"] = ""; -App::$strings["Mark all notices seen"] = ""; -App::$strings["Groups"] = ""; -App::$strings["New Registrations"] = ""; -App::$strings["New Registrations Notifications"] = ""; -App::$strings["Public Stream Notifications"] = ""; -App::$strings["View the public stream"] = ""; -App::$strings["Sorry, you have got no notifications at the moment"] = ""; -App::$strings["__ctx:widget__ Activity"] = ""; -App::$strings["Profile Creation"] = ""; -App::$strings["Upload profile photo"] = ""; -App::$strings["Upload cover photo"] = ""; -App::$strings["Edit your profile"] = ""; -App::$strings["Find and Connect with others"] = ""; -App::$strings["View the directory"] = ""; -App::$strings["View friend suggestions"] = ""; -App::$strings["Manage your connections"] = ""; -App::$strings["Communicate"] = ""; -App::$strings["View your channel homepage"] = ""; -App::$strings["View your stream"] = ""; -App::$strings["View public stream"] = ""; -App::$strings["New Member Links"] = ""; -App::$strings["Direct Messages"] = ""; -App::$strings["Show direct (private) messages"] = ""; -App::$strings["Personal Posts"] = ""; -App::$strings["Show posts that mention or involve me"] = ""; -App::$strings["Saved Posts"] = ""; -App::$strings["Show posts that I have saved"] = ""; -App::$strings["Show posts that include events"] = ""; -App::$strings["Polls"] = ""; -App::$strings["Show posts that include polls"] = ""; -App::$strings["Show posts related to the %s access list"] = ""; -App::$strings["Show my access lists"] = ""; -App::$strings["Show posts to this group"] = ""; -App::$strings["New post"] = ""; -App::$strings["Show groups"] = ""; -App::$strings["Show posts to this collection"] = ""; -App::$strings["Collections"] = ""; -App::$strings["Show collections"] = ""; -App::$strings["Show posts that I have filed to %s"] = ""; -App::$strings["Show filed post categories"] = ""; -App::$strings["Show posts with hashtag %s"] = ""; -App::$strings["Followed Hashtags"] = ""; -App::$strings["Show followed hashtags"] = ""; -App::$strings["Remove active filter"] = ""; -App::$strings["Stream Filters"] = ""; -App::$strings["Select Channel"] = ""; -App::$strings["Read-write"] = ""; -App::$strings["Read-only"] = ""; -App::$strings["Channel Calendar"] = ""; -App::$strings["Shared CalDAV Calendars"] = ""; -App::$strings["Share this calendar"] = ""; -App::$strings["Calendar name and color"] = ""; -App::$strings["Create new CalDAV calendar"] = ""; -App::$strings["Calendar Name"] = ""; -App::$strings["Calendar Tools"] = ""; -App::$strings["Import calendar"] = ""; -App::$strings["Select a calendar to import to"] = ""; -App::$strings["Addressbooks"] = ""; -App::$strings["Addressbook name"] = ""; -App::$strings["Create new addressbook"] = ""; -App::$strings["Addressbook Name"] = ""; -App::$strings["Addressbook Tools"] = ""; -App::$strings["Import addressbook"] = ""; -App::$strings["Select an addressbook to import to"] = ""; -App::$strings["Delete this item?"] = ""; -App::$strings["%s show less"] = ""; -App::$strings["%s expand"] = ""; -App::$strings["%s collapse"] = ""; -App::$strings["Password too short"] = ""; -App::$strings["Passwords do not match"] = ""; -App::$strings["everybody"] = ""; -App::$strings["Secret Passphrase"] = ""; -App::$strings["Passphrase hint"] = ""; -App::$strings["Notice: Permissions have changed but have not yet been submitted."] = ""; -App::$strings["close all"] = ""; -App::$strings["Nothing new here"] = ""; -App::$strings["Rate This Channel (this is public)"] = ""; -App::$strings["Describe (optional)"] = ""; -App::$strings["Please enter a link URL"] = ""; -App::$strings["Unsaved changes. Are you sure you wish to leave this page?"] = ""; -App::$strings["lovely"] = ""; -App::$strings["wonderful"] = ""; -App::$strings["fantastic"] = ""; -App::$strings["great"] = ""; -App::$strings["Your chosen nickname was either already taken or not valid. Please use our suggestion ("] = ""; -App::$strings[") or enter a new one."] = ""; -App::$strings["Thank you, this nickname is valid."] = ""; -App::$strings["A channel name is required."] = ""; -App::$strings["This is a "] = ""; -App::$strings[" channel name"] = ""; -App::$strings["Pinned"] = ""; -App::$strings["timeago.prefixAgo"] = ""; -App::$strings["timeago.prefixFromNow"] = ""; -App::$strings["timeago.suffixAgo"] = ""; -App::$strings["timeago.suffixFromNow"] = ""; -App::$strings["less than a minute"] = ""; -App::$strings["about a minute"] = ""; -App::$strings["%d minutes"] = ""; -App::$strings["about an hour"] = ""; -App::$strings["about %d hours"] = ""; -App::$strings["a day"] = ""; -App::$strings["%d days"] = ""; -App::$strings["about a month"] = ""; -App::$strings["%d months"] = ""; -App::$strings["about a year"] = ""; -App::$strings["%d years"] = ""; -App::$strings[" "] = ""; -App::$strings["timeago.numbers"] = ""; -App::$strings["January"] = ""; -App::$strings["February"] = ""; -App::$strings["March"] = ""; -App::$strings["April"] = ""; -App::$strings["__ctx:long__ May"] = ""; -App::$strings["June"] = ""; -App::$strings["July"] = ""; -App::$strings["August"] = ""; -App::$strings["September"] = ""; -App::$strings["October"] = ""; -App::$strings["November"] = ""; -App::$strings["December"] = ""; -App::$strings["Jan"] = ""; -App::$strings["Feb"] = ""; -App::$strings["Mar"] = ""; -App::$strings["Apr"] = ""; -App::$strings["__ctx:short__ May"] = ""; -App::$strings["Jun"] = ""; -App::$strings["Jul"] = ""; -App::$strings["Aug"] = ""; -App::$strings["Sep"] = ""; -App::$strings["Oct"] = ""; -App::$strings["Nov"] = ""; -App::$strings["Dec"] = ""; -App::$strings["Sun"] = ""; -App::$strings["Mon"] = ""; -App::$strings["Tue"] = ""; -App::$strings["Wed"] = ""; -App::$strings["Thu"] = ""; -App::$strings["Fri"] = ""; -App::$strings["Sat"] = ""; -App::$strings["__ctx:calendar__ today"] = ""; -App::$strings["__ctx:calendar__ month"] = ""; -App::$strings["__ctx:calendar__ week"] = ""; -App::$strings["__ctx:calendar__ day"] = ""; -App::$strings["__ctx:calendar__ All day"] = ""; -App::$strings["Delegation session ended."] = ""; -App::$strings["Logged out."] = ""; -App::$strings["Email validation is incomplete. Please check your email."] = ""; -App::$strings["Failed authentication"] = ""; -App::$strings["Login failed."] = ""; -App::$strings["Birthday"] = ""; -App::$strings["Age: "] = ""; -App::$strings["YYYY-MM-DD or MM-DD"] = ""; -App::$strings["never"] = ""; -App::$strings["less than a second ago"] = ""; -App::$strings["__ctx:e.g. 22 hours ago, 1 minute ago__ %1\$d %2\$s ago"] = ""; -App::$strings["__ctx:relative_date__ year"] = [ - 0 => "", - 1 => "", +App::$strings['Find Channels'] = ''; +App::$strings['Enter name or interest'] = ''; +App::$strings['Connect/Follow'] = ''; +App::$strings['Examples: Robert Morgenstein, Fishing'] = ''; +App::$strings['Advanced example: name=fred and country=iceland'] = ''; +App::$strings['Friend zoom in/out'] = ''; +App::$strings['Ignore/Hide'] = ''; +App::$strings['Suggestions'] = ''; +App::$strings['See more...'] = ''; +App::$strings['New Stream Activity'] = ''; +App::$strings['New Stream Activity Notifications'] = ''; +App::$strings['View your stream activity'] = ''; +App::$strings['Mark all notifications read'] = ''; +App::$strings['Show new posts only'] = ''; +App::$strings['Filter by name'] = ''; +App::$strings['New Home Activity'] = ''; +App::$strings['New Home Activity Notifications'] = ''; +App::$strings['View your home activity'] = ''; +App::$strings['Mark all notifications seen'] = ''; +App::$strings['New Mails'] = ''; +App::$strings['New Mails Notifications'] = ''; +App::$strings['View your private mails'] = ''; +App::$strings['Mark all messages seen'] = ''; +App::$strings['New Events'] = ''; +App::$strings['New Events Notifications'] = ''; +App::$strings['View events'] = ''; +App::$strings['Mark all events seen'] = ''; +App::$strings['New Connections Notifications'] = ''; +App::$strings['View all connections'] = ''; +App::$strings['New Files'] = ''; +App::$strings['New Files Notifications'] = ''; +App::$strings['Notices'] = ''; +App::$strings['View all notices'] = ''; +App::$strings['Mark all notices seen'] = ''; +App::$strings['Groups'] = ''; +App::$strings['New Registrations'] = ''; +App::$strings['New Registrations Notifications'] = ''; +App::$strings['Public Stream Notifications'] = ''; +App::$strings['View the public stream'] = ''; +App::$strings['Sorry, you have got no notifications at the moment'] = ''; +App::$strings['__ctx:widget__ Activity'] = ''; +App::$strings['Profile Creation'] = ''; +App::$strings['Upload profile photo'] = ''; +App::$strings['Upload cover photo'] = ''; +App::$strings['Edit your profile'] = ''; +App::$strings['Find and Connect with others'] = ''; +App::$strings['View the directory'] = ''; +App::$strings['View friend suggestions'] = ''; +App::$strings['Manage your connections'] = ''; +App::$strings['Communicate'] = ''; +App::$strings['View your channel homepage'] = ''; +App::$strings['View your stream'] = ''; +App::$strings['View public stream'] = ''; +App::$strings['New Member Links'] = ''; +App::$strings['Direct Messages'] = ''; +App::$strings['Show direct (private) messages'] = ''; +App::$strings['Personal Posts'] = ''; +App::$strings['Show posts that mention or involve me'] = ''; +App::$strings['Saved Posts'] = ''; +App::$strings['Show posts that I have saved'] = ''; +App::$strings['Show posts that include events'] = ''; +App::$strings['Polls'] = ''; +App::$strings['Show posts that include polls'] = ''; +App::$strings['Show posts related to the %s access list'] = ''; +App::$strings['Show my access lists'] = ''; +App::$strings['Show posts to this group'] = ''; +App::$strings['New post'] = ''; +App::$strings['Show groups'] = ''; +App::$strings['Show posts to this collection'] = ''; +App::$strings['Collections'] = ''; +App::$strings['Show collections'] = ''; +App::$strings['Show posts that I have filed to %s'] = ''; +App::$strings['Show filed post categories'] = ''; +App::$strings['Show posts with hashtag %s'] = ''; +App::$strings['Followed Hashtags'] = ''; +App::$strings['Show followed hashtags'] = ''; +App::$strings['Remove active filter'] = ''; +App::$strings['Stream Filters'] = ''; +App::$strings['Select Channel'] = ''; +App::$strings['Read-write'] = ''; +App::$strings['Read-only'] = ''; +App::$strings['Channel Calendar'] = ''; +App::$strings['Shared CalDAV Calendars'] = ''; +App::$strings['Share this calendar'] = ''; +App::$strings['Calendar name and color'] = ''; +App::$strings['Create new CalDAV calendar'] = ''; +App::$strings['Calendar Name'] = ''; +App::$strings['Calendar Tools'] = ''; +App::$strings['Import calendar'] = ''; +App::$strings['Select a calendar to import to'] = ''; +App::$strings['Addressbooks'] = ''; +App::$strings['Addressbook name'] = ''; +App::$strings['Create new addressbook'] = ''; +App::$strings['Addressbook Name'] = ''; +App::$strings['Addressbook Tools'] = ''; +App::$strings['Import addressbook'] = ''; +App::$strings['Select an addressbook to import to'] = ''; +App::$strings['Delete this item?'] = ''; +App::$strings['%s show less'] = ''; +App::$strings['%s expand'] = ''; +App::$strings['%s collapse'] = ''; +App::$strings['Password too short'] = ''; +App::$strings['Passwords do not match'] = ''; +App::$strings['everybody'] = ''; +App::$strings['Secret Passphrase'] = ''; +App::$strings['Passphrase hint'] = ''; +App::$strings['Notice: Permissions have changed but have not yet been submitted.'] = ''; +App::$strings['close all'] = ''; +App::$strings['Nothing new here'] = ''; +App::$strings['Rate This Channel (this is public)'] = ''; +App::$strings['Describe (optional)'] = ''; +App::$strings['Please enter a link URL'] = ''; +App::$strings['Unsaved changes. Are you sure you wish to leave this page?'] = ''; +App::$strings['lovely'] = ''; +App::$strings['wonderful'] = ''; +App::$strings['fantastic'] = ''; +App::$strings['great'] = ''; +App::$strings['Your chosen nickname was either already taken or not valid. Please use our suggestion ('] = ''; +App::$strings[') or enter a new one.'] = ''; +App::$strings['Thank you, this nickname is valid.'] = ''; +App::$strings['A channel name is required.'] = ''; +App::$strings['This is a '] = ''; +App::$strings[' channel name'] = ''; +App::$strings['Pinned'] = ''; +App::$strings['timeago.prefixAgo'] = ''; +App::$strings['timeago.prefixFromNow'] = ''; +App::$strings['timeago.suffixAgo'] = ''; +App::$strings['timeago.suffixFromNow'] = ''; +App::$strings['less than a minute'] = ''; +App::$strings['about a minute'] = ''; +App::$strings['%d minutes'] = ''; +App::$strings['about an hour'] = ''; +App::$strings['about %d hours'] = ''; +App::$strings['a day'] = ''; +App::$strings['%d days'] = ''; +App::$strings['about a month'] = ''; +App::$strings['%d months'] = ''; +App::$strings['about a year'] = ''; +App::$strings['%d years'] = ''; +App::$strings[' '] = ''; +App::$strings['timeago.numbers'] = ''; +App::$strings['January'] = ''; +App::$strings['February'] = ''; +App::$strings['March'] = ''; +App::$strings['April'] = ''; +App::$strings['__ctx:long__ May'] = ''; +App::$strings['June'] = ''; +App::$strings['July'] = ''; +App::$strings['August'] = ''; +App::$strings['September'] = ''; +App::$strings['October'] = ''; +App::$strings['November'] = ''; +App::$strings['December'] = ''; +App::$strings['Jan'] = ''; +App::$strings['Feb'] = ''; +App::$strings['Mar'] = ''; +App::$strings['Apr'] = ''; +App::$strings['__ctx:short__ May'] = ''; +App::$strings['Jun'] = ''; +App::$strings['Jul'] = ''; +App::$strings['Aug'] = ''; +App::$strings['Sep'] = ''; +App::$strings['Oct'] = ''; +App::$strings['Nov'] = ''; +App::$strings['Dec'] = ''; +App::$strings['Sun'] = ''; +App::$strings['Mon'] = ''; +App::$strings['Tue'] = ''; +App::$strings['Wed'] = ''; +App::$strings['Thu'] = ''; +App::$strings['Fri'] = ''; +App::$strings['Sat'] = ''; +App::$strings['__ctx:calendar__ today'] = ''; +App::$strings['__ctx:calendar__ month'] = ''; +App::$strings['__ctx:calendar__ week'] = ''; +App::$strings['__ctx:calendar__ day'] = ''; +App::$strings['__ctx:calendar__ All day'] = ''; +App::$strings['Delegation session ended.'] = ''; +App::$strings['Logged out.'] = ''; +App::$strings['Email validation is incomplete. Please check your email.'] = ''; +App::$strings['Failed authentication'] = ''; +App::$strings['Login failed.'] = ''; +App::$strings['Birthday'] = ''; +App::$strings['Age: '] = ''; +App::$strings['YYYY-MM-DD or MM-DD'] = ''; +App::$strings['never'] = ''; +App::$strings['less than a second ago'] = ''; +App::$strings["__ctx:e.g. 22 hours ago, 1 minute ago__ %1\$d %2\$s ago"] = ''; +App::$strings['__ctx:relative_date__ year'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:relative_date__ month"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:relative_date__ month'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:relative_date__ week"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:relative_date__ week'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:relative_date__ day"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:relative_date__ day'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:relative_date__ hour"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:relative_date__ hour'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:relative_date__ minute"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:relative_date__ minute'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:relative_date__ second"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:relative_date__ second'] = [ + 0 => '', + 1 => '', ]; -App::$strings["%1\$s's birthday"] = ""; -App::$strings["Happy Birthday %1\$s"] = ""; -App::$strings["Cannot locate DNS info for database server '%s'"] = ""; -App::$strings["View PDF"] = ""; -App::$strings[" by "] = ""; -App::$strings[" on "] = ""; -App::$strings["Embedded content"] = ""; -App::$strings["Embedding disabled"] = ""; -App::$strings["OpenWebAuth: %1\$s welcomes %2\$s"] = ""; -App::$strings["Friendica"] = ""; -App::$strings["OStatus"] = ""; -App::$strings["GNU-Social"] = ""; -App::$strings["RSS/Atom"] = ""; -App::$strings["Diaspora"] = ""; -App::$strings["Facebook"] = ""; -App::$strings["Zot"] = ""; -App::$strings["LinkedIn"] = ""; -App::$strings["XMPP/IM"] = ""; -App::$strings["MySpace"] = ""; -App::$strings["Remote authentication"] = ""; -App::$strings["Click to authenticate to your home hub"] = ""; -App::$strings["Manage your channels"] = ""; -App::$strings["Manage your access lists"] = ""; -App::$strings["Account/Channel Settings"] = ""; -App::$strings["(is on)"] = ""; -App::$strings["(is off)"] = ""; -App::$strings["Content filtering"] = ""; -App::$strings["Logout"] = ""; -App::$strings["End this session"] = ""; -App::$strings["Your profile page"] = ""; -App::$strings["Manage/Edit profiles"] = ""; -App::$strings["Sign in"] = ""; -App::$strings["Take me home"] = ""; -App::$strings["Log me out of this site"] = ""; -App::$strings["Create an account"] = ""; -App::$strings["Help and documentation"] = ""; -App::$strings["Search site @name, #tag, content"] = ""; -App::$strings["Site Setup and Configuration"] = ""; -App::$strings["Powered by \$Projectname"] = ""; -App::$strings["@name, #tag, content"] = ""; -App::$strings["Please wait..."] = ""; -App::$strings["Add/Manage Apps"] = ""; -App::$strings["Arrange Apps"] = ""; -App::$strings["Toggle System Apps"] = ""; -App::$strings["Status Messages and Posts"] = ""; -App::$strings["About"] = ""; -App::$strings["Profile Details"] = ""; -App::$strings["Photo Albums"] = ""; -App::$strings["Files and Storage"] = ""; -App::$strings["Bookmarks"] = ""; -App::$strings["Saved Bookmarks"] = ""; -App::$strings["View Cards"] = ""; -App::$strings["View Articles"] = ""; -App::$strings["View Webpages"] = ""; -App::$strings["Wikis"] = ""; -App::$strings["l F d, Y \\@ g:i A"] = ""; -App::$strings["Starts:"] = ""; -App::$strings["Finishes:"] = ""; -App::$strings["This event has been added to your calendar."] = ""; -App::$strings["Not specified"] = ""; -App::$strings["Needs Action"] = ""; -App::$strings["Completed"] = ""; -App::$strings["In Process"] = ""; -App::$strings["Cancelled"] = ""; -App::$strings["Home, Voice"] = ""; -App::$strings["Home, Fax"] = ""; -App::$strings["Work, Voice"] = ""; -App::$strings["Work, Fax"] = ""; -App::$strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = ""; -App::$strings["Trending"] = ""; -App::$strings["Keywords"] = ""; -App::$strings["have"] = ""; -App::$strings["has"] = ""; -App::$strings["want"] = ""; -App::$strings["wants"] = ""; -App::$strings["likes"] = ""; -App::$strings["dislikes"] = ""; -App::$strings["Not a valid email address"] = ""; -App::$strings["Your email domain is not among those allowed on this site"] = ""; -App::$strings["Your email address is already registered at this site."] = ""; -App::$strings["An invitation is required."] = ""; -App::$strings["Invitation could not be verified."] = ""; -App::$strings["Please enter the required information."] = ""; -App::$strings["Failed to store account information."] = ""; -App::$strings["Registration confirmation for %s"] = ""; -App::$strings["Registration request at %s"] = ""; -App::$strings["your registration password"] = ""; -App::$strings["Registration details for %s"] = ""; -App::$strings["Account approved."] = ""; -App::$strings["Registration revoked for %s"] = ""; -App::$strings["Click here to upgrade."] = ""; -App::$strings["This action exceeds the limits set by your subscription plan."] = ""; -App::$strings["This action is not available under your subscription plan."] = ""; -App::$strings["Encrypted content"] = ""; -App::$strings["(Embedded app '%s' could not be displayed)."] = ""; -App::$strings["Install %1\$s element %2\$s"] = ""; -App::$strings["This post contains an installable %s element, however you lack permissions to install it on this site."] = ""; -App::$strings["card"] = ""; -App::$strings["article"] = ""; -App::$strings["Click to open/close"] = ""; -App::$strings["spoiler"] = ""; -App::$strings["Different viewers will see this text differently"] = ""; -App::$strings["$1 wrote:"] = ""; -App::$strings["Item was not found."] = ""; -App::$strings["Unknown error."] = ""; -App::$strings["No source file."] = ""; -App::$strings["Cannot locate file to replace"] = ""; -App::$strings["Cannot locate file to revise/update"] = ""; -App::$strings["File exceeds size limit of %d"] = ""; -App::$strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = ""; -App::$strings["File upload failed. Possible system limit or action terminated."] = ""; -App::$strings["Stored file could not be verified. Upload failed."] = ""; -App::$strings["Path not available."] = ""; -App::$strings["Empty pathname"] = ""; -App::$strings["duplicate filename or path"] = ""; -App::$strings["Path not found."] = ""; -App::$strings["mkdir failed."] = ""; -App::$strings["database storage failed."] = ""; -App::$strings["Empty path"] = ""; -App::$strings["Unable to obtain identity information from database"] = ""; -App::$strings["Empty name"] = ""; -App::$strings["Name too long"] = ""; -App::$strings["No account identifier"] = ""; -App::$strings["Nickname is required."] = ""; -App::$strings["Unable to retrieve created identity"] = ""; -App::$strings["Default Profile"] = ""; -App::$strings["Unable to retrieve modified identity"] = ""; -App::$strings["(Unknown)"] = ""; -App::$strings["Visible to anybody on the internet."] = ""; -App::$strings["Visible to you only."] = ""; -App::$strings["Visible to anybody in this network."] = ""; -App::$strings["Visible to anybody authenticated."] = ""; -App::$strings["Visible to anybody on %s."] = ""; -App::$strings["Visible to all connections."] = ""; -App::$strings["Visible to approved connections."] = ""; -App::$strings["Visible to specific connections."] = ""; -App::$strings["Privacy group not found."] = ""; -App::$strings["Privacy group is empty."] = ""; -App::$strings["Privacy group: %s"] = ""; -App::$strings["Connection not found."] = ""; -App::$strings["profile photo"] = ""; -App::$strings["[Edited %s]"] = ""; -App::$strings["__ctx:edit_activity__ Post"] = ""; -App::$strings["__ctx:edit_activity__ Comment"] = ""; -App::$strings["prev"] = ""; -App::$strings["first"] = ""; -App::$strings["last"] = ""; -App::$strings["next"] = ""; -App::$strings["older"] = ""; -App::$strings["newer"] = ""; -App::$strings["poke"] = ""; -App::$strings["poked"] = ""; -App::$strings["ping"] = ""; -App::$strings["pinged"] = ""; -App::$strings["prod"] = ""; -App::$strings["prodded"] = ""; -App::$strings["slap"] = ""; -App::$strings["slapped"] = ""; -App::$strings["finger"] = ""; -App::$strings["fingered"] = ""; -App::$strings["rebuff"] = ""; -App::$strings["rebuffed"] = ""; -App::$strings["happy"] = ""; -App::$strings["sad"] = ""; -App::$strings["mellow"] = ""; -App::$strings["tired"] = ""; -App::$strings["perky"] = ""; -App::$strings["angry"] = ""; -App::$strings["stupefied"] = ""; -App::$strings["puzzled"] = ""; -App::$strings["interested"] = ""; -App::$strings["bitter"] = ""; -App::$strings["cheerful"] = ""; -App::$strings["alive"] = ""; -App::$strings["annoyed"] = ""; -App::$strings["anxious"] = ""; -App::$strings["cranky"] = ""; -App::$strings["disturbed"] = ""; -App::$strings["frustrated"] = ""; -App::$strings["depressed"] = ""; -App::$strings["motivated"] = ""; -App::$strings["relaxed"] = ""; -App::$strings["surprised"] = ""; -App::$strings["May"] = ""; -App::$strings["Unknown Attachment"] = ""; -App::$strings["unknown"] = ""; -App::$strings["remove category"] = ""; -App::$strings["remove from file"] = ""; -App::$strings["Added to your calendar"] = ""; -App::$strings["Link"] = ""; -App::$strings["Poll has ended."] = ""; -App::$strings["Poll ends: %s"] = ""; -App::$strings["vote"] = ""; -App::$strings["Download binary/encrypted content"] = ""; -App::$strings["Page layout"] = ""; -App::$strings["You can create your own with the layouts tool"] = ""; -App::$strings["BBcode"] = ""; -App::$strings["HTML"] = ""; -App::$strings["Markdown"] = ""; -App::$strings["Text"] = ""; -App::$strings["Comanche Layout"] = ""; -App::$strings["PHP"] = ""; -App::$strings["Page content type"] = ""; -App::$strings["activity"] = ""; -App::$strings["a-z, 0-9, -, and _ only"] = ""; -App::$strings["Design Tools"] = ""; -App::$strings["Pages"] = ""; -App::$strings["Import website..."] = ""; -App::$strings["Select folder to import"] = ""; -App::$strings["Import from a zipped folder:"] = ""; -App::$strings["Import from cloud files:"] = ""; -App::$strings["/cloud/channel/path/to/folder"] = ""; -App::$strings["Enter path to website files"] = ""; -App::$strings["Select folder"] = ""; -App::$strings["Export website..."] = ""; -App::$strings["Export to a zip file"] = ""; -App::$strings["website.zip"] = ""; -App::$strings["Enter a name for the zip file."] = ""; -App::$strings["Export to cloud files"] = ""; -App::$strings["/path/to/export/folder"] = ""; -App::$strings["Enter a path to a cloud files destination."] = ""; -App::$strings["Specify folder"] = ""; -App::$strings["General Features"] = ""; -App::$strings["Display new member quick links menu"] = ""; -App::$strings["Advanced Profiles"] = ""; -App::$strings["Additional profile sections and selections"] = ""; -App::$strings["Private Notes"] = ""; -App::$strings["Enables a tool to store notes and reminders (note: not encrypted)"] = ""; -App::$strings["Create interactive articles"] = ""; -App::$strings["Photo Location"] = ""; -App::$strings["If location data is available on uploaded photos, link this to a map."] = ""; -App::$strings["Event Timezone Selection"] = ""; -App::$strings["Allow event creation in timezones other than your own."] = ""; -App::$strings["Advanced Directory Search"] = ""; -App::$strings["Allows creation of complex directory search queries"] = ""; -App::$strings["Advanced Theme and Layout Settings"] = ""; -App::$strings["Allows fine tuning of themes and page layouts"] = ""; -App::$strings["Access Control and Permissions"] = ""; -App::$strings["Privacy Groups"] = ""; -App::$strings["Enable management and selection of privacy groups"] = ""; -App::$strings["OAuth2 Clients"] = ""; -App::$strings["Manage OAuth2 authenticatication tokens for mobile and remote apps."] = ""; -App::$strings["Post Composition Features"] = ""; -App::$strings["Auto-save drafts of posts and comments"] = ""; -App::$strings["Automatically saves post and comment drafts in local browser storage to help prevent accidental loss of compositions"] = ""; -App::$strings["Network and Stream Filtering"] = ""; -App::$strings["Post/Comment Tools"] = ""; -App::$strings["Community Tagging"] = ""; -App::$strings["Ability to tag existing posts"] = ""; -App::$strings["Post Categories"] = ""; -App::$strings["Add categories to your posts"] = ""; -App::$strings["Emoji Reactions"] = ""; -App::$strings["Add emoji reaction ability to posts"] = ""; -App::$strings["Ability to file posts under folders"] = ""; -App::$strings["Dislike Posts"] = ""; -App::$strings["Ability to dislike posts/comments"] = ""; -App::$strings["Tag Cloud"] = ""; -App::$strings["Provide a personal tag cloud on your channel page"] = ""; -App::$strings["Who can see this?"] = ""; -App::$strings["Custom selection"] = ""; -App::$strings["Select \"Show\" to allow viewing. \"Don't show\" lets you override and limit the scope of \"Show\"."] = ""; -App::$strings["Show"] = ""; -App::$strings["Don't show"] = ""; -App::$strings["Post permissions cannot be changed after a post is shared.
      These permissions set who is allowed to view the post."] = ""; -App::$strings["New window"] = ""; -App::$strings["Open the selected location in a different window or browser tab"] = ""; -App::$strings["No connections"] = ""; -App::$strings["View all %s connections"] = ""; -App::$strings["Network: %s"] = ""; -App::$strings["Unable to import a removed channel."] = ""; -App::$strings["A channel with these settings was discovered and is not usable as it was removed or reserved for system use. Import failed."] = ""; -App::$strings["Cannot create a duplicate channel identifier on this system. Import failed."] = ""; -App::$strings["Unable to create a unique channel address. Import failed."] = ""; -App::$strings["Cloned channel not found. Import failed."] = ""; -App::$strings["Image exceeds website size limit of %lu bytes"] = ""; -App::$strings["Image file is empty."] = ""; -App::$strings["Photo storage failed."] = ""; -App::$strings["a new photo"] = ""; -App::$strings["__ctx:photo_upload__ %1\$s posted %2\$s to %3\$s"] = ""; -App::$strings["Upload New Photos"] = ""; -App::$strings["%1\$s repeated %2\$s's %3\$s"] = ""; -App::$strings["likes %1\$s's %2\$s"] = ""; -App::$strings["doesn't like %1\$s's %2\$s"] = ""; -App::$strings["repeated %1\$s's %2\$s"] = ""; -App::$strings["%1\$s is now connected with %2\$s"] = ""; -App::$strings["%1\$s poked %2\$s"] = ""; -App::$strings["Toggle Star Status"] = ""; -App::$strings["View %s's profile @ %s"] = ""; -App::$strings["Categories:"] = ""; -App::$strings["Filed under:"] = ""; -App::$strings["View Conversation"] = ""; -App::$strings["remove"] = ""; -App::$strings["Loading..."] = ""; -App::$strings["Delete Selected Items"] = ""; -App::$strings["View Source"] = ""; -App::$strings["Follow Thread"] = ""; -App::$strings["Unfollow Thread"] = ""; -App::$strings["Visit"] = ""; -App::$strings["Edit Connection"] = ""; -App::$strings["Message"] = ""; -App::$strings["Block author's site"] = ""; -App::$strings["Block author"] = ""; -App::$strings["%s likes this."] = ""; -App::$strings["%s doesn't like this."] = ""; +App::$strings["%1\$s's birthday"] = ''; +App::$strings["Happy Birthday %1\$s"] = ''; +App::$strings["Cannot locate DNS info for database server '%s'"] = ''; +App::$strings['View PDF'] = ''; +App::$strings[' by '] = ''; +App::$strings[' on '] = ''; +App::$strings['Embedded content'] = ''; +App::$strings['Embedding disabled'] = ''; +App::$strings["OpenWebAuth: %1\$s welcomes %2\$s"] = ''; +App::$strings['Friendica'] = ''; +App::$strings['OStatus'] = ''; +App::$strings['GNU-Social'] = ''; +App::$strings['RSS/Atom'] = ''; +App::$strings['Diaspora'] = ''; +App::$strings['Facebook'] = ''; +App::$strings['Zot'] = ''; +App::$strings['LinkedIn'] = ''; +App::$strings['XMPP/IM'] = ''; +App::$strings['MySpace'] = ''; +App::$strings['Remote authentication'] = ''; +App::$strings['Click to authenticate to your home hub'] = ''; +App::$strings['Manage your channels'] = ''; +App::$strings['Manage your access lists'] = ''; +App::$strings['Account/Channel Settings'] = ''; +App::$strings['(is on)'] = ''; +App::$strings['(is off)'] = ''; +App::$strings['Content filtering'] = ''; +App::$strings['Logout'] = ''; +App::$strings['End this session'] = ''; +App::$strings['Your profile page'] = ''; +App::$strings['Manage/Edit profiles'] = ''; +App::$strings['Sign in'] = ''; +App::$strings['Take me home'] = ''; +App::$strings['Log me out of this site'] = ''; +App::$strings['Create an account'] = ''; +App::$strings['Help and documentation'] = ''; +App::$strings['Search site @name, #tag, content'] = ''; +App::$strings['Site Setup and Configuration'] = ''; +App::$strings["Powered by \$Projectname"] = ''; +App::$strings['@name, #tag, content'] = ''; +App::$strings['Please wait...'] = ''; +App::$strings['Add/Manage Apps'] = ''; +App::$strings['Arrange Apps'] = ''; +App::$strings['Toggle System Apps'] = ''; +App::$strings['Status Messages and Posts'] = ''; +App::$strings['About'] = ''; +App::$strings['Profile Details'] = ''; +App::$strings['Photo Albums'] = ''; +App::$strings['Files and Storage'] = ''; +App::$strings['Bookmarks'] = ''; +App::$strings['Saved Bookmarks'] = ''; +App::$strings['View Cards'] = ''; +App::$strings['View Articles'] = ''; +App::$strings['View Webpages'] = ''; +App::$strings['Wikis'] = ''; +App::$strings["l F d, Y \\@ g:i A"] = ''; +App::$strings['Starts:'] = ''; +App::$strings['Finishes:'] = ''; +App::$strings['This event has been added to your calendar.'] = ''; +App::$strings['Not specified'] = ''; +App::$strings['Needs Action'] = ''; +App::$strings['Completed'] = ''; +App::$strings['In Process'] = ''; +App::$strings['Cancelled'] = ''; +App::$strings['Home, Voice'] = ''; +App::$strings['Home, Fax'] = ''; +App::$strings['Work, Voice'] = ''; +App::$strings['Work, Fax'] = ''; +App::$strings['The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it.'] = ''; +App::$strings['Trending'] = ''; +App::$strings['Keywords'] = ''; +App::$strings['have'] = ''; +App::$strings['has'] = ''; +App::$strings['want'] = ''; +App::$strings['wants'] = ''; +App::$strings['likes'] = ''; +App::$strings['dislikes'] = ''; +App::$strings['Not a valid email address'] = ''; +App::$strings['Your email domain is not among those allowed on this site'] = ''; +App::$strings['Your email address is already registered at this site.'] = ''; +App::$strings['An invitation is required.'] = ''; +App::$strings['Invitation could not be verified.'] = ''; +App::$strings['Please enter the required information.'] = ''; +App::$strings['Failed to store account information.'] = ''; +App::$strings['Registration confirmation for %s'] = ''; +App::$strings['Registration request at %s'] = ''; +App::$strings['your registration password'] = ''; +App::$strings['Registration details for %s'] = ''; +App::$strings['Account approved.'] = ''; +App::$strings['Registration revoked for %s'] = ''; +App::$strings['Click here to upgrade.'] = ''; +App::$strings['This action exceeds the limits set by your subscription plan.'] = ''; +App::$strings['This action is not available under your subscription plan.'] = ''; +App::$strings['Encrypted content'] = ''; +App::$strings["(Embedded app '%s' could not be displayed)."] = ''; +App::$strings["Install %1\$s element %2\$s"] = ''; +App::$strings['This post contains an installable %s element, however you lack permissions to install it on this site.'] = ''; +App::$strings['card'] = ''; +App::$strings['article'] = ''; +App::$strings['Click to open/close'] = ''; +App::$strings['spoiler'] = ''; +App::$strings['Different viewers will see this text differently'] = ''; +App::$strings['$1 wrote:'] = ''; +App::$strings['Item was not found.'] = ''; +App::$strings['Unknown error.'] = ''; +App::$strings['No source file.'] = ''; +App::$strings['Cannot locate file to replace'] = ''; +App::$strings['Cannot locate file to revise/update'] = ''; +App::$strings['File exceeds size limit of %d'] = ''; +App::$strings['You have reached your limit of %1$.0f Mbytes attachment storage.'] = ''; +App::$strings['File upload failed. Possible system limit or action terminated.'] = ''; +App::$strings['Stored file could not be verified. Upload failed.'] = ''; +App::$strings['Path not available.'] = ''; +App::$strings['Empty pathname'] = ''; +App::$strings['duplicate filename or path'] = ''; +App::$strings['Path not found.'] = ''; +App::$strings['mkdir failed.'] = ''; +App::$strings['database storage failed.'] = ''; +App::$strings['Empty path'] = ''; +App::$strings['Unable to obtain identity information from database'] = ''; +App::$strings['Empty name'] = ''; +App::$strings['Name too long'] = ''; +App::$strings['No account identifier'] = ''; +App::$strings['Nickname is required.'] = ''; +App::$strings['Unable to retrieve created identity'] = ''; +App::$strings['Default Profile'] = ''; +App::$strings['Unable to retrieve modified identity'] = ''; +App::$strings['(Unknown)'] = ''; +App::$strings['Visible to anybody on the internet.'] = ''; +App::$strings['Visible to you only.'] = ''; +App::$strings['Visible to anybody in this network.'] = ''; +App::$strings['Visible to anybody authenticated.'] = ''; +App::$strings['Visible to anybody on %s.'] = ''; +App::$strings['Visible to all connections.'] = ''; +App::$strings['Visible to approved connections.'] = ''; +App::$strings['Visible to specific connections.'] = ''; +App::$strings['Privacy group not found.'] = ''; +App::$strings['Privacy group is empty.'] = ''; +App::$strings['Privacy group: %s'] = ''; +App::$strings['Connection not found.'] = ''; +App::$strings['profile photo'] = ''; +App::$strings['[Edited %s]'] = ''; +App::$strings['__ctx:edit_activity__ Post'] = ''; +App::$strings['__ctx:edit_activity__ Comment'] = ''; +App::$strings['prev'] = ''; +App::$strings['first'] = ''; +App::$strings['last'] = ''; +App::$strings['next'] = ''; +App::$strings['older'] = ''; +App::$strings['newer'] = ''; +App::$strings['poke'] = ''; +App::$strings['poked'] = ''; +App::$strings['ping'] = ''; +App::$strings['pinged'] = ''; +App::$strings['prod'] = ''; +App::$strings['prodded'] = ''; +App::$strings['slap'] = ''; +App::$strings['slapped'] = ''; +App::$strings['finger'] = ''; +App::$strings['fingered'] = ''; +App::$strings['rebuff'] = ''; +App::$strings['rebuffed'] = ''; +App::$strings['happy'] = ''; +App::$strings['sad'] = ''; +App::$strings['mellow'] = ''; +App::$strings['tired'] = ''; +App::$strings['perky'] = ''; +App::$strings['angry'] = ''; +App::$strings['stupefied'] = ''; +App::$strings['puzzled'] = ''; +App::$strings['interested'] = ''; +App::$strings['bitter'] = ''; +App::$strings['cheerful'] = ''; +App::$strings['alive'] = ''; +App::$strings['annoyed'] = ''; +App::$strings['anxious'] = ''; +App::$strings['cranky'] = ''; +App::$strings['disturbed'] = ''; +App::$strings['frustrated'] = ''; +App::$strings['depressed'] = ''; +App::$strings['motivated'] = ''; +App::$strings['relaxed'] = ''; +App::$strings['surprised'] = ''; +App::$strings['May'] = ''; +App::$strings['Unknown Attachment'] = ''; +App::$strings['unknown'] = ''; +App::$strings['remove category'] = ''; +App::$strings['remove from file'] = ''; +App::$strings['Added to your calendar'] = ''; +App::$strings['Link'] = ''; +App::$strings['Poll has ended.'] = ''; +App::$strings['Poll ends: %s'] = ''; +App::$strings['vote'] = ''; +App::$strings['Download binary/encrypted content'] = ''; +App::$strings['Page layout'] = ''; +App::$strings['You can create your own with the layouts tool'] = ''; +App::$strings['BBcode'] = ''; +App::$strings['HTML'] = ''; +App::$strings['Markdown'] = ''; +App::$strings['Text'] = ''; +App::$strings['Comanche Layout'] = ''; +App::$strings['PHP'] = ''; +App::$strings['Page content type'] = ''; +App::$strings['activity'] = ''; +App::$strings['a-z, 0-9, -, and _ only'] = ''; +App::$strings['Design Tools'] = ''; +App::$strings['Pages'] = ''; +App::$strings['Import website...'] = ''; +App::$strings['Select folder to import'] = ''; +App::$strings['Import from a zipped folder:'] = ''; +App::$strings['Import from cloud files:'] = ''; +App::$strings['/cloud/channel/path/to/folder'] = ''; +App::$strings['Enter path to website files'] = ''; +App::$strings['Select folder'] = ''; +App::$strings['Export website...'] = ''; +App::$strings['Export to a zip file'] = ''; +App::$strings['website.zip'] = ''; +App::$strings['Enter a name for the zip file.'] = ''; +App::$strings['Export to cloud files'] = ''; +App::$strings['/path/to/export/folder'] = ''; +App::$strings['Enter a path to a cloud files destination.'] = ''; +App::$strings['Specify folder'] = ''; +App::$strings['General Features'] = ''; +App::$strings['Display new member quick links menu'] = ''; +App::$strings['Advanced Profiles'] = ''; +App::$strings['Additional profile sections and selections'] = ''; +App::$strings['Private Notes'] = ''; +App::$strings['Enables a tool to store notes and reminders (note: not encrypted)'] = ''; +App::$strings['Create interactive articles'] = ''; +App::$strings['Photo Location'] = ''; +App::$strings['If location data is available on uploaded photos, link this to a map.'] = ''; +App::$strings['Event Timezone Selection'] = ''; +App::$strings['Allow event creation in timezones other than your own.'] = ''; +App::$strings['Advanced Directory Search'] = ''; +App::$strings['Allows creation of complex directory search queries'] = ''; +App::$strings['Advanced Theme and Layout Settings'] = ''; +App::$strings['Allows fine tuning of themes and page layouts'] = ''; +App::$strings['Access Control and Permissions'] = ''; +App::$strings['Privacy Groups'] = ''; +App::$strings['Enable management and selection of privacy groups'] = ''; +App::$strings['OAuth2 Clients'] = ''; +App::$strings['Manage OAuth2 authenticatication tokens for mobile and remote apps.'] = ''; +App::$strings['Post Composition Features'] = ''; +App::$strings['Auto-save drafts of posts and comments'] = ''; +App::$strings['Automatically saves post and comment drafts in local browser storage to help prevent accidental loss of compositions'] = ''; +App::$strings['Network and Stream Filtering'] = ''; +App::$strings['Post/Comment Tools'] = ''; +App::$strings['Community Tagging'] = ''; +App::$strings['Ability to tag existing posts'] = ''; +App::$strings['Post Categories'] = ''; +App::$strings['Add categories to your posts'] = ''; +App::$strings['Emoji Reactions'] = ''; +App::$strings['Add emoji reaction ability to posts'] = ''; +App::$strings['Ability to file posts under folders'] = ''; +App::$strings['Dislike Posts'] = ''; +App::$strings['Ability to dislike posts/comments'] = ''; +App::$strings['Tag Cloud'] = ''; +App::$strings['Provide a personal tag cloud on your channel page'] = ''; +App::$strings['Who can see this?'] = ''; +App::$strings['Custom selection'] = ''; +App::$strings["Select \"Show\" to allow viewing. \"Don't show\" lets you override and limit the scope of \"Show\"."] = ''; +App::$strings['Show'] = ''; +App::$strings["Don't show"] = ''; +App::$strings['Post permissions cannot be changed after a post is shared.
      These permissions set who is allowed to view the post.'] = ''; +App::$strings['New window'] = ''; +App::$strings['Open the selected location in a different window or browser tab'] = ''; +App::$strings['No connections'] = ''; +App::$strings['View all %s connections'] = ''; +App::$strings['Network: %s'] = ''; +App::$strings['Unable to import a removed channel.'] = ''; +App::$strings['A channel with these settings was discovered and is not usable as it was removed or reserved for system use. Import failed.'] = ''; +App::$strings['Cannot create a duplicate channel identifier on this system. Import failed.'] = ''; +App::$strings['Unable to create a unique channel address. Import failed.'] = ''; +App::$strings['Cloned channel not found. Import failed.'] = ''; +App::$strings['Image exceeds website size limit of %lu bytes'] = ''; +App::$strings['Image file is empty.'] = ''; +App::$strings['Photo storage failed.'] = ''; +App::$strings['a new photo'] = ''; +App::$strings["__ctx:photo_upload__ %1\$s posted %2\$s to %3\$s"] = ''; +App::$strings['Upload New Photos'] = ''; +App::$strings["%1\$s repeated %2\$s's %3\$s"] = ''; +App::$strings["likes %1\$s's %2\$s"] = ''; +App::$strings["doesn't like %1\$s's %2\$s"] = ''; +App::$strings["repeated %1\$s's %2\$s"] = ''; +App::$strings["%1\$s is now connected with %2\$s"] = ''; +App::$strings["%1\$s poked %2\$s"] = ''; +App::$strings['Toggle Star Status'] = ''; +App::$strings["View %s's profile @ %s"] = ''; +App::$strings['Categories:'] = ''; +App::$strings['Filed under:'] = ''; +App::$strings['View Conversation'] = ''; +App::$strings['remove'] = ''; +App::$strings['Loading...'] = ''; +App::$strings['Delete Selected Items'] = ''; +App::$strings['View Source'] = ''; +App::$strings['Follow Thread'] = ''; +App::$strings['Unfollow Thread'] = ''; +App::$strings['Visit'] = ''; +App::$strings['Edit Connection'] = ''; +App::$strings['Message'] = ''; +App::$strings["Block author's site"] = ''; +App::$strings['Block author'] = ''; +App::$strings['%s likes this.'] = ''; +App::$strings["%s doesn't like this."] = ''; App::$strings["%2\$d people like this."] = [ - 0 => "", - 1 => "", + 0 => '', + 1 => '', ]; App::$strings["%2\$d people don't like this."] = [ - 0 => "", - 1 => "", + 0 => '', + 1 => '', ]; -App::$strings["and"] = ""; -App::$strings[", and %d other people"] = [ - 0 => "", - 1 => "", +App::$strings['and'] = ''; +App::$strings[', and %d other people'] = [ + 0 => '', + 1 => '', ]; -App::$strings["%s like this."] = ""; -App::$strings["%s don't like this."] = ""; -App::$strings["Set your location"] = ""; -App::$strings["Clear browser location"] = ""; -App::$strings["Embed (existing) photo from your photo albums"] = ""; -App::$strings["Tag term:"] = ""; -App::$strings["Where are you right now?"] = ""; -App::$strings["Choose a different album..."] = ""; -App::$strings["Comments enabled"] = ""; -App::$strings["Comments disabled"] = ""; -App::$strings["Page link name"] = ""; -App::$strings["Post as"] = ""; -App::$strings["Please enter a link location (URL)"] = ""; -App::$strings["Insert link only"] = ""; -App::$strings["Embed content if possible"] = ""; -App::$strings["Embed an image from your albums"] = ""; -App::$strings["Toggle voting"] = ""; -App::$strings["Toggle poll"] = ""; -App::$strings["Option"] = ""; -App::$strings["Add option"] = ""; -App::$strings["Minutes"] = ""; -App::$strings["Hours"] = ""; -App::$strings["Days"] = ""; -App::$strings["Allow multiple answers"] = ""; -App::$strings["Disable comments"] = ""; -App::$strings["Toggle comments"] = ""; -App::$strings["Categories (optional, comma-separated list)"] = ""; -App::$strings["Other networks and post services"] = ""; -App::$strings["Set expiration date"] = ""; -App::$strings["Set publish date"] = ""; -App::$strings["Find remote media players (oEmbed)"] = ""; -App::$strings["Find shareable objects (Zot)"] = ""; -App::$strings["Post to Collections"] = ""; -App::$strings["articles"] = ""; -App::$strings["__ctx:noun__ Attending"] = [ - 0 => "", - 1 => "", +App::$strings['%s like this.'] = ''; +App::$strings["%s don't like this."] = ''; +App::$strings['Set your location'] = ''; +App::$strings['Clear browser location'] = ''; +App::$strings['Embed (existing) photo from your photo albums'] = ''; +App::$strings['Tag term:'] = ''; +App::$strings['Where are you right now?'] = ''; +App::$strings['Choose a different album...'] = ''; +App::$strings['Comments enabled'] = ''; +App::$strings['Comments disabled'] = ''; +App::$strings['Page link name'] = ''; +App::$strings['Post as'] = ''; +App::$strings['Please enter a link location (URL)'] = ''; +App::$strings['Insert link only'] = ''; +App::$strings['Embed content if possible'] = ''; +App::$strings['Embed an image from your albums'] = ''; +App::$strings['Toggle voting'] = ''; +App::$strings['Toggle poll'] = ''; +App::$strings['Option'] = ''; +App::$strings['Add option'] = ''; +App::$strings['Minutes'] = ''; +App::$strings['Hours'] = ''; +App::$strings['Days'] = ''; +App::$strings['Allow multiple answers'] = ''; +App::$strings['Disable comments'] = ''; +App::$strings['Toggle comments'] = ''; +App::$strings['Categories (optional, comma-separated list)'] = ''; +App::$strings['Other networks and post services'] = ''; +App::$strings['Set expiration date'] = ''; +App::$strings['Set publish date'] = ''; +App::$strings['Find remote media players (oEmbed)'] = ''; +App::$strings['Find shareable objects (Zot)'] = ''; +App::$strings['Post to Collections'] = ''; +App::$strings['articles'] = ''; +App::$strings['__ctx:noun__ Attending'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:noun__ Not Attending"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:noun__ Not Attending'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:noun__ Undecided"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:noun__ Undecided'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:noun__ Agree"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:noun__ Agree'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:noun__ Disagree"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:noun__ Disagree'] = [ + 0 => '', + 1 => '', ]; -App::$strings["__ctx:noun__ Abstain"] = [ - 0 => "", - 1 => "", +App::$strings['__ctx:noun__ Abstain'] = [ + 0 => '', + 1 => '', ]; -App::$strings["Source channel not found."] = ""; -App::$strings["Focus (Hubzilla default)"] = ""; -App::$strings["Theme settings"] = ""; -App::$strings["Narrow navbar"] = ""; -App::$strings["Navigation bar background color"] = ""; -App::$strings["Navigation bar icon color "] = ""; -App::$strings["Navigation bar active icon color "] = ""; -App::$strings["Link color"] = ""; -App::$strings["Set font-color for banner"] = ""; -App::$strings["Set the background color"] = ""; -App::$strings["Set the background image"] = ""; -App::$strings["Set the background color of items"] = ""; -App::$strings["Set the background color of comments"] = ""; -App::$strings["Set font-size for the entire application"] = ""; -App::$strings["Examples: 1rem, 100%, 16px"] = ""; -App::$strings["Set font-color for posts and comments"] = ""; -App::$strings["Set radius of corners"] = ""; -App::$strings["Example: 4px"] = ""; -App::$strings["Set shadow depth of photos"] = ""; -App::$strings["Set maximum width of content region in pixel"] = ""; -App::$strings["Leave empty for default width"] = ""; -App::$strings["Set size of conversation author photo"] = ""; -App::$strings["Set size of followup author photos"] = ""; -App::$strings["Cover Photo"] = ""; -App::$strings["An account has been created for you."] = ""; -App::$strings["Authentication successful but rejected: account creation is disabled."] = ""; -App::$strings["Logfile archive directory"] = ""; -App::$strings["Directory to store rotated logs"] = ""; -App::$strings["Logfile size in bytes before rotating, example 10M"] = ""; -App::$strings["Number of logfiles to retain"] = ""; -App::$strings["NSFW Settings saved."] = ""; -App::$strings["This addon app looks in posts for the words/text you specify below, and collapses any content containing those keywords so it is not displayed at inappropriate times, such as sexual innuendo that may be improper in a work setting. It is polite and recommended to tag any content containing nudity with #NSFW. This filter can also match any other word/text you specify, and can thereby be used as a general purpose content filter."] = ""; -App::$strings["Comma separated list of keywords to hide"] = ""; -App::$strings["Word, /regular-expression/, lang=xx, lang!=xx"] = ""; -App::$strings["Collapse entire conversation if a match is found"] = ""; -App::$strings["Not Safe For Work Settings"] = ""; -App::$strings["General Purpose Content Filter"] = ""; -App::$strings["Conversation muted"] = ""; -App::$strings["Possible adult content"] = ""; -App::$strings["%s - view"] = ""; -App::$strings["This addon app provides a selector on your stream page allowing you to change the sort order of the page between 'recently commented' (default), 'posted order', or 'unthreaded' which displays single activities as received."] = ""; -App::$strings["Channel is required."] = ""; -App::$strings["Zotpost Settings saved."] = ""; -App::$strings["This addon app allows you to cross-post to other Zot services and channels. After installing the app, select it to configure the destination settings and preferences."] = ""; -App::$strings["Zot server URL"] = ""; -App::$strings["https://example.com"] = ""; -App::$strings["Zot channel name"] = ""; -App::$strings["Zot password"] = ""; -App::$strings["Send public postings to Zot channel by default"] = ""; -App::$strings["Zotpost Settings"] = ""; -App::$strings["Post to Zot"] = ""; -App::$strings["Add some colour to tag clouds"] = ""; -App::$strings["Rainbow Tag"] = ""; -App::$strings["No server specified"] = ""; -App::$strings["Posts imported"] = ""; -App::$strings["Files imported"] = ""; -App::$strings["This addon app copies existing content and file storage to a cloned/copied channel. Once the app is installed, visit the newly installed app. This will allow you to set the location of your original channel and an optional date range of files/conversations to copy."] = ""; -App::$strings["This will import all your conversations and cloud files from a cloned channel on another server. This may take a while if you have lots of posts and or files."] = ""; -App::$strings["Include posts"] = ""; -App::$strings["Conversations, Articles, Cards, and other posted content"] = ""; -App::$strings["Include files"] = ""; -App::$strings["Files, Photos and other cloud storage"] = ""; -App::$strings["Original Server base URL"] = ""; -App::$strings["Since modified date yyyy-mm-dd"] = ""; -App::$strings["Until modified date yyyy-mm-dd"] = ""; -App::$strings["View Larger"] = ""; -App::$strings["Tile Server URL"] = ""; -App::$strings["A list of public tile servers"] = ""; -App::$strings["Nominatim (reverse geocoding) Server URL"] = ""; -App::$strings["A list of Nominatim servers"] = ""; -App::$strings["Default zoom"] = ""; -App::$strings["The default zoom level. (1:world, 18:highest, also depends on tile server)"] = ""; -App::$strings["Include marker on map"] = ""; -App::$strings["Include a marker on the map."] = ""; -App::$strings["Profile Unavailable."] = ""; -App::$strings["Not allowed."] = ""; -App::$strings["Photo Gallery"] = ""; -App::$strings["Gallery App"] = ""; -App::$strings["A simple gallery for your photo albums"] = ""; -App::$strings["Face detection is not activated"] = ""; -App::$strings["Face detection is still busy"] = ""; -App::$strings["Errors encountered deleting all rows of database table "] = ""; -App::$strings["Create an account to access services and applications"] = ""; -App::$strings["Login/Email"] = ""; -App::$strings["Password"] = ""; -App::$strings["Remember me"] = ""; -App::$strings["Forgot your password?"] = ""; -App::$strings["[\$Projectname] Website SSL error for %s"] = ""; -App::$strings["Website SSL certificate is not valid. Please correct."] = ""; -App::$strings["[\$Projectname] Cron tasks not running on %s"] = ""; -App::$strings["Cron/Scheduled tasks not running."] = ""; +App::$strings['Source channel not found.'] = ''; +App::$strings['Focus (Hubzilla default)'] = ''; +App::$strings['Theme settings'] = ''; +App::$strings['Narrow navbar'] = ''; +App::$strings['Navigation bar background color'] = ''; +App::$strings['Navigation bar icon color '] = ''; +App::$strings['Navigation bar active icon color '] = ''; +App::$strings['Link color'] = ''; +App::$strings['Set font-color for banner'] = ''; +App::$strings['Set the background color'] = ''; +App::$strings['Set the background image'] = ''; +App::$strings['Set the background color of items'] = ''; +App::$strings['Set the background color of comments'] = ''; +App::$strings['Set font-size for the entire application'] = ''; +App::$strings['Examples: 1rem, 100%, 16px'] = ''; +App::$strings['Set font-color for posts and comments'] = ''; +App::$strings['Set radius of corners'] = ''; +App::$strings['Example: 4px'] = ''; +App::$strings['Set shadow depth of photos'] = ''; +App::$strings['Set maximum width of content region in pixel'] = ''; +App::$strings['Leave empty for default width'] = ''; +App::$strings['Set size of conversation author photo'] = ''; +App::$strings['Set size of followup author photos'] = ''; +App::$strings['Cover Photo'] = ''; +App::$strings['An account has been created for you.'] = ''; +App::$strings['Authentication successful but rejected: account creation is disabled.'] = ''; +App::$strings['Logfile archive directory'] = ''; +App::$strings['Directory to store rotated logs'] = ''; +App::$strings['Logfile size in bytes before rotating, example 10M'] = ''; +App::$strings['Number of logfiles to retain'] = ''; +App::$strings['NSFW Settings saved.'] = ''; +App::$strings['This addon app looks in posts for the words/text you specify below, and collapses any content containing those keywords so it is not displayed at inappropriate times, such as sexual innuendo that may be improper in a work setting. It is polite and recommended to tag any content containing nudity with #NSFW. This filter can also match any other word/text you specify, and can thereby be used as a general purpose content filter.'] = ''; +App::$strings['Comma separated list of keywords to hide'] = ''; +App::$strings['Word, /regular-expression/, lang=xx, lang!=xx'] = ''; +App::$strings['Collapse entire conversation if a match is found'] = ''; +App::$strings['Not Safe For Work Settings'] = ''; +App::$strings['General Purpose Content Filter'] = ''; +App::$strings['Conversation muted'] = ''; +App::$strings['Possible adult content'] = ''; +App::$strings['%s - view'] = ''; +App::$strings["This addon app provides a selector on your stream page allowing you to change the sort order of the page between 'recently commented' (default), 'posted order', or 'unthreaded' which displays single activities as received."] = ''; +App::$strings['Channel is required.'] = ''; +App::$strings['Zotpost Settings saved.'] = ''; +App::$strings['This addon app allows you to cross-post to other Zot services and channels. After installing the app, select it to configure the destination settings and preferences.'] = ''; +App::$strings['Zot server URL'] = ''; +App::$strings['https://example.com'] = ''; +App::$strings['Zot channel name'] = ''; +App::$strings['Zot password'] = ''; +App::$strings['Send public postings to Zot channel by default'] = ''; +App::$strings['Zotpost Settings'] = ''; +App::$strings['Post to Zot'] = ''; +App::$strings['Add some colour to tag clouds'] = ''; +App::$strings['Rainbow Tag'] = ''; +App::$strings['No server specified'] = ''; +App::$strings['Posts imported'] = ''; +App::$strings['Files imported'] = ''; +App::$strings['This addon app copies existing content and file storage to a cloned/copied channel. Once the app is installed, visit the newly installed app. This will allow you to set the location of your original channel and an optional date range of files/conversations to copy.'] = ''; +App::$strings['This will import all your conversations and cloud files from a cloned channel on another server. This may take a while if you have lots of posts and or files.'] = ''; +App::$strings['Include posts'] = ''; +App::$strings['Conversations, Articles, Cards, and other posted content'] = ''; +App::$strings['Include files'] = ''; +App::$strings['Files, Photos and other cloud storage'] = ''; +App::$strings['Original Server base URL'] = ''; +App::$strings['Since modified date yyyy-mm-dd'] = ''; +App::$strings['Until modified date yyyy-mm-dd'] = ''; +App::$strings['View Larger'] = ''; +App::$strings['Tile Server URL'] = ''; +App::$strings["A list of public tile servers"] = ''; +App::$strings['Nominatim (reverse geocoding) Server URL'] = ''; +App::$strings["A list of Nominatim servers"] = ''; +App::$strings['Default zoom'] = ''; +App::$strings['The default zoom level. (1:world, 18:highest, also depends on tile server)'] = ''; +App::$strings['Include marker on map'] = ''; +App::$strings['Include a marker on the map.'] = ''; +App::$strings['Profile Unavailable.'] = ''; +App::$strings['Not allowed.'] = ''; +App::$strings['Photo Gallery'] = ''; +App::$strings['Gallery App'] = ''; +App::$strings['A simple gallery for your photo albums'] = ''; +App::$strings['Face detection is not activated'] = ''; +App::$strings['Face detection is still busy'] = ''; +App::$strings['Errors encountered deleting all rows of database table '] = ''; +App::$strings['Create an account to access services and applications'] = ''; +App::$strings['Login/Email'] = ''; +App::$strings['Password'] = ''; +App::$strings['Remember me'] = ''; +App::$strings['Forgot your password?'] = ''; +App::$strings["[\$Projectname] Website SSL error for %s"] = ''; +App::$strings['Website SSL certificate is not valid. Please correct.'] = ''; +App::$strings["[\$Projectname] Cron tasks not running on %s"] = ''; +App::$strings['Cron/Scheduled tasks not running.'] = '';