Compare commits

...
Sign in to create a new pull request.

219 commits

Author SHA1 Message Date
fb0816eb39 Merge pull request 'New converse.js based XMPP addon' (#1621) from heluecht/friendica-addons:xmpp-converse into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1621
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-12-16 16:02:57 +01:00
f31047f3c8 XMPP addon is created 2025-12-16 16:02:57 +01:00
51c0b11287 Merge pull request 'Fix PHPStan error' (#1625) from heluecht/friendica-addons:phpstan into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1625
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-12-16 15:58:54 +01:00
b060be281f Fix PHPStan error 2025-12-16 15:58:54 +01:00
ff7025d852 Merge pull request 'Add references header for more robust threading in mail clients' (#1624) from mexon/friendica-addons:mat/mailstream-references into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1624
2025-12-14 12:02:18 +01:00
Matthew Exon
cfc7193122 Add references header for more robust threading in mail clients 2025-12-13 11:29:59 +01:00
0bf1d3eec9 Merge pull request 'Increased speed for "follow" requests' (#1622) from heluecht/friendica-addons:follow-speed into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1622
2025-12-01 18:09:41 +01:00
53ca699b16 Increased speed for "follow" requests 2025-12-01 18:09:41 +01:00
633c6799d8 Merge pull request '[CI] Add All-In-One Archive' (#1616) from nupplaPhil/friendica-addons:ci/full-archive into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1616
2025-11-21 23:51:36 +01:00
d47e20b0d4 Enable CI Pipeline 2025-11-21 23:51:36 +01:00
38dcc81d3c Merge pull request 'GitHub Issue 14872: Change Ratioed default sort order' (#1619) from haheute/friendica-addons:ratioed-sort-order into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1619
2025-11-21 23:49:43 +01:00
1fdc6d9794 GitHub Issue 14872: Change Ratioed default sort order 2025-11-20 15:46:44 +01:00
9b3278ffd9 Merge pull request 'add messages.po file for ratioed addon' (#1618) from mexon/friendica-addons:mat/ratioed-translation into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1618
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-11-12 14:36:34 +01:00
Matthew Exon
427f39ad57 add messages.po file for ratioed addon 2025-11-10 07:26:04 +01:00
0562623117 Merge pull request 'Update Link to Transifex Friendica page' (#1617) from haheute/friendica-addons:update-transifex-url into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1617
2025-11-09 19:57:26 +01:00
8d42f99aff Update Link to Transifex Friendica page 2025-11-08 12:34:47 +01:00
6a342088a5 Merge pull request 'Avoid sending group posts through connectors' (#1615) from heluecht/friendica-addons:no-group-posts into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1615
2025-09-14 18:07:56 +02:00
6dcf3cbf5c Avoid sending group posts through connectors 2025-09-01 01:45:44 +00:00
28fcccd9d5 Merge pull request 'Fix several warnings' (#1613) from heluecht/friendica-addons:warnings into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1613
2025-08-07 21:08:38 +02:00
1cc54a83a9 Fix several warnings 2025-08-04 20:48:06 +00:00
e76575eb52 Merge pull request 'Issue 15048: Support addon filters via API' (#1612) from heluecht/friendica-addons:issue-15048 into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1612
2025-07-30 22:40:55 +02:00
b39ab36cee Issue 15048: Support addon filters via API 2025-07-29 21:23:57 +00:00
ea41e2f1b6 Merge pull request 'update PHPMailer' (#1611) from 20250710-phpmailer into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1611
2025-07-23 23:09:06 +02:00
9387db358c update PHPMailer 2025-07-10 06:30:21 +02:00
715f700323 Merge pull request '[Fix] reset Dice calls for LoggerFactory' (#1610) from Art4/friendica-addons:fix-monolog-addon into 2025.07-rc
Reviewed-on: friendica/friendica-addons#1610
2025-07-08 07:10:24 +02:00
Art4
8a8639b07e reset Dice calls for LoggerFactory 2025-06-05 07:56:53 +00:00
97b09d34e9 Merge pull request 'Issue 14667: Pinned Bluesky feeds are fetched again' (#1605) from heluecht/friendica-addons:bluesky-pinned into develop
Reviewed-on: friendica/friendica-addons#1605
2025-05-03 22:02:16 +02:00
2289fdc97e Issue 14667: Pinned Bluesky feeds are fetched again 2025-05-03 22:02:16 +02:00
d95137ce6b Merge pull request 'Bluesky: Support for mentions' (#1606) from heluecht/friendica-addons:bluesky-mentions into develop
Reviewed-on: friendica/friendica-addons#1606
2025-05-03 22:01:06 +02:00
cd4f102d02 Bluesky: Support for mentions 2025-05-03 22:01:06 +02:00
4daaf17110 Merge pull request 'Replace Addon class with AddonHelper' (#1607) from Art4/friendica-addons:replace-addon-class-with-addonhelper into develop
Reviewed-on: friendica/friendica-addons#1607
2025-05-03 21:59:14 +02:00
Art4
48ff761bdb Replace Addon class with AddonHelper 2025-04-28 13:01:41 +00:00
45d3a6fb74 Merge pull request '[CI] Bump PHP versions in woodpecker' (#1604) from nupplaPhil/friendica-addons:feat/woodpecker into develop
Reviewed-on: friendica/friendica-addons#1604
2025-04-27 02:18:37 +02:00
97a3b5815b [CI] Bump PHP versions in woodpecker 2025-04-27 02:18:37 +02:00
95a9f7038a Merge pull request 'PHPStan level 3' (#1603) from Art4/friendica-addons:phpstan-level-3 into develop
Reviewed-on: friendica/friendica-addons#1603
2025-04-27 02:17:41 +02:00
Art4
06b4f164f5 cast db stmt object to array 2025-03-14 08:21:08 +00:00
Art4
38a8e9a169 remove obvious type cast 2025-03-14 08:15:02 +00:00
Art4
db875bc755 Remove type casting to int 2025-03-14 07:49:20 +00:00
Art4
dd58b000d9 Fix error in bluesky addon 2025-03-13 11:57:28 +00:00
Art4
cdeaa433a1 Fix error in diaspora addon 2025-03-13 11:55:34 +00:00
Art4
ad31685237 Fix error in js_upload addon 2025-03-13 11:51:53 +00:00
Art4
2667b4d78e Fix error in libravatar addon 2025-03-13 11:38:18 +00:00
Art4
c56ec7c7c4 Fix error in mailstream addon 2025-03-13 10:29:47 +00:00
Art4
417a3a8198 Fix error in membersince addon 2025-03-13 09:49:18 +00:00
Art4
dda6710b10 Fix error in notifyall addon 2025-03-13 09:36:34 +00:00
Art4
21a7529a0e fix PHPStan error in phpmailer addon 2025-02-26 15:21:19 +00:00
Art4
bbce8c345f Fix PHPStan errors in phpnut addon 2025-02-26 15:12:25 +00:00
Art4
512ad63dbf Fix PHPStan errors in statusnet addon 2025-02-26 14:35:00 +00:00
Art4
cfe27582ee Fix PHPStan error in tumblr addon 2025-02-26 08:47:06 +00:00
Art4
d488c1907a Fix PHPStan error in webdav_storage addon 2025-02-25 15:24:00 +00:00
81b4d3cab4 Merge pull request '[tumblr] Skip empty tags when saving user-defined tags' (#1602) from MrPetovan/friendica-addons:bug/fatal-errors into develop
Reviewed-on: friendica/friendica-addons#1602
2025-02-24 19:23:47 +01:00
ec718ea294 [tumblr] Skip empty tags when saving user-defined tags
- Skip empty tags when fetching them
↪ Empty tags were triggering a Tumblr API error
- Address https://github.com/friendica/friendica/issues/14646#issuecomment-2628090487
- Using log output from https://github.com/friendica/friendica/issues/14646#issuecomment-2665000962
2025-02-20 23:03:27 -05:00
8411a0f5ed Merge pull request 'Improve accessibility with showmore and rendertime' (#1600) from heluecht/friendica-addons:accessibility into develop
Reviewed-on: friendica/friendica-addons#1600
2025-02-16 11:05:52 +01:00
859d92ab02 Improve accessibility with showmore and rendertime 2025-02-16 11:05:52 +01:00
73d4bed31c Merge pull request 'Bluesky: Avoid duplicated reshares' (#1601) from heluecht/friendica-addons:double-reshare into develop
Reviewed-on: friendica/friendica-addons#1601
2025-02-16 11:05:18 +01:00
07008af9c1 Bluesky: Avoid duplicated reshares 2025-02-16 06:12:49 +00:00
0fb2c05244 Merge pull request '[tumblr] Ward against unexpected response format in tumblr_fetch_tags()' (#1599) from MrPetovan/friendica-addons:bug/fatal-errors into develop
Reviewed-on: friendica/friendica-addons#1599
2025-02-08 16:57:13 +01:00
373c30b5d0 [tumblr] Ward against unexpected response format in tumblr_fetch_tags()
- Adress https://github.com/friendica/friendica/issues/14646#issuecomment-2628090487
2025-02-08 16:57:13 +01:00
4454ce5883 Merge pull request 'Implement monolog addon as LoggerFactory' (#1598) from Art4/friendica-addons:loggerfactory-in-monolog-addon into develop
Reviewed-on: friendica/friendica-addons#1598
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-02-08 04:16:47 +01:00
Art4
5701853d29 Remove config docs, format syntax 2025-02-06 11:35:10 +00:00
Art4
ed75360eb4 Setting the logger_config config is no longer needed 2025-02-06 09:27:22 +00:00
Art4
c4f8c65817 Remove wrong phpdoc 2025-02-05 15:32:24 +00:00
Art4
f7ec934893 bump version to 1.1 2025-02-05 15:20:22 +00:00
Art4
0bafcc78f8 Add READMD.md for monolog addon 2025-02-05 15:20:06 +00:00
Art4
e6d92cc94a Rewrite Monolog factory to implement LoggerFactory 2025-02-05 15:11:14 +00:00
16a8172c37 Merge pull request 'Accessibility: Use different id values for options' (#1597) from heluecht/friendica-addons:accessibility into develop
Reviewed-on: friendica/friendica-addons#1597
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-28 23:09:04 +01:00
16127854dd Accessibility: Use different id values for options 2025-01-28 20:27:52 +00:00
7e1bcbdedb Merge pull request 'Add additional theme-filter for disabling/enabling divs.' (#1596) from jakob/friendica-addons:fix-saml-display-settings into develop
Reviewed-on: friendica/friendica-addons#1596
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-25 14:06:07 +01:00
Jakobus Schürz
8384b74696 add condition for selected theme 2025-01-25 08:05:32 -05:00
c5e3d1f047 Merge pull request 'Issue 14692: Avoid loop situation' (#1595) from heluecht/friendica-addons:issue-14692 into develop
Reviewed-on: friendica/friendica-addons#1595
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-25 13:59:52 +01:00
cbfcfb3349 Issue 14692: Avoid loop situation 2025-01-25 02:44:54 +00:00
cdba300c7b Merge pull request 'Replace Logger class with DI::logger()' (#1594) from Art4/friendica-addons:replace-logger-with-loggerinterface into develop
Reviewed-on: friendica/friendica-addons#1594
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-24 14:34:43 +01:00
Art4
4c8c262b07 fix in googlemaps addon 2025-01-24 12:10:58 +00:00
Art4
dd775645d4 Replace call for Logger with DI::logger() in wppost addon 2025-01-24 11:58:32 +00:00
Art4
e4d14cab62 Replace call for Logger with DI::logger() in twitter addon 2025-01-24 11:58:10 +00:00
Art4
a7b26f6453 Replace call for Logger with DI::logger() in tesseract addon 2025-01-24 11:57:34 +00:00
Art4
763c5026f2 Replace call for Logger with DI::logger() in tumblr addon 2025-01-24 11:57:12 +00:00
Art4
bfdccb451c Replace call for Logger with DI::logger() in statusnet addon 2025-01-24 11:56:45 +00:00
Art4
ac6c1d7a49 Replace call for Logger with DI::logger() in saml addon 2025-01-24 11:56:29 +00:00
Art4
32a3160445 Replace call for Logger with DI::logger() in randplace addon 2025-01-24 11:56:09 +00:00
Art4
d50650b8cf Replace call for Logger with DI::logger() in pumpio addon 2025-01-24 11:55:13 +00:00
Art4
e32ba1ce7b Replace call for Logger with DI::logger() in public_server addon 2025-01-24 11:54:34 +00:00
Art4
119ba0a78e Replace call for Logger with DI::logger() in pnut addon 2025-01-24 11:48:21 +00:00
Art4
469d3e6d61 Replace call for Logger with DI::logger() in planets addon 2025-01-24 11:47:40 +00:00
Art4
757d72c360 Replace call for Logger with DI::logger() in openstreetmap addon 2025-01-24 11:47:24 +00:00
Art4
9ceff8f592 Replace call for Logger with DI::logger() in nominatim addon 2025-01-24 11:46:58 +00:00
Art4
9a91bae363 Replace call for Logger with DI::logger() in mailstream addon 2025-01-24 11:46:30 +00:00
Art4
9ed02034f1 Replace call for Logger with DI::logger() in ljpost addon 2025-01-24 11:46:04 +00:00
Art4
f08750199d Replace call for Logger with DI::logger() in libertree addon 2025-01-24 11:45:25 +00:00
Art4
a488f25131 Replace call for Logger with DI::logger() in ldapauth addon 2025-01-24 11:44:48 +00:00
Art4
5d51c5b56e Replace call for Logger with DI::logger() in js_upload addon 2025-01-24 11:42:25 +00:00
Art4
5002318089 Replace call for Logger with DI::logger() in ijpost addon 2025-01-24 11:41:02 +00:00
Art4
15a951235f Replace call for Logger with DI::logger() in ifttt addon 2025-01-24 11:40:32 +00:00
Art4
e7755584cb Replace call for Logger with DI::logger() in geocoordinates addon 2025-01-24 11:40:12 +00:00
Art4
1db552ead9 Replace call for Logger with DI::logger() in dwpost addon 2025-01-24 11:39:11 +00:00
Art4
b38c2d18be Replace call for Logger with DI::logger() in discourse addon 2025-01-24 11:38:48 +00:00
Art4
4881e6004a Replace call for Logger with DI::logger() in diaspora addon 2025-01-24 11:38:27 +00:00
Art4
1d1a00df27 Replace call for Logger with DI::logger() in cld addon 2025-01-24 11:37:58 +00:00
Art4
77ebaca281 Replace call for Logger with DI::logger() in ratioed addon 2025-01-24 11:37:28 +00:00
Art4
d78ea50516 Replace call for Logger with DI::logger() in bluesky addon 2025-01-24 11:36:23 +00:00
Art4
41f280f0c7 Replace call for Logger with DI::logger() in blockbot addon 2025-01-24 11:34:33 +00:00
Art4
4310c1355d Replace call for Logger with DI::logger() 2025-01-24 10:53:01 +00:00
1cc5a6688e Merge pull request 'rework saml addon' (#1588) from jakob/friendica-addons:fix-saml-display-settings into develop
Reviewed-on: friendica/friendica-addons#1588
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-23 14:31:49 +01:00
Jakobus Schürz
0b4aaac9fd translation for saml-hint 2025-01-23 14:31:49 +01:00
Jakobus Schürz
c506367273 replace password-handling with hint
also add hint to email-field
2025-01-23 14:31:49 +01:00
Jakobus Schürz
792f50f835 fix view in vier and frio 2025-01-23 14:31:49 +01:00
Jakobus Schürz
2b5764c132 rework saml addon
fix #1587
remove css-side hiding of elements, which was broken.
remove them or make them readonly via javascript
2025-01-23 14:31:49 +01:00
69e75ef88b Merge pull request 'Check PHPStan in addons' (#1592) from Art4/friendica-addons:fix-phpstan-error into develop
Reviewed-on: friendica/friendica-addons#1592
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-23 14:29:59 +01:00
Art4
7a7940a8ed Fix PHPStan errors 2025-01-23 08:29:13 -05:00
Art4
2741227bfa Add phpstan in woodpacker 2025-01-23 08:27:48 -05:00
13cffd76db Merge pull request 'Clean up phpstan warning' (#1591) from mexon/friendica-addons:mat/ratioed-fix-warning into develop
Reviewed-on: friendica/friendica-addons#1591
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2025-01-23 14:26:41 +01:00
Matthew Exon
0d0aae36cd Clean up phpstan warning 2025-01-23 08:26:23 -05:00
28d3041694 Merge pull request 'Fix codestyle' (#1590) from heluecht/friendica-addons:ratiod-fix into develop
Reviewed-on: friendica/friendica-addons#1590
2025-01-22 08:49:57 +01:00
cb70a4eaff Fix codestyle 2025-01-18 15:25:50 +00:00
0c96d0f4bb Merge pull request 'Ratioed: add statistics about reply likes and reply guy score' (#1589) from mexon/friendica-addons:mat/reply-guy-score into develop
Reviewed-on: friendica/friendica-addons#1589
2025-01-16 06:43:41 +01:00
Matthew Exon
ee8c852d38 Ratioed: remove action buttons 2025-01-15 19:33:11 +01:00
Matthew Exon
807598dbd0 Ratioed: wrap long lines 2025-01-15 19:32:55 +01:00
Matthew Exon
8ba4cd5f61 Ratioed: bump version number 2025-01-12 14:33:21 +01:00
Matthew Exon
3441c9bd0e Ratioed: add statistics about reply likes and reply guy score 2025-01-12 14:33:21 +01:00
44d2079da2 Merge pull request 'Ratioed: several fixes to functionality' (#1586) from mexon/friendica-addons:mat/ratioed-fixes into develop
Reviewed-on: friendica/friendica-addons#1586
2025-01-12 12:03:00 +01:00
Matthew Exon
b360b553ed Ratioed: remove actions 2025-01-12 12:03:00 +01:00
Matthew Exon
46b3836720 Ratioed: remove create user button 2025-01-12 12:03:00 +01:00
Matthew Exon
81639ff615 Ratioed: fix sorting by columns 2025-01-12 12:03:00 +01:00
Matthew Exon
d495810b2d Ratioed: allow both sorting directions 2025-01-12 12:03:00 +01:00
Matthew Exon
2ef9cb8add Ratioed: fill in zeroes for empty values 2025-01-12 12:03:00 +01:00
Matthew Exon
8e65141cb5 Ratioed: bump version number 2025-01-12 12:03:00 +01:00
Matthew Exon
d034e311cb Ratioed: add help link 2025-01-12 12:03:00 +01:00
db10da2f02 Merge pull request '[CI] Fix releaser' (#1585) from nupplaPhil/friendica-addons:ci/stable_pick into develop
Reviewed-on: friendica/friendica-addons#1585
2025-01-02 08:37:19 +01:00
995e81e951
[CI] Fix releaser 2025-01-01 20:22:42 +01:00
cb2ab0684e Merge branch 'stable' into develop 2024-12-31 18:57:15 +01:00
Art4
5f557ed0ab Merge branch '2024.09-rc' into merge-2024.09-rc-into-develop 2024-12-23 10:15:53 +00:00
a63fb08525 Merge remote-tracking branch '2024.09-rc' into develop
# Conflicts:
#	bluesky/bluesky.php
2024-12-16 09:12:09 -05:00
6cf388f141 Merge remote-tracking branch 'Art4/remove-app-usage' into develop 2024-12-16 09:04:45 -05:00
Art4
c4bea164c7 Merge branch 'develop' into remove-app-usage 2024-12-15 15:55:54 +00:00
04c402607b Merge branch 'Art4/fix-phpstan-error-level-2' into develop 2024-12-15 09:18:47 -05:00
Artur Weigandt
68ee5260b0
Merge branch 'develop' into fix-phpstan-error-level-2 2024-12-13 10:28:15 +01:00
81a84fb895 Merge pull request 'fix-phpstan-error-level-1' (#1579) from MrPetovan/friendica-addons:fix-phpstan-error-level-1 into develop
Reviewed-on: friendica/friendica-addons#1579
2024-12-12 22:37:42 +01:00
Artur Weigandt
729b6e5210 Update mailstream/phpmailer/class.phpmailer.php
Co-authored-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-12 22:37:42 +01:00
Art4
a71db771d9 Fix errors in wppost addon 2024-12-12 22:37:42 +01:00
Art4
2f89827dea fix errors in tictac addon 2024-12-12 22:37:42 +01:00
Art4
8e778593ca fix errors in statusnet addon 2024-12-12 22:37:42 +01:00
Art4
5b623c8368 fix errors in ratioed addon 2024-12-12 22:37:42 +01:00
Art4
bda683c56b fix errors in pumpio addon 2024-12-12 22:37:42 +01:00
Art4
7fa2dfc608 Fix errors in pnut addon 2024-12-12 22:37:42 +01:00
Art4
c0971779c6 Fix errors in nsfw addon 2024-12-12 22:37:42 +01:00
Art4
6b1b043dd8 fix errors in mailstream addon 2024-12-12 22:37:42 +01:00
Art4
984e7c5e5d Fix errors in ljpost addon 2024-12-12 22:37:42 +01:00
Art4
d08a280ba6 Fix errors in libravatar addon 2024-12-12 22:37:42 +01:00
Art4
ee1a917612 Fix errors in leistungsschutzrecht addon 2024-12-12 22:37:42 +01:00
Art4
a53d5ae29b Fix errors in langfilter addon 2024-12-12 22:37:42 +01:00
Art4
3cf53a334d Fix errors in keycloakpassword addon 2024-12-12 22:37:42 +01:00
Art4
81f232d57e Fix errors in js_upload addon 2024-12-12 22:37:42 +01:00
Art4
1860e732ae Fix errors in convert addon 2024-12-12 22:37:42 +01:00
Art4
cf8a7870f3 Fix errors in bluesky addon 2024-12-12 22:37:42 +01:00
Art4
31198294c7 Fix error in bluesky addon 2024-12-12 22:37:42 +01:00
Art4
84659fc1ad Replace DI::app() with DI::appHelper() 2024-12-11 21:47:10 +00:00
Art4
5f7482d081 Remove unused use statements for App 2024-12-11 21:42:48 +00:00
Art4
fff140ad43 Fix last 3 errors 2024-12-09 23:08:31 +00:00
Art4
cfb6b3123f Fix errors in statusnet addon 2024-12-08 23:06:51 +00:00
Art4
b99ac65c0b Fix errors in membersince addon 2024-12-08 22:49:23 +00:00
Art4
89a673cc11 Fix typo 2024-12-08 22:19:58 +00:00
Art4
2fe37c6d4a Fix errors in pnut addon 2024-12-08 21:24:03 +00:00
Art4
5b13274bed Fix class name collision 2024-12-08 21:02:07 +00:00
Art4
82ed43f507 Fix errors 2024-12-07 22:08:59 +00:00
Art4
43c71412e4 Merge branch 'develop' into fix-phpstan-error-level-1 2024-12-01 07:41:27 +00:00
fb9c10f8c5 Merge pull request 'Fix phpstan error level 0 part2' (#1577) from fix-phpstan-error-level-0-part2 into develop
Reviewed-on: friendica/friendica-addons#1577
Reviewed-by: Hypolite Petovan <hypolite@mrpetovan.com>
2024-12-01 03:20:18 +01:00
Art4
1e68417278 Fix classes in s3_storage addon 2024-12-01 03:20:18 +01:00
Art4
7d02c9b53c Fix errors in pumpio addon 2024-12-01 03:20:18 +01:00
Art4
b5c647bd5d fix errors in pnut addon, add support for PHP 7.4 2024-12-01 03:20:18 +01:00
Art4
1bd7cd6e71 fix error in PHPMailer 2024-12-01 03:20:18 +01:00
Art4
def43f3167 Fix errors in mailstream addon 2024-12-01 03:20:18 +01:00
Art4
b661448344 Fix errors in libravatar addon 2024-12-01 03:20:18 +01:00
Art4
922bace555 Fix errors in diaspora addon 2024-12-01 03:20:18 +01:00
Art4
4a2fc7884c remove wrong return tag 2024-12-01 03:20:18 +01:00
Art4
9d172b7082 refactor convert addon, replace each() calls with foreach loop 2024-12-01 03:20:18 +01:00
Art4
4527df602f Add checks for CLD2Detector ans CLD2Encoding classes 2024-12-01 03:20:18 +01:00
Art4
15c21cebb1 Fix errors in wppost addon 2024-11-30 20:36:58 +00:00
Art4
b6a47699bf fix errors in tictac addon 2024-11-30 20:36:07 +00:00
Art4
a41f8c13fe fix errors in statusnet addon 2024-11-30 20:27:57 +00:00
Art4
fccf361ef1 fix errors in ratioed addon 2024-11-30 20:13:41 +00:00
Art4
43ee267d38 fix errors in pumpio addon 2024-11-30 20:12:23 +00:00
Art4
3f89aa1806 Fix errors in pnut addon 2024-11-30 19:51:18 +00:00
Art4
50912fdc17 Fix errors in nsfw addon 2024-11-30 19:50:06 +00:00
Art4
c04016b7d3 fix errors in mailstream addon 2024-11-30 19:48:49 +00:00
Art4
5f6f374f09 Fix errors in ljpost addon 2024-11-30 19:42:40 +00:00
Art4
e86d15993b Fix errors in libravatar addon 2024-11-30 19:41:11 +00:00
Art4
ace19814d7 Fix errors in leistungsschutzrecht addon 2024-11-30 19:37:58 +00:00
Art4
fcec1a3d83 Fix errors in langfilter addon 2024-11-30 19:35:19 +00:00
Art4
04afbe36e3 Fix errors in keycloakpassword addon 2024-11-30 19:32:07 +00:00
Art4
07993f7098 Fix errors in js_upload addon 2024-11-30 19:30:39 +00:00
Art4
bee780552d Fix errors in convert addon 2024-11-30 19:28:38 +00:00
Art4
5664bc84fb Fix errors in bluesky addon 2024-11-30 19:27:50 +00:00
Art4
7246f3deda Merge branch 'fix-phpstan-error-level-0-part2' into fix-phpstan-error-level-1 2024-11-30 19:23:00 +00:00
Art4
0204f54b0e Merge branch 'develop' into fix-phpstan-error-level-0-part2 2024-11-30 06:51:49 +00:00
72e7e2a5b7 Merge remote-tracking branch 'friendica/2024.09-rc' into develop 2024-11-29 21:15:25 -05:00
Art4
5f2a9e9891 Fix error in bluesky addon 2024-11-29 22:36:09 +00:00
Art4
a6de4225c6 Merge branch 'port-rc-branch-into-develop' into fix-phpstan-error-level-0-part2 2024-11-27 23:19:19 +00:00
Art4
23227e5b0f Fix classes in s3_storage addon 2024-11-27 23:18:20 +00:00
Art4
7872400467 Fix errors in pumpio addon 2024-11-27 23:14:01 +00:00
Art4
a5aaea5211 fix errors in pnut addon, add support for PHP 7.4 2024-11-27 22:55:15 +00:00
Art4
7453c6f41a fix error in PHPMailer 2024-11-27 22:33:12 +00:00
Art4
9cb728d19a Merge branch 'develop' into fix-phpstan-error-level-0-part2 2024-11-27 22:25:42 +00:00
Art4
e488f597be Fix errors in mailstream addon 2024-11-27 11:52:59 +00:00
Art4
1346a92505 Fix errors in libravatar addon 2024-11-27 11:43:21 +00:00
Art4
9117626c6a Fix errors in diaspora addon 2024-11-27 11:40:45 +00:00
Art4
90ffd40d58 remove wrong return tag 2024-11-27 11:38:55 +00:00
93a91a95e9 Merge pull request 'Fix PHPStan errors on level 0' (#1575) from MrPetovan/friendica-addons:bug/Art4-1367 into develop
Reviewed-on: friendica/friendica-addons#1575
2024-11-27 08:36:08 +01:00
Art4
fc0dda0cd9 refactor convert addon, replace each() calls with foreach loop 2024-11-26 08:23:27 +00:00
Art4
d7d6a43655 Add checks for CLD2Detector ans CLD2Encoding classes 2024-11-26 07:55:01 +00:00
Art4
c58ca7dcc9 Merge branch '2024.09-rc' into port-rc-branch-into-develop 2024-11-26 07:33:57 +00:00
Art4
6df91dd37b Fix errors in statusnet addon 2024-11-24 19:55:54 +00:00
Art4
e9d3afb483 Fix errors in tictac addon 2024-11-24 19:51:37 +00:00
Art4
348c44c972 inline slim routes and middlewares into advancedcontentfilter addon 2024-11-24 15:36:37 +00:00
58180bd732 Merge pull request 'Remove unused parameter in saml addon' (#1572) from MrPetovan/friendica-addons:bug/Art4-1366 into develop
Reviewed-on: friendica/friendica-addons#1572
2024-11-24 10:17:44 +01:00
Artur Weigandt
bf679262b0 Remove unused parameter in saml addon 2024-11-24 10:17:44 +01:00
c4e24833eb Merge pull request 'Remove unused parameter webdav_storage addon' (#1570) from MrPetovan/friendica-addons:bug/Art4-1364 into develop
Reviewed-on: friendica/friendica-addons#1570
2024-11-24 10:16:47 +01:00
Artur Weigandt
ecf0edb520 Remove unused parameter webdav_storage addon 2024-11-24 10:16:47 +01:00
3a5acf95f7 Merge pull request 'Remove unused App paramter in securemail addon' (#1571) from MrPetovan/friendica-addons:bug/Art4-1365 into develop
Reviewed-on: friendica/friendica-addons#1571
2024-11-24 10:16:25 +01:00
Artur Weigandt
2ea40dc897 Remove unused App paramter in securemail addon 2024-11-23 21:24:34 -05:00
170 changed files with 3352 additions and 1397 deletions

View file

@ -1,6 +1,6 @@
skip_clone: true
pipeline:
steps:
clone_friendica_base:
image: alpine/git
commands:
@ -56,6 +56,10 @@ pipeline:
- /tmp/drone-cache:/tmp/cache
when:
event: pull_request
phpstan:
image: friendicaci/php8.3:php8.3.3
commands:
- ./bin/composer.phar run phpstan;
check:
image: friendicaci/php-cs
commands:

View file

@ -0,0 +1,115 @@
# This prevents executing this pipeline at other servers than ci.friendi.ca
labels:
location: friendica
type: releaser
skip_clone: true
steps:
clone_friendica_base:
image: alpine/git
commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git config --global --add safe.directory $CI_WORKSPACE
- git clone https://github.com/friendica/friendica.git .
- git checkout $CI_COMMIT_BRANCH
when:
repo: friendica/friendica-addons
branch: [ develop, '*-rc' ]
event: push
clone_friendica_addon:
image: alpine/git
commands:
- git config --global user.email "no-reply@friendi.ca"
- git config --global user.name "Friendica"
- git clone $CI_REPO_CLONE_URL addon
- cd addon/
- git checkout $CI_COMMIT_BRANCH
- git fetch origin $CI_COMMIT_REF
- git merge $CI_COMMIT_SHA
when:
repo: friendica/friendica-addons
branch: [ develop, '*-rc' ]
event: push
restore_cache:
image: meltwater/drone-cache:dev
settings:
backend: "filesystem"
restore: true
cache_key: "{{ .Repo.Name }}_php7.4_{{ arch }}_{{ os }}"
archive_format: "gzip"
mount:
- '.composer'
volumes:
- /tmp/drone-cache:/tmp/cache
when:
repo: friendica/friendica-addons
branch: [ develop, '*-rc' ]
event: push
composer_install:
image: friendicaci/php8.2:php8.2.28
commands:
- export COMPOSER_HOME=.composer
- composer validate
- composer install --no-dev --optimize-autoloader
volumes:
- /etc/hosts:/etc/hosts
when:
repo: friendica/friendica-addons
branch: [ develop, '*-rc' ]
event: push
create_artifacts:
image: debian
commands:
- apt-get update
- apt-get install bzip2
- mkdir ./build
- export VERSION="$(cat VERSION)"
- export RELEASE="friendica-all-in-one-$VERSION"
- export ARTIFACT="$RELEASE.tar.gz"
- tar
--exclude='.tx'
--exclude='.git'
--exclude='.editorconfig'
--exclude='.gitattributes'
--exclude='.gitignore'
--exclude='.woodpecker'
--exclude='**/*/messages.po'
-cvzf ./build/$ARTIFACT /
- cd ./build
- sha256sum "$ARTIFACT" > "$ARTIFACT.sum256"
- chmod 664 ./*
- ls -lh
- cat "$ARTIFACT.sum256"
- sha256sum "$ARTIFACT"
when:
repo: friendica/friendica-addons
branch: [ develop, '*-rc' ]
event: push
sign_artifacts:
image: plugins/gpgsign
settings:
key:
from_secret: gpg_key
passphrase:
from_secret: gpg_password
files:
- build/*
exclude:
- build/*.sum256
detach_sign: true
when:
repo: friendica/friendica-addons
branch: [ develop, '*-rc' ]
event: push
publish_artifacts:
image: alpine
commands:
- cp -fr build/* /tmp/friendica_files/
volumes:
- files:/tmp/friendica_files
when:
repo: friendica/friendica-addons
branch: [ develop, '*-rc' ]
event: push

View file

@ -5,7 +5,7 @@ labels:
skip_clone: true
pipeline:
steps:
clone_friendica_base:
image: alpine/git
commands:
@ -48,7 +48,7 @@ pipeline:
branch: [ develop, '*-rc' ]
event: push
composer_install:
image: friendicaci/php8.2:php8.2.16
image: friendicaci/php8.2:php8.2.28
commands:
- export COMPOSER_HOME=.composer
- composer validate

View file

@ -1,6 +1,6 @@
skip_clone: true
pipeline:
steps:
clone_friendica_base:
image: alpine/git
commands:

View file

@ -5,11 +5,13 @@ matrix:
- PHP_MAJOR_VERSION: 8.0
PHP_VERSION: 8.0.30
- PHP_MAJOR_VERSION: 8.1
PHP_VERSION: 8.1.27
PHP_VERSION: 8.1.31
- PHP_MAJOR_VERSION: 8.2
PHP_VERSION: 8.2.16
PHP_VERSION: 8.2.28
- PHP_MAJOR_VERSION: 8.3
PHP_VERSION: 8.3.3
PHP_VERSION: 8.3.17
- PHP_MAJOR_VERSION: 8.4
PHP_VERSION: 8.4.5
# This forces PHP Unit executions at the "opensocial" labeled location (because of much more power...)
labels:
@ -17,7 +19,7 @@ labels:
skip_clone: true
pipeline:
steps:
clone_friendica_base:
image: alpine/git
commands:

View file

@ -5,7 +5,7 @@ labels:
skip_clone: true
pipeline:
steps:
clone_friendica_base:
image: alpine/git
commands:
@ -45,7 +45,7 @@ pipeline:
repo: friendica/friendica-addons
event: tag
composer_install:
image: friendicaci/php8.2:php8.2.16
image: friendicaci/php8.2:php8.2.28
commands:
- export COMPOSER_HOME=.composer
- composer validate

View file

@ -24,6 +24,6 @@ See the [documentation](https://github.com/friendica/friendica/blob/stable/doc/A
## Translation
Addons can be translated like any other part of Friendica.
Translation for addons is done at [the Transifex Friendica page](https://www.transifex.com/Friendica/friendica/dashboard/).
Translation for addons is done at [the Transifex Friendica page](https://app.transifex.com/Friendica/friendica/dashboard/).
Read more about the workflow in the [Friendica translation documentation](https://github.com/friendica/friendica/blob/stable/doc/translations.md#addon).

View file

@ -33,16 +33,13 @@
*
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Content\Text\Markdown;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\DI;
use Friendica\Model\Item;
use Friendica\Model\Post;
use Friendica\Model\Tag;
use Friendica\Model\User;
@ -64,7 +61,7 @@ function advancedcontentfilter_install()
Hook::add('dbstructure_definition' , __FILE__, 'advancedcontentfilter_dbstructure_definition');
DBStructure::performUpdate();
Logger::notice('installed advancedcontentfilter');
DI::logger()->notice('installed advancedcontentfilter');
}
/*
@ -123,21 +120,22 @@ function advancedcontentfilter_prepare_body_content_filter(&$hook_data)
$expressionLanguage = new ExpressionLanguage\ExpressionLanguage();
}
if (!DI::userSession()->getLocalUserId()) {
$uid = $hook_data['uid'] ?? DI::userSession()->getLocalUserId();
if (!$uid) {
return;
}
$vars = advancedcontentfilter_get_filter_fields($hook_data['item']);
$rules = DI::cache()->get('rules_' . DI::userSession()->getLocalUserId());
$rules = DI::cache()->get('rules_' . $uid);
if (!isset($rules)) {
$rules = DBA::toArray(DBA::select(
'advancedcontentfilter_rules',
['name', 'expression', 'serialized'],
['uid' => DI::userSession()->getLocalUserId(), 'active' => true]
['uid' => $uid, 'active' => true]
));
DI::cache()->set('rules_' . DI::userSession()->getLocalUserId(), $rules);
DI::cache()->set('rules_' . $uid, $rules);
}
if ($rules) {
@ -192,9 +190,30 @@ function advancedcontentfilter_init()
if (DI::args()->getArgc() > 1 && DI::args()->getArgv()[1] == 'api') {
$slim = \Slim\Factory\AppFactory::create();
require __DIR__ . '/src/middlewares.php';
/**
* The routing middleware should be added before the ErrorMiddleware
* Otherwise exceptions thrown from it will not be handled
*/
$slim->addRoutingMiddleware();
$slim->addErrorMiddleware(true, true, true, DI::logger());
// register routes
$slim->group('/advancedcontentfilter/api', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->group('/rules', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('', 'advancedcontentfilter_get_rules');
$app->post('', 'advancedcontentfilter_post_rules');
$app->get('/{id}', 'advancedcontentfilter_get_rules_id');
$app->put('/{id}', 'advancedcontentfilter_put_rules_id');
$app->delete('/{id}', 'advancedcontentfilter_delete_rules_id');
});
$app->group('/variables', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('/{guid}', 'advancedcontentfilter_get_variables_guid');
});
});
require __DIR__ . '/src/routes.php';
$slim->run();
exit;
@ -252,7 +271,7 @@ function advancedcontentfilter_content()
'rule_expression' => DI::l10n()->t('Rule Expression'),
'cancel' => DI::l10n()->t('Cancel'),
],
'$current_theme' => DI::app()->getCurrentTheme(),
'$current_theme' => DI::appHelper()->getCurrentTheme(),
'$rules' => DBA::toArray(DBA::select('advancedcontentfilter_rules', [], ['uid' => DI::userSession()->getLocalUserId()])),
'$form_security_token' => BaseModule::getFormSecurityToken()
]);

View file

@ -1,32 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
use Friendica\DI;
/** @var $slim \Slim\App */
/**
* The routing middleware should be added before the ErrorMiddleware
* Otherwise exceptions thrown from it will not be handled
*/
$slim->addRoutingMiddleware();
$errorMiddleware = $slim->addErrorMiddleware(true, true, true, DI::logger());

View file

@ -1,36 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2020, Friendica
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
/* @var $slim Slim\App */
$slim->group('/advancedcontentfilter/api', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->group('/rules', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('', 'advancedcontentfilter_get_rules');
$app->post('', 'advancedcontentfilter_post_rules');
$app->get('/{id}', 'advancedcontentfilter_get_rules_id');
$app->put('/{id}', 'advancedcontentfilter_put_rules_id');
$app->delete('/{id}', 'advancedcontentfilter_delete_rules_id');
});
$app->group('/variables', function (\Slim\Routing\RouteCollectorProxy $app) {
$app->get('/{guid}', 'advancedcontentfilter_get_variables_guid');
});
});

View file

@ -6,9 +6,7 @@
* Author: Fabio <https://kirgroup.com/profile/fabrixxm>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
@ -28,7 +26,7 @@ function birdavatar_install()
Hook::register('addon_settings', __FILE__, 'birdavatar_addon_settings');
Hook::register('addon_settings_post', __FILE__, 'birdavatar_addon_settings_post');
Logger::info('registered birdavatar');
DI::logger()->info('registered birdavatar');
}
/**

View file

@ -44,9 +44,7 @@
* THE SOFTWARE.
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\DI;
@ -78,7 +76,7 @@ function blackout_redirect ($b)
}
if (( $date1 <= $now ) && ( $now <= $date2 )) {
Logger::notice('redirecting user to blackout page');
DI::logger()->notice('redirecting user to blackout page');
System::externalRedirect($myurl);
}
}

View file

@ -11,7 +11,6 @@
use Friendica\Core\Hook;
use Friendica\DI;
use Jaybizzle\CrawlerDetect\CrawlerDetect;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Network\HTTPException\ForbiddenException;
@ -70,7 +69,7 @@ function blockbot_init_1()
}
if (empty($parts)) {
Logger::debug('Known frontend found - accept', $logdata);
DI::logger()->debug('Known frontend found - accept', $logdata);
if ($isCrawler) {
blockbot_save('badly-parsed-agents', $_SERVER['HTTP_USER_AGENT']);
}
@ -80,66 +79,66 @@ function blockbot_init_1()
blockbot_log_activitypub($_SERVER['REQUEST_URI'], $_SERVER['HTTP_USER_AGENT']);
if (blockbot_is_crawler($parts)) {
Logger::debug('Crawler found - reject', $logdata);
DI::logger()->debug('Crawler found - reject', $logdata);
blockbot_reject();
}
if (blockbot_is_searchbot($parts)) {
Logger::debug('Search bot found - reject', $logdata);
DI::logger()->debug('Search bot found - reject', $logdata);
blockbot_reject();
}
if (blockbot_is_unwanted($parts)) {
Logger::debug('Uncategorized unwanted agent found - reject', $logdata);
DI::logger()->debug('Uncategorized unwanted agent found - reject', $logdata);
blockbot_reject();
}
if (blockbot_is_security_checker($parts)) {
if (!DI::config()->get('blockbot', 'security_checker')) {
Logger::debug('Security checker found - reject', $logdata);
DI::logger()->debug('Security checker found - reject', $logdata);
blockbot_reject();
}
Logger::debug('Security checker found - accept', $logdata);
DI::logger()->debug('Security checker found - accept', $logdata);
return;
}
if (blockbot_is_social_media($parts)) {
Logger::debug('Social media service found - accept', $logdata);
DI::logger()->debug('Social media service found - accept', $logdata);
return;
}
if (blockbot_is_fediverse_client($parts)) {
Logger::debug('Fediverse client found - accept', $logdata);
DI::logger()->debug('Fediverse client found - accept', $logdata);
return;
}
if (blockbot_is_feed_reader($parts)) {
Logger::debug('Feed reader found - accept', $logdata);
DI::logger()->debug('Feed reader found - accept', $logdata);
return;
}
if (blockbot_is_fediverse_tool($parts)) {
Logger::debug('Fediverse tool found - accept', $logdata);
DI::logger()->debug('Fediverse tool found - accept', $logdata);
return;
}
if (blockbot_is_service_agent($parts)) {
Logger::debug('Service agent found - accept', $logdata);
DI::logger()->debug('Service agent found - accept', $logdata);
return;
}
if (blockbot_is_monitor($parts)) {
Logger::debug('Monitoring service found - accept', $logdata);
DI::logger()->debug('Monitoring service found - accept', $logdata);
return;
}
if (blockbot_is_validator($parts)) {
Logger::debug('Validation service found - accept', $logdata);
DI::logger()->debug('Validation service found - accept', $logdata);
return;
}
if (blockbot_is_good_tool($parts)) {
Logger::debug('Uncategorized helpful service found - accept', $logdata);
DI::logger()->debug('Uncategorized helpful service found - accept', $logdata);
return;
}
@ -147,10 +146,10 @@ function blockbot_init_1()
if (blockbot_is_http_library($parts)) {
blockbot_check_login_attempt($_SERVER['REQUEST_URI'], $logdata);
if (!DI::config()->get('blockbot', 'http_libraries')) {
Logger::debug('HTTP Library found - reject', $logdata);
DI::logger()->debug('HTTP Library found - reject', $logdata);
blockbot_reject();
}
Logger::debug('HTTP Library found - accept', $logdata);
DI::logger()->debug('HTTP Library found - accept', $logdata);
return;
}
@ -161,12 +160,12 @@ function blockbot_init_1()
if (!$isCrawler) {
blockbot_save('good-agents', $_SERVER['HTTP_USER_AGENT']);
Logger::debug('Non-bot user agent detected', $logdata);
DI::logger()->debug('Non-bot user agent detected', $logdata);
return;
}
blockbot_save('bad-agents', $_SERVER['HTTP_USER_AGENT']);
Logger::notice('Possible bot found - reject', $logdata);
DI::logger()->notice('Possible bot found - reject', $logdata);
blockbot_reject();
}
@ -209,7 +208,7 @@ function blockbot_log_activitypub(string $url, string $agent)
blockbot_save('activitypub-inbox-agents', $agent);
}
if (!empty($_SERVER['HTTP_SIGNATURE']) && !empty(HTTPSignature::getSigner('', $_SERVER))) {
if (!empty($_SERVER['HTTP_SIGNATURE']) && !empty(HTTPSignature::getSigner('', $_SERVER, false))) {
blockbot_save('activitypub-signature-agents', $agent);
}
}
@ -217,7 +216,7 @@ function blockbot_log_activitypub(string $url, string $agent)
function blockbot_check_login_attempt(string $url, array $logdata)
{
if (in_array(trim(parse_url($url, PHP_URL_PATH), '/'), ['login', 'lostpass', 'register'])) {
Logger::debug('Login attempt detected - reject', $logdata);
DI::logger()->debug('Login attempt detected - reject', $logdata);
blockbot_reject();
}
}
@ -443,7 +442,7 @@ function blockbot_is_monitor(array $parts): bool
}
/**
* Services in the centralized and decentralized social media environment
* Services in the centralized and decentralized social media environment
*
* @param array $parts
* @return boolean

View file

@ -30,7 +30,6 @@ use Friendica\Content\Text\Plaintext;
use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\Worker;
@ -73,7 +72,7 @@ function bluesky_install()
function bluesky_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('bluesky'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('bluesky'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function bluesky_check_item_notification(array &$notification_data)
@ -106,16 +105,16 @@ function bluesky_item_by_link(array &$hookData)
if (empty($did)) {
return;
}
Logger::debug('Found bluesky post', ['uri' => $hookData['uri'], 'did' => $did, 'cid' => $matches[2]]);
DI::logger()->debug('Found bluesky post', ['uri' => $hookData['uri'], 'did' => $did, 'cid' => $matches[2]]);
$uri = 'at://' . $did . '/app.bsky.feed.post/' . $matches[2];
} else {
$uri = $hookData['uri'];
}
$uri = DI::atpProcessor()->fetchMissingPost($uri, $hookData['uid'], Item::PR_FETCHED, 0, 0);
Logger::debug('Got post', ['uri' => $uri]);
DI::logger()->debug('Got post', ['uri' => $uri]);
if (!empty($uri)) {
$item = Post::selectFirst(['id'], ['uri' => $uri, 'uid' => $hookData['uid']]);
if (!empty($item['id'])) {
@ -138,8 +137,8 @@ function bluesky_follow(array &$hook_data)
return;
}
Logger::debug('Check if contact is bluesky', ['data' => $hook_data]);
$contact = DBA::selectFirst('contact', [], ['network' => Protocol::BLUESKY, 'url' => $hook_data['url'], 'uid' => [0, $hook_data['uid']]]);
DI::logger()->debug('Check if contact is bluesky', ['data' => $hook_data]);
$contact = DBA::selectFirst('contact', [], ['network' => Protocol::BLUESKY, 'nurl' => Strings::normaliseLink($hook_data['url']), 'uid' => [0, $hook_data['uid']]]);
if (empty($contact)) {
return;
}
@ -159,7 +158,7 @@ function bluesky_follow(array &$hook_data)
$activity = DI::atProtocol()->XRPCPost($hook_data['uid'], 'com.atproto.repo.createRecord', $post);
if (!empty($activity->uri)) {
$hook_data['contact'] = $contact;
Logger::debug('Successfully start following', ['url' => $contact['url'], 'uri' => $activity->uri]);
DI::logger()->debug('Successfully start following', ['url' => $contact['url'], 'uri' => $activity->uri]);
}
}
@ -213,7 +212,7 @@ function bluesky_block(array &$hook_data)
if ($ucid) {
Contact::remove($ucid);
}
Logger::debug('Successfully blocked contact', ['url' => $hook_data['contact']['url'], 'uri' => $activity->uri]);
DI::logger()->debug('Successfully blocked contact', ['url' => $hook_data['contact']['url'], 'uri' => $activity->uri]);
}
}
@ -421,11 +420,11 @@ function bluesky_cron()
if ($last) {
$next = $last + ($poll_interval * 60);
if ($next > time()) {
Logger::notice('poll interval not reached');
DI::logger()->notice('poll interval not reached');
return;
}
}
Logger::notice('cron_start');
DI::logger()->notice('cron_start');
$abandon_days = intval(DI::config()->get('system', 'account_abandon_days'));
if ($abandon_days < 1) {
@ -437,19 +436,19 @@ function bluesky_cron()
$pconfigs = DBA::selectToArray('pconfig', [], ["`cat` = ? AND `k` IN (?, ?) AND `v`", 'bluesky', 'import', 'import_feeds']);
foreach ($pconfigs as $pconfig) {
if (empty(DI::atProtocol()->getUserDid($pconfig['uid']))) {
Logger::debug('User has got no valid DID', ['uid' => $pconfig['uid']]);
DI::logger()->debug('User has got no valid DID', ['uid' => $pconfig['uid']]);
continue;
}
if ($abandon_days != 0) {
if (!DBA::exists('user', ["`uid` = ? AND `login_date` >= ?", $pconfig['uid'], $abandon_limit])) {
Logger::notice('abandoned account: timeline from user will not be imported', ['user' => $pconfig['uid']]);
DI::logger()->notice('abandoned account: timeline from user will not be imported', ['user' => $pconfig['uid']]);
continue;
}
}
// Refresh the token now, so that it doesn't need to be refreshed in parallel by the following workers
Logger::debug('Refresh the token', ['uid' => $pconfig['uid']]);
DI::logger()->debug('Refresh the token', ['uid' => $pconfig['uid']]);
DI::atProtocol()->getUserToken($pconfig['uid']);
$last_sync = DI::pConfig()->get($pconfig['uid'], 'bluesky', 'last_contact_sync');
@ -463,32 +462,32 @@ function bluesky_cron()
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_timeline.php', $pconfig['uid']);
}
if (DI::pConfig()->get($pconfig['uid'], 'bluesky', 'import_feeds')) {
Logger::debug('Fetch feeds for user', ['uid' => $pconfig['uid']]);
DI::logger()->debug('Fetch feeds for user', ['uid' => $pconfig['uid']]);
$feeds = bluesky_get_feeds($pconfig['uid']);
foreach ($feeds as $feed) {
Worker::add(['priority' => Worker::PRIORITY_MEDIUM, 'force_priority' => true], 'addon/bluesky/bluesky_feed.php', $pconfig['uid'], $feed);
}
}
Logger::debug('Polling done for user', ['uid' => $pconfig['uid']]);
DI::logger()->debug('Polling done for user', ['uid' => $pconfig['uid']]);
}
Logger::notice('Polling done for all users');
DI::logger()->notice('Polling done for all users');
DI::keyValue()->set('bluesky_last_poll', time());
$last_clean = DI::keyValue()->get('bluesky_last_clean');
if (empty($last_clean) || ($last_clean + 86400 < time())) {
Logger::notice('Start contact cleanup');
DI::logger()->notice('Start contact cleanup');
$contacts = DBA::select('account-user-view', ['id', 'pid'], ["`network` = ? AND `uid` != ? AND `rel` = ?", Protocol::BLUESKY, 0, Contact::NOTHING]);
while ($contact = DBA::fetch($contacts)) {
Worker::add(Worker::PRIORITY_LOW, 'MergeContact', $contact['pid'], $contact['id'], 0);
}
DBA::close($contacts);
DI::keyValue()->set('bluesky_last_clean', time());
Logger::notice('Contact cleanup done');
DI::logger()->notice('Contact cleanup done');
}
Logger::notice('cron_end');
DI::logger()->notice('cron_end');
}
function bluesky_hook_fork(array &$b)
@ -508,7 +507,7 @@ function bluesky_hook_fork(array &$b)
if (DI::pConfig()->get($post['uid'], 'bluesky', 'import')) {
// Don't post if it isn't a reply to a bluesky post
if (($post['gravity'] != Item::GRAVITY_PARENT) && !Post::exists(['id' => $post['parent'], 'network' => Protocol::BLUESKY])) {
Logger::notice('No bluesky parent found', ['item' => $post['id']]);
DI::logger()->notice('No bluesky parent found', ['item' => $post['id']]);
$b['execute'] = false;
return;
}
@ -554,13 +553,17 @@ function bluesky_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['gravity'] != Item::GRAVITY_PARENT) {
Logger::debug('Got comment', ['item' => $b]);
DI::logger()->debug('Got comment', ['item' => $b]);
if ($b['deleted']) {
$uri = DI::atpProcessor()->getUriClass($b['uri']);
if (empty($uri)) {
Logger::debug('Not a bluesky post', ['uri' => $b['uri']]);
DI::logger()->debug('Not a bluesky post', ['uri' => $b['uri']]);
return;
}
bluesky_delete_post($b['uri'], $b['uid']);
@ -571,12 +574,12 @@ function bluesky_send(array &$b)
$parent = DI::atpProcessor()->getUriClass($b['thr-parent']);
if (empty($root) || empty($parent)) {
Logger::debug('No bluesky post', ['parent' => $b['parent'], 'thr-parent' => $b['thr-parent']]);
DI::logger()->debug('No bluesky post', ['parent' => $b['parent'], 'thr-parent' => $b['thr-parent']]);
return;
}
if ($b['gravity'] == Item::GRAVITY_COMMENT) {
Logger::debug('Posting comment', ['root' => $root, 'parent' => $parent]);
DI::logger()->debug('Posting comment', ['root' => $root, 'parent' => $parent]);
bluesky_create_post($b, $root, $parent);
return;
} elseif (in_array($b['verb'], [Activity::LIKE, Activity::ANNOUNCE])) {
@ -603,6 +606,8 @@ function bluesky_create_activity(array $item, stdClass $parent = null)
return;
}
$post = [];
if ($item['verb'] == Activity::LIKE) {
$record = [
'subject' => $parent,
@ -633,10 +638,10 @@ function bluesky_create_activity(array $item, stdClass $parent = null)
if (empty($activity->uri)) {
return;
}
Logger::debug('Activity done', ['return' => $activity]);
DI::logger()->debug('Activity done', ['return' => $activity]);
$uri = DI::atpProcessor()->getUri($activity);
Item::update(['extid' => $uri], ['guid' => $item['guid']]);
Logger::debug('Set extid', ['id' => $item['id'], 'extid' => $activity]);
DI::logger()->debug('Set extid', ['id' => $item['id'], 'extid' => $activity]);
}
function bluesky_create_post(array $item, stdClass $root = null, stdClass $parent = null)
@ -671,6 +676,8 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
}
}
$item['body'] = bluesky_set_mentions($item['body']);
$urls = bluesky_get_urls($item['body']);
$item['body'] = $urls['body'];
@ -720,26 +727,53 @@ function bluesky_create_post(array $item, stdClass $root = null, stdClass $paren
}
return;
}
Logger::debug('Posting done', ['return' => $parent]);
DI::logger()->debug('Posting done', ['return' => $parent]);
if (empty($root)) {
$root = $parent;
}
if (($key == 0) && ($item['gravity'] != Item::GRAVITY_PARENT)) {
$uri = DI::atpProcessor()->getUri($parent);
Item::update(['extid' => $uri], ['guid' => $item['guid']]);
Logger::debug('Set extid', ['id' => $item['id'], 'extid' => $uri]);
DI::logger()->debug('Set extid', ['id' => $item['id'], 'extid' => $uri]);
}
}
}
function bluesky_get_urls(string $body): array
function bluesky_set_mentions(string $body): string
{
// Remove all hashtag and mention links
// Remove all url based mention links
$body = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', $body);
if (!preg_match_all("/[@!]\[url\=(did:.*?)\](.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER)) {
return $body;
}
foreach ($matches as $match) {
$contact = Contact::selectFirst(['addr'], ['nurl' => $match[1]]);
if (!empty($contact['addr'])) {
$body = str_replace($match[0], '@[url=' . $match[1] . ']' . $contact['addr'] . '[/url]', $body);
} else {
$body = str_replace($match[0], '@' . $match[2], $body);
}
}
return $body;
}
function bluesky_get_urls(string $body): array
{
$body = BBCode::expandVideoLinks($body);
$urls = [];
// Search for Mentions
if (preg_match_all("/[@!]\[url\=(did:.*?)\](.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
$text = '@' . $match[2];
$urls[strpos($body, $match[0])] = ['mention' => $match[1], 'text' => $text, 'hash' => $text];
$body = str_replace($match[0], $text, $body);
}
}
// Search for hash tags
if (preg_match_all("/#\[url\=(https?:.*?)\](.*?)\[\/url\]/ism", $body, $matches, PREG_SET_ORDER)) {
foreach ($matches as $match) {
@ -824,6 +858,9 @@ function bluesky_get_facets(string $body, array $urls): array
} elseif (!empty($url['url'])) {
$feature->uri = $url['url'];
$feature->$type = 'app.bsky.richtext.facet#link';
} elseif (!empty($url['mention'])) {
$feature->did = $url['mention'];
$feature->$type = 'app.bsky.richtext.facet#mention';
} else {
continue;
}
@ -897,20 +934,20 @@ function bluesky_upload_blob(int $uid, array $photo): ?stdClass
$new_size = strlen($content);
if (($size != 0) && ($new_size == 0) && ($retrial == 0)) {
Logger::warning('Size is empty after resize, uploading original file', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
DI::logger()->warning('Size is empty after resize, uploading original file', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
$content = Photo::getImageForPhoto($photo);
} else {
Logger::info('Uploading', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
DI::logger()->info('Uploading', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
}
$data = DI::atProtocol()->post($uid, '/xrpc/com.atproto.repo.uploadBlob', $content, ['Content-type' => $photo['type'], 'Authorization' => ['Bearer ' . DI::atProtocol()->getUserToken($uid)]]);
if (empty($data) || empty($data->blob)) {
Logger::info('Uploading failed', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
DI::logger()->info('Uploading failed', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
return null;
}
Item::incrementOutbound(Protocol::BLUESKY);
Logger::debug('Uploaded blob', ['return' => $data, 'uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
DI::logger()->debug('Uploaded blob', ['return' => $data, 'uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size]);
return $data->blob;
}
@ -918,11 +955,11 @@ function bluesky_delete_post(string $uri, int $uid)
{
$parts = DI::atpProcessor()->getUriParts($uri);
if (empty($parts)) {
Logger::debug('No uri delected', ['uri' => $uri]);
DI::logger()->debug('No uri delected', ['uri' => $uri]);
return;
}
DI::atProtocol()->XRPCPost($uid, 'com.atproto.repo.deleteRecord', $parts);
Logger::debug('Deleted', ['parts' => $parts]);
DI::logger()->debug('Deleted', ['parts' => $parts]);
}
function bluesky_fetch_timeline(int $uid)
@ -1004,6 +1041,10 @@ function bluesky_process_reason(stdClass $reason, string $uri, int $uid)
return;
}
if (Post::exists(['uid' => $item['uid'], 'thr-parent' => $item['thr-parent'], 'verb' => $item['verb'], 'contact-id' => $item['contact-id']])) {
return;
}
$item['guid'] = Item::guidFromUri($item['uri'], $contact['alias']);
$item['owner-name'] = $item['author-name'];
$item['owner-link'] = $item['author-link'];
@ -1024,10 +1065,10 @@ function bluesky_fetch_notifications(int $uid)
foreach ($data->notifications as $notification) {
$uri = DI::atpProcessor()->getUri($notification);
if (Post::exists(['uri' => $uri, 'uid' => $uid]) || Post::exists(['extid' => $uri, 'uid' => $uid])) {
Logger::debug('Notification already processed', ['uid' => $uid, 'reason' => $notification->reason, 'uri' => $uri, 'indexedAt' => $notification->indexedAt]);
DI::logger()->debug('Notification already processed', ['uid' => $uid, 'reason' => $notification->reason, 'uri' => $uri, 'indexedAt' => $notification->indexedAt]);
continue;
}
Logger::debug('Process notification', ['uid' => $uid, 'reason' => $notification->reason, 'uri' => $uri, 'indexedAt' => $notification->indexedAt]);
DI::logger()->debug('Process notification', ['uid' => $uid, 'reason' => $notification->reason, 'uri' => $uri, 'indexedAt' => $notification->indexedAt]);
switch ($notification->reason) {
case 'like':
$item = DI::atpProcessor()->getHeaderFromPost($notification, $uri, $uid, Conversation::PARCEL_CONNECTOR);
@ -1037,9 +1078,9 @@ function bluesky_fetch_notifications(int $uid)
$item['thr-parent'] = DI::atpProcessor()->fetchMissingPost($item['thr-parent'], $uid, Item::PR_FETCHED, $item['contact-id'], 0);
if (!empty($item['thr-parent'])) {
$data = Item::insert($item);
Logger::debug('Got like', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
DI::logger()->debug('Got like', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
} else {
Logger::info('Thread parent not found', ['uid' => $uid, 'parent' => $item['thr-parent'], 'uri' => $uri]);
DI::logger()->info('Thread parent not found', ['uid' => $uid, 'parent' => $item['thr-parent'], 'uri' => $uri]);
}
break;
@ -1051,37 +1092,37 @@ function bluesky_fetch_notifications(int $uid)
$item['thr-parent'] = DI::atpProcessor()->fetchMissingPost($item['thr-parent'], $uid, Item::PR_FETCHED, $item['contact-id'], 0);
if (!empty($item['thr-parent'])) {
$data = Item::insert($item);
Logger::debug('Got repost', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
DI::logger()->debug('Got repost', ['uid' => $uid, 'result' => $data, 'uri' => $uri]);
} else {
Logger::info('Thread parent not found', ['uid' => $uid, 'parent' => $item['thr-parent'], 'uri' => $uri]);
DI::logger()->info('Thread parent not found', ['uid' => $uid, 'parent' => $item['thr-parent'], 'uri' => $uri]);
}
break;
case 'follow':
$contact = DI::atpActor()->getContactByDID($notification->author->did, $uid, $uid);
Logger::debug('New follower', ['uid' => $uid, 'nick' => $contact['nick'], 'uri' => $uri]);
DI::logger()->debug('New follower', ['uid' => $uid, 'nick' => $contact['nick'], 'uri' => $uri]);
break;
case 'mention':
$contact = DI::atpActor()->getContactByDID($notification->author->did, $uid, 0);
$result = DI::atpProcessor()->fetchMissingPost($uri, $uid, Item::PR_TO, $contact['id'], 0);
Logger::debug('Got mention', ['uid' => $uid, 'nick' => $contact['nick'], 'result' => $result, 'uri' => $uri]);
DI::logger()->debug('Got mention', ['uid' => $uid, 'nick' => $contact['nick'], 'result' => $result, 'uri' => $uri]);
break;
case 'reply':
$contact = DI::atpActor()->getContactByDID($notification->author->did, $uid, 0);
$result = DI::atpProcessor()->fetchMissingPost($uri, $uid, Item::PR_COMMENT, $contact['id'], 0);
Logger::debug('Got reply', ['uid' => $uid, 'nick' => $contact['nick'], 'result' => $result, 'uri' => $uri]);
DI::logger()->debug('Got reply', ['uid' => $uid, 'nick' => $contact['nick'], 'result' => $result, 'uri' => $uri]);
break;
case 'quote':
$contact = DI::atpActor()->getContactByDID($notification->author->did, $uid, 0);
$result = DI::atpProcessor()->fetchMissingPost($uri, $uid, Item::PR_PUSHED, $contact['id'], 0);
Logger::debug('Got quote', ['uid' => $uid, 'nick' => $contact['nick'], 'result' => $result, 'uri' => $uri]);
DI::logger()->debug('Got quote', ['uid' => $uid, 'nick' => $contact['nick'], 'result' => $result, 'uri' => $uri]);
break;
default:
Logger::notice('Unhandled reason', ['reason' => $notification->reason, 'uri' => $uri]);
DI::logger()->notice('Unhandled reason', ['reason' => $notification->reason, 'uri' => $uri]);
break;
}
}
@ -1112,16 +1153,16 @@ function bluesky_fetch_feed(int $uid, string $feed)
$languages = $entry->post->record->langs ?? [];
if (!Relay::isWantedLanguage($entry->post->record->text, 0, $contact['id'] ?? 0, $languages)) {
Logger::debug('Unwanted language detected', ['languages' => $languages, 'text' => $entry->post->record->text]);
DI::logger()->debug('Unwanted language detected', ['languages' => $languages, 'text' => $entry->post->record->text]);
continue;
}
$causer = DI::atpActor()->getContactByDID($entry->post->author->did, $uid, 0);
$uri_id = bluesky_complete_post($entry->post, $uid, Item::PR_TAG, $causer['id'], Conversation::PARCEL_CONNECTOR);
if (!empty($uri_id)) {
$stored = Post\Category::storeFileByURIId($uri_id, $uid, Post\Category::SUBCRIPTION, $feedname, $feedurl);
Logger::debug('Stored tag subscription for user', ['uri-id' => $uri_id, 'uid' => $uid, 'name' => $feedname, 'url' => $feedurl, 'stored' => $stored]);
DI::logger()->debug('Stored tag subscription for user', ['uri-id' => $uri_id, 'uid' => $uid, 'name' => $feedname, 'url' => $feedurl, 'stored' => $stored]);
} else {
Logger::notice('Post not found', ['entry' => $entry]);
DI::logger()->notice('Post not found', ['entry' => $entry]);
}
if (!empty($entry->reason)) {
bluesky_process_reason($entry->reason, DI::atpProcessor()->getUri($entry->post), $uid);
@ -1137,8 +1178,14 @@ function bluesky_get_feeds(int $uid): array
return [];
}
foreach ($preferences->preferences as $preference) {
if ($preference->$type == 'app.bsky.actor.defs#savedFeedsPref') {
return $preference->pinned ?? [];
if ($preference->$type == 'app.bsky.actor.defs#savedFeedsPrefV2') {
$pinned = [];
foreach ($preference->items as $item) {
if (($item->type == 'feed') && $item->pinned) {
$pinned[] = $item->value;
}
}
return $pinned;
}
}
return [];

View file

@ -1,6 +1,6 @@
<?php
use Friendica\Core\Logger;
use Friendica\DI;
function bluesky_feed_run($argv, $argc)
{
@ -10,7 +10,7 @@ function bluesky_feed_run($argv, $argc)
return;
}
Logger::debug('Importing feed - start', ['user' => $argv[1], 'feed' => $argv[2]]);
DI::logger()->debug('Importing feed - start', ['user' => $argv[1], 'feed' => $argv[2]]);
bluesky_fetch_feed($argv[1], $argv[2]);
Logger::debug('Importing feed - done', ['user' => $argv[1], 'feed' => $argv[2]]);
DI::logger()->debug('Importing feed - done', ['user' => $argv[1], 'feed' => $argv[2]]);
}

View file

@ -1,6 +1,6 @@
<?php
use Friendica\Core\Logger;
use Friendica\DI;
function bluesky_notifications_run($argv, $argc)
{
@ -10,7 +10,7 @@ function bluesky_notifications_run($argv, $argc)
return;
}
Logger::notice('importing notifications - start', ['user' => $argv[1]]);
DI::logger()->notice('importing notifications - start', ['user' => $argv[1]]);
bluesky_fetch_notifications($argv[1]);
Logger::notice('importing notifications - done', ['user' => $argv[1]]);
DI::logger()->notice('importing notifications - done', ['user' => $argv[1]]);
}

View file

@ -1,6 +1,6 @@
<?php
use Friendica\Core\Logger;
use Friendica\DI;
function bluesky_timeline_run($argv, $argc)
{
@ -10,7 +10,7 @@ function bluesky_timeline_run($argv, $argc)
return;
}
Logger::notice('importing timeline - start', ['user' => $argv[1]]);
DI::logger()->notice('importing timeline - start', ['user' => $argv[1]]);
bluesky_fetch_timeline($argv[1]);
Logger::notice('importing timeline - done', ['user' => $argv[1]]);
DI::logger()->notice('importing timeline - done', ['user' => $argv[1]]);
}

View file

@ -6,7 +6,6 @@
* Author: Mike Macgirvin <mike@macgirvin.com>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

View file

@ -6,7 +6,6 @@
* Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
@ -16,7 +15,7 @@ function calc_install() {
function calc_app_menu(array &$b)
{
$b['app_menu'][] = '<div class="app-title"><a href="calc">Calculator</a></div>';
$b['app_menu'][] = '<div class="app-title"><a href="calc">Calculator</a></div>';
}
/**
@ -296,7 +295,7 @@ $o .= <<< EOT
<h3>Calculator</h3>
<br /><br />
<table>
<tbody><tr><td>
<tbody><tr><td>
<table bgcolor="#af9999" border="1">
<tbody><tr><td>
<table border="1" cellpadding="2" cellspacing="2">
@ -323,7 +322,7 @@ $o .= <<< EOT
<td><input name="multiplication" value="&nbsp;&nbsp;*&nbsp;&nbsp;&nbsp;&nbsp;" onclick="multiplyNumbers()" type="button"></td>
</tr><tr align="left" valign="middle">
<td><input name="zero" value="&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;" onclick="addDisplay(0)" type="button"></td>
<td><input name="pi" value="&nbsp;Pi&nbsp;&nbsp;" onclick="addDisplay(Math.PI)" type="button"> </td>
<td><input name="pi" value="&nbsp;Pi&nbsp;&nbsp;" onclick="addDisplay(Math.PI)" type="button"> </td>
<td><input name="dot" value="&nbsp;&nbsp;&nbsp;.&nbsp;&nbsp;&nbsp;" onclick='addDisplay(".")' type="button"></td>
<td><input name="division" value="&nbsp;&nbsp;&nbsp;/&nbsp;&nbsp;&nbsp;" onclick="divideNumbers()" type="button"></td>
</tr><tr align="left" valign="middle">
@ -345,13 +344,13 @@ $o .= <<< EOT
</form>
<!--
<TD VALIGN=top>
<TD VALIGN=top>
<B>NOTE:</B> All sine and cosine calculations are
<br>done in radians. Remember to convert first
<br>if using degrees.
</TD>
-->
</td></tr></tbody></table>

View file

@ -6,11 +6,8 @@
* Author: Fabio <https://kirgroup.com/profile/fabrixxm>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Contact;
@ -29,7 +26,7 @@ function catavatar_install()
Hook::register('addon_settings', __FILE__, 'catavatar_addon_settings');
Hook::register('addon_settings_post', __FILE__, 'catavatar_addon_settings_post');
Logger::notice('registered catavatar');
DI::logger()->notice('registered catavatar');
}
/**

View file

@ -7,7 +7,6 @@
*/
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\DI;
function cld_install()
@ -18,7 +17,17 @@ function cld_install()
function cld_detect_languages(array &$data)
{
if (!in_array('cld2', get_loaded_extensions())) {
Logger::warning('CLD2 is not installed.');
DI::logger()->warning('CLD2 is not installed.');
return;
}
if (!class_exists('CLD2Detector')) {
DI::logger()->warning('CLD2Detector class does not exist.');
return;
}
if (!class_exists('CLD2Encoding')) {
DI::logger()->warning('CLD2Encoding class does not exist.');
return;
}
@ -43,7 +52,7 @@ function cld_detect_languages(array &$data)
}
if (!$result['is_reliable']) {
Logger::debug('Unreliable detection', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);
DI::logger()->debug('Unreliable detection', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);
if (($original == $detected) && ($data['detected'][$original] < $result['language_probability'] / 100)) {
$data['detected'][$original] = $result['language_probability'] / 100;
}
@ -53,12 +62,12 @@ function cld_detect_languages(array &$data)
$available = array_keys(DI::l10n()->getLanguageCodes());
if (!in_array($detected, $available)) {
Logger::debug('Unsupported language', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);
DI::logger()->debug('Unsupported language', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);
return;
}
if ($original != $detected) {
Logger::debug('Detected different language', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);
DI::logger()->debug('Detected different language', ['uri-id' => $data['uri-id'], 'original' => $original, 'detected' => $detected, 'name' => $result['language_name'], 'probability' => $result['language_probability'], 'text' => $data['text']]);
}
$length = count($data['detected']);

View file

@ -169,7 +169,6 @@ class UnitConvertor
* @param string name of the source unit from which to convert
* @param string name of the target unit to which we are converting
* @param integer double precision of the end result
* @return void
* @access public
*/
function convert($value, $from_unit, $to_unit, $precision)
@ -280,4 +279,4 @@ class UnitConvertor
} // end func getConvSpecs
} // end class UnitConvertor
?>
?>

View file

@ -6,7 +6,6 @@
* Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
*/
use Friendica\App;
use Friendica\Core\Hook;
function convert_install() {
@ -26,7 +25,7 @@ function convert_content() {
// @TODO Let's one day rewrite this to a modern composer package
include 'UnitConvertor.php';
class TP_Converter extends UnitConvertor
$conv = new class('en') extends UnitConvertor
{
public function __construct(string $lang = 'en')
{
@ -43,7 +42,7 @@ function convert_content() {
private function findBaseUnit($from, $to)
{
while (list($skey, $sval) = each($this->bases)) {
foreach ($this->bases as $skey => $sval) {
if ($skey == $from || $to == $skey || in_array($to, $sval) || in_array($from, $sval)) {
return $skey;
}
@ -63,7 +62,7 @@ function convert_content() {
$cells[] = $cell;
// We now have the base unit and value now lets produce the table;
while (list($key, $val) = each($this->bases[$base_unit])) {
foreach ($this->bases[$base_unit] as $val) {
$cell ['value'] = $this->convert($value, $from_unit, $val, $precision) . ' ' . $val;
$cell ['class'] = ($val == $from_unit || $val == $to_unit) ? 'framedred' : '';
$cells[] = $cell;
@ -86,9 +85,7 @@ function convert_content() {
return $string;
}
}
$conv = new TP_Converter('en');
};
$conversions = [
'Temperature' => ['base' => 'Celsius',
@ -176,15 +173,15 @@ function convert_content() {
]
];
while (list($key, $val) = each($conversions)) {
foreach ($conversions as $key => $val) {
$conv->addConversion($val['base'], $val['conv']);
$list[$key][] = $val['base'];
while (list($ukey, $uval) = each($val['conv'])) {
foreach ($val['conv'] as $ukey => $uval) {
$list[$key][] = $ukey;
}
}
$o .= '<h3>Unit Conversions</h3>';
$o = '<h3>Unit Conversions</h3>';
if (isset($_POST['from_unit']) && isset($_POST['value'])) {
$o .= ($conv->getTable(intval($_POST['value']), $_POST['from_unit'], $_POST['to_unit'], 5)) . '</p>';
@ -202,10 +199,9 @@ function convert_content() {
$o .= '<input name="value" type="text" id="value" value="' . $value . '" size="10" maxlength="10" />';
$o .= '<select name="from_unit" size="12">';
reset($list);
while(list($key, $val) = each($list)) {
foreach ($list as $key => $val) {
$o .= "\n\t<optgroup label=\"$key\">";
while(list($ukey, $uval) = each($val)) {
foreach ($val as $ukey => $uval) {
$selected = (($uval == $_POST['from_unit']) ? ' selected="selected" ' : '');
$o .= "\n\t\t<option value=\"$uval\" $selected >$uval</option>";
}

View file

@ -7,7 +7,6 @@
* Author: Peter Liebetrau <https://socivitas/profile/peerteer>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -29,10 +29,10 @@ function getWeather($loc, $units = 'metric', $lang = 'en', $appid = '', $cacheti
$now = new DateTime();
if (!is_null($cached)) {
$cdate = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'curweather', 'last');
$cdate = (int) DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'curweather', 'last');
$cached = unserialize($cached);
if ($cdate + $cachetime > $now->getTimestamp()) {
if ($cdate + (int) $cachetime > $now->getTimestamp()) {
return $cached;
}
}

View file

@ -33,7 +33,6 @@ class Diaspora_Connection {
}
$this->cookiejar = tempnam(System::getTempPath(), 'cookies');
return $this;
}
public function __destruct() {

View file

@ -9,6 +9,8 @@ use Friendica\Core\System;
class Diasphp {
private $cookiejar;
private $token_regex;
private $pod;
function __construct($pod) {
$this->token_regex = '/content="(.*?)" name="csrf-token/';

View file

@ -9,10 +9,8 @@
require_once 'addon/diaspora/Diaspora_Connection.php';
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\Core\Worker;
@ -187,7 +185,7 @@ function diaspora_send(array &$b)
{
$hostname = DI::baseUrl()->getHost();
Logger::notice('diaspora_send: invoked');
DI::logger()->notice('diaspora_send: invoked');
if ($b['deleted'] || ($b['private'] == Item::PRIVATE) || ($b['created'] !== $b['edited'])) {
return;
@ -197,6 +195,10 @@ function diaspora_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['parent'] != $b['id']) {
return;
}
@ -211,14 +213,14 @@ function diaspora_send(array &$b)
return;
}
Logger::info('diaspora_send: prepare posting');
DI::logger()->info('diaspora_send: prepare posting');
$handle = DI::pConfig()->get($b['uid'], 'diaspora', 'handle');
$password = DI::pConfig()->get($b['uid'], 'diaspora', 'password');
$aspect = DI::pConfig()->get($b['uid'], 'diaspora', 'aspect');
if ($handle && $password) {
Logger::info('diaspora_send: all values seem to be okay');
DI::logger()->info('diaspora_send: all values seem to be okay');
$title = $b['title'];
$body = $b['body'];
@ -249,20 +251,20 @@ function diaspora_send(array &$b)
require_once "addon/diaspora/diasphp.php";
try {
Logger::info('diaspora_send: prepare');
DI::logger()->info('diaspora_send: prepare');
$conn = new Diaspora_Connection($handle, $password);
Logger::info('diaspora_send: try to log in ' . $handle);
DI::logger()->info('diaspora_send: try to log in ' . $handle);
$conn->logIn();
Logger::info('diaspora_send: try to send ' . $body);
DI::logger()->info('diaspora_send: try to send ' . $body);
$conn->provider = $hostname;
$conn->postStatusMessage($body, $aspect);
Logger::notice('diaspora_send: success');
DI::logger()->notice('diaspora_send: success');
} catch (Exception $e) {
Logger::notice("diaspora_send: Error submitting the post: " . $e->getMessage());
DI::logger()->notice("diaspora_send: Error submitting the post: " . $e->getMessage());
Logger::info('diaspora_send: requeueing ' . $b['uid']);
DI::logger()->info('diaspora_send: requeueing ' . $b['uid']);
Worker::defer();
}

View file

@ -8,10 +8,8 @@
*
*/
use Friendica\App;
use Friendica\Content\Text\Markdown;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
@ -80,13 +78,13 @@ function discourse_email_getmessage(&$message)
// We do assume that all Discourse servers are running with SSL
if (preg_match('=topic/(.*\d)/(.*\d)@(.*)=', $message['item']['uri'], $matches) &&
discourse_fetch_post_from_api($message, $matches[2], $matches[3])) {
Logger::info('Fetched comment via API (message-id mode)', ['host' => $matches[3], 'topic' => $matches[1], 'post' => $matches[2]]);
DI::logger()->info('Fetched comment via API (message-id mode)', ['host' => $matches[3], 'topic' => $matches[1], 'post' => $matches[2]]);
return;
}
if (preg_match('=topic/(.*\d)@(.*)=', $message['item']['uri'], $matches) &&
discourse_fetch_topic_from_api($message, 'https://' . $matches[2], $matches[1], 1)) {
Logger::info('Fetched starting post via API (message-id mode)', ['host' => $matches[2], 'topic' => $matches[1]]);
DI::logger()->info('Fetched starting post via API (message-id mode)', ['host' => $matches[2], 'topic' => $matches[1]]);
return;
}
@ -96,16 +94,16 @@ function discourse_email_getmessage(&$message)
}
if (empty($message['item']['plink']) || !preg_match('=(http.*)/t/.*/(.*\d)/(.*\d)=', $message['item']['plink'], $matches)) {
Logger::info('This is no Discourse post');
DI::logger()->info('This is no Discourse post');
return;
}
if (discourse_fetch_topic_from_api($message, $matches[1], $matches[2], $matches[3])) {
Logger::info('Fetched post via API (plink mode)', ['host' => $matches[1], 'topic' => $matches[2], 'id' => $matches[3]]);
DI::logger()->info('Fetched post via API (plink mode)', ['host' => $matches[1], 'topic' => $matches[2], 'id' => $matches[3]]);
return;
}
Logger::info('Fallback mode', ['plink' => $message['item']['plink']]);
DI::logger()->info('Fallback mode', ['plink' => $message['item']['plink']]);
// Search in the HTML part for the discourse entry and the author profile
if (!empty($message['html'])) {
$message = discourse_get_html($message);
@ -122,7 +120,7 @@ function discourse_fetch_post($host, $topic, $pid)
$url = $host . '/t/' . $topic . '/' . $pid . '.json';
$curlResult = DI::httpClient()->get($url);
if (!$curlResult->isSuccess()) {
Logger::info('No success', ['url' => $url]);
DI::logger()->info('No success', ['url' => $url]);
return false;
}
@ -134,11 +132,11 @@ function discourse_fetch_post($host, $topic, $pid)
/// @todo Possibly fetch missing posts here
continue;
}
Logger::info('Got post data from topic', $post);
DI::logger()->info('Got post data from topic', $post);
return $post;
}
Logger::info('Post not found', ['host' => $host, 'topic' => $topic, 'pid' => $pid]);
DI::logger()->info('Post not found', ['host' => $host, 'topic' => $topic, 'pid' => $pid]);
return false;
}
@ -170,7 +168,7 @@ function discourse_fetch_post_from_api(&$message, $post, $host)
$message = discourse_process_post($message, $data, $hostaddr);
Logger::info('Got API data', $message);
DI::logger()->info('Got API data', $message);
return true;
}
@ -203,7 +201,7 @@ function discourse_get_user($post, $hostaddr)
$contact['url'] = $hostaddr . '/u/' . $contact['nick'];
$contact['nurl'] = Strings::normaliseLink($contact['url']);
$contact['baseurl'] = $hostaddr;
Logger::info('Contact', $contact);
DI::logger()->info('Contact', $contact);
$contact['id'] = Contact::getIdForURL($contact['url'], 0, false, $contact);
if (!empty($contact['id'])) {
$avatar = $contact['photo'];
@ -269,11 +267,11 @@ function discourse_get_html($message)
$div = $doc2->importNode($result->item(0), true);
$doc2->appendChild($div);
$message['html'] = $doc2->saveHTML();
Logger::info('Found html body', ['html' => $message['html']]);
DI::logger()->info('Found html body', ['html' => $message['html']]);
$profile = discourse_get_profile($xpath);
if (!empty($profile['url'])) {
Logger::info('Found profile', $profile);
DI::logger()->info('Found profile', $profile);
$message['item']['author-id'] = Contact::getIdForURL($profile['url'], 0, false, $profile);
$message['item']['author-link'] = $profile['url'];
$message['item']['author-name'] = $profile['name'];
@ -289,21 +287,21 @@ function discourse_get_text($message)
$text = str_replace("\r", '', $text);
$pos = strpos($text, "\n---\n");
if ($pos == 0) {
Logger::info('No separator found', ['text' => $text]);
DI::logger()->info('No separator found', ['text' => $text]);
return $message;
}
$message['text'] = trim(substr($text, 0, $pos));
Logger::info('Found text body', ['text' => $message['text']]);
DI::logger()->info('Found text body', ['text' => $message['text']]);
$message['text'] = Markdown::toBBCode($message['text']);
$text = substr($text, $pos);
Logger::info('Found footer', ['text' => $text]);
DI::logger()->info('Found footer', ['text' => $text]);
if (preg_match('=\((http.*/t/.*/.*\d/.*\d)\)=', $text, $link)) {
$message['item']['plink'] = $link[1];
Logger::info('Found plink', ['plink' => $message['item']['plink']]);
DI::logger()->info('Found plink', ['plink' => $message['item']['plink']]);
}
return $message;
}

View file

@ -8,10 +8,8 @@
* Author: Cat Gray <https://free-haven.org/profile/catness>
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\Item;
@ -127,6 +125,10 @@ function dwpost_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['parent'] != $b['id']) {
return;
}
@ -186,12 +188,12 @@ function dwpost_send(array &$b)
EOT;
Logger::debug('dwpost: data: ' . $xml);
DI::logger()->debug('dwpost: data: ' . $xml);
if ($dw_blog !== 'test') {
$x = DI::httpClient()->post($dw_blog, $xml, ['Content-Type' => 'text/xml'])->getBodyString();
}
Logger::info('posted to dreamwidth: ' . ($x) ? $x : '');
DI::logger()->info('posted to dreamwidth: ' . ($x) ? $x : '');
}
}

View file

@ -7,7 +7,6 @@
* Status: Unsupported
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
@ -40,7 +39,7 @@ function fancybox_render(array &$b){
function ($text) use ($gallery) {
// This processes images inlined in posts
// Frio / Vier hooks für lightbox are un-hooked in fancybox-config.js. So this works for them, too!
//if (!in_array(DI::app()->getCurrentTheme(),['vier','frio']))
//if (!in_array(DI::appHelper()->getCurrentTheme(),['vier','frio']))
$text = preg_replace(
'#<a[^>]*href="([^"]*)"[^>]*>(<img[^>]*src="[^"]*"[^>]*>)</a>#',
'<a data-fancybox="' . $gallery . '" href="$1">$2</a>',

View file

@ -7,9 +7,7 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -18,7 +16,7 @@ function fromapp_install()
Hook::register('post_local', 'addon/fromapp/fromapp.php', 'fromapp_post_hook');
Hook::register('addon_settings', 'addon/fromapp/fromapp.php', 'fromapp_settings');
Hook::register('addon_settings_post', 'addon/fromapp/fromapp.php', 'fromapp_settings_post');
Logger::notice("installed fromapp");
DI::logger()->notice("installed fromapp");
}
function fromapp_settings_post($post)
@ -76,6 +74,6 @@ function fromapp_post_hook(&$item)
$apps = explode(',', $app);
$item['app'] = trim($apps[mt_rand(0, count($apps)-1)]);
return;
}

View file

@ -6,9 +6,7 @@
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -52,25 +50,25 @@ function geocoordinates_resolve_item(array &$item)
$s = DI::httpClient()->fetch('https://api.opencagedata.com/geocode/v1/json?q=' . $coords[0] . ',' . $coords[1] . '&key=' . $key . '&language=' . $language);
if (!$s) {
Logger::info('API could not be queried');
DI::logger()->info('API could not be queried');
return;
}
$data = json_decode($s);
if ($data->status->code != '200') {
Logger::info('API returned error ' . $data->status->code . ' ' . $data->status->message);
DI::logger()->info('API returned error ' . $data->status->code . ' ' . $data->status->message);
return;
}
if (($data->total_results == 0) || (count($data->results) == 0)) {
Logger::info('No results found for coordinates ' . $item['coord']);
DI::logger()->info('No results found for coordinates ' . $item['coord']);
return;
}
$item['location'] = $data->results[0]->formatted;
Logger::info('Got location for coordinates ' . $coords[0] . '-' . $coords[1] . ': ' . $item['location']);
DI::logger()->info('Got location for coordinates ' . $coords[0] . '-' . $coords[1] . ': ' . $item['location']);
if ($item['location'] != '') {
DI::cache()->set('geocoordinates:' . $language.':' . $coords[0] . '-' . $coords[1], $item['location']);

View file

@ -6,9 +6,7 @@
* Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Core\Config\Util\ConfigFileManager;
@ -35,7 +33,7 @@ function geonames_install()
function geonames_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('geonames'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('geonames'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function geonames_post_hook(array &$item)
@ -46,7 +44,7 @@ function geonames_post_hook(array &$item)
* - The profile owner must have allowed our addon
*/
Logger::notice('geonames invoked');
DI::logger()->notice('geonames invoked');
if (!DI::userSession()->getLocalUserId()) { /* non-zero if this is a logged in user of this system */
return;

View file

@ -4,13 +4,11 @@
* Description: Thread email comment notifications on Gmail and anonymise them
* Version: 1.0
* Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
*
*
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\Notification;
@ -21,7 +19,7 @@ function gnot_install()
Hook::register('addon_settings_post', 'addon/gnot/gnot.php', 'gnot_settings_post');
Hook::register('enotify_mail', 'addon/gnot/gnot.php', 'gnot_enotify_mail');
Logger::notice("installed gnot");
DI::logger()->notice("installed gnot");
}
/**
@ -38,7 +36,7 @@ function gnot_settings_post($post) {
}
/**
* Called from the Addon Setting form.
* Called from the Addon Setting form.
* Add our own settings info to the page.
*/
function gnot_settings(array &$data)

View file

@ -7,15 +7,14 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\DI;
function googlemaps_install()
{
Hook::register('render_location', 'addon/googlemaps/googlemaps.php', 'googlemaps_location');
Logger::notice('installed googlemaps');
DI::logger()->notice('installed googlemaps');
}
function googlemaps_location(&$item)

View file

@ -6,15 +6,11 @@
* Author: Klaus Weidenbach <http://friendica.dszdw.net/profile/klaus>
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Util\Strings;
/**
* Installs the addon hook
@ -23,12 +19,12 @@ function gravatar_install() {
Hook::register('load_config', 'addon/gravatar/gravatar.php', 'gravatar_load_config');
Hook::register('avatar_lookup', 'addon/gravatar/gravatar.php', 'gravatar_lookup');
Logger::notice("registered gravatar in avatar_lookup hook");
DI::logger()->notice("registered gravatar in avatar_lookup hook");
}
function gravatar_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('gravatar'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('gravatar'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
/**

View file

@ -8,9 +8,7 @@
* Note: Please use Circle Text instead
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -6,7 +6,6 @@
* Author: Hypolite Petovan <hypolite@mrpetovan.com>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
@ -18,7 +17,7 @@ function highlightjs_install()
function highlightjs_head(string &$str)
{
if (DI::app()->getCurrentTheme() == 'frio') {
if (DI::appHelper()->getCurrentTheme() == 'frio') {
$style = 'bootstrap';
} else {
$style = 'default';

View file

@ -6,10 +6,8 @@
* Version: 0.1
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
*/
use Friendica\App;
use Friendica\Content\PageInfo;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
@ -87,16 +85,16 @@ function ifttt_post()
$user = DBA::selectFirst('user', ['uid'], ['nickname' => $nickname]);
if (!DBA::isResult($user)) {
Logger::info('User ' . $nickname . ' not found.');
DI::logger()->info('User ' . $nickname . ' not found.');
return;
}
$uid = $user['uid'];
Logger::info('Received a post for user ' . $uid . ' from ifttt ' . print_r($_REQUEST, true));
DI::logger()->info('Received a post for user ' . $uid . ' from ifttt ' . print_r($_REQUEST, true));
if (!isset($_REQUEST['key'])) {
Logger::notice('No key found.');
DI::logger()->notice('No key found.');
return;
}
@ -104,7 +102,7 @@ function ifttt_post()
// Check the key
if ($key != DI::pConfig()->get($uid, 'ifttt', 'key')) {
Logger::info('Invalid key for user ' . $uid);
DI::logger()->info('Invalid key for user ' . $uid);
return;
}
@ -115,7 +113,7 @@ function ifttt_post()
}
if (!in_array($item['type'], ['status', 'link', 'photo'])) {
Logger::info('Unknown item type ' . $item['type']);
DI::logger()->info('Unknown item type ' . $item['type']);
return;
}

View file

@ -8,10 +8,8 @@
* Author: Cat Gray <https://free-haven.org/profile/catness>
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\Item;
@ -124,6 +122,10 @@ function ijpost_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['parent'] != $b['id']) {
return;
}
@ -179,11 +181,11 @@ function ijpost_send(array &$b)
EOT;
Logger::debug('ijpost: data: ' . $xml);
DI::logger()->debug('ijpost: data: ' . $xml);
if ($ij_blog !== 'test') {
$x = DI::httpClient()->post($ij_blog, $xml, ['Content-Type' => 'text/xml'])->getBodyString();
}
Logger::info('posted to insanejournal: ' . $x ? $x : '');
DI::logger()->info('posted to insanejournal: ' . $x ? $x : '');
}
}

View file

@ -7,10 +7,8 @@
* License: 3-clause BSD license
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Core\Config\Util\ConfigFileManager;
@ -21,7 +19,7 @@ function impressum_install()
Hook::register('load_config', 'addon/impressum/impressum.php', 'impressum_load_config');
Hook::register('about_hook', 'addon/impressum/impressum.php', 'impressum_show');
Hook::register('page_end', 'addon/impressum/impressum.php', 'impressum_footer');
Logger::notice("installed impressum Addon");
DI::logger()->notice("installed impressum Addon");
}
/**
@ -56,7 +54,7 @@ function impressum_footer(string &$body)
function impressum_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('impressum'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('impressum'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function impressum_show(string &$body)

View file

@ -6,7 +6,6 @@
* Author: Thomas Willingham <https://kakste.com/profile/beardyunixer>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

View file

@ -54,8 +54,8 @@ function invidious_settings(array &$data)
$t = Renderer::getMarkupTemplate('settings.tpl', 'addon/invidious/');
$html = Renderer::replaceMacros($t, [
'$enabled' => ['enabled', DI::l10n()->t('Replace Youtube links with links to an Invidious server'), $enabled, DI::l10n()->t('If enabled, Youtube links are replaced with the links to the specified Invidious server.')],
'$server' => ['server', DI::l10n()->t('Invidious server'), $server, DI::l10n()->t('See %s for a list of available Invidious servers.', '<a href="https://api.invidious.io/">https://api.invidious.io/</a>')],
'$enabled' => ['invidious-enabled', DI::l10n()->t('Replace Youtube links with links to an Invidious server'), $enabled, DI::l10n()->t('If enabled, Youtube links are replaced with the links to the specified Invidious server.')],
'$server' => ['invidious-server', DI::l10n()->t('Invidious server'), $server, DI::l10n()->t('See %s for a list of available Invidious servers.', '<a href="https://api.invidious.io/">https://api.invidious.io/</a>')],
]);
$data = [
@ -71,9 +71,9 @@ function invidious_settings_post(array &$b)
return;
}
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'invidious', 'enabled', (bool)$_POST['enabled']);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'invidious', 'enabled', (bool)$_POST['invidious-enabled']);
$server = trim($_POST['server'], " \n\r\t\v\x00/");
$server = trim($_POST['invidious-server'], " \n\r\t\v\x00/");
if ($server != DI::config()->get('invidious', 'server', INVIDIOUS_DEFAULT) && !empty($server)) {
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'invidious', 'server', $server);
} else {

View file

@ -7,7 +7,6 @@
* Author: Tobias Diekershoff <https://f.diekershoff.de/u/tobias>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -77,10 +77,10 @@ class qqFileUploader {
public function __construct(array $allowedExtensions = [], $sizeLimit = 10485760)
{
$allowedExtensions = array_map('strtolower', $allowedExtensions);
$this->allowedExtensions = $allowedExtensions;
$this->sizeLimit = $sizeLimit;
$this->checkServerSettings();
if (isset($_GET['qqfile'])) {
@ -88,7 +88,7 @@ class qqFileUploader {
} elseif (isset($_FILES['qqfile'])) {
$this->file = new qqUploadedFileForm();
} else {
$this->file = false;
$this->file = false;
}
}
@ -105,7 +105,7 @@ class qqFileUploader {
private function toBytes(string $str): int
{
$val = trim($str);
$val = (int) trim($str);
$last = strtolower($str[strlen($str) - 1]);
switch($last) {

View file

@ -2,12 +2,12 @@
usleep(100000);
$fileName;
$fileSize;
$fileName = '';
$fileSize = 0;;
if (isset($_GET['qqfile'])){
$fileName = $_GET['qqfile'];
// xhr request
$headers = apache_request_headers();
$fileSize = (int)$headers['Content-Length'];
@ -34,13 +34,13 @@ if ($fileSize > 9 * 1024){
die ('{error: "server-error file size is bigger than 9kB"}');
}
if (count($_GET)){
if (count($_GET)){
array_merge($_GET, array('fileName'=>$fileName));
$response = array_merge($_GET, array('success'=>true, 'fileName'=>$fileName));
// to pass data through iframe you will need to encode all html tags
echo htmlspecialchars(json_encode($response), ENT_NOQUOTES);
// to pass data through iframe you will need to encode all html tags
echo htmlspecialchars(json_encode($response), ENT_NOQUOTES);
} else {
die ('{error: "server-error query params not passed"}');
}

View file

@ -2,11 +2,11 @@
sleep(4);
$fileName;
$fileName = '';
if (isset($_GET['qqfile'])){
$fileName = $_GET['qqfile'];
// xhr request
$headers = apache_request_headers();
if ((int)$headers['Content-Length'] == 0){
@ -14,7 +14,7 @@ if (isset($_GET['qqfile'])){
}
} elseif (isset($_FILES['qqfile'])){
$fileName = basename($_FILES['qqfile']['name']);
// form request
if ($_FILES['qqfile']['size'] == 0){
die ('{error: "file size is zero"}');
@ -25,7 +25,7 @@ if (isset($_GET['qqfile'])){
if (count($_GET)){
$_GET['success'] = true;
echo json_encode(array_merge($_GET));
echo json_encode(array_merge($_GET));
} else {
die ('{error: "query params not passed"}');
}

View file

@ -2,11 +2,11 @@
usleep(300);
$fileName;
$fileName = '';
if (isset($_GET['qqfile'])){
$fileName = $_GET['qqfile'];
// xhr request
$headers = apache_request_headers();
if ((int)$headers['Content-Length'] == 0){
@ -14,7 +14,7 @@ if (isset($_GET['qqfile'])){
}
} elseif (isset($_FILES['qqfile'])){
$fileName = basename($_FILES['qqfile']['name']);
// form request
if ($_FILES['qqfile']['size'] == 0){
die ('{error: "file size is zero"}');
@ -25,7 +25,7 @@ if (isset($_GET['qqfile'])){
if (count($_GET)){
//return query params
echo json_encode(array_merge($_GET, array('fileName'=>$fileName)));
echo json_encode(array_merge($_GET, array('fileName'=>$fileName)));
} else {
die ('{error: "query params not passed"}');
}

View file

@ -8,7 +8,6 @@
*/
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Util\Images;
@ -60,7 +59,7 @@ function js_upload_post_init(array &$b)
// max file size in bytes
$sizeLimit = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'));
$uploader = new qqFileUploader($allowedExtensions, $sizeLimit);
$uploader = new js_upload_qqFileUploader($allowedExtensions, $sizeLimit);
$result = $uploader->handleUpload();
@ -68,7 +67,7 @@ function js_upload_post_init(array &$b)
$js_upload_jsonresponse = htmlspecialchars(json_encode($result), ENT_NOQUOTES);
if (isset($result['error'])) {
Logger::info('mod/photos.php: photos_post(): error uploading photo: ' . $result['error']);
DI::logger()->info('mod/photos.php: photos_post(): error uploading photo: ' . $result['error']);
echo json_encode($result);
exit();
}
@ -91,7 +90,7 @@ function js_upload_post_end(int &$b)
{
global $js_upload_jsonresponse;
Logger::notice('upload_post_end');
DI::logger()->notice('upload_post_end');
if (!empty($js_upload_jsonresponse)) {
echo $js_upload_jsonresponse;
exit();
@ -101,7 +100,7 @@ function js_upload_post_end(int &$b)
/**
* Handle file uploads via XMLHttpRequest
*/
class qqUploadedFileXhr
class js_upload_qqUploadedFileXhr
{
private $pathnm = '';
@ -155,7 +154,7 @@ class qqUploadedFileXhr
/**
* Handle file uploads via regular form post (uses the $_FILES array)
*/
class qqUploadedFileForm
class js_upload_qqUploadedFileForm
{
/**
* Save the file to the specified path
@ -183,10 +182,14 @@ class qqUploadedFileForm
}
}
class qqFileUploader
class js_upload_qqFileUploader
{
private $allowedExtensions;
private $sizeLimit;
/**
* @var js_upload_qqUploadedFileXhr|js_upload_qqUploadedFileForm|false
*/
private $file;
function __construct(array $allowedExtensions = [], $sizeLimit)
@ -197,9 +200,9 @@ class qqFileUploader
$this->sizeLimit = $sizeLimit;
if (isset($_GET['qqfile'])) {
$this->file = new qqUploadedFileXhr();
$this->file = new js_upload_qqUploadedFileXhr();
} elseif (isset($_FILES['qqfile'])) {
$this->file = new qqUploadedFileForm();
$this->file = new js_upload_qqUploadedFileForm();
} else {
$this->file = false;
}
@ -234,7 +237,7 @@ class qqFileUploader
$filename = $pathinfo['filename'];
if (!isset($pathinfo['extension'])) {
Logger::warning('extension isn\'t set.', ['filename' => $filename]);
DI::logger()->warning('extension isn\'t set.', ['filename' => $filename]);
}
$ext = $pathinfo['extension'] ?? '';

View file

@ -6,9 +6,7 @@
* Author: Ryan <https://verya.pe/profile/ryan>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
@ -38,7 +36,7 @@ function keycloakpassword_request($client_id, $secret, $url, $params = [])
$res = curl_exec($ch);
if (curl_errno($ch)) {
Logger::error(curl_error($ch));
DI::logger()->error(curl_error($ch));
}
curl_close($ch);
@ -92,7 +90,7 @@ function keycloakpassword_authenticate(array &$b)
$client_id,
$secret,
$endpoint . '/logout',
[ 'refresh_token' => res['refresh_token'] ]
[ 'refresh_token' => $res['refresh_token'] ]
);
}
}

View file

@ -10,9 +10,7 @@
*"My body was my sacrifice... for my magic. This damage is permanent." - Raistlin Majere
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -32,7 +30,7 @@ function krynn_install()
Hook::register('addon_settings', 'addon/krynn/krynn.php', 'krynn_settings');
Hook::register('addon_settings_post', 'addon/krynn/krynn.php', 'krynn_settings_post');
Logger::notice("installed krynn");
DI::logger()->notice("installed krynn");
}
function krynn_post_hook(&$item)

View file

@ -7,7 +7,6 @@
* License: MIT
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
@ -100,8 +99,8 @@ function langfilter_addon_settings_post(array &$b)
function langfilter_prepare_body_content_filter(&$hook_data)
{
$logged_user = DI::userSession()->getLocalUserId();
if (!$logged_user) {
$uid = $hook_data['uid'] ?? DI::userSession()->getLocalUserId();
if (!$uid) {
return;
}
@ -113,8 +112,8 @@ function langfilter_prepare_body_content_filter(&$hook_data)
}
// Don't filter if language filter is disabled
if (!DI::pConfig()->get($logged_user, 'langfilter', 'enable',
!DI::pConfig()->get($logged_user, 'langfilter', 'disable'))
if (!DI::pConfig()->get($uid, 'langfilter', 'enable',
!DI::pConfig()->get($uid, 'langfilter', 'disable'))
) {
return;
}
@ -128,7 +127,7 @@ function langfilter_prepare_body_content_filter(&$hook_data)
$naked_body = preg_replace('#\s+#', ' ', trim($naked_body));
// Don't filter if body lenght is below minimum
$minlen = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'langfilter', 'minlength', 32);
$minlen = DI::pConfig()->get($uid, 'langfilter', 'minlength', 32);
if (!$minlen) {
$minlen = 32;
}
@ -137,8 +136,8 @@ function langfilter_prepare_body_content_filter(&$hook_data)
return;
}
$read_languages_string = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'langfilter', 'languages');
$minconfidence = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'langfilter', 'minconfidence');
$read_languages_string = DI::pConfig()->get($uid, 'langfilter', 'languages');
$minconfidence = DI::pConfig()->get($uid, 'langfilter', 'minconfidence');
// Don't filter if no spoken languages are configured
if (!$read_languages_string) {
@ -148,6 +147,8 @@ function langfilter_prepare_body_content_filter(&$hook_data)
$iso639 = new Matriphe\ISO639\ISO639;
$confidence = null;
// Extract the language of the post
if (!empty($hook_data['item']['language'])) {
$languages = json_decode($hook_data['item']['language'], true);

View file

@ -29,9 +29,7 @@
* The configuration options for this module are described in the config/ldapauth.config.php file
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\User;
@ -45,7 +43,7 @@ function ldapauth_install()
function ldapauth_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('ldapauth'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('ldapauth'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function ldapauth_hook_authenticate(array &$b)
@ -70,54 +68,54 @@ function ldapauth_authenticate($username, $password)
$ldap_autocreateaccount_nameattribute = DI::config()->get('ldapauth', 'ldap_autocreateaccount_nameattribute');
if (!extension_loaded('ldap') || !strlen($ldap_server)) {
Logger::error('Addon not configured or missing php-ldap extension', ['extension_loaded' => extension_loaded('ldap'), 'server' => $ldap_server]);
DI::logger()->error('Addon not configured or missing php-ldap extension', ['extension_loaded' => extension_loaded('ldap'), 'server' => $ldap_server]);
return false;
}
if (!strlen($password)) {
Logger::error('Empty password disallowed', ['provided_password_length' => strlen($password)]);
DI::logger()->error('Empty password disallowed', ['provided_password_length' => strlen($password)]);
return false;
}
$connect = @ldap_connect($ldap_server);
if ($connect === false) {
Logger::warning('Could not connect to LDAP server', ['server' => $ldap_server]);
DI::logger()->warning('Could not connect to LDAP server', ['server' => $ldap_server]);
return false;
}
@ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
@ldap_set_option($connect, LDAP_OPT_REFERRALS, 0);
if ((@ldap_bind($connect, $ldap_binddn, $ldap_bindpw)) === false) {
Logger::warning('Could not bind to LDAP server', ['server' => $ldap_server, 'binddn' => $ldap_binddn, 'errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
DI::logger()->warning('Could not bind to LDAP server', ['server' => $ldap_server, 'binddn' => $ldap_binddn, 'errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
return false;
}
$res = @ldap_search($connect, $ldap_searchdn, $ldap_userattr . '=' . $username);
if (!$res) {
Logger::notice('LDAP user not found.', ['searchdn' => $ldap_searchdn, 'userattr' => $ldap_userattr, 'username' => $username, 'errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
DI::logger()->notice('LDAP user not found.', ['searchdn' => $ldap_searchdn, 'userattr' => $ldap_userattr, 'username' => $username, 'errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
return false;
}
$id = @ldap_first_entry($connect, $res);
if (!$id) {
Logger::notice('Could not retrieve first LDAP entry.', ['searchdn' => $ldap_searchdn, 'userattr' => $ldap_userattr, 'username' => $username, 'errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
DI::logger()->notice('Could not retrieve first LDAP entry.', ['searchdn' => $ldap_searchdn, 'userattr' => $ldap_userattr, 'username' => $username, 'errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
return false;
}
$dn = @ldap_get_dn($connect, $id);
if (!@ldap_bind($connect, $dn, $password)) {
Logger::notice('Could not authenticate LDAP user with provided password', ['errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
DI::logger()->notice('Could not authenticate LDAP user with provided password', ['errno' => ldap_errno($connect), 'error' => ldap_error($connect)]);
return false;
}
if (strlen($ldap_group) && @ldap_compare($connect, $ldap_group, 'member', $dn) !== true) {
$errno = @ldap_errno($connect);
if ($errno === 32) {
Logger::notice('LDAP Access Control Group does not exist', ['errno' => $errno, 'error' => ldap_error($connect)]);
DI::logger()->notice('LDAP Access Control Group does not exist', ['errno' => $errno, 'error' => ldap_error($connect)]);
} elseif ($errno === 16) {
Logger::notice('LDAP membership attribute does not exist in access control group', ['errno' => $errno, 'error' => ldap_error($connect)]);
DI::logger()->notice('LDAP membership attribute does not exist in access control group', ['errno' => $errno, 'error' => ldap_error($connect)]);
} else {
Logger::notice('LDAP user isn\'t part of the authorized group', ['dn' => $dn]);
DI::logger()->notice('LDAP user isn\'t part of the authorized group', ['dn' => $dn]);
}
@ldap_close($connect);
@ -141,7 +139,7 @@ function ldapauth_authenticate($username, $password)
$authentication = User::getAuthenticationInfo($username);
return User::getById($authentication['uid']);
} catch (Exception $e) {
Logger::notice('LDAP authentication error: ' . $e->getMessage());
DI::logger()->notice('LDAP authentication error: ' . $e->getMessage());
return false;
}
}
@ -149,7 +147,7 @@ function ldapauth_authenticate($username, $password)
function ldap_createaccount($username, $password, $email, $name)
{
if (!strlen($email) || !strlen($name)) {
Logger::notice('Could not create local user from LDAP data, no email or nickname provided');
DI::logger()->notice('Could not create local user from LDAP data, no email or nickname provided');
return false;
}
@ -161,10 +159,10 @@ function ldap_createaccount($username, $password, $email, $name)
'password' => $password,
'verified' => 1
]);
Logger::info('Local user created from LDAP data', ['username' => $username, 'name' => $name]);
DI::logger()->info('Local user created from LDAP data', ['username' => $username, 'name' => $name]);
return $user;
} catch (Exception $ex) {
Logger::error('Could not create local user from LDAP data', ['username' => $username, 'exception' => $ex->getMessage()]);
DI::logger()->error('Could not create local user from LDAP data', ['username' => $username, 'exception' => $ex->getMessage()]);
}
return false;

View file

@ -6,9 +6,7 @@
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\DI;
function leistungsschutzrecht_install()
@ -149,7 +147,7 @@ function leistungsschutzrecht_is_member_site(string $url): bool
$cleanedurlpart = explode('%', $urldata['host']);
$hostname = explode('.', $cleanedurlpart[0]);
if (empty($hostname)) {
if ($hostname === false || $hostname === '') {
return false;
}
@ -169,7 +167,7 @@ function leistungsschutzrecht_cron($b)
if ($last) {
$next = $last + 86400;
if ($next > time()) {
Logger::notice('poll intervall not reached');
DI::logger()->notice('poll intervall not reached');
return;
}
}

View file

@ -6,10 +6,8 @@
* Author: Tony Baldwin <https://free-haven.org/u/tony>
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
@ -131,7 +129,7 @@ function libertree_post_local(array &$b)
function libertree_send(array &$b)
{
Logger::notice('libertree_send: invoked');
DI::logger()->notice('libertree_send: invoked');
if ($b['deleted'] || ($b['private'] == Item::PRIVATE) || ($b['created'] !== $b['edited'])) {
return;
@ -141,6 +139,10 @@ function libertree_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['parent'] != $b['id']) {
return;
}
@ -197,6 +199,6 @@ function libertree_send(array &$b)
];
$result = DI::httpClient()->post($ltree_blog, $params)->getBodyString();
Logger::notice('libertree: ' . $result);
DI::logger()->notice('libertree: ' . $result);
}
}

View file

@ -217,7 +217,7 @@ class Services_Libravatar
*
* @param array $options Array of options for getUrl()
*
* @return void
* @return array
* @throws Exception When an invalid option is used
*/
protected function checkOptionsArray($options)
@ -361,7 +361,7 @@ class Services_Libravatar
protected function domainGet($identifier)
{
if ($identifier === null) {
return null;
return '';
}
// What are we, email or openid? Split ourself up and get the
@ -401,9 +401,8 @@ class Services_Libravatar
*/
protected function srvGet($domain, $https = false)
{
// Are we going secure? Set up a fallback too.
if (isset($https) && $https === true) {
if ($https === true) {
$subdomain = '_avatars-sec._tcp.';
$fallback = 'seccdn.';
} else {
@ -426,6 +425,7 @@ class Services_Libravatar
$top = $srv[0];
$sum = 0;
$pri = [];
// Try to adhere to RFC2782's weighting algorithm, page 3
// "arrange all SRV RRs (that have not been ordered yet) in any order,
@ -462,6 +462,8 @@ class Services_Libravatar
return $v['target'];
}
}
return '';
}
/**

View file

@ -6,10 +6,7 @@
* Author: Klaus Weidenbach <http://friendica.dszdw.net/profile/klaus>
*/
use Friendica\App;
use Friendica\Core\Addon;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Core\Config\Util\ConfigFileManager;
@ -21,12 +18,12 @@ function libravatar_install()
{
Hook::register('load_config', 'addon/libravatar/libravatar.php', 'libravatar_load_config');
Hook::register('avatar_lookup', 'addon/libravatar/libravatar.php', 'libravatar_lookup');
Logger::notice("registered libravatar in avatar_lookup hook");
DI::logger()->notice("registered libravatar in avatar_lookup hook");
}
function libravatar_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('libravatar'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('libravatar'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
/**
@ -73,7 +70,9 @@ function libravatar_addon_admin(string &$o)
'pagan' => DI::l10n()->t('retro adventure game character'),
];
if (Addon::isEnabled('gravatar')) {
$addonHelper = DI::addonHelper();
if ($addonHelper->isAddonEnabled('gravatar')) {
$o = '<h5>' .DI::l10n()->t('Information') .'</h5><p>' .DI::l10n()->t('Gravatar addon is installed. Please disable the Gravatar addon.<br>The Libravatar addon will fall back to Gravatar if nothing was found at Libravatar.') .'</p><br><br>';
}

View file

@ -8,10 +8,8 @@
* Author: Cat Gray <https://free-haven.org/profile/catness>
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\Item;
@ -123,6 +121,10 @@ function ljpost_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['parent'] != $b['id']) {
return;
}
@ -201,12 +203,14 @@ function ljpost_send(array &$b)
</methodCall>
EOT;
Logger::debug('ljpost: data: ' . $xml);
DI::logger()->debug('ljpost: data: ' . $xml);
$x = '';
if ($lj_blog !== 'test') {
$x = DI::httpClient()->post($lj_blog, $xml, ['Content-Type' => 'text/xml'])->getBodyString();
}
Logger::info('posted to livejournal: ' . ($x) ? $x : '');
DI::logger()->info('posted to livejournal: ' . $x);
}
}

View file

@ -8,7 +8,6 @@
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Core\Worker;
@ -32,7 +31,7 @@ function mailstream_install()
Hook::register('post_remote_end', 'addon/mailstream/mailstream.php', 'mailstream_post_hook');
Hook::register('mailstream_send_hook', 'addon/mailstream/mailstream.php', 'mailstream_send_hook');
Logger::info("installed mailstream");
DI::logger()->info("installed mailstream");
}
/**
@ -73,6 +72,68 @@ function mailstream_addon_admin_post()
}
}
/**
* Creates content for the "References" header. When the message is
* part of a thread, this contains a handful of message IDs of other
* messages in the thread. This should provide enough clues for mail
* agents to thread messages together, even if some messages or
* references are missing. See https://www.jwz.org/doc/threading.html
*
* According to RFC 1036, these references should be in forwards
* chronological order separated by spaces. That is, the first
* message ID is the top-level post, then the first-level reply, then
* the second-level reply, and so on, ending in the direct parent.
* The RFC allows for message IDs to be omitted for length. To save
* database queries we only include the three nearest replies in the
* chain, plus the top-level post.
*
* @param array $item content of the item
*
* @return string the set of references as a space-separated string
*/
function mailstream_generate_references(array $item): string
{
$ancestor_message_ids = [];
$top_level_post_uri = "";
if (array_key_exists("parent-uri", $item)) {
$top_level_post_uri = $item["parent-uri"];
}
$ancestor_uri = "";
if (array_key_exists("thr-parent", $item)) {
$ancestor_uri = $item["thr-parent"];
}
while ($ancestor_uri && count($ancestor_message_ids) < 3) {
if ($ancestor_uri == $top_level_post_uri) {
break;
}
$ancestor_message_id = mailstream_generate_id($ancestor_uri);
array_unshift($ancestor_message_ids, $ancestor_message_id);
$ancestor = Post::selectFirst([], array("uid" => $item["uid"], "uri" => $ancestor_uri));
if (empty($ancestor)) {
DI::logger()->error("Could not retrieve ancestor post", ["uri" => $item["uri"], "uid" => $item["uid"], "ancestor-uri" => $ancestor_uri]);
break;
}
if (!array_key_exists("thr-parent", $ancestor)) {
break;
}
$ancestor_uri = $ancestor["thr-parent"];
}
if ($top_level_post_uri) {
$top_level_post_message_id = mailstream_generate_id($top_level_post_uri);
array_unshift($ancestor_message_ids, $top_level_post_message_id);
}
if (empty($ancestor_message_ids)) {
DI::logger()->error('cannot generate references for item with no parent', ["uri" => $item['uri']]);
return "";
}
return implode(" ", $ancestor_message_ids);
}
/**
* Creates a message ID for a post URI in accordance with RFC 1036
* See also http://www.jwz.org/doc/mid.html
@ -86,7 +147,7 @@ function mailstream_generate_id(string $uri): string
$host = DI::baseUrl()->getHost();
$resource = hash('md5', $uri);
$message_id = "<" . $resource . "@" . $host . ">";
Logger::debug('generated message ID', ['id' => $message_id, 'uri' => $uri]);
DI::logger()->debug('generated message ID', ['id' => $message_id, 'uri' => $uri]);
return $message_id;
}
@ -95,20 +156,20 @@ function mailstream_send_hook(array $data)
$criteria = array('uid' => $data['uid'], 'contact-id' => $data['contact-id'], 'uri' => $data['uri']);
$item = Post::selectFirst([], $criteria);
if (empty($item)) {
Logger::error('could not find item');
DI::logger()->error('could not find item');
return;
}
$user = User::getById($item['uid']);
if (empty($user)) {
Logger::error('could not find user', ['uid' => $item['uid']]);
DI::logger()->error('could not find user', ['uid' => $item['uid']]);
return;
}
if (!mailstream_send($data['message_id'], $item, $user)) {
Logger::debug('send failed, will retry', $data);
DI::logger()->debug('send failed, will retry', $data);
if (!Worker::defer()) {
Logger::error('failed and could not defer', $data);
DI::logger()->error('failed and could not defer', $data);
}
}
}
@ -124,32 +185,32 @@ function mailstream_send_hook(array $data)
function mailstream_post_hook(array &$item)
{
if ($item['uid'] === 0) {
Logger::debug('mailstream: root user, skipping item ' . $item['id']);
DI::logger()->debug('mailstream: root user, skipping item ' . $item['id']);
return;
}
if (!DI::pConfig()->get($item['uid'], 'mailstream', 'enabled')) {
Logger::debug('mailstream: not enabled.', ['item' => $item['id'], ' uid ' => $item['uid']]);
DI::logger()->debug('mailstream: not enabled.', ['item' => $item['id'], ' uid ' => $item['uid']]);
return;
}
if (!$item['contact-id']) {
Logger::debug('no contact-id', ['item' => $item['id']]);
DI::logger()->debug('no contact-id', ['item' => $item['id']]);
return;
}
if (!$item['uri']) {
Logger::debug('no uri', ['item' => $item['id']]);
DI::logger()->debug('no uri', ['item' => $item['id']]);
return;
}
if ($item['verb'] == Activity::ANNOUNCE) {
Logger::debug('ignoring announce', ['item' => $item['id']]);
DI::logger()->debug('ignoring announce', ['item' => $item['id']]);
return;
}
if (DI::pConfig()->get($item['uid'], 'mailstream', 'nolikes')) {
if ($item['verb'] == Activity::LIKE) {
Logger::debug('ignoring like', ['item' => $item['id']]);
DI::logger()->debug('ignoring like', ['item' => $item['id']]);
return;
}
if ($item['verb'] == Activity::DISLIKE) {
Logger::debug('ignoring dislike', ['item' => $item['id']]);
DI::logger()->debug('ignoring dislike', ['item' => $item['id']]);
return;
}
}
@ -180,7 +241,7 @@ function mailstream_post_hook(array &$item)
function mailstream_do_images(array &$item, array &$attachments)
{
if (!DI::pConfig()->get($item['uid'], 'mailstream', 'attachimg')) {
return;
return $attachments;
}
$attachments = [];
@ -200,7 +261,7 @@ function mailstream_do_images(array &$item, array &$attachments)
try {
$curlResult = DI::httpClient()->get($url, HttpClientAccept::DEFAULT, [HttpClientOptions::COOKIEJAR => $cookiejar]);
if (!$curlResult->isSuccess()) {
Logger::debug('mailstream: fetch image url failed', [
DI::logger()->debug('mailstream: fetch image url failed', [
'url' => $url,
'item_id' => $item['id'],
'return_code' => $curlResult->getReturnCode()
@ -208,7 +269,7 @@ function mailstream_do_images(array &$item, array &$attachments)
continue;
}
} catch (InvalidArgumentException $e) {
Logger::error('exception fetching url', ['url' => $url, 'item_id' => $item['id']]);
DI::logger()->error('exception fetching url', ['url' => $url, 'item_id' => $item['id']]);
continue;
}
$attachments[$url] = [
@ -309,7 +370,7 @@ function mailstream_subject(array $item): string
}
$contact = Contact::selectFirst([], ['id' => $item['contact-id'], 'uid' => $item['uid']]);
if (!DBA::isResult($contact)) {
Logger::error('no contact', [
DI::logger()->error('no contact', [
'item' => $item['id'],
'plink' => $item['plink'],
'contact id' => $item['contact-id'],
@ -351,16 +412,16 @@ function mailstream_subject(array $item): string
function mailstream_send(string $message_id, array $item, array $user): bool
{
if (!is_array($item)) {
Logger::error('item is empty', ['message_id' => $message_id]);
DI::logger()->error('item is empty', ['message_id' => $message_id]);
return false;
}
if (!$item['visible']) {
Logger::debug('item not yet visible', ['item uri' => $item['uri']]);
DI::logger()->debug('item not yet visible', ['item uri' => $item['uri']]);
return false;
}
if (!$message_id) {
Logger::error('no message ID supplied', ['item uri' => $item['uri'], 'user email' => $user['email']]);
DI::logger()->error('no message ID supplied', ['item uri' => $item['uri'], 'user email' => $user['email']]);
return true;
}
@ -378,7 +439,7 @@ function mailstream_send(string $message_id, array $item, array $user): bool
if (!$address) {
$address = $user['email'];
}
$mail = new PHPmailer();
$mail = new PHPMailer();
try {
$mail->XMailer = 'Friendica Mailstream Addon';
$mail->SetFrom($frommail, mailstream_sender($item));
@ -387,6 +448,7 @@ function mailstream_send(string $message_id, array $item, array $user): bool
$mail->Subject = mailstream_subject($item);
if ($item['thr-parent'] != $item['uri']) {
$mail->addCustomHeader('In-Reply-To: ' . mailstream_generate_id($item['thr-parent']));
$mail->addCustomHeader('References: ' . mailstream_generate_references($item));
}
$mail->addCustomHeader('X-Friendica-Mailstream-URI: ' . $item['uri']);
if ($item['plink']) {
@ -418,15 +480,15 @@ function mailstream_send(string $message_id, array $item, array $user): bool
if (!$mail->Send()) {
throw new Exception($mail->ErrorInfo);
}
Logger::debug('sent message', [
DI::logger()->debug('sent message', [
'message ID' => $mail->MessageID,
'subject' => $mail->Subject,
'address' => $address
]);
} catch (phpmailerException $e) {
Logger::debug('PHPMailer exception sending message', ['id' => $message_id, 'error' => $e->errorMessage()]);
DI::logger()->debug('PHPMailer exception sending message', ['id' => $message_id, 'error' => $e->errorMessage()]);
} catch (Exception $e) {
Logger::debug('exception sending message', ['id' => $message_id, 'error' => $e->getMessage()]);
DI::logger()->debug('exception sending message', ['id' => $message_id, 'error' => $e->getMessage()]);
}
return true;

View file

@ -2690,10 +2690,10 @@ class PHPMailer
if (!is_readable($path)) {
throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
}
$magic_quotes = get_magic_quotes_runtime();
$magic_quotes = false;
if ($magic_quotes) {
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
set_magic_quotes_runtime(false);
//set_magic_quotes_runtime(false);
} else {
//Doesn't exist in PHP 5.4, but we don't need to check because
//get_magic_quotes_runtime always returns false in 5.4+
@ -2705,7 +2705,7 @@ class PHPMailer
$file_buffer = $this->encodeString($file_buffer, $encoding);
if ($magic_quotes) {
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
set_magic_quotes_runtime($magic_quotes);
//set_magic_quotes_runtime($magic_quotes);
} else {
ini_set('magic_quotes_runtime', $magic_quotes);
}
@ -3286,7 +3286,7 @@ class PHPMailer
$result = 'localhost.localdomain';
if (!empty($this->Hostname)) {
$result = $this->Hostname;
} elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
} elseif (!empty($_SERVER['SERVER_NAME'])) {
$result = $_SERVER['SERVER_NAME'];
} elseif (function_exists('gethostname') && gethostname() !== false) {
$result = gethostname();

View file

@ -5,7 +5,6 @@
* Version: 0.1
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Content\Text\Markdown;
use Friendica\Core\Renderer;
@ -27,7 +26,7 @@ function markdown_addon_settings(array &$data)
$t = Renderer::getMarkupTemplate('settings.tpl', 'addon/markdown/');
$html = Renderer::replaceMacros($t, [
'$enabled' => ['enabled', DI::l10n()->t('Enable Markdown parsing'), $enabled, DI::l10n()->t('If enabled, adds Markdown support to the Compose Post form.')],
'$enabled' => ['markdown-enabled', DI::l10n()->t('Enable Markdown parsing'), $enabled, DI::l10n()->t('If enabled, adds Markdown support to the Compose Post form.')],
]);
$data = [
@ -43,7 +42,7 @@ function markdown_addon_settings_post(array &$b)
return;
}
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'markdown', 'enabled', intval($_POST['enabled']));
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'markdown', 'enabled', intval($_POST['markdown-enabled']));
}
function markdown_post_local_start(&$request) {

View file

@ -8,7 +8,6 @@
* License: 3-clause BSD license
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -7,9 +7,9 @@
* Status: Unsupported
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
use Friendica\Model\User;
use Friendica\Util\DateTimeFormat;
function membersince_install()
@ -17,9 +17,25 @@ function membersince_install()
Hook::register('profile_advanced', 'addon/membersince/membersince.php', 'membersince_display');
}
function membersince_display(array &$b)
/**
* @param array|string|null $b
* @return void
*/
function membersince_display(&$b)
{
if (DI::app()->getCurrentTheme() == 'frio') {
$uid = DI::userSession()->getLocalUserId();
if ($uid === false) {
return;
}
$user = User::getById($uid, ['register_date']);
if ($user === false || !array_key_exists('register_date', $user)) {
return;
}
if (DI::appHelper()->getCurrentTheme() == 'frio') {
// Works in Frio.
$doc = new DOMDocument();
$doc->loadHTML(mb_convert_encoding($b, 'HTML-ENTITIES', 'UTF-8'));
@ -39,7 +55,7 @@ function membersince_display(array &$b)
$label->setAttribute('class', 'col-lg-4 col-md-4 col-sm-4 col-xs-12 profile-label-name text-muted');
// The div for the register date of the profile owner.
$entry = $doc->createElement('div', DateTimeFormat::local(DI::app()->profile['register_date']));
$entry = $doc->createElement('div', DateTimeFormat::local($user['register_date']));
$entry->setAttribute('class', 'col-lg-8 col-md-8 col-sm-8 col-xs-12 profile-entry');
$div->appendChild($hr);
@ -47,9 +63,9 @@ function membersince_display(array &$b)
$div->appendChild($entry);
$elm->parentNode->insertBefore($div, $elm->nextSibling);
$b = $doc->saveHTML();
$b = (string) $doc->saveHTML();
} else {
// Works in Vier.
$b = preg_replace('/<\/dl>/', "</dl>\n\n\n<dl id=\"aprofile-membersince\" class=\"aprofile\">\n<dt>" . DI::l10n()->t('Member since:') . "</dt>\n<dd>" . DateTimeFormat::local(DI::app()->profile['register_date']) . "</dd>\n</dl>", $b, 1);
$b = preg_replace('/<\/dl>/', "</dl>\n\n\n<dl id=\"aprofile-membersince\" class=\"aprofile\">\n<dt>" . DI::l10n()->t('Member since:') . "</dt>\n<dd>" . DateTimeFormat::local($user['register_date']) . "</dd>\n</dl>", $b, 1);
}
}

4
monolog/README.md Normal file
View file

@ -0,0 +1,4 @@
# Monolog Addon
A Logging framework with lots of additions (see [Monolog](https://github.com/Seldaek/monolog/)).
There are just Friendica additions inside the src directory.

View file

@ -1,7 +1,7 @@
<?php
/*
* Name: Monolog
* Description: A Logging framework with lots of additions (see [Monolog](https://github.com/Seldaek/monolog/)). There are just Friendica additions inside the src directory
* Version: 1.0
* Description: A Logging framework with lots of additions, customized for Friendica.
* Version: 1.1
* Author: Philipp Holzer
*/

View file

@ -4,7 +4,8 @@ namespace Friendica\Addon\monolog\src\Factory;
use Friendica\Addon\monolog\src\Monolog\IntrospectionProcessor;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Logger\Factory\AbstractLoggerTypeFactory;
use Friendica\Core\Logger\Capability\IHaveCallIntrospections;
use Friendica\Core\Logger\Factory\LoggerFactory;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
@ -16,32 +17,49 @@ use Psr\Log\LogLevel;
require_once __DIR__ . '/../../vendor/autoload.php';
class Monolog extends AbstractLoggerTypeFactory
final class MonologFactory implements LoggerFactory
{
public function create(IManageConfigValues $config, string $loglevel = null): LoggerInterface
private IHaveCallIntrospections $introspection;
private IManageConfigValues $config;
public function __construct(IHaveCallIntrospections $introspection, IManageConfigValues $config)
{
$this->introspection = $introspection;
$this->config = $config;
}
/**
* Creates and returns a PSR-3 Logger instance.
*
* Calling this method multiple times with the same parameters SHOULD return the same object.
*
* @param \Psr\Log\LogLevel::* $logLevel The log level
* @param \Friendica\Core\Logger\Capability\LogChannel::* $logChannel The log channel
*/
public function createLogger(string $logLevel, string $logChannel): LoggerInterface
{
$loggerTimeZone = new \DateTimeZone('UTC');
$logger = new Logger($this->channel);
$logger = new Logger($logChannel);
$logger->setTimezone($loggerTimeZone);
$logger->pushProcessor(new PsrLogMessageProcessor());
$logger->pushProcessor(new ProcessIdProcessor());
$logger->pushProcessor(new UidProcessor());
$logger->pushProcessor(new IntrospectionProcessor($this->introspection, LogLevel::DEBUG));
$logfile = $config->get('system', 'logfile');
$logfile = $this->config->get('system', 'logfile');
// just add a stream in case it's either writable or not file
if (is_writable($logfile)) {
$loglevel = $loglevel ?? static::mapLegacyConfigDebugLevel($config->get('system', 'loglevel'));
$loglevel = Logger::toMonologLevel($loglevel);
$logLevel = Logger::toMonologLevel($logLevel);
// fallback to notice if an invalid loglevel is set
if (!is_int($loglevel)) {
$loglevel = LogLevel::NOTICE;
if (!is_int($logLevel)) {
$logLevel = LogLevel::NOTICE;
}
$fileHandler = new StreamHandler($logfile, $loglevel);
$fileHandler = new StreamHandler($logfile, $logLevel);
$formatter = new LineFormatter("%datetime% %channel% [%level_name%]: %message% %context% %extra%\n");
$fileHandler->setFormatter($formatter);

View file

@ -20,10 +20,8 @@
*/
return [
\Monolog\Logger::class => [
'instanceOf' => \Friendica\Addon\monolog\src\Factory\Monolog::class,
'call' => [
['create', [], \Dice\Dice::CHAIN_CALL],
],
\Friendica\Core\Logger\Factory\LoggerFactory::class => [
'instanceOf' => \Friendica\Addon\monolog\src\Factory\MonologFactory::class,
'call' => null,
],
];

View file

@ -1,26 +0,0 @@
<?php
/**
* @copyright Copyright (C) 2010-2023, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
return [
\Psr\Log\LoggerInterface::class => [
\Monolog\Logger::class => ['monolog'],
],
];

View file

@ -8,7 +8,6 @@
* Status: Deprecated
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

View file

@ -7,7 +7,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

View file

@ -6,10 +6,8 @@
* Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
***/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Model\User;
@ -17,7 +15,7 @@ use Friendica\Model\User;
function newmemberwidget_install()
{
Hook::register( 'network_mod_init', 'addon/newmemberwidget/newmemberwidget.php', 'newmemberwidget_network_mod_init');
Logger::notice('newmemberwidget installed');
DI::logger()->notice('newmemberwidget installed');
}
function newmemberwidget_network_mod_init ($b)

View file

@ -25,7 +25,6 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -6,9 +6,7 @@
* Author: Michael Vogel <https://pirati.ca/profile/heluecht>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -46,19 +44,19 @@ function nominatim_resolve_item(array &$item)
$s = DI::httpClient()->fetch('https://nominatim.openstreetmap.org/reverse?lat=' . $coords[0] . '&lon=' . $coords[1] . '&format=json&addressdetails=0&accept-language=' . $language);
if (empty($s)) {
Logger::info('API could not be queried');
DI::logger()->info('API could not be queried');
return;
}
$data = json_decode($s, true);
if (empty($data['display_name'])) {
Logger::info('No results found for coordinates', ['coordinates' => $item['coord'], 'data' => $data]);
DI::logger()->info('No results found for coordinates', ['coordinates' => $item['coord'], 'data' => $data]);
return;
}
$item['location'] = $data['display_name'];
Logger::info('Got location', ['lat' => $coords[0], 'long' => $coords[1], 'location' => $item['location']]);
DI::logger()->info('Got location', ['lat' => $coords[0], 'long' => $coords[1], 'location' => $item['location']]);
if (!empty($item['location'])) {
DI::cache()->set('nominatim:' . $language . ':' . $coords[0] . '-' . $coords[1], $item['location']);

View file

@ -9,9 +9,7 @@
*/
use Friendica\Addon\notifyall\NotifyAllEmail;
use Friendica\App;
use Friendica\Database\DBA;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -59,7 +57,7 @@ function notifyall_post()
$notifyEmail = new NotifyAllEmail(DI::l10n(), DI::config(), DI::baseUrl(), $text);
foreach ($recipients as $recipient) {
foreach (DBA::toArray($recipients) as $recipient) {
DI::emailer()->send($notifyEmail->withRecipient($recipient['email']));
}

View file

@ -8,7 +8,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -105,12 +104,13 @@ function nsfw_addon_settings_post(array &$b)
function nsfw_prepare_body_content_filter(&$hook_data)
{
$words = null;
if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'nsfw', 'disable')) {
$uid = $hook_data['uid'] ?? DI::userSession()->getLocalUserId();
if (DI::pConfig()->get($uid, 'nsfw', 'disable')) {
return;
}
if (DI::userSession()->getLocalUserId()) {
$words = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'nsfw', 'words');
if ($uid) {
$words = DI::pConfig()->get($uid, 'nsfw', 'words');
}
if ($words) {
@ -119,7 +119,9 @@ function nsfw_prepare_body_content_filter(&$hook_data)
$word_list = ['nsfw'];
}
$found = false;
$found = false;
$tag_search = false;
if (count($word_list)) {
$body = $hook_data['item']['title'] . "\n" . nsfw_extract_photos($hook_data['item']['body']);
@ -129,17 +131,16 @@ function nsfw_prepare_body_content_filter(&$hook_data)
continue;
}
$tag_search = false;
switch ($word[0]) {
case '/'; // Regular expression
$found = @preg_match($word, $body);
break;
case '#': // Hashtag-only search
$tag_search = true;
$found = nsfw_find_word_in_item_tags($hook_data['item']['hashtags'], substr($word, 1));
$found = nsfw_find_word_in_item_tags($hook_data['item']['hashtags'] ?? [], substr($word, 1));
break;
default:
$found = strpos($body, $word) !== false || nsfw_find_word_in_item_tags($hook_data['item']['tags'], $word);
$found = strpos($body, $word) !== false || nsfw_find_word_in_item_tags($hook_data['item']['tags'] ?? [], $word);
break;
}

View file

@ -6,9 +6,7 @@
* Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -17,7 +15,7 @@ function numfriends_install() {
Hook::register('addon_settings', 'addon/numfriends/numfriends.php', 'numfriends_settings');
Hook::register('addon_settings_post', 'addon/numfriends/numfriends.php', 'numfriends_settings_post');
Logger::notice("installed numfriends");
DI::logger()->notice("installed numfriends");
}
/**
@ -39,7 +37,7 @@ function numfriends_settings_post($post) {
/**
*
* Called from the Addon Setting form.
* Called from the Addon Setting form.
* Add our own settings info to the page.
*
*/
@ -50,7 +48,7 @@ function numfriends_settings(array &$data)
}
$numfriends = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'display_friend_count', 24);
$t = Renderer::getMarkupTemplate('settings.tpl', 'addon/numfriends/');
$html = Renderer::replaceMacros($t, [
'$numfriends' => ['numfriends', DI::l10n()->t('How many contacts to display on profile sidebar'), $numfriends],

View file

@ -9,10 +9,8 @@
*
*/
use Friendica\App;
use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Core\Config\Util\ConfigFileManager;
@ -32,12 +30,12 @@ function openstreetmap_install()
Hook::register('Map::getCoordinates', 'addon/openstreetmap/openstreetmap.php', 'openstreetmap_get_coordinates');
Hook::register('page_header', 'addon/openstreetmap/openstreetmap.php', 'openstreetmap_alterheader');
Logger::notice("installed openstreetmap");
DI::logger()->notice("installed openstreetmap");
}
function openstreetmap_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('openstreetmap'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('openstreetmap'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function openstreetmap_alterheader(&$navHtml)
@ -155,8 +153,8 @@ function openstreetmap_generate_map(array &$b)
$lat = $b['lat']; // round($b['lat'], 5);
$lon = $b['lon']; // round($b['lon'], 5);
Logger::debug('lat: ' . $lat);
Logger::debug('lon: ' . $lon);
DI::logger()->debug('lat: ' . $lat);
DI::logger()->debug('lon: ' . $lon);
$cardlink = '<a href="' . $tmsserver;
@ -174,7 +172,7 @@ function openstreetmap_generate_map(array &$b)
$b['html'] .= '<br/>' . $cardlink;
}
Logger::debug('generate_map: ' . $b['html']);
DI::logger()->debug('generate_map: ' . $b['html']);
}
function openstreetmap_addon_admin(string &$o)

View file

@ -8,12 +8,7 @@
*/
use Friendica\DI;
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Network\HTTPException;
use Friendica\Database\DBA;
use Friendica\Core\Renderer;
use Friendica\Core\Protocol;
use Friendica\Model\Contact;
use Friendica\Model\User;
@ -22,7 +17,7 @@ function opmlexport_install()
{
Hook::register('addon_settings', __FILE__, 'opmlexport_addon_settings');
Hook::register('addon_settings_post', __FILE__, 'opmlexport_addon_settings_post');
Logger::notice('installed opmlexport Addon');
DI::logger()->notice('installed opmlexport Addon');
}

View file

@ -5,10 +5,9 @@
* Version: 1.1
* Author: Keith Fernie <http://friendika.me4.it/profile/keith>
* Hauke Altmann <https://snarl.de/profile/tugelblend>
*
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -8,16 +8,16 @@
"packages": [
{
"name": "phpmailer/phpmailer",
"version": "v6.9.1",
"version": "v6.10.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18"
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18",
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
"shasum": ""
},
"require": {
@ -75,24 +75,28 @@
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0"
},
"funding": [
{
"url": "https://github.com/Synchro",
"type": "github"
}
],
"time": "2023-11-25T22:23:28+00:00"
"time": "2025-04-24T15:19:31+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=7.0"
},
"platform-dev": [],
"plugin-api-version": "1.1.0"
"platform-dev": {},
"plugin-api-version": "2.6.0"
}

View file

@ -7,7 +7,6 @@
* Maintainer: Hypolite Petovan <hypolite@friendica.mrpetovan.com>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
use Friendica\Object\EMail\IEmail;
@ -25,14 +24,18 @@ function phpmailer_install()
function phpmailer_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('phpmailer'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('phpmailer'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
/**
* @param IEmail $email
* @param null|IEmail $email
*/
function phpmailer_emailer_send_prepare(IEmail &$email)
function phpmailer_emailer_send_prepare(?IEmail &$email)
{
if ($email === null) {
return;
}
// Passing `true` enables exceptions
$mailer = new PHPMailer(true);
try {

View file

@ -2,6 +2,24 @@
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitPhpMailerAddon::getLoader();

View file

@ -37,26 +37,81 @@ namespace Composer\Autoload;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
* @see https://www.php-fig.org/psr/psr-0/
* @see https://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
/** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir;
// PSR-4
/**
* @var array<string, array<string, int>>
*/
private $prefixLengthsPsr4 = array();
/**
* @var array<string, list<string>>
*/
private $prefixDirsPsr4 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr4 = array();
// PSR-0
/**
* List of PSR-0 prefixes
*
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/
private $prefixesPsr0 = array();
/**
* @var list<string>
*/
private $fallbackDirsPsr0 = array();
/** @var bool */
private $useIncludePath = false;
/**
* @var array<string, string>
*/
private $classMap = array();
/** @var bool */
private $classMapAuthoritative = false;
/**
* @var array<string, bool>
*/
private $missingClasses = array();
/** @var string|null */
private $apcuPrefix;
/**
* @var array<string, self>
*/
private static $registeredLoaders = array();
/**
* @param string|null $vendorDir
*/
public function __construct($vendorDir = null)
{
$this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
@ -66,28 +121,42 @@ class ClassLoader
return array();
}
/**
* @return array<string, list<string>>
*/
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
/**
* @return list<string>
*/
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
/**
* @return list<string>
*/
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
/**
* @return array<string, string> Array of classname => path
*/
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
* @param array<string, string> $classMap Class to filename map
*
* @return void
*/
public function addClassMap(array $classMap)
{
@ -102,22 +171,25 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*
* @return void
*/
public function add($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
$paths
);
}
@ -126,19 +198,19 @@ class ClassLoader
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
$this->prefixesPsr0[$first][$prefix] = $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
$paths
);
}
}
@ -147,25 +219,28 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
$paths = (array) $paths;
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
$paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@ -175,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
$this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
$paths
);
}
}
@ -195,8 +270,10 @@ class ClassLoader
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
* @param string $prefix The prefix
* @param list<string>|string $paths The PSR-0 base directories
*
* @return void
*/
public function set($prefix, $paths)
{
@ -211,10 +288,12 @@ class ClassLoader
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param list<string>|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*
* @return void
*/
public function setPsr4($prefix, $paths)
{
@ -234,6 +313,8 @@ class ClassLoader
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*
* @return void
*/
public function setUseIncludePath($useIncludePath)
{
@ -256,6 +337,8 @@ class ClassLoader
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*
* @return void
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
@ -276,6 +359,8 @@ class ClassLoader
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*
* @return void
*/
public function setApcuPrefix($apcuPrefix)
{
@ -296,33 +381,55 @@ class ClassLoader
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*
* @return void
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
if (null === $this->vendorDir) {
return;
}
if ($prepend) {
self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
} else {
unset(self::$registeredLoaders[$this->vendorDir]);
self::$registeredLoaders[$this->vendorDir] = $this;
}
}
/**
* Unregisters this instance as an autoloader.
*
* @return void
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
if (null !== $this->vendorDir) {
unset(self::$registeredLoaders[$this->vendorDir]);
}
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
* @return true|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
$includeFile = self::$includeFile;
$includeFile($file);
return true;
}
return null;
}
/**
@ -367,6 +474,21 @@ class ClassLoader
return $file;
}
/**
* Returns the currently registered loaders keyed by their corresponding vendor directories.
*
* @return array<string, self>
*/
public static function getRegisteredLoaders()
{
return self::$registeredLoaders;
}
/**
* @param string $class
* @param string $ext
* @return string|false
*/
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
@ -432,14 +554,26 @@ class ClassLoader
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*
* @param string $file
* @return void
*/
self::$includeFile = \Closure::bind(static function($file) {
include $file;
}, null, null);
}
}

View file

@ -0,0 +1,359 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer;
use Composer\Autoload\ClassLoader;
use Composer\Semver\VersionParser;
/**
* This class is copied in every Composer installed project and available to all
*
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
/**
* @var bool|null
*/
private static $canGetVendors;
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
/**
* Returns a list of all package names which are present, either by being installed, replaced or provided
*
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackages()
{
$packages = array();
foreach (self::getInstalled() as $installed) {
$packages[] = array_keys($installed['versions']);
}
if (1 === \count($packages)) {
return $packages[0];
}
return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
}
/**
* Returns a list of all package names with a specific type e.g. 'library'
*
* @param string $type
* @return string[]
* @psalm-return list<string>
*/
public static function getInstalledPackagesByType($type)
{
$packagesByType = array();
foreach (self::getInstalled() as $installed) {
foreach ($installed['versions'] as $name => $package) {
if (isset($package['type']) && $package['type'] === $type) {
$packagesByType[] = $name;
}
}
}
return $packagesByType;
}
/**
* Checks whether the given package is installed
*
* This also returns true if the package name is provided or replaced by another package
*
* @param string $packageName
* @param bool $includeDevRequirements
* @return bool
*/
public static function isInstalled($packageName, $includeDevRequirements = true)
{
foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
}
}
return false;
}
/**
* Checks whether the given package satisfies a version constraint
*
* e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
*
* Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
*
* @param VersionParser $parser Install composer/semver to have access to this class and functionality
* @param string $packageName
* @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
* @return bool
*/
public static function satisfies(VersionParser $parser, $packageName, $constraint)
{
$constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint);
}
/**
* Returns a version constraint representing all the range(s) which are installed for a given package
*
* It is easier to use this via isInstalled() with the $constraint argument if you need to check
* whether a given version of a package is installed, and not just whether it exists
*
* @param string $packageName
* @return string Version constraint usable with composer/semver
*/
public static function getVersionRanges($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
$ranges = array();
if (isset($installed['versions'][$packageName]['pretty_version'])) {
$ranges[] = $installed['versions'][$packageName]['pretty_version'];
}
if (array_key_exists('aliases', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
}
if (array_key_exists('replaced', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
}
if (array_key_exists('provided', $installed['versions'][$packageName])) {
$ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
}
return implode(' || ', $ranges);
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['version'])) {
return null;
}
return $installed['versions'][$packageName]['version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
*/
public static function getPrettyVersion($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['pretty_version'])) {
return null;
}
return $installed['versions'][$packageName]['pretty_version'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
*/
public static function getReference($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
if (!isset($installed['versions'][$packageName]['reference'])) {
return null;
}
return $installed['versions'][$packageName]['reference'];
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @param string $packageName
* @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
*/
public static function getInstallPath($packageName)
{
foreach (self::getInstalled() as $installed) {
if (!isset($installed['versions'][$packageName])) {
continue;
}
return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
}
throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
}
/**
* @return array
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
$installed = self::getInstalled();
return $installed[0]['root'];
}
/**
* Returns the raw installed.php data for custom implementations
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
}
}
return self::$installed;
}
/**
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
return self::getInstalled();
}
/**
* Lets you reload the static array from another file
*
* This is only useful for complex integrations in which a project needs to use
* this class but then also needs to execute another project's autoloader in process,
* and wants to ensure both projects have access to their version of installed.php.
*
* A typical case would be PHPUnit, where it would need to make sure it reads all
* the data it needs from this class, then call reload() with
* `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
* the project in which it runs can then also use this class safely, without
* interference between PHPUnit's dependencies and the project's dependencies.
*
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
self::$installed = $data;
self::$installedByVendor = array();
}
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{
if (null === self::$canGetVendors) {
self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
}
$installed = array();
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1];
}
}
}
}
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') {
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else {
self::$installed = array();
}
}
if (self::$installed !== array()) {
$installed[] = self::$installed;
}
return $installed;
}
}

View file

@ -2,10 +2,11 @@
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'PHPMailer\\PHPMailer\\DSNConfigurator' => $vendorDir . '/phpmailer/phpmailer/src/DSNConfigurator.php',
'PHPMailer\\PHPMailer\\Exception' => $vendorDir . '/phpmailer/phpmailer/src/Exception.php',
'PHPMailer\\PHPMailer\\OAuth' => $vendorDir . '/phpmailer/phpmailer/src/OAuth.php',

View file

@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View file

@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(

View file

@ -22,31 +22,14 @@ class ComposerAutoloaderInitPhpMailerAddon
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInitPhpMailerAddon', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInitPhpMailerAddon', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitPhpMailerAddon::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitPhpMailerAddon::getInitializer($loader));
$loader->register(true);

View file

@ -21,6 +21,7 @@ class ComposerStaticInitPhpMailerAddon
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'PHPMailer\\PHPMailer\\DSNConfigurator' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/DSNConfigurator.php',
'PHPMailer\\PHPMailer\\Exception' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/Exception.php',
'PHPMailer\\PHPMailer\\OAuth' => __DIR__ . '/..' . '/phpmailer/phpmailer/src/OAuth.php',

View file

@ -1,81 +1,90 @@
[
{
"name": "phpmailer/phpmailer",
"version": "v6.9.1",
"version_normalized": "6.9.1.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/039de174cd9c17a8389754d3b877a2ed22743e18",
"reference": "039de174cd9c17a8389754d3b877a2ed22743e18",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-filter": "*",
"ext-hash": "*",
"php": ">=5.5.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.7.2",
"yoast/phpunit-polyfills": "^1.0.4"
},
"suggest": {
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
},
"time": "2023-11-25T22:23:28+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"PHPMailer\\PHPMailer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-only"
{
"packages": [
{
"name": "phpmailer/phpmailer",
"version": "v6.10.0",
"version_normalized": "6.10.0.0",
"source": {
"type": "git",
"url": "https://github.com/PHPMailer/PHPMailer.git",
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
"reference": "bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-filter": "*",
"ext-hash": "*",
"php": ">=5.5.0"
},
"require-dev": {
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"doctrine/annotations": "^1.2.6 || ^1.13.3",
"php-parallel-lint/php-console-highlighter": "^1.0.0",
"php-parallel-lint/php-parallel-lint": "^1.3.2",
"phpcompatibility/php-compatibility": "^9.3.5",
"roave/security-advisories": "dev-latest",
"squizlabs/php_codesniffer": "^3.7.2",
"yoast/phpunit-polyfills": "^1.0.4"
},
"suggest": {
"decomplexity/SendOauth2": "Adapter for using XOAUTH2 authentication",
"ext-mbstring": "Needed to send email in multibyte encoding charset or decode encoded addresses",
"ext-openssl": "Needed for secure SMTP sending and DKIM signing",
"greew/oauth2-azure-provider": "Needed for Microsoft Azure XOAUTH2 authentication",
"hayageek/oauth2-yahoo": "Needed for Yahoo XOAUTH2 authentication",
"league/oauth2-google": "Needed for Google XOAUTH2 authentication",
"psr/log": "For optional PSR-3 debug logging",
"symfony/polyfill-mbstring": "To support UTF-8 if the Mbstring PHP extension is not enabled (^1.2)",
"thenetworg/oauth2-azure": "Needed for Microsoft XOAUTH2 authentication"
},
"time": "2025-04-24T15:19:31+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"PHPMailer\\PHPMailer\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1-only"
],
"authors": [
{
"name": "Marcus Bointon",
"email": "phpmailer@synchromedia.co.uk"
},
{
"name": "Jim Jagielski",
"email": "jimjag@gmail.com"
},
{
"name": "Andy Prevost",
"email": "codeworxtech@users.sourceforge.net"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"support": {
"issues": "https://github.com/PHPMailer/PHPMailer/issues",
"source": "https://github.com/PHPMailer/PHPMailer/tree/v6.10.0"
},
"funding": [
{
"url": "https://github.com/Synchro",
"type": "github"
}
],
"install-path": "../phpmailer/phpmailer"
}
],
"authors": [
{
"name": "Marcus Bointon",
"email": "phpmailer@synchromedia.co.uk"
},
{
"name": "Jim Jagielski",
"email": "jimjag@gmail.com"
},
{
"name": "Andy Prevost",
"email": "codeworxtech@users.sourceforge.net"
},
{
"name": "Brent R. Matzelle"
}
],
"description": "PHPMailer is a full-featured email creation and transfer class for PHP",
"funding": [
{
"url": "https://github.com/Synchro",
"type": "github"
}
]
}
]
"dev": true,
"dev-package-names": []
}

32
phpmailer/vendor/composer/installed.php vendored Normal file
View file

@ -0,0 +1,32 @@
<?php return array(
'root' => array(
'name' => 'friendica-addons/phpmailer',
'pretty_version' => 'dev-2025.07-rc',
'version' => 'dev-2025.07-rc',
'reference' => '715f70032330ad14f710284104c8593c7800e125',
'type' => 'friendica-addon',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'friendica-addons/phpmailer' => array(
'pretty_version' => 'dev-2025.07-rc',
'version' => 'dev-2025.07-rc',
'reference' => '715f70032330ad14f710284104c8593c7800e125',
'type' => 'friendica-addon',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'phpmailer/phpmailer' => array(
'pretty_version' => 'v6.10.0',
'version' => '6.10.0.0',
'reference' => 'bf74d75a1fde6beaa34a0ddae2ec5fce0f72a144',
'type' => 'library',
'install_path' => __DIR__ . '/../phpmailer/phpmailer',
'aliases' => array(),
'dev_requirement' => false,
),
),
);

View file

@ -0,0 +1,26 @@
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 70000)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 7.0.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
trigger_error(
'Composer detected issues in your platform: ' . implode(' ', $issues),
E_USER_ERROR
);
}

View file

@ -1,15 +0,0 @@
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{yml,yaml}]
indent_size = 2

View file

@ -20,34 +20,35 @@
- Multipart/alternative emails for mail clients that do not read HTML email
- Add attachments, including inline
- Support for UTF-8 content and 8bit, base64, binary, and quoted-printable encodings
- SMTP authentication with LOGIN, PLAIN, CRAM-MD5, and XOAUTH2 mechanisms over SMTPS and SMTP+STARTTLS transports
- Full UTF-8 support when using servers that support `SMTPUTF8`.
- Support for iCal events in multiparts and attachments
- SMTP authentication with `LOGIN`, `PLAIN`, `CRAM-MD5`, and `XOAUTH2` mechanisms over SMTPS and SMTP+STARTTLS transports
- Validates email addresses automatically
- Protects against header injection attacks
- Error messages in over 50 languages!
- DKIM and S/MIME signing support
- Compatible with PHP 5.5 and later, including PHP 8.2
- Compatible with PHP 5.5 and later, including PHP 8.4
- Namespaced to prevent name clashes
- Much more!
## Why you might need it
Many PHP developers need to send email from their code. The only PHP function that supports this directly is [`mail()`](https://www.php.net/manual/en/function.mail.php). However, it does not provide any assistance for making use of popular features such as encryption, authentication, HTML messages, and attachments.
Many PHP developers need to send email from their code. The only PHP function that supports this directly is [`mail()`](https://www.php.net/manual/en/function.mail.php). However, it does not provide any assistance for making use of popular features such as authentication, HTML messages, and attachments.
Formatting email correctly is surprisingly difficult. There are myriad overlapping (and conflicting) standards, requiring tight adherence to horribly complicated formatting and encoding rules the vast majority of code that you'll find online that uses the `mail()` function directly is just plain wrong, if not unsafe!
The PHP `mail()` function usually sends via a local mail server, typically fronted by a `sendmail` binary on Linux, BSD, and macOS platforms, however, Windows usually doesn't include a local mail server; PHPMailer's integrated SMTP client allows email sending on all platforms without needing a local mail server. Be aware though, that the `mail()` function should be avoided when possible; it's both faster and [safer](https://exploitbox.io/paper/Pwning-PHP-Mail-Function-For-Fun-And-RCE.html) to use SMTP to localhost.
*Please* don't be tempted to do it yourself if you don't use PHPMailer, there are many other excellent libraries that
you should look at before rolling your own. Try [SwiftMailer](https://swiftmailer.symfony.com/)
, [Laminas/Mail](https://docs.laminas.dev/laminas-mail/), [ZetaComponents](https://github.com/zetacomponents/Mail), etc.
you should look at before rolling your own. Try [Symfony Mailer](https://symfony.com/doc/current/mailer.html), [Laminas/Mail](https://docs.laminas.dev/laminas-mail/), [ZetaComponents](https://github.com/zetacomponents/Mail), etc.
## License
This software is distributed under the [LGPL 2.1](http://www.gnu.org/licenses/lgpl-2.1.html) license, along with the [GPL Cooperation Commitment](https://gplcc.github.io/gplcc/). Please read [LICENSE](https://github.com/PHPMailer/PHPMailer/blob/master/LICENSE) for information on the software availability and distribution.
This software is distributed under the [LGPL 2.1](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html) license, along with the [GPL Cooperation Commitment](https://gplcc.github.io/gplcc/). Please read [LICENSE](https://github.com/PHPMailer/PHPMailer/blob/master/LICENSE) for information on the software availability and distribution.
## Installation & loading
PHPMailer is available on [Packagist](https://packagist.org/packages/phpmailer/phpmailer) (using semantic versioning), and installation via [Composer](https://getcomposer.org) is the recommended way to install PHPMailer. Just add this line to your `composer.json` file:
```json
"phpmailer/phpmailer": "^6.9.1"
"phpmailer/phpmailer": "^6.10.0"
```
or run
@ -74,7 +75,7 @@ require 'path/to/PHPMailer/src/PHPMailer.php';
require 'path/to/PHPMailer/src/SMTP.php';
```
If you're not using the `SMTP` class explicitly (you're probably not), you don't need a `use` line for the SMTP class. Even if you're not using exceptions, you do still need to load the `Exception` class as it is used internally.
If you're not using the `SMTP` class explicitly (you're probably not), you don't need a `use` line for it. Even if you're not using exceptions, you do still need to load the `Exception` class as it is used internally.
## Legacy versions
PHPMailer 5.2 (which is compatible with PHP 5.0 — 7.0) is no longer supported, even for security updates. You will find the latest version of 5.2 in the [5.2-stable branch](https://github.com/PHPMailer/PHPMailer/tree/5.2-stable). If you're using PHP 5.5 or later (which you should be), switch to the 6.x releases.
@ -95,7 +96,7 @@ use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
//Load Composer's autoloader
//Load Composer's autoloader (created by composer, not included with PHPMailer)
require 'vendor/autoload.php';
//Create an instance; passing `true` enables exceptions
@ -144,7 +145,7 @@ If you are re-using the instance (e.g. when sending to a mailing list), you may
That's it. You should now be ready to use PHPMailer!
## Localization
PHPMailer defaults to English, but in the [language](https://github.com/PHPMailer/PHPMailer/tree/master/language/) folder, you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain [ISO 639-1](http://en.wikipedia.org/wiki/ISO_639-1) language code for the translations, for example `fr` for French. To specify a language, you need to tell PHPMailer which one to use, like this:
PHPMailer defaults to English, but in the [language](https://github.com/PHPMailer/PHPMailer/tree/master/language/) folder, you'll find many translations for PHPMailer error messages that you may encounter. Their filenames contain [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) language code for the translations, for example `fr` for French. To specify a language, you need to tell PHPMailer which one to use, like this:
```php
//To load the French version
@ -162,9 +163,9 @@ To reduce PHPMailer's deployed code footprint, examples are not included if you
Complete generated API documentation is [available online](https://phpmailer.github.io/PHPMailer/).
You can generate complete API-level documentation by running `phpdoc` in the top-level folder, and documentation will appear in the `docs` folder, though you'll need to have [PHPDocumentor](http://www.phpdoc.org) installed. You may find [the unit tests](https://github.com/PHPMailer/PHPMailer/blob/master/test/PHPMailerTest.php) a good reference for how to do various operations such as encryption.
You can generate complete API-level documentation by running `phpdoc` in the top-level folder, and documentation will appear in the `docs` folder, though you'll need to have [PHPDocumentor](https://www.phpdoc.org) installed. You may find [the unit tests](https://github.com/PHPMailer/PHPMailer/blob/master/test/PHPMailer/PHPMailerTest.php) a good reference for how to do various operations such as encryption.
If the documentation doesn't cover what you need, search the [many questions on Stack Overflow](http://stackoverflow.com/questions/tagged/phpmailer), and before you ask a question about "SMTP Error: Could not connect to SMTP host.", [read the troubleshooting guide](https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting).
If the documentation doesn't cover what you need, search the [many questions on Stack Overflow](https://stackoverflow.com/questions/tagged/phpmailer), and before you ask a question about "SMTP Error: Could not connect to SMTP host.", [read the troubleshooting guide](https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting).
## Tests
[PHPMailer tests](https://github.com/PHPMailer/PHPMailer/tree/master/test/) use PHPUnit 9, with [a polyfill](https://github.com/Yoast/PHPUnit-Polyfills) to let 9-style tests run on older PHPUnit and PHP versions.
@ -213,7 +214,7 @@ use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-phpmailer-php
See [changelog](changelog.md).
## History
- PHPMailer was originally written in 2001 by Brent R. Matzelle as a [SourceForge project](http://sourceforge.net/projects/phpmailer/).
- PHPMailer was originally written in 2001 by Brent R. Matzelle as a [SourceForge project](https://sourceforge.net/projects/phpmailer/).
- [Marcus Bointon](https://github.com/Synchro) (`coolbru` on SF) and Andy Prevost (`codeworxtech`) took over the project in 2004.
- Became an Apache incubator project on Google Code in 2010, managed by Jim Jagielski.
- Marcus created [his fork on GitHub](https://github.com/Synchro/PHPMailer) in 2008.

View file

@ -13,13 +13,13 @@ PHPMailer versions 6.1.5 and earlier contain an output escaping bug that occurs
PHPMailer versions prior to 6.0.6 and 5.2.27 are vulnerable to an object injection attack by passing `phar://` paths into `addAttachment()` and other functions that may receive unfiltered local paths, possibly leading to RCE. Recorded as [CVE-2018-19296](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2018-19296). See [this article](https://knasmueller.net/5-answers-about-php-phar-exploitation) for more info on this type of vulnerability. Mitigated by blocking the use of paths containing URL-protocol style prefixes such as `phar://`. Reported by Sehun Oh of cyberone.kr.
PHPMailer versions prior to 5.2.24 (released July 26th 2017) have an XSS vulnerability in one of the code examples, [CVE-2017-11503](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-11503). The `code_generator.phps` example did not filter user input prior to output. This file is distributed with a `.phps` extension, so it it not normally executable unless it is explicitly renamed, and the file is not included when PHPMailer is loaded through composer, so it is safe by default. There was also an undisclosed potential XSS vulnerability in the default exception handler (unused by default). Patches for both issues kindly provided by Patrick Monnerat of the Fedora Project.
PHPMailer versions prior to 5.2.24 (released July 26th 2017) have an XSS vulnerability in one of the code examples, [CVE-2017-11503](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-11503). The `code_generator.phps` example did not filter user input prior to output. This file is distributed with a `.phps` extension, so it is not normally executable unless it is explicitly renamed, and the file is not included when PHPMailer is loaded through composer, so it is safe by default. There was also an undisclosed potential XSS vulnerability in the default exception handler (unused by default). Patches for both issues kindly provided by Patrick Monnerat of the Fedora Project.
PHPMailer versions prior to 5.2.22 (released January 9th 2017) have a local file disclosure vulnerability, [CVE-2017-5223](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2017-5223). If content passed into `msgHTML()` is sourced from unfiltered user input, relative paths can map to absolute local file paths and added as attachments. Also note that `addAttachment` (just like `file_get_contents`, `passthru`, `unlink`, etc) should not be passed user-sourced params either! Reported by Yongxiang Li of Asiasecurity.
PHPMailer versions prior to 5.2.20 (released December 28th 2016) are vulnerable to [CVE-2016-10045](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-10045) a remote code execution vulnerability, responsibly reported by [Dawid Golunski](https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10045-Vuln-Patch-Bypass.html), and patched by Paul Buonopane (@Zenexer).
PHPMailer versions prior to 5.2.18 (released December 2016) are vulnerable to [CVE-2016-10033](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-10033) a remote code execution vulnerability, responsibly reported by [Dawid Golunski](http://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html).
PHPMailer versions prior to 5.2.18 (released December 2016) are vulnerable to [CVE-2016-10033](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2016-10033) a remote code execution vulnerability, responsibly reported by [Dawid Golunski](https://legalhackers.com/advisories/PHPMailer-Exploit-Remote-Code-Exec-CVE-2016-10033-Vuln.html).
PHPMailer versions prior to 5.2.14 (released November 2015) are vulnerable to [CVE-2015-8476](https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2015-8476) an SMTP CRLF injection bug permitting arbitrary message sending.

View file

@ -0,0 +1,48 @@
# A short history of UTF-8 in email
## Background
For most of its existence, SMTP has been a 7-bit channel, only supporting US-ASCII characters. This has been a problem for many languages, especially those that use non-Latin scripts, and has led to the development of various workarounds.
The first major improvement, introduced in 1994 in [RFC 1652](https://www.rfc-editor.org/rfc/rfc1652) and extended in 2011 in [RFC 6152](https://www.rfc-editor.org/rfc/rfc6152), was the addition of the `8BITMIME` SMTP extension, which allowed raw 8-bit data to be included in message bodies sent over SMTP.
This allowed the message *contents* to contain 8-bit data, including things like UTF-8 text, even though the SMTP protocol itself was still firmly 7-bit. This worked by having the server switch to 8-bit after the headers, and then back to 7-bit after the completion of a `DATA` command.
From 1996, messages could support [RFC 2047 encoding](https://www.rfc-editor.org/rfc/rfc2047), which permitted inserting characters from any character set into header *values* (but not names), but only by encoding them in somewhat unreadable ways to allow them to survive passage through a 7-bit channel. An example with a subject of "Schrödinger's cat" would be:
```
Subject: =?utf-8?Q=Schr=C3=B6dinger=92s_Cat?=
```
Here the accented `ö` is encoded as `=C3=B6`, which is the UTF-8 encoding of the 2-byte character, and the whole thing is wrapped in `=?utf-8?Q?` to indicate that it uses the UTF-8 charset and `quoted-printable` encoding. This is a bit of a hack, and not very human-friendly, but it works.
Similarly, 8-bit message bodies could be encoded using the same `quoted-printable` and `base64` content transfer encoding (CTE) schemes, which preserved the 8-bit content while encoding it in a format that could survive transmission through a 7-bit channel.
Domain names were originally also stuck in a 7-bit world, actually even more constrained to only a subset of the US-ASCII character set. But of course, many people want to have domains in their own language/script. Internationalized domain name (IDN) permitted this, using yet another complex encoding scheme called punycode, defined for domain names in 2003 in [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492). This finally allowed the domain part (after the `@`) of email addresses to contain UTF-8, though it was actually an illusion preserved by email client applications. For example, an address of
`user@café.example.com` translates to
`user@xn--caf-dma.example.com` in punycode, rendering it mostly unreadable, but 7-bit friendly, and remaining compatible with email clients that don't know about IDN.
The one remaining part of email that could not handle UTF-8 is the local part of email addresses (the part before the `@`).
I've only mentioned UTF-8 here, but most of these approaches also allowed other character sets that were popular, such as [the ISO-8859 family](https://en.wikipedia.org/wiki/ISO/IEC_8859). However, UTF-8 solves so many problems that these other character sets are gradually falling out of favour, as UTF-8 can support all languages.
This patchwork of overlapping approaches has served us well, but we have to admit that it's a mess.
## SMTPUTF8
`SMTPUTF8` is another SMTP extension, defined in [RFC 6531](https://www.rfc-editor.org/rfc/rfc6531) in 2012. This essentially solves the whole problem, allowing the entire SMTP conversation — commands, headers, and message bodies — to be sent in raw, unencoded UTF-8.
But there's a problem with this approach: adoption. If you send a UTF-8 message to a recipient whose mail server doesn't support this format, the sender has to somehow downgrade the message to make it survive a transition to 7-bit. This is a hard problem to solve, especially since there is no way to make a 7-bit system support UTF-8 in the local parts of addresses. This downgrade problem is what held up the adoption of `SMTPUTF8` in PHPMailer for many years, but in that time the *de facto* approach has become to simply fail in that situation, and tell the recipient it's time they upgraded their mail server 😅.
The vast majority of large email providers (gmail, Yahoo, Microsoft, etc), mail servers (postfix, exim, IIS, etc), and mail clients (Apple Mail, Outlook, Thunderbird, etc) now all support SMTPUTF8, so the need for backward compatibility is no longer what it was.
## SMTPUTF8 in PHPMailer
Several other PHP email libraries have implemented a halfway solution to `SMTPUTF8`, adding only the ability to support UTF-8 in email addresses, not elsewhere in the protocol. I wanted PHPMailer to do it "the right way", and this has taken much longer. PHPMailer now supports UTF-8 everywhere, and does not need to use transfer or header encodings for UTF-8 text when connecting to an `SMTPUTF8`-capable mail server.
This support is handled automatically: if you add an email address that requires UTF-8, PHPMailer will use UTF-8 for everything. If not, it will fall back to 7-bit and encode the message as necessary.
The one place you will need to be careful is in the selection of the address validator. By default, PHPMailer uses PHP's built-in `filter_var` validator, which does not allow UTF-8 email addresses. When PHPMailer spots that you have submitted a UTF-8 address, but have not altered the default validator, it will automatically switch to using a UTF-8-compatible validator. As soon as you do this, any SMTP connection you make will *require* that the server you connect to supports `SMTPUTF8`. You can select this validator explicitly by setting `PHPMailer::$validator = 'eai'` (an acronym for Email Address Internationalization).
### Postfix gotcha
Postfix has supported `SMTPUTF8` for a long time, but it has a peculiarity that it does not always advertise that it does so. However, rather surprisingly, if you use UTF-8 in the conversation, it will work anyway.

View file

@ -1 +1 @@
6.9.1
6.10.0

View file

@ -28,7 +28,8 @@
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true
}
},
"lock": false
},
"require": {
"php": ">=5.5.0",

View file

@ -12,7 +12,7 @@
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
@ -36,7 +36,7 @@ namespace PHPMailer\PHPMailer;
* Aliases for League Provider Classes
* Make sure you have added these to your composer.json and run `composer install`
* Plenty to choose from here:
* @see http://oauth2-client.thephpleague.com/providers/thirdparty/
* @see https://oauth2-client.thephpleague.com/providers/thirdparty/
*/
//@see https://github.com/thephpleague/oauth2-google
use League\OAuth2\Client\Provider\Google;
@ -178,5 +178,5 @@ if (!isset($_GET['code'])) {
);
//Use this to interact with an API on the users behalf
//Use this to get a new access token if the old one expires
echo 'Refresh Token: ', $token->getRefreshToken();
echo 'Refresh Token: ', htmlspecialchars($token->getRefreshToken());
}

View file

@ -5,27 +5,32 @@
* @package PHPMailer
* @author Matt Sturdy <matt.sturdy@gmail.com>
* @author Crystopher Glodzienski Cardoso <crystopher.glodzienski@gmail.com>
* @author Daniel Cruz <danicruz0415@gmail.com>
*/
$PHPMAILER_LANG['authenticate'] = 'Error SMTP: Imposible autentificar.';
$PHPMAILER_LANG['buggy_php'] = 'Tu versión de PHP está afectada por un bug que puede resultar en mensajes corruptos. Para arreglarlo, cambia a enviar usando SMTP, deshabilita la opción mail.add_x_header en tu php.ini, cambia a MacOS o Linux, o actualiza tu PHP a la versión 7.0.17+ o 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Error SMTP: Imposible conectar al servidor SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Error SMTP: Datos no aceptados.';
$PHPMAILER_LANG['empty_message'] = 'El cuerpo del mensaje está vacío.';
$PHPMAILER_LANG['encoding'] = 'Codificación desconocida: ';
$PHPMAILER_LANG['execute'] = 'Imposible ejecutar: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
$PHPMAILER_LANG['file_access'] = 'Imposible acceder al archivo: ';
$PHPMAILER_LANG['file_open'] = 'Error de Archivo: Imposible abrir el archivo: ';
$PHPMAILER_LANG['from_failed'] = 'La(s) siguiente(s) direcciones de remitente fallaron: ';
$PHPMAILER_LANG['instantiate'] = 'Imposible crear una instancia de la función Mail.';
$PHPMAILER_LANG['invalid_address'] = 'Imposible enviar: dirección de email inválido: ';
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';
$PHPMAILER_LANG['invalid_hostentry'] = 'Hostentry inválido: ';
$PHPMAILER_LANG['invalid_host'] = 'Host inválido: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer no está soportado.';
$PHPMAILER_LANG['provide_address'] = 'Debe proporcionar al menos una dirección de email de destino.';
$PHPMAILER_LANG['recipients_failed'] = 'Error SMTP: Los siguientes destinos fallaron: ';
$PHPMAILER_LANG['signing'] = 'Error al firmar: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensión faltante: ';
$PHPMAILER_LANG['smtp_code'] = 'Código del servidor SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Información adicional del servidor SMTP: ';
$PHPMAILER_LANG['invalid_header'] = 'Nombre o valor de encabezado no válido';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falló.';
$PHPMAILER_LANG['smtp_detail'] = 'Detalle: ';
$PHPMAILER_LANG['smtp_error'] = 'Error del servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'No se pudo configurar la variable: ';

View file

@ -6,7 +6,6 @@
* Some French punctuation requires a thin non-breaking space (U+202F) character before it,
* for example before a colon or exclamation mark.
* There is one of these characters between these quotes: ""
* @see http://unicode.org/udhr/n/notes_fra.html
*/
$PHPMAILER_LANG['authenticate'] = 'Erreur SMTP: échec de lauthentification.';
@ -31,7 +30,7 @@ $PHPMAILER_LANG['recipients_failed'] = 'Erreur SMTP:les destinataires s
$PHPMAILER_LANG['signing'] = 'Erreur de signature: ';
$PHPMAILER_LANG['smtp_code'] = 'Code SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Informations supplémentaires SMTP: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'La fonction SMTP connect() a échouée.';
$PHPMAILER_LANG['smtp_connect_failed'] = 'La fonction SMTP connect() a échoué.';
$PHPMAILER_LANG['smtp_detail'] = 'Détails: ';
$PHPMAILER_LANG['smtp_error'] = 'Erreur du serveur SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Impossible dinitialiser ou de réinitialiser une variable: ';

View file

@ -3,27 +3,35 @@
/**
* Japanese PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer
* @author Mitsuhiro Yoshida <http://mitstek.com/>
* @author Mitsuhiro Yoshida <https://mitstek.com>
* @author Yoshi Sakai <http://bluemooninc.jp/>
* @author Arisophy <https://github.com/arisophy/>
* @author ARAKI Musashi <https://github.com/arakim/>
*/
$PHPMAILER_LANG['authenticate'] = 'SMTPエラー: 認証できませんでした。';
$PHPMAILER_LANG['buggy_php'] = 'ご利用のバージョンのPHPには不具合があり、メッセージが破損するおそれがあります。問題の解決は以下のいずれかを行ってください。SMTPでの送信に切り替える。php.iniのmail.add_x_headerをoffにする。MacOSまたはLinuxに切り替える。PHPバージョン7.0.17以降または7.1.3以降にアップグレードする。';
$PHPMAILER_LANG['connect_host'] = 'SMTPエラー: SMTPホストに接続できませんでした。';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTPエラー: データが受け付けられませんでした。';
$PHPMAILER_LANG['empty_message'] = 'メール本文が空です。';
$PHPMAILER_LANG['encoding'] = '不明なエンコーディング: ';
$PHPMAILER_LANG['execute'] = '実行できませんでした: ';
$PHPMAILER_LANG['extension_missing'] = '拡張機能が見つかりません: ';
$PHPMAILER_LANG['file_access'] = 'ファイルにアクセスできません: ';
$PHPMAILER_LANG['file_open'] = 'ファイルエラー: ファイルを開けません: ';
$PHPMAILER_LANG['from_failed'] = 'Fromアドレスを登録する際にエラーが発生しました: ';
$PHPMAILER_LANG['instantiate'] = 'メール関数が正常に動作しませんでした。';
$PHPMAILER_LANG['invalid_address'] = '不正なメールアドレス: ';
$PHPMAILER_LANG['provide_address'] = '少なくとも1つメールアドレスを 指定する必要があります。';
$PHPMAILER_LANG['invalid_header'] = '不正なヘッダー名またはその内容';
$PHPMAILER_LANG['invalid_hostentry'] = '不正なホストエントリー: ';
$PHPMAILER_LANG['invalid_host'] = '不正なホスト: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' メーラーがサポートされていません。';
$PHPMAILER_LANG['provide_address'] = '少なくとも1つメールアドレスを 指定する必要があります。';
$PHPMAILER_LANG['recipients_failed'] = 'SMTPエラー: 次の受信者アドレスに 間違いがあります: ';
$PHPMAILER_LANG['signing'] = '署名エラー: ';
$PHPMAILER_LANG['smtp_code'] = 'SMTPコード: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'SMTP追加情報: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP接続に失敗しました。';
$PHPMAILER_LANG['smtp_detail'] = '詳細: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTPサーバーエラー: ';
$PHPMAILER_LANG['variable_set'] = '変数が存在しません: ';
$PHPMAILER_LANG['extension_missing'] = '拡張機能が見つかりません: ';

View file

@ -0,0 +1,27 @@
<?php
/**
* Kurdish (Sorani) PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer
* @author Halo Salman <halo@home4t.com>
*/
$PHPMAILER_LANG['authenticate'] = 'هەڵەی SMTP : نەتوانرا کۆدەکە پشتڕاست بکرێتەوە ';
$PHPMAILER_LANG['connect_host'] = 'هەڵەی SMTP: نەتوانرا پەیوەندی بە سێرڤەرەوە بکات SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'هەڵەی SMTP: ئەو زانیاریانە قبوڵ نەکرا.';
$PHPMAILER_LANG['empty_message'] = 'پەیامەکە بەتاڵە';
$PHPMAILER_LANG['encoding'] = 'کۆدکردنی نەزانراو : ';
$PHPMAILER_LANG['execute'] = 'ناتوانرێت جێبەجێ بکرێت: ';
$PHPMAILER_LANG['file_access'] = 'ناتوانرێت دەستت بگات بە فایلەکە: ';
$PHPMAILER_LANG['file_open'] = 'هەڵەی پەڕگە(فایل): ناتوانرێت بکرێتەوە: ';
$PHPMAILER_LANG['from_failed'] = 'هەڵە لە ئاستی ناونیشانی نێرەر: ';
$PHPMAILER_LANG['instantiate'] = 'ناتوانرێت خزمەتگوزاری پۆستە پێشکەش بکرێت.';
$PHPMAILER_LANG['invalid_address'] = 'نەتوانرا بنێردرێت ، چونکە ناونیشانی ئیمەیڵەکە نادروستە: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' مەیلەر پشتگیری ناکات';
$PHPMAILER_LANG['provide_address'] = 'دەبێت ناونیشانی ئیمەیڵی لانیکەم یەک وەرگر دابین بکرێت.';
$PHPMAILER_LANG['recipients_failed'] = ' هەڵەی SMTP: ئەم هەڵانەی خوارەوەشکستی هێنا لە ناردن بۆ هەردووکیان: ';
$PHPMAILER_LANG['signing'] = 'هەڵەی واژۆ: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect()پەیوەندی شکستی هێنا .';
$PHPMAILER_LANG['smtp_error'] = 'هەڵەی ئاستی سێرڤەری SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'ناتوانرێت بیگۆڕیت یان دوبارە بینێریتەوە: ';
$PHPMAILER_LANG['extension_missing'] = 'درێژکراوە نەماوە: ';

View file

@ -3,25 +3,32 @@
/**
* Portuguese (European) PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer
* @author Jonadabe <jonadabe@hotmail.com>
* @author João Vieira <mail@joaovieira.eu>
*/
$PHPMAILER_LANG['authenticate'] = 'Erro do SMTP: Não foi possível realizar a autenticação.';
$PHPMAILER_LANG['connect_host'] = 'Erro do SMTP: Não foi possível realizar ligação com o servidor SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Erro do SMTP: Os dados foram rejeitados.';
$PHPMAILER_LANG['empty_message'] = 'A mensagem no e-mail está vazia.';
$PHPMAILER_LANG['authenticate'] = 'Erro SMTP: Falha na autenticação.';
$PHPMAILER_LANG['buggy_php'] = 'A sua versão do PHP tem um bug que pode causar mensagens corrompidas. Para resolver, utilize o envio por SMTP, desative a opção mail.add_x_header no ficheiro php.ini, mude para MacOS ou Linux, ou atualize o PHP para a versão 7.0.17+ ou 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Erro SMTP: Não foi possível ligar ao servidor SMTP.';
$PHPMAILER_LANG['data_not_accepted'] = 'Erro SMTP: Dados não aceites.';
$PHPMAILER_LANG['empty_message'] = 'A mensagem de e-mail está vazia.';
$PHPMAILER_LANG['encoding'] = 'Codificação desconhecida: ';
$PHPMAILER_LANG['execute'] = 'Não foi possível executar: ';
$PHPMAILER_LANG['file_access'] = 'Não foi possível aceder o ficheiro: ';
$PHPMAILER_LANG['file_open'] = 'Abertura do ficheiro: Não foi possível abrir o ficheiro: ';
$PHPMAILER_LANG['from_failed'] = 'Ocorreram falhas nos endereços dos seguintes remententes: ';
$PHPMAILER_LANG['instantiate'] = 'Não foi possível iniciar uma instância da função mail.';
$PHPMAILER_LANG['invalid_address'] = 'Não foi enviado nenhum e-mail para o endereço de e-mail inválido: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' mailer não é suportado.';
$PHPMAILER_LANG['provide_address'] = 'Tem de fornecer pelo menos um endereço como destinatário do e-mail.';
$PHPMAILER_LANG['recipients_failed'] = 'Erro do SMTP: O endereço do seguinte destinatário falhou: ';
$PHPMAILER_LANG['signing'] = 'Erro ao assinar: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP Connect() falhou.';
$PHPMAILER_LANG['smtp_error'] = 'Erro de servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: ';
$PHPMAILER_LANG['extension_missing'] = 'Extensão em falta: ';
$PHPMAILER_LANG['file_access'] = 'Não foi possível aceder ao ficheiro: ';
$PHPMAILER_LANG['file_open'] = 'Erro ao abrir o ficheiro: ';
$PHPMAILER_LANG['from_failed'] = 'O envio falhou para o seguinte endereço do remetente: ';
$PHPMAILER_LANG['instantiate'] = 'Não foi possível instanciar a função mail.';
$PHPMAILER_LANG['invalid_address'] = 'Endereço de e-mail inválido: ';
$PHPMAILER_LANG['invalid_header'] = 'Nome ou valor do cabeçalho inválido.';
$PHPMAILER_LANG['invalid_hostentry'] = 'Entrada de host inválida: ';
$PHPMAILER_LANG['invalid_host'] = 'Host inválido: ';
$PHPMAILER_LANG['mailer_not_supported'] = 'O cliente de e-mail não é suportado.';
$PHPMAILER_LANG['provide_address'] = 'Deve fornecer pelo menos um endereço de destinatário.';
$PHPMAILER_LANG['recipients_failed'] = 'Erro SMTP: Falha no envio para os seguintes destinatários: ';
$PHPMAILER_LANG['signing'] = 'Erro ao assinar: ';
$PHPMAILER_LANG['smtp_code'] = 'Código SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Informações adicionais SMTP: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'Falha na função SMTP connect().';
$PHPMAILER_LANG['smtp_detail'] = 'Detalhes: ';
$PHPMAILER_LANG['smtp_error'] = 'Erro do servidor SMTP: ';
$PHPMAILER_LANG['variable_set'] = 'Não foi possível definir ou redefinir a variável: ';

View file

@ -5,24 +5,32 @@
* @package PHPMailer
* @author Alexey Chumakov <alex@chumakov.ru>
* @author Foster Snowhill <i18n@forstwoof.ru>
* @author ProjectSoft <projectsoft2009@yandex.ru>
*/
$PHPMAILER_LANG['authenticate'] = 'Ошибка SMTP: ошибка авторизации.';
$PHPMAILER_LANG['authenticate'] = 'Ошибка SMTP: не удалось пройти аутентификацию.';
$PHPMAILER_LANG['buggy_php'] = 'В вашей версии PHP есть ошибка, которая может привести к повреждению сообщений. Чтобы исправить, переключитесь на отправку по SMTP, отключите опцию mail.add_x_header в ваш php.ini, переключитесь на MacOS или Linux или обновите PHP до версии 7.0.17+ или 7.1.3+.';
$PHPMAILER_LANG['connect_host'] = 'Ошибка SMTP: не удается подключиться к SMTP-серверу.';
$PHPMAILER_LANG['data_not_accepted'] = 'Ошибка SMTP: данные не приняты.';
$PHPMAILER_LANG['empty_message'] = 'Пустое сообщение';
$PHPMAILER_LANG['encoding'] = 'Неизвестная кодировка: ';
$PHPMAILER_LANG['execute'] = 'Невозможно выполнить команду: ';
$PHPMAILER_LANG['extension_missing'] = 'Расширение отсутствует: ';
$PHPMAILER_LANG['file_access'] = 'Нет доступа к файлу: ';
$PHPMAILER_LANG['file_open'] = 'Файловая ошибка: не удаётся открыть файл: ';
$PHPMAILER_LANG['from_failed'] = 'Неверный адрес отправителя: ';
$PHPMAILER_LANG['instantiate'] = 'Невозможно запустить функцию mail().';
$PHPMAILER_LANG['provide_address'] = 'Пожалуйста, введите хотя бы один email-адрес получателя.';
$PHPMAILER_LANG['mailer_not_supported'] = ' — почтовый сервер не поддерживается.';
$PHPMAILER_LANG['recipients_failed'] = 'Ошибка SMTP: не удалась отправка таким адресатам: ';
$PHPMAILER_LANG['empty_message'] = 'Пустое сообщение';
$PHPMAILER_LANG['invalid_address'] = 'Не отправлено из-за неправильного формата email-адреса: ';
$PHPMAILER_LANG['invalid_header'] = 'Неверное имя или значение заголовка';
$PHPMAILER_LANG['invalid_hostentry'] = 'Неверная запись хоста: ';
$PHPMAILER_LANG['invalid_host'] = 'Неверный хост: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' — почтовый сервер не поддерживается.';
$PHPMAILER_LANG['provide_address'] = 'Вы должны указать хотя бы один адрес электронной почты получателя.';
$PHPMAILER_LANG['recipients_failed'] = 'Ошибка SMTP: Ошибка следующих получателей: ';
$PHPMAILER_LANG['signing'] = 'Ошибка подписи: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'Ошибка соединения с SMTP-сервером';
$PHPMAILER_LANG['smtp_code'] = 'Код SMTP: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'Дополнительная информация SMTP: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'Ошибка соединения с SMTP-сервером.';
$PHPMAILER_LANG['smtp_detail'] = 'Детали: ';
$PHPMAILER_LANG['smtp_error'] = 'Ошибка SMTP-сервера: ';
$PHPMAILER_LANG['variable_set'] = 'Невозможно установить или сбросить переменную: ';
$PHPMAILER_LANG['extension_missing'] = 'Расширение отсутствует: ';

View file

@ -11,21 +11,28 @@
*/
$PHPMAILER_LANG['authenticate'] = 'SMTP Hatası: Oturum açılamadı.';
$PHPMAILER_LANG['buggy_php'] = 'PHP sürümünüz iletilerin bozulmasına neden olabilecek bir hatadan etkileniyor. Bunu düzeltmek için, SMTP kullanarak göndermeye geçin, mail.add_x_header seçeneğini devre dışı bırakın php.ini dosyanızdaki mail.add_x_header seçeneğini devre dışı bırakın, MacOS veya Linux geçin veya PHP sürümünü 7.0.17+ veya 7.1.3+ sürümüne yükseltin,';
$PHPMAILER_LANG['connect_host'] = 'SMTP Hatası: SMTP sunucusuna bağlanılamadı.';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP Hatası: Veri kabul edilmedi.';
$PHPMAILER_LANG['empty_message'] = 'Mesajın içeriği boş';
$PHPMAILER_LANG['encoding'] = 'Bilinmeyen karakter kodlama: ';
$PHPMAILER_LANG['execute'] = 'Çalıştırılamadı: ';
$PHPMAILER_LANG['extension_missing'] = 'Eklenti bulunamadı: ';
$PHPMAILER_LANG['file_access'] = 'Dosyaya erişilemedi: ';
$PHPMAILER_LANG['file_open'] = 'Dosya Hatası: Dosya açılamadı: ';
$PHPMAILER_LANG['from_failed'] = 'Belirtilen adreslere gönderme başarısız: ';
$PHPMAILER_LANG['instantiate'] = 'Örnek e-posta fonksiyonu oluşturulamadı.';
$PHPMAILER_LANG['invalid_address'] = 'Geçersiz e-posta adresi: ';
$PHPMAILER_LANG['invalid_header'] = 'Geçersiz başlık adı veya değeri: ';
$PHPMAILER_LANG['invalid_hostentry'] = 'Geçersiz ana bilgisayar girişi: ';
$PHPMAILER_LANG['invalid_host'] = 'Geçersiz ana bilgisayar: ';
$PHPMAILER_LANG['mailer_not_supported'] = ' e-posta kütüphanesi desteklenmiyor.';
$PHPMAILER_LANG['provide_address'] = 'En az bir alıcı e-posta adresi belirtmelisiniz.';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP Hatası: Belirtilen alıcılara ulaşılamadı: ';
$PHPMAILER_LANG['signing'] = 'İmzalama hatası: ';
$PHPMAILER_LANG['smtp_code'] = 'SMTP kodu: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'ek SMTP bilgileri: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP connect() fonksiyonu başarısız.';
$PHPMAILER_LANG['smtp_detail'] = 'SMTP SMTP Detayı: ';
$PHPMAILER_LANG['smtp_error'] = 'SMTP sunucu hatası: ';
$PHPMAILER_LANG['variable_set'] = 'Değişken ayarlanamadı ya da sıfırlanamadı: ';
$PHPMAILER_LANG['extension_missing'] = 'Eklenti bulunamadı: ';

View file

@ -0,0 +1,30 @@
<?php
/**
* Urdu PHPMailer language file: refer to English translation for definitive list
* @package PHPMailer
* @author Saqib Ali Siddiqui <saqibsra@gmail.com>
*/
$PHPMAILER_LANG['authenticate'] = 'SMTP خرابی: تصدیق کرنے سے قاصر۔';
$PHPMAILER_LANG['connect_host'] = 'SMTP خرابی: سرور سے منسلک ہونے سے قاصر۔';
$PHPMAILER_LANG['data_not_accepted'] = 'SMTP خرابی: ڈیٹا قبول نہیں کیا گیا۔';
$PHPMAILER_LANG['empty_message'] = 'پیغام کی باڈی خالی ہے۔';
$PHPMAILER_LANG['encoding'] = 'نامعلوم انکوڈنگ: ';
$PHPMAILER_LANG['execute'] = 'عمل کرنے کے قابل نہیں ';
$PHPMAILER_LANG['file_access'] = 'فائل تک رسائی سے قاصر:';
$PHPMAILER_LANG['file_open'] = 'فائل کی خرابی: فائل کو کھولنے سے قاصر:';
$PHPMAILER_LANG['from_failed'] = 'درج ذیل بھیجنے والے کا پتہ ناکام ہو گیا:';
$PHPMAILER_LANG['instantiate'] = 'میل فنکشن کی مثال بنانے سے قاصر۔';
$PHPMAILER_LANG['invalid_address'] = 'بھیجنے سے قاصر: غلط ای میل پتہ:';
$PHPMAILER_LANG['mailer_not_supported'] = ' میلر تعاون یافتہ نہیں ہے۔';
$PHPMAILER_LANG['provide_address'] = 'آپ کو کم از کم ایک منزل کا ای میل پتہ فراہم کرنا چاہیے۔';
$PHPMAILER_LANG['recipients_failed'] = 'SMTP خرابی: درج ذیل پتہ پر نہیں بھیجا جاسکا: ';
$PHPMAILER_LANG['signing'] = 'دستخط کی خرابی: ';
$PHPMAILER_LANG['smtp_connect_failed'] = 'SMTP ملنا ناکام ہوا';
$PHPMAILER_LANG['smtp_error'] = 'SMTP سرور کی خرابی: ';
$PHPMAILER_LANG['variable_set'] = 'متغیر سیٹ نہیں کیا جا سکا: ';
$PHPMAILER_LANG['extension_missing'] = 'ایکٹینشن موجود نہیں ہے۔ ';
$PHPMAILER_LANG['smtp_code'] = 'SMTP سرور کوڈ: ';
$PHPMAILER_LANG['smtp_code_ex'] = 'اضافی SMTP سرور کی معلومات:';
$PHPMAILER_LANG['invalid_header'] = 'غلط ہیڈر کا نام یا قدر';

View file

@ -13,7 +13,7 @@
* @copyright 2012 - 2023 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.

View file

@ -13,7 +13,7 @@
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.

View file

@ -13,7 +13,7 @@
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
@ -29,7 +29,7 @@ use League\OAuth2\Client\Token\AccessToken;
* OAuth - OAuth2 authentication wrapper class.
* Uses the oauth2-client package from the League of Extraordinary Packages.
*
* @see http://oauth2-client.thephpleague.com
* @see https://oauth2-client.thephpleague.com
*
* @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
*/

View file

@ -13,7 +13,7 @@
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.

View file

@ -13,7 +13,7 @@
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
@ -152,8 +152,7 @@ class PHPMailer
* Only supported in simple alt or alt_inline message types
* To generate iCal event structures, use classes like EasyPeasyICS or iCalcreator.
*
* @see http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
* @see http://kigkonsult.se/iCalcreator/
* @see https://kigkonsult.se/iCalcreator/
*
* @var string
*/
@ -254,7 +253,7 @@ class PHPMailer
* You can set your own, but it must be in the format "<id@domain>",
* as defined in RFC5322 section 3.6.4 or it will be ignored.
*
* @see https://tools.ietf.org/html/rfc5322#section-3.6.4
* @see https://www.rfc-editor.org/rfc/rfc5322#section-3.6.4
*
* @var string
*/
@ -358,7 +357,7 @@ class PHPMailer
public $AuthType = '';
/**
* SMTP SMTPXClient command attibutes
* SMTP SMTPXClient command attributes
*
* @var array
*/
@ -388,7 +387,7 @@ class PHPMailer
* 'DELAY' will notify you if there is an unusual delay in delivery, but the actual
* delivery's outcome (success or failure) is not yet decided.
*
* @see https://tools.ietf.org/html/rfc3461 See section 4.1 for more information about NOTIFY
* @see https://www.rfc-editor.org/rfc/rfc3461.html#section-4.1 for more information about NOTIFY
*/
public $dsn = '';
@ -468,7 +467,7 @@ class PHPMailer
* Only applicable when sending via SMTP.
*
* @see https://en.wikipedia.org/wiki/Variable_envelope_return_path
* @see http://www.postfix.org/VERP_README.html Postfix VERP info
* @see https://www.postfix.org/VERP_README.html Postfix VERP info
*
* @var bool
*/
@ -551,10 +550,10 @@ class PHPMailer
* The function that handles the result of the send email action.
* It is called out by send() for each email sent.
*
* Value can be any php callable: http://www.php.net/is_callable
* Value can be any php callable: https://www.php.net/is_callable
*
* Parameters:
* bool $result result of the send action
* bool $result result of the send action
* array $to email addresses of the recipients
* array $cc cc email addresses
* array $bcc bcc email addresses
@ -581,6 +580,10 @@ class PHPMailer
* May be a callable to inject your own validator, but there are several built-in validators.
* The default validator uses PHP's FILTER_VALIDATE_EMAIL filter_var option.
*
* If CharSet is UTF8, the validator is left at the default value,
* and you send to addresses that use non-ASCII local parts, then
* PHPMailer automatically changes to the 'eai' validator.
*
* @see PHPMailer::validateAddress()
*
* @var string|callable
@ -660,6 +663,14 @@ class PHPMailer
*/
protected $ReplyToQueue = [];
/**
* Whether the need for SMTPUTF8 has been detected. Set by
* preSend() if necessary.
*
* @var bool
*/
public $UseSMTPUTF8 = false;
/**
* The array of attachments.
*
@ -757,7 +768,7 @@ class PHPMailer
*
* @var string
*/
const VERSION = '6.9.1';
const VERSION = '6.10.0';
/**
* Error severity: message only, continue processing.
@ -903,7 +914,7 @@ class PHPMailer
}
//Is this a PSR-3 logger?
if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) {
$this->Debugoutput->debug($str);
$this->Debugoutput->debug(rtrim($str, "\r\n"));
return;
}
@ -1072,7 +1083,7 @@ class PHPMailer
* be modified after calling this function), addition of such addresses is delayed until send().
* Addresses that have been added already return false, but do not throw exceptions.
*
* @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
* @param string $kind One of 'to', 'cc', 'bcc', or 'Reply-To'
* @param string $address The email address
* @param string $name An optional username associated with the address
*
@ -1111,19 +1122,22 @@ class PHPMailer
$params = [$kind, $address, $name];
//Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
//Domain is assumed to be whatever is after the last @ symbol in the address
if (static::idnSupported() && $this->has8bitChars(substr($address, ++$pos))) {
if ('Reply-To' !== $kind) {
if (!array_key_exists($address, $this->RecipientsQueue)) {
$this->RecipientsQueue[$address] = $params;
if ($this->has8bitChars(substr($address, ++$pos))) {
if (static::idnSupported()) {
if ('Reply-To' !== $kind) {
if (!array_key_exists($address, $this->RecipientsQueue)) {
$this->RecipientsQueue[$address] = $params;
return true;
}
} elseif (!array_key_exists($address, $this->ReplyToQueue)) {
$this->ReplyToQueue[$address] = $params;
return true;
}
} elseif (!array_key_exists($address, $this->ReplyToQueue)) {
$this->ReplyToQueue[$address] = $params;
return true;
}
//We have an 8-bit domain, but we are missing the necessary extensions to support it
//Or we are already sending to this address
return false;
}
@ -1161,6 +1175,15 @@ class PHPMailer
*/
protected function addAnAddress($kind, $address, $name = '')
{
if (
self::$validator === 'php' &&
((bool) preg_match('/[\x80-\xFF]/', $address))
) {
//The caller has not altered the validator and is sending to an address
//with UTF-8, so assume that they want UTF-8 support instead of failing
$this->CharSet = self::CHARSET_UTF8;
self::$validator = 'eai';
}
if (!in_array($kind, ['to', 'cc', 'bcc', 'Reply-To'])) {
$error_message = sprintf(
'%s: %s',
@ -1212,7 +1235,7 @@ class PHPMailer
* Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
* Note that quotes in the name part are removed.
*
* @see http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
* @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
*
* @param string $addrstr The address list string
* @param bool $useimap Whether to use the IMAP extension to parse the list
@ -1363,6 +1386,7 @@ class PHPMailer
* * `pcre` Use old PCRE implementation;
* * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
* * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
* * `eai` Use a pattern similar to the HTML5 spec for 'email' and to firefox, extended to support EAI (RFC6530).
* * `noregex` Don't use a regex: super fast, really dumb.
* Alternatively you may pass in a callable to inject your own validator, for example:
*
@ -1407,7 +1431,6 @@ class PHPMailer
* * IPv6 literals: 'first.last@[IPv6:a1::]'
* Not all of these will necessarily work for sending!
*
* @see http://squiloople.com/2009/12/20/email-address-validation/
* @copyright 2009-2010 Michael Rushton
* Feel free to use and redistribute this code. But please keep this copyright notice.
*/
@ -1434,6 +1457,24 @@ class PHPMailer
'[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
$address
);
case 'eai':
/*
* This is the pattern used in the HTML5 spec for validation of 'email' type
* form input elements (as above), modified to accept Unicode email addresses.
* This is also more lenient than Firefox' html5 spec, in order to make the regex faster.
* 'eai' is an acronym for Email Address Internationalization.
* This validator is selected automatically if you attempt to use recipient addresses
* that contain Unicode characters in the local part.
*
* @see https://html.spec.whatwg.org/#e-mail-state-(type=email)
* @see https://en.wikipedia.org/wiki/International_email
*/
return (bool) preg_match(
'/^[-\p{L}\p{N}\p{M}.!#$%&\'*+\/=?^_`{|}~]+@[\p{L}\p{N}\p{M}](?:[\p{L}\p{N}\p{M}-]{0,61}' .
'[\p{L}\p{N}\p{M}])?(?:\.[\p{L}\p{N}\p{M}]' .
'(?:[-\p{L}\p{N}\p{M}]{0,61}[\p{L}\p{N}\p{M}])?)*$/usD',
$address
);
case 'php':
default:
return filter_var($address, FILTER_VALIDATE_EMAIL) !== false;
@ -1567,9 +1608,26 @@ class PHPMailer
$this->error_count = 0; //Reset errors
$this->mailHeader = '';
//The code below tries to support full use of Unicode,
//while remaining compatible with legacy SMTP servers to
//the greatest degree possible: If the message uses
//Unicode in the local parts of any addresses, it is sent
//using SMTPUTF8. If not, it it sent using
//punycode-encoded domains and plain SMTP.
if (
static::CHARSET_UTF8 === strtolower($this->CharSet) &&
($this->anyAddressHasUnicodeLocalPart($this->RecipientsQueue) ||
$this->anyAddressHasUnicodeLocalPart(array_keys($this->all_recipients)) ||
$this->anyAddressHasUnicodeLocalPart($this->ReplyToQueue) ||
$this->addressHasUnicodeLocalPart($this->From))
) {
$this->UseSMTPUTF8 = true;
}
//Dequeue recipient and Reply-To addresses with IDN
foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
$params[1] = $this->punyencodeAddress($params[1]);
if (!$this->UseSMTPUTF8) {
$params[1] = $this->punyencodeAddress($params[1]);
}
call_user_func_array([$this, 'addAnAddress'], $params);
}
if (count($this->to) + count($this->cc) + count($this->bcc) < 1) {
@ -1734,9 +1792,8 @@ class PHPMailer
//This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
//A space after `-f` is optional, but there is a long history of its presence
//causing problems, so we don't use one
//Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
//Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html
//Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
//Exim docs: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
//Sendmail docs: https://www.sendmail.org/~ca/email/man/sendmail.html
//Example problem: https://www.drupal.org/node/1057954
//PHP 5.6 workaround
@ -1874,7 +1931,7 @@ class PHPMailer
*/
protected static function isPermittedPath($path)
{
//Matches scheme definition from https://tools.ietf.org/html/rfc3986#section-3.1
//Matches scheme definition from https://www.rfc-editor.org/rfc/rfc3986#section-3.1
return !preg_match('#^[a-z][a-z\d+.-]*://#i', $path);
}
@ -1901,7 +1958,7 @@ class PHPMailer
/**
* Send mail using the PHP mail() function.
*
* @see http://www.php.net/manual/en/book.mail.php
* @see https://www.php.net/manual/en/book.mail.php
*
* @param string $header The message headers
* @param string $body The message body
@ -1931,9 +1988,8 @@ class PHPMailer
//This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
//A space after `-f` is optional, but there is a long history of its presence
//causing problems, so we don't use one
//Exim docs: http://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
//Sendmail docs: http://www.sendmail.org/~ca/email/man/sendmail.html
//Qmail docs: http://www.qmail.org/man/man8/qmail-inject.html
//Exim docs: https://www.exim.org/exim-html-current/doc/html/spec_html/ch-the_exim_command_line.html
//Sendmail docs: https://www.sendmail.org/~ca/email/man/sendmail.html
//Example problem: https://www.drupal.org/node/1057954
//CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped.
@ -2062,6 +2118,11 @@ class PHPMailer
if (!$this->smtpConnect($this->SMTPOptions)) {
throw new Exception($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
}
//If we have recipient addresses that need Unicode support,
//but the server doesn't support it, stop here
if ($this->UseSMTPUTF8 && !$this->smtp->getServerExt('SMTPUTF8')) {
throw new Exception($this->lang('no_smtputf8'), self::STOP_CRITICAL);
}
//Sender already validated in preSend()
if ('' === $this->Sender) {
$smtp_from = $this->From;
@ -2163,6 +2224,7 @@ class PHPMailer
$this->smtp->setDebugLevel($this->SMTPDebug);
$this->smtp->setDebugOutput($this->Debugoutput);
$this->smtp->setVerp($this->do_verp);
$this->smtp->setSMTPUTF8($this->UseSMTPUTF8);
if ($this->Host === null) {
$this->Host = 'localhost';
}
@ -2360,6 +2422,7 @@ class PHPMailer
'smtp_detail' => 'Detail: ',
'smtp_error' => 'SMTP server error: ',
'variable_set' => 'Cannot set or reset variable: ',
'no_smtputf8' => 'Server does not support SMTPUTF8 needed to send to Unicode addresses',
];
if (empty($lang_path)) {
//Calculate an absolute path so it can work if CWD is not here
@ -2709,7 +2772,7 @@ class PHPMailer
}
//Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
//https://tools.ietf.org/html/rfc5322#section-3.6.4
//https://www.rfc-editor.org/rfc/rfc5322#section-3.6.4
if (
'' !== $this->MessageID &&
preg_match(
@ -2874,7 +2937,9 @@ class PHPMailer
$bodyEncoding = $this->Encoding;
$bodyCharSet = $this->CharSet;
//Can we do a 7-bit downgrade?
if (static::ENCODING_8BIT === $bodyEncoding && !$this->has8bitChars($this->Body)) {
if ($this->UseSMTPUTF8) {
$bodyEncoding = static::ENCODING_8BIT;
} elseif (static::ENCODING_8BIT === $bodyEncoding && !$this->has8bitChars($this->Body)) {
$bodyEncoding = static::ENCODING_7BIT;
//All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
$bodyCharSet = static::CHARSET_ASCII;
@ -3511,7 +3576,8 @@ class PHPMailer
/**
* Encode a header value (not including its label) optimally.
* Picks shortest of Q, B, or none. Result includes folding if needed.
* See RFC822 definitions for phrase, comment and text positions.
* See RFC822 definitions for phrase, comment and text positions,
* and RFC2047 for inline encodings.
*
* @param string $str The header value to encode
* @param string $position What context the string will be used in
@ -3520,6 +3586,11 @@ class PHPMailer
*/
public function encodeHeader($str, $position = 'text')
{
$position = strtolower($position);
if ($this->UseSMTPUTF8 && !("comment" === $position)) {
return trim(static::normalizeBreaks($str));
}
$matchcount = 0;
switch (strtolower($position)) {
case 'phrase':
@ -3634,7 +3705,7 @@ class PHPMailer
* without breaking lines within a character.
* Adapted from a function by paravoid.
*
* @see http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
* @see https://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
*
* @param string $str multi-byte text to wrap encode
* @param string $linebreak string to use as linefeed/end-of-line
@ -3690,7 +3761,7 @@ class PHPMailer
/**
* Encode a string using Q encoding.
*
* @see http://tools.ietf.org/html/rfc2047#section-4.2
* @see https://www.rfc-editor.org/rfc/rfc2047#section-4.2
*
* @param string $str the text to encode
* @param string $position Where the text is going to be used, see the RFC for what that means
@ -4184,7 +4255,7 @@ class PHPMailer
if ('smtp' === $this->Mailer && null !== $this->smtp) {
$lasterror = $this->smtp->getError();
if (!empty($lasterror['error'])) {
$msg .= $this->lang('smtp_error') . $lasterror['error'];
$msg .= ' ' . $this->lang('smtp_error') . $lasterror['error'];
if (!empty($lasterror['detail'])) {
$msg .= ' ' . $this->lang('smtp_detail') . $lasterror['detail'];
}
@ -4228,7 +4299,7 @@ class PHPMailer
$result = $_SERVER['SERVER_NAME'];
} elseif (function_exists('gethostname') && gethostname() !== false) {
$result = gethostname();
} elseif (php_uname('n') !== false) {
} elseif (php_uname('n') !== '') {
$result = php_uname('n');
}
if (!static::isValidHost($result)) {
@ -4253,7 +4324,7 @@ class PHPMailer
empty($host)
|| !is_string($host)
|| strlen($host) > 256
|| !preg_match('/^([a-zA-Z\d.-]*|\[[a-fA-F\d:]+\])$/', $host)
|| !preg_match('/^([a-z\d.-]*|\[[a-f\d:]+\])$/i', $host)
) {
return false;
}
@ -4267,10 +4338,49 @@ class PHPMailer
//Is it a valid IPv4 address?
return filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) !== false;
}
//Is it a syntactically valid hostname (when embeded in a URL)?
return filter_var('http://' . $host, FILTER_VALIDATE_URL) !== false;
//Is it a syntactically valid hostname (when embedded in a URL)?
return filter_var('https://' . $host, FILTER_VALIDATE_URL) !== false;
}
/**
* Check whether the supplied address uses Unicode in the local part.
*
* @return bool
*/
protected function addressHasUnicodeLocalPart($address)
{
return (bool) preg_match('/[\x80-\xFF].*@/', $address);
}
/**
* Check whether any of the supplied addresses use Unicode in the local part.
*
* @return bool
*/
protected function anyAddressHasUnicodeLocalPart($addresses)
{
foreach ($addresses as $address) {
if (is_array($address)) {
$address = $address[0];
}
if ($this->addressHasUnicodeLocalPart($address)) {
return true;
}
}
return false;
}
/**
* Check whether the message requires SMTPUTF8 based on what's known so far.
*
* @return bool
*/
public function needsSMTPUTF8()
{
return $this->UseSMTPUTF8;
}
/**
* Get an error message in the current language.
*
@ -4679,7 +4789,7 @@ class PHPMailer
* Multi-byte-safe pathinfo replacement.
* Drop-in replacement for pathinfo(), but multibyte- and cross-platform-safe.
*
* @see http://www.php.net/manual/en/function.pathinfo.php#107461
* @see https://www.php.net/manual/en/function.pathinfo.php#107461
*
* @param string $path A filename or path, does not need to exist as a file
* @param int|string $options Either a PATHINFO_* constant,
@ -4914,7 +5024,7 @@ class PHPMailer
* Uses the 'relaxed' algorithm from RFC6376 section 3.4.2.
* Canonicalized headers should *always* use CRLF, regardless of mailer setting.
*
* @see https://tools.ietf.org/html/rfc6376#section-3.4.2
* @see https://www.rfc-editor.org/rfc/rfc6376#section-3.4.2
*
* @param string $signHeader Header
*
@ -4926,7 +5036,7 @@ class PHPMailer
$signHeader = static::normalizeBreaks($signHeader, self::CRLF);
//Unfold header lines
//Note PCRE \s is too broad a definition of whitespace; RFC5322 defines it as `[ \t]`
//@see https://tools.ietf.org/html/rfc5322#section-2.2
//@see https://www.rfc-editor.org/rfc/rfc5322#section-2.2
//That means this may break if you do something daft like put vertical tabs in your headers.
$signHeader = preg_replace('/\r\n[ \t]+/', ' ', $signHeader);
//Break headers out into an array
@ -4958,7 +5068,7 @@ class PHPMailer
* Uses the 'simple' algorithm from RFC6376 section 3.4.3.
* Canonicalized bodies should *always* use CRLF, regardless of mailer setting.
*
* @see https://tools.ietf.org/html/rfc6376#section-3.4.3
* @see https://www.rfc-editor.org/rfc/rfc6376#section-3.4.3
*
* @param string $body Message Body
*
@ -4994,7 +5104,7 @@ class PHPMailer
$DKIMquery = 'dns/txt'; //Query method
$DKIMtime = time();
//Always sign these headers without being asked
//Recommended list from https://tools.ietf.org/html/rfc6376#section-5.4.1
//Recommended list from https://www.rfc-editor.org/rfc/rfc6376#section-5.4.1
$autoSignHeaders = [
'from',
'to',
@ -5100,7 +5210,7 @@ class PHPMailer
}
//The DKIM-Signature header is included in the signature *except for* the value of the `b` tag
//which is appended after calculating the signature
//https://tools.ietf.org/html/rfc6376#section-3.5
//https://www.rfc-editor.org/rfc/rfc6376#section-3.5
$dkimSignatureHeader = 'DKIM-Signature: v=1;' .
' d=' . $this->DKIM_domain . ';' .
' s=' . $this->DKIM_selector . ';' . static::$LE .

View file

@ -13,7 +13,7 @@
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
@ -46,7 +46,7 @@ class POP3
*
* @var string
*/
const VERSION = '6.9.1';
const VERSION = '6.10.0';
/**
* Default POP3 port number.
@ -250,7 +250,9 @@ class POP3
//On Windows this will raise a PHP Warning error if the hostname doesn't exist.
//Rather than suppress it with @fsockopen, capture it cleanly instead
set_error_handler([$this, 'catchWarning']);
set_error_handler(function () {
call_user_func_array([$this, 'catchWarning'], func_get_args());
});
if (false === $port) {
$port = static::DEFAULT_PORT;

View file

@ -13,7 +13,7 @@
* @copyright 2012 - 2020 Marcus Bointon
* @copyright 2010 - 2012 Jim Jagielski
* @copyright 2004 - 2009 Andy Prevost
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @license https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html GNU Lesser General Public License
* @note This program is distributed in the hope that it will be useful - WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE.
@ -35,7 +35,7 @@ class SMTP
*
* @var string
*/
const VERSION = '6.9.1';
const VERSION = '6.10.0';
/**
* SMTP line break constant.
@ -62,7 +62,7 @@ class SMTP
* The maximum line length allowed by RFC 5321 section 4.5.3.1.6,
* *excluding* a trailing CRLF break.
*
* @see https://tools.ietf.org/html/rfc5321#section-4.5.3.1.6
* @see https://www.rfc-editor.org/rfc/rfc5321#section-4.5.3.1.6
*
* @var int
*/
@ -72,7 +72,7 @@ class SMTP
* The maximum line length allowed for replies in RFC 5321 section 4.5.3.1.5,
* *including* a trailing CRLF line break.
*
* @see https://tools.ietf.org/html/rfc5321#section-4.5.3.1.5
* @see https://www.rfc-editor.org/rfc/rfc5321#section-4.5.3.1.5
*
* @var int
*/
@ -152,19 +152,28 @@ class SMTP
/**
* Whether to use VERP.
*
* @see http://en.wikipedia.org/wiki/Variable_envelope_return_path
* @see http://www.postfix.org/VERP_README.html Info on VERP
* @see https://en.wikipedia.org/wiki/Variable_envelope_return_path
* @see https://www.postfix.org/VERP_README.html Info on VERP
*
* @var bool
*/
public $do_verp = false;
/**
* Whether to use SMTPUTF8.
*
* @see https://www.rfc-editor.org/rfc/rfc6531
*
* @var bool
*/
public $do_smtputf8 = false;
/**
* The timeout value for connection, in seconds.
* Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2.
* This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure.
*
* @see http://tools.ietf.org/html/rfc2821#section-4.5.3.2
* @see https://www.rfc-editor.org/rfc/rfc2821#section-4.5.3.2
*
* @var int
*/
@ -187,12 +196,12 @@ class SMTP
*/
protected $smtp_transaction_id_patterns = [
'exim' => '/[\d]{3} OK id=(.*)/',
'sendmail' => '/[\d]{3} 2.0.0 (.*) Message/',
'postfix' => '/[\d]{3} 2.0.0 Ok: queued as (.*)/',
'Microsoft_ESMTP' => '/[0-9]{3} 2.[\d].0 (.*)@(?:.*) Queued mail for delivery/',
'sendmail' => '/[\d]{3} 2\.0\.0 (.*) Message/',
'postfix' => '/[\d]{3} 2\.0\.0 Ok: queued as (.*)/',
'Microsoft_ESMTP' => '/[0-9]{3} 2\.[\d]\.0 (.*)@(?:.*) Queued mail for delivery/',
'Amazon_SES' => '/[\d]{3} Ok (.*)/',
'SendGrid' => '/[\d]{3} Ok: queued as (.*)/',
'CampaignMonitor' => '/[\d]{3} 2.0.0 OK:([a-zA-Z\d]{48})/',
'CampaignMonitor' => '/[\d]{3} 2\.0\.0 OK:([a-zA-Z\d]{48})/',
'Haraka' => '/[\d]{3} Message Queued \((.*)\)/',
'ZoneMTA' => '/[\d]{3} Message queued as (.*)/',
'Mailjet' => '/[\d]{3} OK queued as (.*)/',
@ -280,7 +289,8 @@ class SMTP
}
//Is this a PSR-3 logger?
if ($this->Debugoutput instanceof \Psr\Log\LoggerInterface) {
$this->Debugoutput->debug($str);
//Remove trailing line breaks potentially added by calls to SMTP::client_send()
$this->Debugoutput->debug(rtrim($str, "\r\n"));
return;
}
@ -293,6 +303,7 @@ class SMTP
switch ($this->Debugoutput) {
case 'error_log':
//Don't output, just log
/** @noinspection ForgottenDebugOutputInspection */
error_log($str);
break;
case 'html':
@ -371,7 +382,7 @@ class SMTP
}
//Anything other than a 220 response means something went wrong
//RFC 5321 says the server will wait for us to send a QUIT in response to a 554 error
//https://tools.ietf.org/html/rfc5321#section-3.1
//https://www.rfc-editor.org/rfc/rfc5321#section-3.1
if ($responseCode === 554) {
$this->quit();
}
@ -404,7 +415,9 @@ class SMTP
$errstr = '';
if ($streamok) {
$socket_context = stream_context_create($options);
set_error_handler([$this, 'errorHandler']);
set_error_handler(function () {
call_user_func_array([$this, 'errorHandler'], func_get_args());
});
$connection = stream_socket_client(
$host . ':' . $port,
$errno,
@ -419,7 +432,9 @@ class SMTP
'Connection: stream_socket_client not available, falling back to fsockopen',
self::DEBUG_CONNECTION
);
set_error_handler([$this, 'errorHandler']);
set_error_handler(function () {
call_user_func_array([$this, 'errorHandler'], func_get_args());
});
$connection = fsockopen(
$host,
$port,
@ -483,7 +498,9 @@ class SMTP
}
//Begin encrypted connection
set_error_handler([$this, 'errorHandler']);
set_error_handler(function () {
call_user_func_array([$this, 'errorHandler'], func_get_args());
});
$crypto_ok = stream_socket_enable_crypto(
$this->smtp_conn,
true,
@ -574,7 +591,7 @@ class SMTP
}
//Send encoded username and password
if (
//Format from https://tools.ietf.org/html/rfc4616#section-2
//Format from https://www.rfc-editor.org/rfc/rfc4616#section-2
//We skip the first field (it's forgery), so the string starts with a null byte
!$this->sendCommand(
'User & Password',
@ -648,7 +665,7 @@ class SMTP
}
//The following borrowed from
//http://php.net/manual/en/function.mhash.php#27225
//https://www.php.net/manual/en/function.mhash.php#27225
//RFC 2104 HMAC implementation for php.
//Creates an md5 HMAC.
@ -787,7 +804,7 @@ class SMTP
//Send the lines to the server
foreach ($lines_out as $line_out) {
//Dot-stuffing as per RFC5321 section 4.5.2
//https://tools.ietf.org/html/rfc5321#section-4.5.2
//https://www.rfc-editor.org/rfc/rfc5321#section-4.5.2
if (!empty($line_out) && $line_out[0] === '.') {
$line_out = '.' . $line_out;
}
@ -905,7 +922,15 @@ class SMTP
* $from. Returns true if successful or false otherwise. If True
* the mail transaction is started and then one or more recipient
* commands may be called followed by a data command.
* Implements RFC 821: MAIL <SP> FROM:<reverse-path> <CRLF>.
* Implements RFC 821: MAIL <SP> FROM:<reverse-path> <CRLF> and
* two extensions, namely XVERP and SMTPUTF8.
*
* The server's EHLO response is not checked. If use of either
* extensions is enabled even though the server does not support
* that, mail submission will fail.
*
* XVERP is documented at https://www.postfix.org/VERP_README.html
* and SMTPUTF8 is specified in RFC 6531.
*
* @param string $from Source address of this message
*
@ -914,10 +939,11 @@ class SMTP
public function mail($from)
{
$useVerp = ($this->do_verp ? ' XVERP' : '');
$useSmtputf8 = ($this->do_smtputf8 ? ' SMTPUTF8' : '');
return $this->sendCommand(
'MAIL FROM',
'MAIL FROM:<' . $from . '>' . $useVerp,
'MAIL FROM:<' . $from . '>' . $useSmtputf8 . $useVerp,
250
);
}
@ -1162,7 +1188,9 @@ class SMTP
} else {
$this->edebug('CLIENT -> SERVER: ' . $data, self::DEBUG_CLIENT);
}
set_error_handler([$this, 'errorHandler']);
set_error_handler(function () {
call_user_func_array([$this, 'errorHandler'], func_get_args());
});
$result = fwrite($this->smtp_conn, $data);
restore_error_handler();
@ -1265,7 +1293,9 @@ class SMTP
while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
//Must pass vars in here as params are by reference
//solution for signals inspired by https://github.com/symfony/symfony/pull/6540
set_error_handler([$this, 'errorHandler']);
set_error_handler(function () {
call_user_func_array([$this, 'errorHandler'], func_get_args());
});
$n = stream_select($selR, $selW, $selW, $this->Timelimit);
restore_error_handler();
@ -1352,6 +1382,26 @@ class SMTP
return $this->do_verp;
}
/**
* Enable or disable use of SMTPUTF8.
*
* @param bool $enabled
*/
public function setSMTPUTF8($enabled = false)
{
$this->do_smtputf8 = $enabled;
}
/**
* Get SMTPUTF8 use.
*
* @return bool
*/
public function getSMTPUTF8()
{
return $this->do_smtputf8;
}
/**
* Set error messages and codes.
*

View file

@ -35,9 +35,7 @@
* setting.
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Core\Config\Util\ConfigFileManager;
@ -46,12 +44,12 @@ function piwik_install() {
Hook::register('load_config', 'addon/piwik/piwik.php', 'piwik_load_config');
Hook::register('page_end', 'addon/piwik/piwik.php', 'piwik_analytics');
Logger::notice("installed piwik addon");
DI::logger()->notice("installed piwik addon");
}
function piwik_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('piwik'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('piwik'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function piwik_analytics(string &$b)
@ -76,7 +74,7 @@ function piwik_analytics(string &$b)
* Add the Piwik tracking code for the site.
* If async is set to true use asynchronous tracking
*/
$scriptAsyncValue = $async ? 'true' : 'false';
$scriptPhpEndpoint = $shortendpoint ? 'js/' : 'piwik.php';
$scriptJsEndpoint = $shortendpoint ? 'js/' : 'piwik.js';

View file

@ -7,9 +7,7 @@
* Author: Tony Baldwin <https://free-haven.org/profile/tony>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -29,7 +27,7 @@ function planets_install()
Hook::register('addon_settings', 'addon/planets/planets.php', 'planets_settings');
Hook::register('addon_settings_post', 'addon/planets/planets.php', 'planets_settings_post');
Logger::notice("installed planets");
DI::logger()->notice("installed planets");
}
/**
@ -40,7 +38,7 @@ function planets_install()
*/
function planets_post_hook(&$item)
{
Logger::notice('planets invoked');
DI::logger()->notice('planets invoked');
if (!DI::userSession()->getLocalUserId()) {
/* non-zero if this is a logged in user of this system */

View file

@ -2,6 +2,8 @@
namespace phpnut;
use CURLFile;
/**
* phpnut.php
* pnut.io PHP library
@ -99,10 +101,14 @@ class phpnut
// if processing stream_markers or any fast stream, decrease $sleepFor
public $streamingSleepFor = 20000;
private $_clientId;
private $_clientSecret;
/**
* Constructs an phpnut PHP object with the specified client ID and
* client secret.
* @param string $client_id The client ID you received from pnut.io when
* @param string $client_id_or_token The client ID you received from pnut.io when
* creating your app.
* @param string $client_secret The client secret you received from
* pnut.io when creating your app.
@ -155,14 +161,14 @@ class phpnut
* or not access to your app. Usually you would place this as a link for
* the user to client, or a redirect to send them to the auth URL.
* Also can be called after authentication for additional scopes
* @param string $callbackUri Where you want the user to be directed
* @param string $callback_uri Where you want the user to be directed
* after authenticating with pnut.io. This must be one of the URIs
* allowed by your pnut.io application settings.
* @param array $scope An array of scopes (permissions) you wish to obtain
* from the user. If you don't specify anything, you'll only receive
* access to the user's basic profile (the default).
*/
public function getAuthUrl(?string $callback_uri=null, array|string|null $scope=null): string
public function getAuthUrl(?string $callback_uri=null, array $scope=null): string
{
if (empty($this->_clientId)) {
throw new phpnutException('You must specify your pnut client ID');
@ -256,8 +262,10 @@ class phpnut
/**
* Check the scope of current token to see if it has required scopes
* has to be done after a check
*
* @return int|array
*/
public function checkScopes(array $app_scopes): int|array
public function checkScopes(array $app_scopes)
{
if (count($this->_scopes) === 0) {
return -1; // _scope is empty
@ -303,7 +311,7 @@ class phpnut
{
return $this->httpReq('delete', "{$this->_baseUrl}token");
}
/**
* Retrieve an app access token from the app.net API. This allows you
* to access the API without going through the user access flow if you
@ -314,7 +322,7 @@ class phpnut
* @return string The app access token
*/
public function getAppAccessToken()
{
{
if (empty($this->_clientId) || empty($this->_clientSecret)) {
throw new phpnutException('You must specify your Pnut client ID and client secret');
}
@ -450,8 +458,10 @@ class phpnut
/**
* Internal function to handle all
* HTTP requests (POST,PUT,GET,DELETE)
*
* @param string|array $params
*/
protected function httpReq(string $act, string $req, string|array $params=[], string $contentType='application/x-www-form-urlencoded')
protected function httpReq(string $act, string $req, $params = [], string $contentType='application/x-www-form-urlencoded')
{
$ch = curl_init($req);
$headers = [];
@ -520,7 +530,7 @@ class phpnut
} else {
throw new phpnutException($response['error']);
}
}
}
// look for response migration errors
elseif (isset($response['meta'], $response['meta']['error_message'])) {
@ -588,7 +598,7 @@ class phpnut
{
return $this->_last_request;
}
public function getLastResponse()
{
return $this->_last_response;
@ -738,7 +748,7 @@ class phpnut
* Delete a Post. The current user must be the same user who created the Post.
* It returns the deleted Post on success.
* @param integer $post_id The ID of the post to delete
* @param array An associative array representing the post that was deleted
* @return array An associative array representing the post that was deleted
*/
public function deletePost(int $post_id)
{
@ -752,7 +762,7 @@ class phpnut
* Retrieve the Posts that are 'in reply to' a specific Post.
* @param integer $post_id The ID of the post you want to retrieve replies for.
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getPostThread(int $post_id, array $params=[])
{
@ -767,7 +777,7 @@ class phpnut
* Retrieve revisions of a post. Currently only one can be created.
* @param integer $post_id The ID of the post you want to retrieve previous revisions of.
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getPostRevisions(int $post_id, array $params=[])
{
@ -781,13 +791,13 @@ class phpnut
/**
* Get the most recent Posts created by a specific User in reverse
* chronological order (most recent first).
* @param mixed $user_id Either the ID of the user you wish to retrieve posts by,
* @param string|int $user_id $user_id Either the ID of the user you wish to retrieve posts by,
* or the string "me", which will retrieve posts for the user you're authenticated
* as.
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getUserPosts(string|int $user_id='me', array $params=[])
public function getUserPosts($user_id = 'me', array $params=[])
{
return $this->httpReq(
'get',
@ -799,13 +809,13 @@ class phpnut
/**
* Get the most recent Posts mentioning by a specific User in reverse
* chronological order (newest first).
* @param mixed $user_id Either the ID of the user who is being mentioned, or
* @param string|int $user_id Either the ID of the user who is being mentioned, or
* the string "me", which will retrieve posts for the user you're authenticated
* as.
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getUserMentions(string|int $user_id='me', array $params=[])
public function getUserMentions($user_id='me', array $params=[])
{
return $this->httpReq(
'get',
@ -817,7 +827,7 @@ class phpnut
/**
* Get the currently authenticated user's recent messages
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getUserMessages(array $params=[])
{
@ -832,7 +842,7 @@ class phpnut
* Return the 20 most recent posts from the current User and
* the Users they follow.
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getUserStream(array $params=[])
{
@ -847,7 +857,7 @@ class phpnut
* Retrieve a list of all public Posts on pnut.io, often referred to as the
* global stream.
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getPublicPosts(array $params=[])
{
@ -860,7 +870,7 @@ class phpnut
/**
* Retrieve a list of "explore" streams
* @return An array of associative arrays, each representing a single explore stream.
* @return array An array of associative arrays, each representing a single explore stream.
*/
public function getPostExploreStreams()
{
@ -874,7 +884,7 @@ class phpnut
* Retrieve a list of posts from an "explore" stream on pnut.io.
* @param string $slug [<description>]
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getPostExploreStream(string $slug, array $params=[])
{
@ -916,10 +926,11 @@ class phpnut
* are: count, before_id, since_id, include_muted, include_deleted,
* and include_post_raw.
* See https://github.com/phpnut/api-spec/blob/master/resources/posts.md#general-parameters
* @param string|int $user_id
* @return array An array of associative arrays, each representing a single
* user who has bookmarked a post
*/
public function getBookmarked(string|int $user_id='me', array $params=[])
public function getBookmarked($user_id='me', array $params=[])
{
return $this->httpReq(
'get',
@ -967,7 +978,7 @@ class phpnut
/**
* Repost an existing Post object.
* @param integer $post_id The id of the post
* @return the reposted post
* @return mixed the reposted post
*/
public function repost(int $post_id)
{
@ -980,7 +991,7 @@ class phpnut
/**
* Delete a post that the user has reposted.
* @param integer $post_id The id of the post
* @return the un-reposted post
* @return mixed the un-reposted post
*/
public function deleteRepost(int $post_id)
{
@ -997,7 +1008,7 @@ class phpnut
* This will likely change as the API evolves, as of this writing allowed keys
* are: count, before_id, since_id, include_muted, include_deleted,
* include_directed_posts, and include_raw.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function searchHashtags(string $hashtag, array $params=[])
{
@ -1014,7 +1025,7 @@ class phpnut
* see: https://docs.pnut.io/resources/posts/search
* @param string $query The search query. Supports
* normal search terms. Searches post text.
* @return array An array of associative arrays, each representing one post.
* @return string|array|false An array of associative arrays, each representing one post.
* or false on error
*/
public function searchPosts(array $params=[], string $query='', string $order='default')
@ -1044,7 +1055,7 @@ class phpnut
* This will likely change as the API evolves, as of this writing allowed keys
* are: count, before_id, since_id, include_muted, include_deleted,
* and include_post_raw.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getUserPersonalStream(array $params=[])
{
@ -1063,7 +1074,7 @@ class phpnut
);
}
}
/**
* Return the 20 most recent Posts from the current User's personalized stream
* and mentions stream merged into one stream.
@ -1071,7 +1082,7 @@ class phpnut
* This will likely change as the API evolves, as of this writing allowed keys
* are: count, before_id, since_id, include_muted, include_deleted,
* include_directed_posts, and include_raw.
* @return An array of associative arrays, each representing a single post.
* @return array An array of associative arrays, each representing a single post.
*/
public function getUserUnifiedStream(array $params=[])
{
@ -1096,14 +1107,14 @@ class phpnut
/**
* Returns a specific user object.
* @param mixed $user_id The ID of the user you want to retrieve, or the string "@-username", or the string
* @param string|int $user_id The ID of the user you want to retrieve, or the string "@-username", or the string
* "me" to retrieve data for the users you're currently authenticated as.
* @param array $params An associative array of optional general parameters.
* This will likely change as the API evolves, as of this writing allowed keys
* are: include_raw|include_user_raw.
* @return array An associative array representing the user data.
*/
public function getUser(string|int $user_id='me', array $params=[])
public function getUser($user_id='me', array $params=[])
{
return $this->httpReq(
'get',
@ -1131,10 +1142,10 @@ class phpnut
/**
* Add the specified user ID to the list of users followed.
* Returns the User object of the user being followed.
* @param integer $user_id The user ID of the user to follow.
* @param string|int $user_id The user ID of the user to follow.
* @return array An associative array representing the user you just followed.
*/
public function followUser(string|int $user_id)
public function followUser($user_id)
{
return $this->httpReq(
'put',
@ -1145,10 +1156,10 @@ class phpnut
/**
* Removes the specified user ID to the list of users followed.
* Returns the User object of the user being unfollowed.
* @param integer $user_id The user ID of the user to unfollow.
* @param string|int $user_id The user ID of the user to unfollow.
* @return array An associative array representing the user you just unfollowed.
*/
public function unfollowUser(string|int $user_id)
public function unfollowUser($user_id)
{
return $this->httpReq(
'delete',
@ -1158,13 +1169,13 @@ class phpnut
/**
* Returns an array of User objects the specified user is following.
* @param mixed $user_id Either the ID of the user being followed, or
* @param string|int $user_id Either the ID of the user being followed, or
* the string "me", which will retrieve posts for the user you're authenticated
* as.
* @return array An array of associative arrays, each representing a single
* user following $user_id
*/
public function getFollowing(string|int $user_id='me', array $params=[])
public function getFollowing($user_id='me', array $params=[])
{
return $this->httpReq(
'get',
@ -1172,31 +1183,31 @@ class phpnut
. $this->buildQueryString($params)
);
}
/**
* Returns an array of User ids the specified user is following.
* @param mixed $user_id Either the ID of the user being followed, or
* @param string|int $user_id Either the ID of the user being followed, or
* the string "me", which will retrieve posts for the user you're authenticated
* as.
* @return array user ids the specified user is following.
*/
public function getFollowingIDs(string|int $user_id='me')
public function getFollowingIDs($user_id='me')
{
return $this->httpReq(
'get',
"{$this->_baseUrl}users/{$user_id}/following?include_user=0"
);
}
/**
* Returns an array of User objects for users following the specified user.
* @param mixed $user_id Either the ID of the user being followed, or
* @param string|int $user_id Either the ID of the user being followed, or
* the string "me", which will retrieve posts for the user you're authenticated
* as.
* @return array An array of associative arrays, each representing a single
* user following $user_id
*/
public function getFollowers(string|int $user_id='me', array $params=[])
public function getFollowers($user_id='me', array $params=[])
{
return $this->httpReq(
'get',
@ -1204,15 +1215,15 @@ class phpnut
. $this->buildQueryString($params)
);
}
/**
* Returns an array of User ids for users following the specified user.
* @param mixed $user_id Either the ID of the user being followed, or
* @param string|int $user_id Either the ID of the user being followed, or
* the string "me", which will retrieve posts for the user you're authenticated
* as.
* @return array user ids for users following the specified user
*/
public function getFollowersIDs(string|int $user_id='me')
public function getFollowersIDs($user_id='me')
{
return $this->httpReq(
'get',
@ -1236,9 +1247,9 @@ class phpnut
/**
* Mute a user
* @param integer $user_id The user ID to mute
* @param string|int $user_id The user ID to mute
*/
public function muteUser(string|int $user_id)
public function muteUser($user_id)
{
return $this->httpReq(
'put',
@ -1248,9 +1259,9 @@ class phpnut
/**
* Unmute a user
* @param integer $user_id The user ID to unmute
* @param string|int $user_id The user ID to unmute
*/
public function unmuteUser(string|int $user_id)
public function unmuteUser($user_id)
{
return $this->httpReq(
'delete',
@ -1285,10 +1296,10 @@ class phpnut
/**
* List the users who match a specific search term
* @param string $search The search query. Supports @username or #tag searches as
* @param string $query The search query. Supports @username or #tag searches as
* well as normal search terms. Searches username, display name, bio information.
* Does not search posts.
* @return array An array of associative arrays, each representing one user.
* @return array|false An array of associative arrays, each representing one user.
*/
public function searchUsers(array $params=[], string $query='')
{
@ -1328,12 +1339,14 @@ class phpnut
*/
protected function updateUserImage(string $image, string $which='avatar')
{
$mimeType = '';
$test = @getimagesize($image);
if ($test && array_key_exists('mime', $test)) {
$mimeType = $test['mime'];
}
$data = [
$which => new CurlFile($image, $mimeType)
$which => new CURLFile($image, $mimeType)
];
return $this->httpReq(
'post-raw',
@ -1445,10 +1458,10 @@ class phpnut
/**
* get an existing private message channel between multiple users
* @param mixed $users Can be a comma- or space-separated string, or an array.
* @param string|array $users Can be a comma- or space-separated string, or an array.
* Usernames with @-symbol, or user ids.
*/
public function getExistingPM(string|array $users, array $params=[])
public function getExistingPM($users, array $params=[])
{
if (is_string($users)) {
$users = explode(',', str_replace(' ', ',', $users));
@ -1561,7 +1574,7 @@ class phpnut
/**
* Retrieve a list of "explore" streams
* @return An array of associative arrays, each representing a single explore stream.
* @return array An array of associative arrays, each representing a single explore stream.
*/
public function getChannelExploreStreams()
{
@ -1575,7 +1588,7 @@ class phpnut
* Retrieve a list of channels from an "explore" stream on pnut.io.
* @param string $slug [<description>]
* @param array $params An associative array of optional general parameters.
* @return An array of associative arrays, each representing a single channel.
* @return array An array of associative arrays, each representing a single channel.
*/
public function getChannelExploreStream(string $slug, array $params=[])
{
@ -1585,7 +1598,7 @@ class phpnut
. $this->buildQueryString($params)
);
}
/**
* mark channel inactive
*/
@ -1685,11 +1698,11 @@ class phpnut
/**
* create message
* @param $channelid numeric or "pm" for auto-channel (type=io.pnut.core.pm)
* @param string|int $channelid numeric or "pm" for auto-channel (type=io.pnut.core.pm)
* @param array $data array('text'=>'YOUR_MESSAGE') If a type=io.pnut.core.pm, then "destinations" key can be set to address as an array of people to send this PM too
* @param array $params query parameters
*/
public function createMessage(string|int $channelid, array $data, array $params=[])
public function createMessage($channelid, array $data, array $params=[])
{
if (isset($data['destinations'])) {
if (is_string($data['destinations'])) {
@ -1756,7 +1769,7 @@ class phpnut
* see: https://docs.pnut.io/resources/messages/search
* @param string $query The search query. Supports
* normal search terms. Searches common channel raw.
* @return array An array of associative arrays, each representing one channel.
* @return string|array|false An array of associative arrays, each representing one channel.
* or false on error
*/
public function searchMessages(array $params=[], string $query='', string $order='default')
@ -1802,16 +1815,16 @@ class phpnut
public function createFile($file, array $data, array $params=[])
{
if (!$file) {
throw new PhpnutException('You must specify a path to a file');
throw new phpnutException('You must specify a path to a file');
}
if (!file_exists($file)) {
throw new PhpnutException('File path specified does not exist');
throw new phpnutException('File path specified does not exist');
}
if (!is_readable($file)) {
throw new PhpnutException('File path specified is not readable');
throw new phpnutException('File path specified is not readable');
}
if (!array_key_exists('type', $data) || !$data['type']) {
throw new PhpnutException('Type is required when creating a file');
throw new phpnutException('Type is required when creating a file');
}
if (!array_key_exists('name', $data)) {
$data['name'] = basename($file);
@ -1823,7 +1836,7 @@ class phpnut
$mimeType = null;
}
if (!array_key_exists('kind', $data)) {
$test = @getimagesize($path);
$test = @getimagesize($file);
if ($test && array_key_exists('mime', $test)) {
$data['kind'] = 'image';
if (!$mimeType) {
@ -1840,7 +1853,7 @@ class phpnut
finfo_close($finfo);
}
if (!$mimeType) {
throw new PhpnutException('Unable to determine mime type of file, try specifying it explicitly');
throw new phpnutException('Unable to determine mime type of file, try specifying it explicitly');
}
$data['content'] = new \CurlFile($file, $mimeType);
return $this->httpReq(
@ -2001,7 +2014,7 @@ class phpnut
$json = json_encode($data);
return $this->httpReq(
'post',
$this->_baseUrl.'polls?'.$this->buildQueryString($params),
$this->_baseUrl.'polls?'.$this->buildQueryString($params),
$json,
'application/json'
);
@ -2010,7 +2023,7 @@ class phpnut
/**
* Responds to a poll.
* @param integer $poll_id The ID of the poll to respond to
* @param array list of positions for the poll response
* @param array $positions list of positions for the poll response
* @param array $params An associative array of optional general parameters.
*/
public function respondToPoll(int $poll_id, array $positions, array $params=[])
@ -2019,7 +2032,7 @@ class phpnut
return $this->httpReq(
'put',
$this->_baseUrl.'polls/'.urlencode($poll_id).'/response?'.$this->buildQueryString($params),
$json,
$json,
'application/json'
);
}
@ -2085,8 +2098,6 @@ class phpnut
* List the polls that match a specific search term
* @param array $params a list of filter, search query, and general Poll parameters
* see: https://docs.pnut.io/resources/channels/search
* @param string $query The search query. Supports
* normal search terms.
* @return array An array of associative arrays, each representing one poll.
* or false on error
*/
@ -2118,7 +2129,7 @@ class phpnut
$params
);
}
/**
* Get User Information
*/
@ -2129,7 +2140,7 @@ class phpnut
"{$this->_baseUrl}token"
);
}
/**
* Get Application Authorized User IDs
*/
@ -2147,7 +2158,7 @@ class phpnut
$params
);
}
/**
* Get Application Authorized User Tokens
*/
@ -2166,14 +2177,12 @@ class phpnut
);
}
/**
* Registers your function (or an array of object and method) to be called
* whenever an event is received via an open pnut.io stream. Your function
* will receive a single parameter, which is the object wrapper containing
* the meta and data.
* @param mixed A PHP callback (either a string containing the function name,
* @param mixed $function A PHP callback (either a string containing the function name,
* or an array where the first element is the class/object and the second
* is the method).
*/
@ -2181,7 +2190,7 @@ class phpnut
{
$this->_streamCallback = $function;
}
/**
* Opens a stream that's been created for this user/app and starts sending
* events/objects to your defined callback functions. You must define at
@ -2231,10 +2240,9 @@ class phpnut
);
return true;
}
/**
* Close the currently open stream.
* @return true;
*/
public function closeStream(): void
{
@ -2251,7 +2259,7 @@ class phpnut
$this->_currentStream = null;
$this->_multiStream = null;
}
/**
* Retrieve all streams for the current access token.
* @return array An array of stream definitions.
@ -2263,7 +2271,7 @@ class phpnut
"{$this->_baseUrl}streams"
);
}
/**
* Returns a single stream specified by a stream ID. The stream must have been
* created with the current access token.
@ -2276,7 +2284,7 @@ class phpnut
$this->_baseUrl.'streams/'.urlencode($streamId)
);
}
/**
* Creates a stream for the current app access token.
*
@ -2307,7 +2315,7 @@ class phpnut
);
return $response;
}
/**
* Update stream for the current app access token
*
@ -2338,7 +2346,7 @@ class phpnut
);
return $response;
}
/**
* Deletes a stream if you no longer need it.
*
@ -2352,7 +2360,7 @@ class phpnut
$this->_baseUrl.'streams/'.urlencode($streamId)
);
}
/**
* Deletes all streams created by the current access token.
*/
@ -2363,7 +2371,7 @@ class phpnut
"{$this->_baseUrl}streams"
);
}
/**
* Internal function used to process incoming chunks from the stream. This is only
* public because it needs to be accessed by CURL. Do not call or use this function
@ -2394,7 +2402,7 @@ class phpnut
}
return strlen($data);
}
/**
* Opens a long lived HTTP connection to the pnut.io servers, and sends data
* received to the httpStreamReceive function. As a general rule you should not
@ -2426,7 +2434,7 @@ class phpnut
$this->_lastStreamActivity = time();
curl_multi_add_handle($this->_multiStream, $this->_currentStream);
}
public function reconnectStream(): void
{
$this->closeStream();
@ -2442,12 +2450,12 @@ class phpnut
}
$this->httpStream('get', $this->_streamUrl);
}
/**
* Process an open stream for x microseconds, then return. This is useful if you want
* to be doing other things while processing the stream. If you just want to
* consume the stream without other actions, you can call processForever() instead.
* @param float @microseconds The number of microseconds to process for before
* @param null|float $microseconds The number of microseconds to process for before
* returning. There are 1,000,000 microseconds in a second.
*
* @return void
@ -2487,7 +2495,7 @@ class phpnut
}
} while ($timeSoFar+$sleepFor < $microseconds);
}
/**
* Process an open stream forever. This function will never return, if you
* want to perform other actions while consuming the stream, you should use

View file

@ -14,7 +14,6 @@ use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\Plaintext;
use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\DI;
@ -76,7 +75,7 @@ function pnut_connect()
try {
$token = $nut->getAccessToken($callback_url);
Logger::debug('Got Token', [$token]);
DI::logger()->debug('Got Token', [$token]);
$o = DI::l10n()->t('You are now authenticated with pnut.io.');
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'pnut', 'access_token', $token);
} catch (phpnutException $e) {
@ -90,7 +89,7 @@ function pnut_connect()
function pnut_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('pnut'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('pnut'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function pnut_addon_admin(string &$o)
@ -266,8 +265,12 @@ function pnut_post_hook(array &$b)
return;
}
Logger::notice('PNUT post invoked', ['id' => $b['id'], 'guid' => $b['guid'], 'plink' => $b['plink']]);
Logger::debug('PNUT array', $b);
if (Item::isGroupPost($b['uri-id'])) {
return;
}
DI::logger()->notice('PNUT post invoked', ['id' => $b['id'], 'guid' => $b['guid'], 'plink' => $b['plink']]);
DI::logger()->debug('PNUT array', $b);
$token = DI::pConfig()->get($b['uid'], 'pnut', 'access_token');
$nut = new phpnut\phpnut($token);
@ -276,7 +279,7 @@ function pnut_post_hook(array &$b)
$text = $msgarr['text'];
$raw = [];
Logger::debug('PNUT msgarr', $msgarr);
DI::logger()->debug('PNUT msgarr', $msgarr);
if (count($msgarr['parts']) > 1) {
$tstamp = time();
@ -292,23 +295,23 @@ function pnut_post_hook(array &$b)
if ($msgarr['type'] == 'photo') {
$fileraw = ['type' => 'dev.mcmillian.friendica.image', 'kind' => 'image', 'is_public' => true];
foreach ($msgarr['images'] as $image) {
Logger::debug('PNUT image', $image);
DI::logger()->debug('PNUT image', $image);
if (!empty($image['id'])) {
$photo = Photo::selectFirst([], ['id' => $image['id']]);
Logger::debug('PNUT selectFirst');
DI::logger()->debug('PNUT selectFirst');
} else {
$photo = Photo::createPhotoForExternalResource($image['url']);
Logger::debug('PNUT createPhotoForExternalResource');
DI::logger()->debug('PNUT createPhotoForExternalResource');
}
$picturedata = Photo::getImageForPhoto($photo);
Logger::debug('PNUT photo', $photo);
DI::logger()->debug('PNUT photo', $photo);
$picurefile = tempnam(System::getTempPath(), 'pnut');
file_put_contents($picurefile, $picturedata);
Logger::debug('PNUT got file?', ['filename' => $picurefile]);
DI::logger()->debug('PNUT got file?', ['filename' => $picurefile]);
$imagefile = $nut->createFile($picurefile, $fileraw);
Logger::debug('PNUT file', ['pnutimagefile' => $imagefile]);
DI::logger()->debug('PNUT file', ['pnutimagefile' => $imagefile]);
unlink($picurefile);
$raw['io.pnut.core.oembed'][] = ['+io.pnut.core.file' => ['file_id' => $imagefile['id'], 'file_token' => $imagefile['file_token'], 'format' => 'oembed']];
@ -318,5 +321,5 @@ function pnut_post_hook(array &$b)
$raw['io.pnut.core.crosspost'][] = ['canonical_url' => $b['plink']];
$nut->createPost($text, ['raw' => $raw]);
Logger::debug('PNUT post complete', ['id' => $b['id'], 'text' => $text, 'raw' => $raw]);
DI::logger()->debug('PNUT post complete', ['id' => $b['id'], 'text' => $text, 'raw' => $raw]);
}

View file

@ -6,10 +6,8 @@
* Author: Keith Fernie <http://friendika.me4.it/profile/keith>
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
@ -29,7 +27,7 @@ function public_server_install()
function public_server_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('public_server'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('public_server'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function public_server_register_account($b)
@ -48,7 +46,7 @@ function public_server_register_account($b)
function public_server_cron($b)
{
Logger::notice("public_server: cron start");
DI::logger()->notice("public_server: cron start");
$users = DBA::selectToArray('user', [], ["`account_expires_on` > ? AND `account_expires_on` < ?
AND `expire_notification_sent` <= ?", DBA::NULL_DATETIME, DateTimeFormat::utc('now + 5 days'), DBA::NULL_DATETIME]);
@ -97,7 +95,7 @@ function public_server_cron($b)
}
}
Logger::notice("public_server: cron end");
DI::logger()->notice("public_server: cron end");
}
function public_server_enotify(array &$b)

View file

@ -109,9 +109,11 @@ class http_class
var $connected_port = -1;
var $connected_ssl = 0;
private $content_length_set;
/* Private methods - DO NOT CALL */
Function Tokenize($string,$separator="")
private function Tokenize($string,$separator="")
{
if(!strcmp($separator,""))
{
@ -135,18 +137,18 @@ class http_class
}
}
Function CookieEncode($value, $name)
private function CookieEncode($value, $name)
{
return($name ? str_replace("=", "%25", $value) : str_replace(";", "%3B", $value));
}
Function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
private function SetError($error, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
{
$this->error_code = $error_code;
return($this->error=$error);
}
Function SetPHPError($error, &$php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
private function SetPHPError($error, &$php_error_message, $error_code = HTTP_CLIENT_ERROR_UNSPECIFIED_ERROR)
{
if(IsSet($php_error_message)
&& strlen($php_error_message))
@ -154,7 +156,7 @@ class http_class
return($this->SetError($error, $error_code));
}
Function SetDataAccessError($error,$check_connection=0)
private function SetDataAccessError($error,$check_connection=0)
{
$this->error=$error;
$this->error_code = HTTP_CLIENT_ERROR_COMMUNICATION_FAILURE;
@ -174,7 +176,7 @@ class http_class
}
}
Function OutputDebug($message)
private function OutputDebug($message)
{
if($this->log_debug)
error_log($message);
@ -188,7 +190,7 @@ class http_class
}
}
Function GetLine()
private function GetLine()
{
for($line="";;)
{
@ -227,7 +229,7 @@ class http_class
}
}
Function PutLine($line)
private function PutLine($line)
{
if($this->debug)
$this->OutputDebug("C $line");
@ -239,7 +241,7 @@ class http_class
return(1);
}
Function PutData($data)
private function PutData($data)
{
if(strlen($data))
{
@ -254,7 +256,7 @@ class http_class
return(1);
}
Function FlushData()
private function FlushData()
{
if(!fflush($this->connection))
{
@ -264,7 +266,7 @@ class http_class
return(1);
}
Function ReadChunkSize()
private function ReadChunkSize()
{
if($this->remaining_chunk==0)
{
@ -289,7 +291,7 @@ class http_class
return("");
}
Function ReadBytes($length)
private function ReadBytes($length)
{
if($this->use_curl)
{
@ -356,7 +358,7 @@ class http_class
return($bytes);
}
Function EndOfInput()
private function EndOfInput()
{
if($this->use_curl)
return($this->read_response>=strlen($this->response));
@ -367,7 +369,7 @@ class http_class
return(feof($this->connection));
}
Function Resolve($domain, &$ip, $server_type)
private function Resolve($domain, &$ip, $server_type)
{
if(preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/',$domain))
$ip=$domain;
@ -385,7 +387,7 @@ class http_class
return('');
}
Function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
private function Connect($host_name, $host_port, $ssl, $server_type = 'HTTP')
{
$domain=$host_name;
$port = $host_port;
@ -552,7 +554,7 @@ class http_class
}
}
Function Disconnect()
private function Disconnect()
{
if($this->debug)
$this->OutputDebug("Disconnected from ".$this->connected_host);
@ -569,7 +571,7 @@ class http_class
/* Public methods */
Function GetRequestArguments($url, &$arguments)
public function GetRequestArguments($url, &$arguments)
{
$this->error = '';
$this->error_code = HTTP_CLIENT_ERROR_NO_ERROR;
@ -621,7 +623,7 @@ class http_class
return("");
}
Function Open($arguments)
public function Open($arguments)
{
if(strlen($this->error))
return($this->error);
@ -750,7 +752,7 @@ class http_class
return("");
}
Function Close($force = 0)
public function Close($force = 0)
{
if($this->state=="Disconnected")
return("1 already disconnected");
@ -767,7 +769,7 @@ class http_class
return($this->Disconnect());
}
Function PickCookies(&$cookies,$secure)
private function PickCookies(&$cookies,$secure)
{
if(IsSet($this->cookies[$secure]))
{
@ -803,7 +805,7 @@ class http_class
}
}
Function GetFileDefinition($file, &$definition)
private function GetFileDefinition($file, &$definition)
{
$name="";
if(IsSet($file["FileName"]))
@ -990,9 +992,6 @@ class http_class
if(GetType($length=@filesize($file["FileName"]))!="integer")
{
$error="it was not possible to determine the length of the file ".$file["FileName"];
if(IsSet($php_errormsg)
&& strlen($php_errormsg))
$error.=": ".$php_errormsg;
if(!file_exists($file["FileName"]))
$error="it was not possible to access the file ".$file["FileName"];
return($error);
@ -1007,7 +1006,7 @@ class http_class
return("");
}
Function ConnectFromProxy($arguments, &$headers)
private function ConnectFromProxy($arguments, &$headers)
{
if(!$this->PutLine('CONNECT '.$this->host_name.':'.($this->host_port ? $this->host_port : 443).' HTTP/1.0')
|| (strlen($this->user_agent)
@ -1052,7 +1051,7 @@ class http_class
return("");
}
Function SendRequest($arguments)
public function SendRequest($arguments)
{
if(strlen($this->error))
return($this->error);
@ -1440,7 +1439,7 @@ class http_class
return("");
}
Function SetCookie($name, $value, $expires="" , $path="/" , $domain="" , $secure=0, $verbatim=0)
private function SetCookie($name, $value, $expires="" , $path="/" , $domain="" , $secure=0, $verbatim=0)
{
if(strlen($this->error))
return($this->error);
@ -1472,7 +1471,7 @@ class http_class
return("");
}
Function SendRequestBody($data, $end_of_data)
private function SendRequestBody($data, $end_of_data)
{
if(strlen($this->error))
return($this->error);
@ -1508,7 +1507,7 @@ class http_class
return("");
}
Function ReadReplyHeadersResponse(&$headers)
private function ReadReplyHeadersResponse(&$headers)
{
$headers=array();
if(strlen($this->error))
@ -1635,7 +1634,7 @@ class http_class
return("");
}
Function Redirect(&$headers)
private function Redirect(&$headers)
{
if($this->follow_redirect)
{
@ -1678,7 +1677,7 @@ class http_class
return("");
}
Function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation)
private function Authenticate(&$headers, $proxy, &$proxy_authorization, &$user, &$password, &$realm, &$workstation)
{
if($proxy)
{
@ -1697,9 +1696,10 @@ class http_class
if(IsSet($headers[$authenticate_header])
&& $this->sasl_authenticate)
{
if(function_exists("class_exists")
&& !class_exists("sasl_client_class"))
if(!class_exists('sasl_client_class'))
{
return($this->SetError("the SASL client class needs to be loaded to be able to authenticate".($proxy ? " with the proxy server" : "")." and access this site", HTTP_CLIENT_ERROR_INVALID_PARAMETERS));
}
if(GetType($headers[$authenticate_header])=="array")
$authenticate=$headers[$authenticate_header];
else
@ -1719,7 +1719,7 @@ class http_class
else
$mechanisms[]=$mechanism;
}
$sasl=new sasl_client_class;
$sasl=new \sasl_client_class();
if(IsSet($user))
$sasl->SetCredential("user",$user);
if(IsSet($password))
@ -1731,6 +1731,8 @@ class http_class
$sasl->SetCredential("uri",$this->request_uri);
$sasl->SetCredential("method",$this->request_method);
$sasl->SetCredential("session",$this->session);
$message = '';
$interactions = [];
do
{
$status=$sasl->Start($mechanisms,$message,$interactions);
@ -1906,8 +1908,8 @@ class http_class
}
return("");
}
Function ReadReplyHeaders(&$headers)
public function ReadReplyHeaders(&$headers)
{
if(strlen($error=$this->ReadReplyHeadersResponse($headers)))
return($error);
@ -1938,7 +1940,7 @@ class http_class
return("");
}
Function ReadReplyBody(&$body,$length)
private function ReadReplyBody(&$body,$length)
{
$body="";
if(strlen($this->error))
@ -1980,7 +1982,7 @@ class http_class
return("");
}
Function ReadWholeReplyBody(&$body)
public function ReadWholeReplyBody(&$body)
{
$body = '';
for(;;)
@ -1993,7 +1995,7 @@ class http_class
}
}
Function SaveCookies(&$cookies, $domain='', $secure_only=0, $persistent_only=0)
private function SaveCookies(&$cookies, $domain='', $secure_only=0, $persistent_only=0)
{
$now=gmdate("Y-m-d H-i-s");
$cookies=array();
@ -2034,17 +2036,17 @@ class http_class
}
}
Function SavePersistentCookies(&$cookies, $domain='', $secure_only=0)
private function SavePersistentCookies(&$cookies, $domain='', $secure_only=0)
{
$this->SaveCookies($cookies, $domain, $secure_only, 1);
}
Function GetPersistentCookies(&$cookies, $domain='', $secure_only=0)
private function GetPersistentCookies(&$cookies, $domain='', $secure_only=0)
{
$this->SavePersistentCookies($cookies, $domain, $secure_only);
}
Function RestoreCookies($cookies, $clear=1)
private function RestoreCookies($cookies, $clear=1)
{
$new_cookies=($clear ? array() : $this->cookies);
for($secure_cookies=0, Reset($cookies); $secure_cookies<count($cookies); Next($cookies), $secure_cookies++)

View file

@ -6,12 +6,9 @@
* Author: Michael Vogel <http://pirati.ca/profile/heluecht>
*/
use Friendica\App;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Core\Addon;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\Worker;
@ -108,7 +105,7 @@ function pumpio_registerclient($host)
$params['logo_url'] = DI::baseUrl() . '/images/friendica-256.png';
$params['redirect_uris'] = DI::baseUrl() . '/pumpio/connect';
Logger::info('pumpio_registerclient: ' . $url . ' parameters', $params);
DI::logger()->info('pumpio_registerclient: ' . $url . ' parameters', $params);
// @TODO Rewrite this to our own HTTP client
$ch = curl_init($url);
@ -123,10 +120,10 @@ function pumpio_registerclient($host)
if ($curl_info['http_code'] == '200') {
$values = json_decode($s);
Logger::info('pumpio_registerclient: success ', (array)$values);
DI::logger()->info('pumpio_registerclient: success ', (array)$values);
return $values;
}
Logger::info('pumpio_registerclient: failed: ', $curl_info);
DI::logger()->info('pumpio_registerclient: failed: ', $curl_info);
return false;
}
@ -139,7 +136,7 @@ function pumpio_connect()
$hostname = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'pumpio', 'host');
if ((($consumer_key == '') || ($consumer_secret == '')) && ($hostname != '')) {
Logger::notice('pumpio_connect: register client');
DI::logger()->notice('pumpio_connect: register client');
$clientdata = pumpio_registerclient($hostname);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'pumpio', 'consumer_key', $clientdata->client_id);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'pumpio', 'consumer_secret', $clientdata->client_secret);
@ -147,11 +144,11 @@ function pumpio_connect()
$consumer_key = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'pumpio', 'consumer_key');
$consumer_secret = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'pumpio', 'consumer_secret');
Logger::info('pumpio_connect: ckey: ' . $consumer_key . ' csecrect: ' . $consumer_secret);
DI::logger()->info('pumpio_connect: ckey: ' . $consumer_key . ' csecrect: ' . $consumer_secret);
}
if (($consumer_key == '') || ($consumer_secret == '')) {
Logger::notice('pumpio_connect: '.sprintf('Unable to register the client at the pump.io server "%s".', $hostname));
DI::logger()->notice('pumpio_connect: '.sprintf('Unable to register the client at the pump.io server "%s".', $hostname));
return DI::l10n()->t("Unable to register the client at the pump.io server '%s'.", $hostname);
}
@ -180,7 +177,7 @@ function pumpio_connect()
if (($success = $client->Initialize())) {
if (($success = $client->Process())) {
if (strlen($client->access_token)) {
Logger::info('pumpio_connect: otoken: ' . $client->access_token . ', osecrect: ' . $client->access_token_secret);
DI::logger()->info('pumpio_connect: otoken: ' . $client->access_token . ', osecrect: ' . $client->access_token_secret);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'pumpio', 'oauth_token', $client->access_token);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'pumpio', 'oauth_token_secret', $client->access_token_secret);
}
@ -192,11 +189,11 @@ function pumpio_connect()
}
if ($success) {
Logger::notice('pumpio_connect: authenticated');
DI::logger()->notice('pumpio_connect: authenticated');
$o = DI::l10n()->t('You are now authenticated to pumpio.');
$o .= '<br /><a href="' . DI::baseUrl() . '/settings/connectors">' . DI::l10n()->t('return to the connector page') . '</a>';
} else {
Logger::notice('pumpio_connect: could not connect');
DI::logger()->notice('pumpio_connect: could not connect');
$o = 'Could not connect to pumpio. Refresh the page or try again later.';
}
@ -320,7 +317,7 @@ function pumpio_settings_post(array &$b)
function pumpio_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('pumpio'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('pumpio'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function pumpio_hook_fork(array &$b)
@ -346,7 +343,7 @@ function pumpio_hook_fork(array &$b)
if (DI::pConfig()->get($post['uid'], 'pumpio', 'import')) {
// Don't fork if it isn't a reply to a pump.io post
if (($post['gravity'] != Item::GRAVITY_PARENT) && !Post::exists(['id' => $post['parent'], 'network' => Protocol::PUMPIO])) {
Logger::notice('No pump.io parent found for item ' . $post['id']);
DI::logger()->notice('No pump.io parent found for item ' . $post['id']);
$b['execute'] = false;
return;
}
@ -390,7 +387,11 @@ function pumpio_send(array &$b)
return;
}
Logger::debug('pumpio_send: parameter ', $b);
if (Item::isGroupPost($b['uri-id'])) {
return;
}
DI::logger()->debug('pumpio_send: parameter ', $b);
$b['body'] = Post\Media::addAttachmentsToBody($b['uri-id'], DI::contentItem()->addSharedPost($b));
@ -400,7 +401,7 @@ function pumpio_send(array &$b)
$orig_post = Post::selectFirst([], $condition);
if (!DBA::isResult($orig_post)) {
Logger::notice('pumpio_send: no pumpio post ' . $b['parent']);
DI::logger()->notice('pumpio_send: no pumpio post ' . $b['parent']);
return;
} else {
$iscomment = true;
@ -410,7 +411,7 @@ function pumpio_send(array &$b)
$receiver = pumpio_getreceiver($b);
Logger::notice('pumpio_send: receiver ', $receiver);
DI::logger()->notice('pumpio_send: receiver ', $receiver);
if (!count($receiver) && ($b['private'] == Item::PRIVATE) || !strstr($b['postopts'], 'pumpio')) {
return;
@ -544,13 +545,13 @@ function pumpio_send(array &$b)
}
$post_id = $user->object->id;
Logger::notice('pumpio_send ' . $username . ': success ' . $post_id);
DI::logger()->notice('pumpio_send ' . $username . ': success ' . $post_id);
if ($post_id && $iscomment) {
Logger::notice('pumpio_send ' . $username . ': Update extid ' . $post_id . ' for post id ' . $b['id']);
DI::logger()->notice('pumpio_send ' . $username . ': Update extid ' . $post_id . ' for post id ' . $b['id']);
Item::update(['extid' => $post_id], ['id' => $b['id']]);
}
} else {
Logger::notice('pumpio_send '.$username.': '.$url.' general error: ' . print_r($user, true));
DI::logger()->notice('pumpio_send '.$username.': '.$url.' general error: ' . print_r($user, true));
Worker::defer();
}
}
@ -582,6 +583,8 @@ function pumpio_action(int $uid, string $uri, string $action, string $content =
$uri = $orig_post['uri'];
}
$objectType = '';
if (($orig_post['object-type'] != '') && (strstr($orig_post['object-type'], ActivityNamespace::ACTIVITY_SCHEMA))) {
$objectType = str_replace(ActivityNamespace::ACTIVITY_SCHEMA, '', $orig_post['object-type']);
} elseif (strstr($uri, '/api/comment/')) {
@ -618,16 +621,18 @@ function pumpio_action(int $uid, string $uri, string $action, string $content =
}
if ($success) {
Logger::notice('pumpio_action '.$username.' '.$action.': success '.$uri);
DI::logger()->notice('pumpio_action '.$username.' '.$action.': success '.$uri);
} else {
Logger::notice('pumpio_action '.$username.' '.$action.': general error: '.$uri);
DI::logger()->notice('pumpio_action '.$username.' '.$action.': general error: '.$uri);
Worker::defer();
}
}
function pumpio_sync()
{
if (!Addon::isEnabled('pumpio')) {
$addonHelper = DI::addonHelper();
if (!$addonHelper->isAddonEnabled('pumpio')) {
return;
}
@ -638,15 +643,15 @@ function pumpio_sync()
if ($last) {
$next = $last + ($poll_interval * 60);
if ($next > time()) {
Logger::notice('pumpio: poll intervall not reached');
DI::logger()->notice('pumpio: poll intervall not reached');
return;
}
}
Logger::notice('pumpio: cron_start');
DI::logger()->notice('pumpio: cron_start');
$pconfigs = DBA::selectToArray('pconfig', ['uid'], ['cat' => 'pumpio', 'k' => 'mirror', 'v' => '1']);
foreach ($pconfigs as $rr) {
Logger::notice('pumpio: mirroring user '.$rr['uid']);
DI::logger()->notice('pumpio: mirroring user '.$rr['uid']);
pumpio_fetchtimeline($rr['uid']);
}
@ -661,12 +666,12 @@ function pumpio_sync()
foreach ($pconfigs as $rr) {
if ($abandon_days != 0) {
if (DBA::exists('user', ["uid = ? AND `login_date` >= ?", $rr['uid'], $abandon_limit])) {
Logger::notice('abandoned account: timeline from user '.$rr['uid'].' will not be imported');
DI::logger()->notice('abandoned account: timeline from user '.$rr['uid'].' will not be imported');
continue;
}
}
Logger::notice('pumpio: importing timeline from user '.$rr['uid']);
DI::logger()->notice('pumpio: importing timeline from user '.$rr['uid']);
pumpio_fetchinbox($rr['uid']);
// check for new contacts once a day
@ -683,7 +688,7 @@ function pumpio_sync()
}
}
Logger::notice('pumpio: cron_end');
DI::logger()->notice('pumpio: cron_end');
DI::keyValue()->set('pumpio_last_poll', time());
}
@ -728,7 +733,7 @@ function pumpio_fetchtimeline(int $uid)
$url = 'https://'.$hostname.'/api/user/'.$username.'/feed/major';
Logger::notice('pumpio: fetching for user ' . $uid . ' ' . $url . ' C:' . $client->client_id . ' CS:' . $client->client_secret . ' T:' . $client->access_token . ' TS:' . $client->access_token_secret);
DI::logger()->notice('pumpio: fetching for user ' . $uid . ' ' . $url . ' C:' . $client->client_id . ' CS:' . $client->client_secret . ' T:' . $client->access_token . ' TS:' . $client->access_token_secret);
$useraddr = $username.'@'.$hostname;
@ -740,7 +745,7 @@ function pumpio_fetchtimeline(int $uid)
}
if (!$success) {
Logger::notice('pumpio: error fetching posts for user ' . $uid . ' ' . $useraddr . ' ', $user);
DI::logger()->notice('pumpio: error fetching posts for user ' . $uid . ' ' . $useraddr . ' ', $user);
return;
}
@ -800,11 +805,11 @@ function pumpio_fetchtimeline(int $uid)
}
}
Logger::notice('pumpio: posting for user ' . $uid);
DI::logger()->notice('pumpio: posting for user ' . $uid);
Item::insert($postarray, true);
Logger::notice('pumpio: posting done - user ' . $uid);
DI::logger()->notice('pumpio: posting done - user ' . $uid);
}
}
}
@ -827,6 +832,7 @@ function pumpio_dounlike(int $uid, array $self, $post, string $own_id)
}
$contactid = 0;
$contact = [];
if (Strings::compareLink($post->actor->url, $own_id)) {
$contactid = $self['id'];
@ -844,16 +850,16 @@ function pumpio_dounlike(int $uid, array $self, $post, string $own_id)
Item::markForDeletion(['verb' => Activity::LIKE, 'uid' => $uid, 'contact-id' => $contactid, 'thr-parent' => $orig_post['uri']]);
if (DBA::isResult($contact)) {
Logger::notice('pumpio_dounlike: unliked existing like. User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' URI ' . $orig_post['uri']);
DI::logger()->notice('pumpio_dounlike: unliked existing like. User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' URI ' . $orig_post['uri']);
} else {
Logger::notice('pumpio_dounlike: not found. User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' Url ' . $orig_post['uri']);
DI::logger()->notice('pumpio_dounlike: not found. User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' Url ' . $orig_post['uri']);
}
}
function pumpio_dolike(int $uid, array $self, $post, string $own_id, $threadcompletion = true)
{
if (empty($post->object->id)) {
Logger::info('Got empty like: '.print_r($post, true));
DI::logger()->info('Got empty like: '.print_r($post, true));
return;
}
@ -898,7 +904,7 @@ function pumpio_dolike(int $uid, array $self, $post, string $own_id, $threadcomp
];
if (Post::exists($condition)) {
Logger::notice('pumpio_dolike: found existing like. User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' URI ' . $orig_post['uri']);
DI::logger()->notice('pumpio_dolike: found existing like. User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' URI ' . $orig_post['uri']);
return;
}
@ -932,7 +938,7 @@ function pumpio_dolike(int $uid, array $self, $post, string $own_id, $threadcomp
$ret = Item::insert($likedata);
Logger::notice('pumpio_dolike: ' . $ret . ' User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' URI ' . $orig_post['uri']);
DI::logger()->notice('pumpio_dolike: ' . $ret . ' User ' . $own_id . ' ' . $uid . ' Contact: ' . $contactid . ' URI ' . $orig_post['uri']);
}
function pumpio_get_contact($uid, $contact, $no_insert = false)
@ -1403,7 +1409,7 @@ function pumpio_fetchallcomments($uid, $id)
$hostname = DI::pConfig()->get($uid, 'pumpio', 'host');
$username = DI::pConfig()->get($uid, 'pumpio', 'user');
Logger::notice('pumpio_fetchallcomments: completing comment for user ' . $uid . ' post id ' . $id);
DI::logger()->notice('pumpio_fetchallcomments: completing comment for user ' . $uid . ' post id ' . $id);
$own_id = 'https://' . $hostname . '/' . $username;
@ -1428,7 +1434,9 @@ function pumpio_fetchallcomments($uid, $id)
$client->access_token = $otoken;
$client->access_token_secret = $osecret;
Logger::notice('pumpio_fetchallcomments: fetching comment for user ' . $uid . ', URL ' . $url);
DI::logger()->notice('pumpio_fetchallcomments: fetching comment for user ' . $uid . ', URL ' . $url);
$item = new \stdClass();
if (pumpio_reachable($url)) {
$success = $client->CallAPI($url, 'GET', [], ['FailOnAccessError' => true], $item);
@ -1491,7 +1499,7 @@ function pumpio_fetchallcomments($uid, $id)
$post->object = $item;
Logger::notice('pumpio_fetchallcomments: posting comment ' . $post->object->id . ' ', json_decode(json_encode($post), true));
DI::logger()->notice('pumpio_fetchallcomments: posting comment ' . $post->object->id . ' ', json_decode(json_encode($post), true));
pumpio_dopost($client, $uid, $self, $post, $own_id, false);
}
}

View file

@ -1,5 +1,5 @@
<?php
use Friendica\Core\Logger;
use Friendica\DI;
function pumpio_sync_run(array $argv, int $argc) {
@ -8,7 +8,7 @@ function pumpio_sync_run(array $argv, int $argc) {
if (function_exists('sys_getloadavg')) {
$load = sys_getloadavg();
if (intval($load[0]) > DI::config()->get('system', 'maxloadavg', 50)) {
Logger::notice('system: load ' . $load[0] . ' too high. Pumpio sync deferred to next scheduled run.');
DI::logger()->notice('system: load ' . $load[0] . ' too high. Pumpio sync deferred to next scheduled run.');
return;
}
}

View file

@ -18,7 +18,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -19,9 +19,7 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -41,7 +39,7 @@ function randplace_install()
Hook::register('addon_settings', 'addon/randplace/randplace.php', 'randplace_settings');
Hook::register('addon_settings_post', 'addon/randplace/randplace.php', 'randplace_settings_post');
Logger::notice("installed randplace");
DI::logger()->notice("installed randplace");
}
function randplace_uninstall()
@ -51,7 +49,7 @@ function randplace_uninstall()
*
* Except hooks, they are all unregistered automatically and don't need to be unregistered manually.
*/
Logger::notice("removed randplace");
DI::logger()->notice("removed randplace");
}
function randplace_post_hook(&$item)
@ -62,7 +60,7 @@ function randplace_post_hook(&$item)
* - A status post by a profile owner
* - The profile owner must have allowed our addon
*/
Logger::notice('randplace invoked');
DI::logger()->notice('randplace invoked');
if (!DI::userSession()->getLocalUserId()) {
/* non-zero if this is a logged in user of this system */

View file

@ -3,12 +3,13 @@
namespace Friendica\Addon\ratioed;
use Friendica\Content\Pager;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\User;
use Friendica\Model\Verb;
use Friendica\Module\Moderation\Users\Active;
use Friendica\Protocol\Activity;
/**
* This class implements the "Behaviour" panel in Moderation/Users
@ -24,38 +25,17 @@ class RatioedPanel extends Active
return Renderer::replaceMacros($template, array('$config' => DI::baseUrl() . '/settings/addon'));
}
$action = $this->parameters['action'] ?? '';
$uid = $this->parameters['uid'] ?? 0;
$user = [];
if ($uid) {
$user = User::getById($uid, ['username', 'blocked']);
if (!$user) {
$this->systemMessages->addNotice($this->t('User not found'));
$this->baseUrl->redirect('moderation/users');
$this->baseUrl->redirect('ratioed');
}
}
switch ($action) {
case 'delete':
if ($this->session->getLocalUserId() != $uid) {
self::checkFormSecurityTokenRedirectOnError('moderation/users/active', 'moderation_users_active', 't');
// delete user
User::remove($uid);
$this->systemMessages->addNotice($this->t('User "%s" deleted', $user['username']));
} else {
$this->systemMessages->addNotice($this->t('You can\'t remove yourself'));
}
$this->baseUrl->redirect('moderation/users/active');
break;
case 'block':
self::checkFormSecurityTokenRedirectOnError('moderation/users/active', 'moderation_users_active', 't');
User::block($uid);
$this->systemMessages->addNotice($this->t('User "%s" blocked', $user['username']));
$this->baseUrl->redirect('moderation/users/active');
break;
}
$pager = new Pager($this->l10n, $this->args->getQueryString(), 100);
$valid_orders = [
@ -69,10 +49,10 @@ class RatioedPanel extends Active
$order = 'last-item';
$order_direction = '-';
if (!empty($request['o'])) {
$new_order = $request['o'];
if ($new_order[0] === '-') {
$order_direction = '-';
if (!empty($_REQUEST['o'])) {
$new_order = $_REQUEST['o'];
if ($new_order[0] !== '-') {
$order_direction = '+';
$new_order = substr($new_order, 1);
}
@ -96,6 +76,11 @@ class RatioedPanel extends Active
$this->t('Comments last 24h'),
$this->t('Reactions last 24h'),
$this->t('Ratio last 24h'),
$this->t('Replies last month'),
$this->t('Reply likes'),
$this->t('Respondee likes'),
$this->t('OP likes'),
$this->t('Reply guy score'),
];
$field_names = [
'name',
@ -108,6 +93,11 @@ class RatioedPanel extends Active
'comments',
'reactions',
'ratio',
'reply_count',
'reply_likes',
'reply_respondee_likes',
'reply_op_likes',
'reply_guy_score',
];
$th_users = array_map(null, $header_titles, $valid_orders, $field_names);
@ -146,9 +136,130 @@ class RatioedPanel extends Active
]);
}
protected function getReplyGuyRow($contact_uid)
{
$like_vid = Verb::getID(Activity::LIKE);
$post_vid = Verb::getID(Activity::POST);
/*
* This is a complicated query.
*
* The innermost select retrieves a chain of four posts: an
* original post, a target comment (possibly deep down in the
* thread), a reply from our user, and a like for that reply.
* If there's no like, we still want to count the reply, so we
* use an outer join.
*
* The second select adds "points" for different kinds of
* likes. The outermost select then counts up these points,
* and the number of distinct replies.
*/
$reply_guy_result = DBA::p('
SELECT
COUNT(distinct reply_id) AS replies_total,
SUM(like_point) AS like_total,
SUM(target_like_point) AS target_like_total,
SUM(original_like_point) AS original_like_total
FROM (
SELECT
reply_id,
like_date,
like_date IS NOT NULL AS like_point,
like_author = target_author AS target_like_point,
like_author = original_author AS original_like_point
FROM (
SELECT
original_post.`uri-id` AS original_id,
original_post.`author-id` AS original_author,
original_post.created AS original_date,
target_post.`uri-id` AS target_id,
target_post.`author-id` AS target_author,
target_post.created AS target_date,
reply_post.`uri-id` AS reply_id,
reply_post.`author-id` AS reply_author,
reply_post.created AS reply_date,
like_post.`uri-id` AS like_id,
like_post.`author-id` AS like_author,
like_post.created AS like_date
FROM
post AS original_post
JOIN
post AS target_post
ON
original_post.`uri-id` = target_post.`parent-uri-id`
JOIN
post AS reply_post
ON
target_post.`uri-id` = reply_post.`thr-parent-id` AND
reply_post.`author-id` = ? AND
reply_post.`author-id` != target_post.`author-id` AND
reply_post.`author-id` != original_post.`author-id` AND
reply_post.`uri-id` != reply_post.`thr-parent-id` AND
reply_post.vid = ? AND
reply_post.created > CURDATE() - INTERVAL 1 MONTH
LEFT OUTER JOIN
post AS like_post
ON
reply_post.`uri-id` = like_post.`thr-parent-id` AND
like_post.vid = ? AND
like_post.`author-id` != reply_post.`author-id`
) AS post_meta
) AS reply_counts
', $contact_uid, $post_vid, $like_vid);
return $reply_guy_result;
}
// https://stackoverflow.com/a/48283297/235936
protected function sigFig($value, $digits)
{
if ($value == 0) {
$decimalPlaces = $digits - 1;
} elseif ($value < 0) {
$decimalPlaces = $digits - floor(log10($value * -1)) - 1;
} else {
$decimalPlaces = $digits - floor(log10($value)) - 1;
}
$answer = ($decimalPlaces > 0) ?
number_format($value, $decimalPlaces) : round($value, $decimalPlaces);
return $answer;
}
protected function fillReplyGuyData(&$user)
{
$reply_guy_result = $this->getReplyGuyRow($user['user_contact_uid']);
if (DBA::isResult($reply_guy_result)) {
$reply_guy_result_row = DBA::fetch($reply_guy_result);
$user['reply_count'] = (int) $reply_guy_result_row['replies_total'] ?? 0;
$user['reply_likes'] = (int) $reply_guy_result_row['like_total'] ?? 0;
$user['reply_respondee_likes'] = (int) $reply_guy_result_row['target_like_total'] ?? 0;
$user['reply_op_likes'] = (int) $reply_guy_result_row['original_like_total'] ?? 0;
$denominator = $user['reply_likes'] + $user['reply_respondee_likes'] + $user['reply_op_likes'];
if ($user['reply_count'] === 0) {
$user['reply_guy'] = false;
$user['reply_guy_score'] = 0;
} elseif ($denominator == 0) {
$user['reply_guy'] = true;
$user['reply_guy_score'] = '∞';
} else {
$reply_guy_score = $user['reply_count'] / $denominator;
$user['reply_guy'] = $reply_guy_score >= 1.0;
$user['reply_guy_score'] = $this->sigFig($reply_guy_score, 2);
}
} else {
$user['reply_count'] = "error";
$user['reply_likes'] = "error";
$user['reply_respondee_likes'] = "error";
$user['reply_op_likes'] = "error";
$user['reply_guy'] = false;
$user['reply_guy_score'] = 0;
}
}
protected function setupUserCallback(): \Closure
{
Logger::debug("ratioed: setupUserCallback");
DI::logger()->debug("ratioed: setupUserCallback");
$parentCallback = parent::setupUserCallback();
return function ($user) use ($parentCallback) {
$blocked_count = DBA::count('user-contact', ['uid' => $user['uid'], 'is-blocked' => 1]);
@ -158,9 +269,8 @@ class RatioedPanel extends Active
if (DBA::isResult($self_contact_result)) {
$self_contact_result_row = DBA::fetch($self_contact_result);
$user['user_contact_uid'] = $self_contact_result_row['user_contact_uid'];
}
else {
$user['user_contact_uid'] = NULL;
} else {
$user['user_contact_uid'] = null;
}
if ($user['user_contact_uid']) {
@ -172,34 +282,34 @@ class RatioedPanel extends Active
if ($user['reactions'] > 0) {
$user['ratio'] = number_format($user['comments'] / $user['reactions'], 1, '.', '');
$user['ratioed'] = (float)($user['ratio']) >= 2.0;
}
else {
} else {
$user['reactions'] = 0;
if ($user['comments'] == 0) {
$user['ratio'] = '0';
$user['comments'] = 0;
$user['ratio'] = 0;
$user['ratioed'] = false;
}
else {
} else {
$user['ratio'] = '∞';
$user['ratioed'] = false;
}
}
}
else {
} else {
$user['comments'] = 'error';
$user['reactions'] = 'error';
$user['ratio'] = 'error';
$user['ratioed'] = false;
}
}
else {
} else {
$user['comments'] = 'error';
$user['reactions'] = 'error';
$user['ratio'] = 'error';
$user['ratioed'] = false;
}
$this->fillReplyGuyData($user);
$user = $parentCallback($user);
Logger::debug("ratioed: setupUserCallback", [
DI::logger()->debug("ratioed: setupUserCallback", [
'uid' => $user['uid'],
'blocked_by' => $user['blocked_by'],
'comments' => $user['comments'],

130
ratioed/lang/C/messages.po Normal file
View file

@ -0,0 +1,130 @@
# ADDON ratioed
# Copyright (C)
# This file is distributed under the same license as the Friendica ratioed addon package.
#
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-08 13:50+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: RatioedPanel.php:34
msgid "User not found"
msgstr ""
#: RatioedPanel.php:69
msgid "Name"
msgstr ""
#: RatioedPanel.php:70
msgid "Email"
msgstr ""
#: RatioedPanel.php:71
msgid "Register date"
msgstr ""
#: RatioedPanel.php:72
msgid "Last login"
msgstr ""
#: RatioedPanel.php:73
msgid "Last public item"
msgstr ""
#: RatioedPanel.php:74
msgid "Type"
msgstr ""
#: RatioedPanel.php:75
msgid "Blocked by"
msgstr ""
#: RatioedPanel.php:76
msgid "Comments last 24h"
msgstr ""
#: RatioedPanel.php:77
msgid "Reactions last 24h"
msgstr ""
#: RatioedPanel.php:78
msgid "Ratio last 24h"
msgstr ""
#: RatioedPanel.php:79
msgid "Replies last month"
msgstr ""
#: RatioedPanel.php:80
msgid "Reply likes"
msgstr ""
#: RatioedPanel.php:81
msgid "Respondee likes"
msgstr ""
#: RatioedPanel.php:82
msgid "OP likes"
msgstr ""
#: RatioedPanel.php:83
msgid "Reply guy score"
msgstr ""
#: RatioedPanel.php:109
msgid "Moderation"
msgstr ""
#: RatioedPanel.php:111 ratioed.php:39
msgid "Behaviour"
msgstr ""
#: RatioedPanel.php:112
msgid "select all"
msgstr ""
#: RatioedPanel.php:113
msgid "Delete"
msgstr ""
#: RatioedPanel.php:114
msgid "Block"
msgstr ""
#: RatioedPanel.php:115
msgid "User blocked"
msgstr ""
#: RatioedPanel.php:116
msgid "Site admin"
msgstr ""
#: RatioedPanel.php:117
msgid "Account expired"
msgstr ""
#: RatioedPanel.php:118
msgid "Create a new user"
msgstr ""
#: RatioedPanel.php:124
msgid "Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"
msgstr ""
#: RatioedPanel.php:125
msgid "The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"
msgstr ""
#: ratioed.php:42
msgid "Statistics about users behaviour"
msgstr ""

View file

@ -2,13 +2,12 @@
/**
* Name: Ratioed
* Description: Additional moderation user table with statistics about user behaviour
* Version: 0.1
* Version: 0.3
* Author: Matthew Exon <http://mat.exon.name>
*/
use Friendica\Addon\ratioed\RatioedPanel;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\DI;
/**
@ -18,7 +17,7 @@ function ratioed_install()
{
Hook::register('moderation_users_tabs', 'addon/ratioed/ratioed.php', 'ratioed_users_tabs');
Logger::info("ratioed: installed");
DI::logger()->info("ratioed: installed");
}
/**
@ -34,7 +33,7 @@ function ratioed_module() {}
* @param array $arr Parameters, including "tabs" which is the list to modify, and "selectedTab", which is the currently selected tab ID
*/
function ratioed_users_tabs(array &$arr) {
Logger::debug("ratioed: users tabs");
DI::logger()->debug("ratioed: users tabs");
array_push($arr['tabs'], [
'label' => DI::l10n()->t('Behaviour'),
@ -50,7 +49,7 @@ function ratioed_users_tabs(array &$arr) {
* @brief Displays the ratioed tab in the moderation panel
*/
function ratioed_content() {
Logger::debug("ratioed: content");
DI::logger()->debug("ratioed: content");
$ratioed = DI::getDice()->create(RatioedPanel::class, [$_SERVER]);
$httpException = DI::getDice()->create(Friendica\Module\Special\HTTPException::class);

View file

@ -2,7 +2,7 @@
<div class="panel-body">
<h2>Ratioed Plugin Help</h2>
<p>
This plugin provides administrators with additional statistics about
This plugin provides moderators with additional statistics about
the behaviour of users. These may be useful as early warning signs
that warrant more carefully watching the behaviour of a user. They
are <em>not</em> suitable as a trigger for instantly blocking,
@ -28,7 +28,7 @@
<p>
This plugin allows viewing of an actual ratio, calculated over the
last 24 hours. This is a useful timeframe for sudden dogpiling
events that administrators might not otherwise notice. The plugin
events that moderators might not otherwise notice. The plugin
also calculates other statistics.
</p>
<h3>Explanation of Statistics</h3>
@ -68,10 +68,63 @@
24h". It is intended to approximate the traditional ratio as
understood on Twitter.
</p>
<h4>Replies last month</h4>
<p>
This is the number of times the user posted a reply to someone
else, on a thread the user did not start, any time in the last
month.
</p>
<h4>Reply likes</h4>
<p>
This is the number of likes received by the user on their
replies to other people's posts in the last month. Replies that
receive likes can be assumed to be more of a valuable
contribution than replies that do not.
</p>
<h4>Respondee likes</h4>
<p>
The number of times in the last month the user replied to
someone else's comment and that person then liked the reply.
Likes to replies are not necessarily a positive thing, but if
the person you're replying to approves the reply, that's a very
good sign. Of course it's also common in a debate for neither
side to like the other side's comments without that indicating
an unhealthy interaction, so interpret this statistic cautiously.
</p>
<h4>OP likes</h4>
<p>
The number of times in the last month the user replied on a
thread and the original poster that started the thread liked the
reply. While there is no formal concept of "ownership" of a
thread, conventionally the original poster is assumed to have
started the thread for a reason, and making replies that do not
fulfil that purpose are bad etiquette. Getting approval from
the original poster therefore is a good sign that the user is
posting replies that are wanted.
</p>
<h4>Reply guy score</h4>
<p>
A <a href="https://en.wikipedia.org/wiki/Reply_guy">"reply
guy"</a> is a common Internet phenomenon of people
(disproportionately male) posting unwanted comments on other
(disproportionately female) people's threads, derailing the
conversation. This score loosely quantifies this phenomenon,
as the ratio betwen the number of replies and the sum of likes,
respondee likes, and OP likes. This formula gives extra weight
to particularly relevant likes: a reply to a top-level post that
is liked by the original poster scores the maximum of 3
"points". A score above 1.0 might indicate cause for concern
for moderators.
</p>
<p>
Since this is indicative of long-term behaviour, the score is
calculated over a month instead of 24 hours.
</p>
</p>
<h3>Performance</h3>
<p>
The statistics are computed from scratch each time the page loads.
It's possible that this might put a heavy load on the database. and
It's possible that this might put a heavy load on the database, and
the page may take a long time to load.
</p>
<h3>Extending</h3>

View file

@ -2,26 +2,21 @@
<link rel="stylesheet" href="view/theme/frio/css/mod_admin.css?v={{constant('\Friendica\App::VERSION')}}" type="text/css" media="screen"/>
<div id="admin-users" class="adminpage generic-page-wrapper">
<h1>{{$title}} - {{$page}} ({{$count}})</h1>
<p>
<a href="{{$base_url}}/moderation/users/create" class="btn btn-primary"><i class="fa fa-user-plus"></i> {{$h_newuser}}</a>
</p>
<h1>
{{$title}} - {{$page}} ({{$count}})
<a href="{{$base_url}}/ratioed/help"><i style="float: right; font-size: 60%" class="fa fa-question-circle fa-fw" aria-hidden="true"></i></a>
</h1>
<form action="{{$baseurl}}/{{$query_string}}" method="post">
<input type="hidden" name="form_security_token" value="{{$form_security_token}}">
<table id="users" class="table table-hover">
<thead>
<tr>
<th>
<div class="checkbox">
<input type="checkbox" id="admin-settings-users-select" class="selecttoggle" data-select-class="users_ckbx"/>
<label for="admin-settings-users-select"></label>
</div>
</th>
<th></th>
<th></th>
{{foreach $th_users as $k=>$th}}
{{if $k < 2 || $order_users == $th.1 || ($k==5 && !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1])) }}
{{if $k < 2 || $order_users == $th.1 || ($k==4 && !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.5.1])) }}
<th class="th-{{$k}}">
<a href="{{$baseurl}}/moderation/users/active?o={{if $order_direction_users == "+"}}-{{/if}}{{$th.1}}" class="table-order">
<a href="{{$baseurl}}/ratioed?o={{if $order_direction_users == "+"}}-{{/if}}{{$th.1}}" class="table-order">
{{if $order_users == $th.1}}
{{if $order_direction_users == "+"}}
&#8595;
@ -41,17 +36,8 @@
</thead>
<tbody>
{{foreach $users as $u}}
<tr id="user-{{$u.uid}}" class="{{if $u.ratioed}}blocked{{/if}}">
<td>
{{if $u.is_deletable}}
<div class="checkbox">
<input type="checkbox" class="users_ckbx" id="id_user_{{$u.uid}}" name="user[]" value="{{$u.uid}}"/>
<label for="id_user_{{$u.uid}}"></label>
</div>
{{else}}
&nbsp;
{{/if}}
</td>
<tr id="user-{{$u.uid}}" class="{{if $u.ratioed || $u.reply_guy}}blocked{{/if}}">
<td></td>
<td><img class="avatar-nano" src="{{$u.micro}}" title="{{$u.nickname}}"></td>
<td><a href="{{$u.url}}" title="{{$u.nickname}}"> {{$u.name}}</a></td>
<td>{{$u.email}}</td>
@ -63,11 +49,7 @@
<td>{{$u.login_date}}</td>
{{/if}}
{{if $order_users == $th_users.4.1}}
<td>{{$u.lastitem_date}}</td>
{{/if}}
{{if !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.4.1]) }}
{{if $order_users == $th_users.5.1}}
<td>
<i class="fa
{{if $u.page_flags_raw==0}}fa-user{{/if}} {{* PAGE_NORMAL *}}
@ -91,6 +73,10 @@
</td>
{{/if}}
{{if !in_array($order_users,[$th_users.2.1, $th_users.3.1, $th_users.5.1]) }}
<td>{{$u.lastitem_date}}</td>
{{/if}}
<td class="text-right">
<button type="button" class="btn-link admin-settings-action-link" onclick="return details({{$u.uid}})"><span class="caret"></span></button>
</td>
@ -135,30 +121,11 @@
{{/foreach}}
</td>
<td class="text-right">
{{if $u.is_deletable}}
<a href="{{$baseurl}}/moderation/users/active/block/{{$u.uid}}?t={{$form_security_token}}" class="admin-settings-action-link" title="{{$block}}">
<i class="fa fa-ban" aria-hidden="true"></i>
</a>
<a href="{{$baseurl}}/moderation/users/active/delete/{{$u.uid}}?t={{$form_security_token}}" class="admin-settings-action-link" title="{{$delete}}" onclick="return confirm_delete('{{$confirm_delete}}','{{$u.name}}')">
<i class="fa fa-trash" aria-hidden="true"></i>
</a>
{{else}}
&nbsp;
{{/if}}
</td>
<td class="text-right"></td>
</tr>
{{/foreach}}
</tbody>
</table>
<div class="panel-footer">
<button type="submit" name="page_users_block" value="1" class="btn btn-warning">
<i class="fa fa-ban" aria-hidden="true"></i> {{$block}}
</button>
<button type="submit" name="page_users_delete" value="1" class="btn btn-danger" onclick="return confirm_delete('{{$confirm_delete_multi}}')">
<i class="fa fa-trash" aria-hidden="true"></i> {{$delete}}
</button>
</div>
{{$pager nofilter}}
</form>
</div>

View file

@ -7,7 +7,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -60,7 +59,7 @@ function rendertime_page_end(string &$o)
if (DI::userSession()->isSiteAdmin() && (($_GET['mode'] ?? '') != 'minimal') && !DI::mode()->isMobile() && !DI::mode()->isMobile() && !$ignored) {
$o = $o . '<div class="renderinfo">' . DI::l10n()->t("Database: %s/%s, Network: %s, Rendering: %s, Session: %s, I/O: %s, Other: %s, Total: %s",
$o = $o . '<div class="renderinfo" aria-hidden="true">' . DI::l10n()->t("Database: %s/%s, Network: %s, Rendering: %s, Session: %s, I/O: %s, Other: %s, Total: %s",
round($profiler->get('database') - $profiler->get('database_write'), 3),
round($profiler->get('database_write'), 3),
round($profiler->get('network'), 2),

View file

@ -8,7 +8,6 @@
use Friendica\Addon\s3_storage\src\S3Client;
use Friendica\Addon\s3_storage\src\S3Config;
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

View file

@ -4,10 +4,10 @@ namespace Friendica\Addon\s3_storage\src;
defined('AKEEBAENGINE') or define('AKEEBAENGINE', 1);
use Akeeba\Engine\Postproc\Connector\S3v4\Configuration;
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
use Akeeba\Engine\Postproc\Connector\S3v4\Exception\CannotDeleteFile;
use Akeeba\Engine\Postproc\Connector\S3v4\Input;
use Akeeba\S3\Configuration;
use Akeeba\S3\Connector;
use Akeeba\S3\Exception\CannotDeleteFile;
use Akeeba\S3\Input;
use Friendica\Core\Storage\Capability\ICanWriteToStorage;
use Friendica\Core\Storage\Exception\StorageException;
use Friendica\Util\Strings;

View file

@ -4,8 +4,8 @@ namespace Friendica\Addon\s3_storage\src;
defined('AKEEBAENGINE') or define('AKEEBAENGINE', 1);
use Akeeba\Engine\Postproc\Connector\S3v4\Configuration;
use Akeeba\Engine\Postproc\Connector\S3v4\Connector;
use Akeeba\S3\Configuration;
use Akeeba\S3\Connector;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\L10n;
use Friendica\Core\Storage\Capability\ICanConfigureStorage;

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-05-18 07:23+0200\n"
"POT-Creation-Date: 2025-01-17 03:23+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,82 +17,82 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: saml.php:231
#: saml.php:81
msgid "managed via SAML authentication"
msgstr ""
#: saml.php:246
msgid "Settings statement"
msgstr ""
#: saml.php:232
msgid ""
"A statement on the settings page explaining where the user should go to "
"change their e-mail and password. BBCode allowed."
msgstr ""
#: saml.php:237
msgid "IdP ID"
msgstr ""
#: saml.php:238
msgid ""
"Identity provider (IdP) entity URI (e.g., https://example.com/auth/realms/"
"user)."
msgstr ""
#: saml.php:242
msgid "Client ID"
msgstr ""
#: saml.php:243
msgid "Identifier assigned to client by the identity provider (IdP)."
msgstr ""
#: saml.php:247
msgid "IdP SSO URL"
msgstr ""
#: saml.php:248
msgid "The URL for your identity provider's SSO endpoint."
msgid "A statement on the settings page explaining where the user should go to change their e-mail and password. BBCode allowed."
msgstr ""
#: saml.php:252
msgid "IdP SLO request URL"
msgid "IdP ID"
msgstr ""
#: saml.php:253
msgid "The URL for your identity provider's SLO request endpoint."
msgid "Identity provider (IdP) entity URI (e.g., https://example.com/auth/realms/user)."
msgstr ""
#: saml.php:257
msgid "IdP SLO response URL"
msgid "Client ID"
msgstr ""
#: saml.php:258
msgid "The URL for your identity provider's SLO response endpoint."
msgid "Identifier assigned to client by the identity provider (IdP)."
msgstr ""
#: saml.php:262
msgid "SP private key"
msgid "IdP SSO URL"
msgstr ""
#: saml.php:263
msgid "The private key the addon should use to authenticate."
msgid "The URL for your identity provider's SSO endpoint."
msgstr ""
#: saml.php:267
msgid "SP certificate"
msgid "IdP SLO request URL"
msgstr ""
#: saml.php:268
msgid "The certficate for the addon's private key."
msgid "The URL for your identity provider's SLO request endpoint."
msgstr ""
#: saml.php:272
msgid "IdP certificate"
msgid "IdP SLO response URL"
msgstr ""
#: saml.php:273
msgid "The URL for your identity provider's SLO response endpoint."
msgstr ""
#: saml.php:277
msgid "SP private key"
msgstr ""
#: saml.php:278
msgid "The private key the addon should use to authenticate."
msgstr ""
#: saml.php:282
msgid "SP certificate"
msgstr ""
#: saml.php:283
msgid "The certficate for the addon's private key."
msgstr ""
#: saml.php:287
msgid "IdP certificate"
msgstr ""
#: saml.php:288
msgid "The x509 certficate for your identity provider."
msgstr ""
#: saml.php:276
#: saml.php:291
msgid "Save Settings"
msgstr ""

View file

@ -1 +0,0 @@
#settings-form > div:first-of-type, #settings-form > h2:first-of-type, #wrapper_mpassword, #wrapper_email { display: none !important; }

View file

@ -8,7 +8,6 @@
use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
@ -63,7 +62,7 @@ function saml_metadata()
);
}
} catch (Exception $e) {
Logger::error($e->getMessage());
DI::logger()->error($e->getMessage());
}
}
@ -75,18 +74,38 @@ function saml_install()
Hook::register('footer', __FILE__, 'saml_footer');
}
function saml_head(string &$body)
{
DI::page()->registerStylesheet(__DIR__ . '/saml.css');
}
function saml_footer(string &$body)
{
$fragment = addslashes(BBCode::convertForUriId(User::getSystemUriId(), DI::config()->get('saml', 'settings_statement')));
$samlhint = DI::l10n()->t('managed via SAML authentication');
$body .= <<<EOL
<script>
var target=$("#settings-nickname-desc");
if (target.length) { target.append("<p>$fragment</p>"); }
var saml_hint = document.createElement("span");
var saml_hint_text = document.createTextNode('$samlhint');
saml_hint.appendChild(saml_hint_text);
if ( document.getElementById('id_email') != null ) {
document.getElementById('id_email').setAttribute('readonly', 'readonly');
document.getElementById('id_email').parentNode.insertBefore(saml_hint, document.getElementById('id_email').nextSibling);
}
// Frio theme
if ( document.getElementById('password-settings-collapse') != null ) {
document.getElementById('password-settings-collapse').replaceChildren(saml_hint.cloneNode(true));
}
if ( document.getElementById('id_mpassword_wrapper') != null ) {
document.getElementById('id_mpassword_wrapper').parentNode.appendChild(saml_hint.cloneNode(true));
document.getElementById('id_mpassword_wrapper').remove();
document.getElementById('id_email').nextElementSibling.classList.add('help-block');
}
// Vier theme
if ( document.getElementById('wrapper_mpassword') != null ) {
document.getElementById('wrapper_mpassword').remove();
document.getElementById('id_email').nextElementSibling.classList.add('field_help');
}
if ( document.getElementById('wrapper_password') != null ) {
document.getElementById('wrapper_password').parentNode.replaceChildren(saml_hint.cloneNode(true));
}
</script>
EOL;
}
@ -107,7 +126,7 @@ function saml_is_configured()
function saml_sso_initiate(string &$body)
{
if (!saml_is_configured()) {
Logger::warning('SAML SSO tried to trigger, but the SAML addon is not configured yet!');
DI::logger()->warning('SAML SSO tried to trigger, but the SAML addon is not configured yet!');
return;
}
@ -136,7 +155,7 @@ function saml_sso_reply()
if (!empty($errors)) {
echo 'Errors encountered.';
Logger::error(implode(', ', $errors));
DI::logger()->error(implode(', ', $errors));
exit();
}
@ -161,7 +180,7 @@ function saml_sso_reply()
}
if (!empty($user['uid'])) {
DI::auth()->setForUser(DI::app(), $user);
DI::auth()->setForUser($user);
}
if (isset($_POST['RelayState']) && Utils::getSelfURL() != $_POST['RelayState']) {
@ -172,7 +191,7 @@ function saml_sso_reply()
function saml_slo_initiate()
{
if (!saml_is_configured()) {
Logger::warning('SAML SLO tried to trigger, but the SAML addon is not configured yet!');
DI::logger()->warning('SAML SLO tried to trigger, but the SAML addon is not configured yet!');
return;
}
@ -203,7 +222,7 @@ function saml_slo_reply()
if (empty($errors)) {
$auth->redirectTo(DI::baseUrl());
} else {
Logger::error(implode(', ', $errors));
DI::logger()->error(implode(', ', $errors));
}
}
@ -296,7 +315,7 @@ function saml_addon_admin_post()
function saml_create_user($username, $email, $name)
{
if (!strlen($email) || !strlen($name)) {
Logger::error('Could not create user: no email or username given.');
DI::logger()->error('Could not create user: no email or username given.');
return false;
}
@ -318,7 +337,7 @@ function saml_create_user($username, $email, $name)
return $user;
} catch (Exception $e) {
Logger::error(
DI::logger()->error(
'Exception while creating user',
[
'username' => $username,

View file

@ -21,7 +21,6 @@
namespace Friendica\Addon\securemail;
use Friendica\App;
use Friendica\App\BaseURL;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;

View file

@ -7,9 +7,7 @@
*/
use Friendica\Addon\securemail\SecureTestEmail;
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Object\EMail\IEmail;
@ -23,7 +21,7 @@ function securemail_install()
Hook::register('emailer_send_prepare', 'addon/securemail/securemail.php', 'securemail_emailer_send_prepare', 10);
Logger::notice('installed securemail');
DI::logger()->notice('installed securemail');
}
/**
@ -32,8 +30,6 @@ function securemail_install()
* @link https://github.com/friendica/friendica/blob/develop/doc/Addons.md#addon_settings 'addon_settings' hook
*
* @param array $data
*
* @see App
*/
function securemail_settings(array &$data)
{
@ -67,8 +63,6 @@ function securemail_settings(array &$data)
* @link https://github.com/friendica/friendica/blob/develop/doc/Addons.md#addon_settings_post 'addon_settings_post' hook
*
* @param array $b hook data
*
* @see App
*/
function securemail_settings_post(array &$b)
{
@ -82,7 +76,7 @@ function securemail_settings_post(array &$b)
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'securemail', 'enable', $enable);
if (!empty($_POST['securemail-test'])) {
$res = DI::emailer()->send(new SecureTestEmail(DI::app(), DI::config(), DI::pConfig(), DI::baseUrl()));
$res = DI::emailer()->send(new SecureTestEmail(DI::config(), DI::pConfig(), DI::baseUrl()));
// revert to saved value
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'securemail', 'enable', $enable);
@ -102,8 +96,6 @@ function securemail_settings_post(array &$b)
* @link https://github.com/friendica/friendica/blob/develop/doc/Addons.md#emailer_send_prepare 'emailer_send_prepare' hook
*
* @param IEmail $email Email
*
* @see App
*/
function securemail_emailer_send_prepare(IEmail &$email)
{

View file

@ -8,7 +8,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;
@ -79,6 +78,7 @@ function get_body_length($body)
* Checking any possible syntax of the style attribute with xpath is impossible
* So we just get any element with a style attribute, and check them with a regexp
*/
/** @var DOMNodeList $xr */
$xr = $xpath->query('//*[@style]');
foreach ($xr as $node) {
if (preg_match('/.*display: *none *;.*/',$node->getAttribute('style'))) {

View file

@ -59,7 +59,7 @@ function addHeightToggleHandler($item) {
$item.data("item-id", itemId);
var toggleId = "wall-item-body-toggle-" + itemId;
$item.append('<div class="wall-item-body-toggle" data-item-id="' + itemId + '" id="' + toggleId + '" ><button type="button" class="wall-item-body-toggle-text">' + showmore_dyn_showmore_linktext + '</button></div>');
$item.append('<div class="wall-item-body-toggle" data-item-id="' + itemId + '" id="' + toggleId + '" ><button type="button" class="wall-item-body-toggle-text" aria-hidden="true">' + showmore_dyn_showmore_linktext + '</button></div>');
$item.addClass("limitable limit-height");
var $toggle = $("#" + toggleId);

View file

@ -7,12 +7,8 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
function showmore_dyn_install()

View file

@ -3,11 +3,10 @@
* Name: Smiley Pack (Español)
* Description: Pack of smileys that make master too AOLish.
* Version: 1.02
* Author: Thomas Willingham (based on Mike Macgirvin's Adult Smile template)
* Author: Thomas Willingham (based on Mike Macgirvin's Adult Smile template)
* All smileys from sites offering them as Public Domain
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
@ -19,7 +18,7 @@ function smiley_pack_smilies_es(array &$b) {
#Smileys are split into various directories by the intended range of emotions. This is in case we get too big and need to modularise things. We can then cut and paste the right lines, move the right directory, and just change the name of the addon to happy_smilies or whatever.
#Be careful with invocation strings. If you have a smiley called foo, and another called foobar, typing :foobar will call foo. Avoid this with clever naming, using ~ instead of :
#Be careful with invocation strings. If you have a smiley called foo, and another called foobar, typing :foobar will call foo. Avoid this with clever naming, using ~ instead of :
#when all else fails.
@ -49,7 +48,7 @@ function smiley_pack_smilies_es(array &$b) {
$b['texts'][] = ':vaca';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/cow.gif' . '" alt="' . ':vaca' . '" />';
$b['texts'][] = ':cangrejo';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/crab.gif' . '" alt="' . ':cangrejo' . '" />';
@ -70,7 +69,7 @@ function smiley_pack_smilies_es(array &$b) {
$b['texts'][] = ':caballo';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/horse.gif' . '" alt="' . ':caballo' . '" />';
$b['texts'][] = ':loro';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/parrot.gif' . '" alt="' . ':loro' . '" />';
@ -107,7 +106,7 @@ function smiley_pack_smilies_es(array &$b) {
$b['texts'][] = ':cuna';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/babycot.gif' . '" alt="' . ':cuna' . '" />';
$b['texts'][] = ':embarazada';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/pregnant.gif' . '" alt="' . ':embarazada' . '" />';
@ -116,10 +115,10 @@ function smiley_pack_smilies_es(array &$b) {
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/stork.gif' . '" alt="' . ':cigüeña' . '" />';
#Confused Smileys
#Confused Smileys
$b['texts'][] = ':confundido';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/confused.gif' . '" alt="' . ':confundido' . '" />';
$b['texts'][] = ':encogehombros';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/shrug.gif' . '" alt="' . ':encogehombros' . '" />';
@ -154,13 +153,13 @@ function smiley_pack_smilies_es(array &$b) {
$b['texts'][] = ':diabólico';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/devil.gif' . '" alt="' . ':diabólico' . '" />';
$b['texts'][] = ':adbalancín';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/daseesaw.gif' . '" alt="' . ':adbalancín' . '" />';
$b['texts'][] = ':vuelvedemonio';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/turnevil.gif' . '" alt="' . ':vuelvedemonio' . '" />';
$b['texts'][] = ':santo';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/saint.gif' . '" alt="' . ':santo' . '" />';
@ -242,7 +241,7 @@ function smiley_pack_smilies_es(array &$b) {
$b['texts'][] = ':billar';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/snooker.gif' . '" alt="' . ':billar' . '" />';
$b['texts'][] = ':tenis';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/tennis.gif' . '" alt="' . ':tenis' . '" />';

View file

@ -9,7 +9,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
@ -23,7 +22,7 @@ function smiley_pack_fr_smilies(array &$b)
#Smileys are split into various directories by the intended range of emotions. This is in case we get too big and need to modularise things. We can then cut and paste the right lines, move the right directory, and just change the name of the addon to happy_smilies or whatever.
#Be careful with invocation strings. If you have a smiley called foo, and another called foobar, typing :foobar will call foo. Avoid this with clever naming, using ~ instead of :
#Be careful with invocation strings. If you have a smiley called foo, and another called foobar, typing :foobar will call foo. Avoid this with clever naming, using ~ instead of :
#when all else fails.
@ -56,7 +55,7 @@ function smiley_pack_fr_smilies(array &$b)
$b['texts'][] = ':vache';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/cow.gif' . '" alt="' . ':vache' . '" />';
$b['texts'][] = ':crabe';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/crab.gif' . '" alt="' . ':crabe' . '" />';
@ -74,7 +73,7 @@ function smiley_pack_fr_smilies(array &$b)
$b['texts'][] = ':cheval';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/horse.gif' . '" alt="' . ':cheval' . '" />';
$b['texts'][] = ':perroquet';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/animals/parrot.gif' . '" alt="' . ':perroquet' . '" />';
@ -108,7 +107,7 @@ function smiley_pack_fr_smilies(array &$b)
$b['texts'][] = ':litbébé';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/babycot.gif' . '" alt="' . ':litbébé' . '" />';
$b['texts'][] = ':enceinte';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/pregnant.gif' . '" alt="' . ':enceinte' . '" />';
@ -117,10 +116,10 @@ function smiley_pack_fr_smilies(array &$b)
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/babies/stork.gif' . '" alt="' . ':cigogne' . '" />';
#Confused Smileys
#Confused Smileys
$b['texts'][] = ':paumé';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/confused.gif' . '" alt="' . ':paumé' . '" />';
$b['texts'][] = ':hausseépaules';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/confused/shrug.gif' . '" alt="' . ':hausseépaules' . '" />';
@ -152,13 +151,13 @@ function smiley_pack_fr_smilies(array &$b)
$b['texts'][] = ':démoniaque';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/devil.gif' . '" alt="' . ':démoniaque' . '" />';
$b['texts'][] = ':bascule';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/daseesaw.gif' . '" alt="' . ':bascule' . '" />';
$b['texts'][] = ':possédé';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/turnevil.gif' . '" alt="' . ':possédé' . '" />';
$b['texts'][] = ':tombe';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/devilangel/graveside.gif' . '" alt="' . ':tombe' . '" />';
@ -225,7 +224,7 @@ function smiley_pack_fr_smilies(array &$b)
$b['texts'][] = ':billard';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/snooker.gif' . '" alt="' . ':billard' . '" />';
$b['texts'][] = ':équitation';
$b['icons'][] = '<img src="' . DI::baseUrl() . '/addon/smiley_pack/icons/sport/horseriding.gif' . '" alt="' . ':équitation' . '" />';

View file

@ -7,7 +7,6 @@
* Maintainer: Hypolite Petovan <https://friendica.mrpetovan.com/profile/hypolite>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
@ -20,7 +19,7 @@ function smileybutton_install()
function smileybutton_jot_tool(string &$body)
{
// Disable if theme is quattro
if (DI::app()->getCurrentTheme() == 'quattro') {
if (DI::appHelper()->getCurrentTheme() == 'quattro') {
return;
}
@ -97,7 +96,7 @@ function smileybutton_jot_tool(string &$body)
$s .= '</tr></table>';
//Add css to header
$css_file = __DIR__ . '/view/' . DI::app()->getCurrentTheme() . '.css';
$css_file = __DIR__ . '/view/' . DI::appHelper()->getCurrentTheme() . '.css';
if (!file_exists($css_file)) {
$css_file = __DIR__ . '/view/default.css';
}
@ -105,7 +104,7 @@ function smileybutton_jot_tool(string &$body)
DI::page()->registerStylesheet($css_file);
//Get the correct image for the theme
$image = 'addon/smileybutton/view/' . DI::app()->getCurrentTheme() . '.png';
$image = 'addon/smileybutton/view/' . DI::appHelper()->getCurrentTheme() . '.png';
if (!file_exists($image)) {
$image = 'addon/smileybutton/view/default.png';
}

View file

@ -4,12 +4,11 @@
* Description: Smily icons that could or should not be included in core
* Version: 1.0
* Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
*
*
* This is a template for how to extend the "smily" code.
*
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

View file

@ -7,7 +7,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -31,11 +31,10 @@ use Friendica\Core\System;
/**
* Define constants
*/
$constants = explode(' ', 'OBJECT ARRAY JSON');
foreach ($constants as $i => $id) {
$id = 'CODEBIRD_RETURNFORMAT_' . $id;
defined($id) or define($id, $i);
}
defined('CODEBIRD_RETURNFORMAT_ARRAY') or define('CODEBIRD_RETURNFORMAT_ARRAY', 0);
defined('CODEBIRD_RETURNFORMAT_JSON') or define('CODEBIRD_RETURNFORMAT_JSON', 1);
defined('CODEBIRD_RETURNFORMAT_OBJECT') or define('CODEBIRD_RETURNFORMAT_OBJECT', 2);
$constants = array(
'CURLE_SSL_CERTPROBLEM' => 58,
'CURLE_SSL_CACERT' => 60,
@ -55,6 +54,8 @@ unset($id);
*
* @package codebird
* @subpackage codebird-php
*
* @method object statuses_update(array $postdata)
*/
class CodebirdSN
{
@ -117,7 +118,7 @@ class CodebirdSN
* Returns singleton class instance
* Always use this method unless you're working with multiple authenticated users at once
*
* @return Codebird The instance
* @return CodebirdSN The instance
*/
public static function getInstance()
{
@ -421,6 +422,7 @@ class CodebirdSN
}
break;
case CODEBIRD_RETURNFORMAT_OBJECT:
/** @var object $reply */
$reply->httpstatus = $httpstatus;
if ($httpstatus == 200) {
self::setBearerToken($reply->access_token);
@ -491,7 +493,7 @@ class CodebirdSN
/**
* Generates a (hopefully) unique random string
*
* @param int optional $length The length of the string to generate
* @param int $length The optional length of the string to generate
*
* @return string The random string
*/
@ -506,9 +508,9 @@ class CodebirdSN
/**
* Generates an OAuth signature
*
* @param string $httpmethod Usually either 'GET' or 'POST' or 'DELETE'
* @param string $method The API method to call
* @param array optional $params The API call parameters, associative
* @param string $httpmethod Usually either 'GET' or 'POST' or 'DELETE'
* @param string $method The API method to call
* @param array $params optional The API call parameters, associative
*
* @return string Authorization HTTP header
*/
@ -762,13 +764,13 @@ class CodebirdSN
* @param string $method The API method to call
* @param array $params The parameters to send along
*
* @return void
* @return string
*/
protected function _buildMultipart($method, $params)
{
// well, files will only work in multipart methods
if (! $this->_detectMultipart($method)) {
return;
return '';
}
// only check specific parameters
@ -783,18 +785,19 @@ class CodebirdSN
);
// method might have files?
if (! in_array($method, array_keys($possible_files))) {
return;
return '';
}
$possible_files = explode(' ', $possible_files[$method]);
$data = '';
$multipart_border = '--------------------' . $this->_nonce();
$multipart_request = '';
foreach ($params as $key => $value) {
// is it an array?
if (is_array($value)) {
throw new \Exception('Using URL-encoded parameters is not supported for uploading media.');
continue;
}
// check for filenames
@ -871,12 +874,12 @@ class CodebirdSN
/**
* Calls the API using cURL
*
* @param string $httpmethod The HTTP method to use for making the request
* @param string $method The API method to call
* @param string $method_template The templated API method to call
* @param array optional $params The parameters to send along
* @param bool optional $multipart Whether to use multipart/form-data
* @param bool optional $app_only_auth Whether to use app-only bearer authentication
* @param string $httpmethod The HTTP method to use for making the request
* @param string $method The API method to call
* @param string $method_template The templated API method to call
* @param array $params optional The parameters to send along
* @param bool $multipart optional Whether to use multipart/form-data
* @param bool $app_only_auth optional Whether to use app-only bearer authentication
*
* @return mixed The API reply, encoded in the set return_format
*/
@ -918,7 +921,7 @@ class CodebirdSN
$authorization = 'Authorization: Bearer ' . self::$_oauth_bearer_token;
}
$request_headers = array();
if (isset($authorization)) {
if ($authorization !== '') {
$request_headers[] = $authorization;
$request_headers[] = 'Expect:';
}
@ -959,6 +962,7 @@ class CodebirdSN
$httpstatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$reply = $this->_parseApiReply($method_template, $reply);
if ($this->_return_format == CODEBIRD_RETURNFORMAT_OBJECT) {
/** @var object $reply */
$reply->httpstatus = $httpstatus;
} elseif ($this->_return_format == CODEBIRD_RETURNFORMAT_ARRAY) {
$reply['httpstatus'] = $httpstatus;
@ -972,7 +976,7 @@ class CodebirdSN
* @param string $method The method that has been called
* @param string $reply The actual reply, JSON-encoded or URL-encoded
*
* @return array|object The parsed reply
* @return string|array|object The parsed reply
*/
protected function _parseApiReply($method, $reply)
{

View file

@ -12,7 +12,7 @@ require_once __DIR__ . DIRECTORY_SEPARATOR . 'twitteroauth.php';
*/
class StatusNetOAuth extends TwitterOAuth
{
function get_maxlength()
public function get_maxlength()
{
$config = $this->get($this->host . 'statusnet/config.json');
if (empty($config)) {
@ -21,27 +21,27 @@ class StatusNetOAuth extends TwitterOAuth
return $config->site->textlimit;
}
function accessTokenURL()
public function accessTokenURL()
{
return $this->host . 'oauth/access_token';
}
function authenticateURL()
public function authenticateURL()
{
return $this->host . 'oauth/authenticate';
}
function authorizeURL()
public function authorizeURL()
{
return $this->host . 'oauth/authorize';
}
function requestTokenURL()
public function requestTokenURL()
{
return $this->host . 'oauth/request_token';
}
function __construct($apipath, $consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL)
public function __construct($apipath, $consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL)
{
parent::__construct($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
$this->host = $apipath;
@ -52,14 +52,9 @@ class StatusNetOAuth extends TwitterOAuth
*
* Copied here from the TwitterOAuth library and complemented by applying the proxy settings of Friendica
*
* @param string $method
* @param string $host
* @param string $path
* @param array $parameters
*
* @return array|object API results
* @return array|object|mixed API results
*/
function http($url, $method, $postfields = NULL)
public function http($url, $method, $postfields = NULL)
{
$this->http_info = [];
$ci = curl_init();

View file

@ -45,11 +45,11 @@ class TwitterOAuth
public $http_header;
/**
* Contains the last HTTP request info
* @var string
* @var array
*/
public $http_info;
/** @var OAuthToken */
/** @var OAuthToken|null */
private $token;
/** @var OAuthConsumer */
private $consumer;
@ -59,27 +59,27 @@ class TwitterOAuth
/**
* Set API URLS
*/
function accessTokenURL()
public function accessTokenURL()
{
return 'https://api.twitter.com/oauth/access_token';
}
function authenticateURL()
public function authenticateURL()
{
return 'https://twitter.com/oauth/authenticate';
}
function authorizeURL()
public function authorizeURL()
{
return 'https://twitter.com/oauth/authorize';
}
function requestTokenURL()
public function requestTokenURL()
{
return 'https://api.twitter.com/oauth/request_token';
}
function __construct($consumer_key, $consumer_secret, $oauth_token = null, $oauth_token_secret = null)
public function __construct($consumer_key, $consumer_secret, $oauth_token = null, $oauth_token_secret = null)
{
$this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
$this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
@ -93,10 +93,10 @@ class TwitterOAuth
/**
* Get a request_token
*
* @param callback $oauth_callback
* @param callable $oauth_callback
* @return array
*/
function getRequestToken($oauth_callback = null)
public function getRequestToken($oauth_callback = null)
{
$parameters = [];
if (!empty($oauth_callback)) {
@ -112,11 +112,9 @@ class TwitterOAuth
/**
* Get the authorize URL
*
* @param array $token
* @param bool $sign_in_with_tumblr
* @return string
*/
function getAuthorizeURL($token, $sign_in_with_twitter = TRUE)
public function getAuthorizeURL($token, $sign_in_with_twitter = TRUE)
{
if (is_array($token)) {
$token = $token['oauth_token'];
@ -139,7 +137,7 @@ class TwitterOAuth
* "user_id" => "9436992",
* "screen_name" => "abraham")
*/
function getAccessToken($oauth_verifier = FALSE)
public function getAccessToken($oauth_verifier = FALSE)
{
$parameters = [];
if (!empty($oauth_verifier)) {
@ -164,7 +162,7 @@ class TwitterOAuth
* "screen_name" => "abraham",
* "x_auth_expires" => "0")
*/
function getXAuthToken($username, $password)
public function getXAuthToken($username, $password)
{
$parameters = [];
$parameters['x_auth_username'] = $username;
@ -184,7 +182,7 @@ class TwitterOAuth
* @param array $parameters
* @return mixed|string
*/
function get($url, $parameters = [])
public function get($url, $parameters = [])
{
$response = $this->oAuthRequest($url, 'GET', $parameters);
if ($this->format === 'json' && $this->decode_json) {
@ -201,7 +199,7 @@ class TwitterOAuth
* @param array $parameters
* @return mixed|string
*/
function post($url, $parameters = [])
public function post($url, $parameters = [])
{
$response = $this->oAuthRequest($url, 'POST', $parameters);
if ($this->format === 'json' && $this->decode_json) {
@ -218,7 +216,7 @@ class TwitterOAuth
* @param array $parameters
* @return mixed|string
*/
function delete($url, $parameters = [])
public function delete($url, $parameters = [])
{
$response = $this->oAuthRequest($url, 'DELETE', $parameters);
if ($this->format === 'json' && $this->decode_json) {
@ -236,7 +234,7 @@ class TwitterOAuth
* @param array $parameters
* @return mixed|string
*/
function oAuthRequest($url, $method, $parameters)
public function oAuthRequest($url, $method, $parameters)
{
if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
$url = "{$this->host}{$url}.{$this->format}";
@ -260,9 +258,9 @@ class TwitterOAuth
* @param string $url
* @param string $method
* @param mixed $postfields
* @return string API results
* @return string|bool|mixed API results
*/
function http($url, $method, $postfields = null)
public function http($url, $method, $postfields = null)
{
$this->http_info = [];
$ci = curl_init();
@ -307,7 +305,7 @@ class TwitterOAuth
* @param string $header
* @return int
*/
function getHeader($ch, $header)
public function getHeader($ch, $header)
{
$i = strpos($header, ':');
if (!empty($i)) {

View file

@ -38,10 +38,8 @@ define('STATUSNET_DEFAULT_POLL_INTERVAL', 5); // given in minutes
require_once __DIR__ . DIRECTORY_SEPARATOR . 'library' . DIRECTORY_SEPARATOR . 'statusnetoauth.php';
use CodebirdSN\CodebirdSN;
use Friendica\App;
use Friendica\Content\Text\Plaintext;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\System;
use Friendica\Database\DBA;
@ -59,7 +57,7 @@ function statusnet_install()
Hook::register('hook_fork', 'addon/statusnet/statusnet.php', 'statusnet_hook_fork');
Hook::register('post_local', 'addon/statusnet/statusnet.php', 'statusnet_post_local');
Hook::register('jot_networks', 'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
Logger::notice('installed GNU Social');
DI::logger()->notice('installed GNU Social');
}
function statusnet_jot_nets(array &$jotnets_fields)
@ -340,6 +338,10 @@ function statusnet_post_hook(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
$b['body'] = Post\Media::addAttachmentsToBody($b['uri-id'], DI::contentItem()->addSharedPost($b));
$api = DI::pConfig()->get($b['uid'], 'statusnet', 'baseapi');
@ -356,7 +358,7 @@ function statusnet_post_hook(array &$b)
return;
}
Logger::notice('GNU Socialpost invoked');
DI::logger()->notice('GNU Socialpost invoked');
DI::pConfig()->load($b['uid'], 'statusnet');
@ -366,6 +368,8 @@ function statusnet_post_hook(array &$b)
$otoken = DI::pConfig()->get($b['uid'], 'statusnet', 'oauthtoken');
$osecret = DI::pConfig()->get($b['uid'], 'statusnet', 'oauthsecret');
$iscomment = null;
if ($ckey && $csecret && $otoken && $osecret) {
$dent = new StatusNetOAuth($api, $ckey, $csecret, $otoken, $osecret);
$max_char = $dent->get_maxlength(); // max. length for a dent
@ -406,7 +410,7 @@ function statusnet_post_hook(array &$b)
$cb->setToken($otoken, $osecret);
$result = $cb->statuses_update($postdata);
//$result = $dent->post('statuses/update', $postdata);
Logger::info('statusnet_post send, result: ' . print_r($result, true) .
DI::logger()->info('statusnet_post send, result: ' . print_r($result, true) .
"\nmessage: " . $msg . "\nOriginal post: " . print_r($b, true) . "\nPost Data: " . print_r($postdata, true));
if (!empty($result->source)) {
@ -414,9 +418,9 @@ function statusnet_post_hook(array &$b)
}
if (!empty($result->error)) {
Logger::notice('Send to GNU Social failed: "' . $result->error . '"');
DI::logger()->notice('Send to GNU Social failed: "' . $result->error . '"');
} elseif ($iscomment) {
Logger::notice('statusnet_post: Update extid ' . $result->id . ' for post id ' . $b['id']);
DI::logger()->notice('statusnet_post: Update extid ' . $result->id . ' for post id ' . $b['id']);
Item::update(['extid' => $hostname . '::' . $result->id, 'body' => $result->text], ['id' => $b['id']]);
}
}

View file

@ -7,8 +7,8 @@
*/
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\DI;
use thiagoalessio\TesseractOCR\TesseractOCR;
require_once __DIR__ . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
@ -17,7 +17,7 @@ function tesseract_install()
{
Hook::register('ocr-detection', __FILE__, 'tesseract_ocr_detection');
Logger::notice('installed tesseract');
DI::logger()->notice('installed tesseract');
}
function tesseract_ocr_detection(&$media)
@ -26,12 +26,13 @@ function tesseract_ocr_detection(&$media)
try {
$languages = $ocr->availableLanguages();
if ($languages) {
// @phpstan-ignore-next-line
$ocr->lang(implode('+', $languages));
}
$ocr->tempDir(System::getTempPath());
$ocr->imageData($media['img_str'], strlen($media['img_str']));
$media['description'] = $ocr->run();
} catch (\Throwable $th) {
Logger::info('Error calling TesseractOCR', ['message' => $th->getMessage()]);
}
DI::logger()->info('Error calling TesseractOCR', ['message' => $th->getMessage()]);
}
}

View file

@ -6,7 +6,6 @@
* Author: Mike Macgirvin <http://macgirvin.com/profile/mike>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Search;
use Friendica\Database\DBA;
@ -27,7 +26,7 @@ function testdrive_install()
function testdrive_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('testdrive'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('testdrive'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function testdrive_globaldir_update(array &$b)

View file

@ -7,7 +7,6 @@
* Status: unsupported
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
@ -30,7 +29,12 @@ function tictac_module() {}
function tictac_content() {
$o = '';
$o = '';
$dimen = 3;
$handicap = 0;
$mefirst = 0;
$yours = '';
$mine = '';
if($_POST['move']) {
$handicap = DI::args()->get(1);
@ -45,9 +49,6 @@ function tictac_content() {
$handicap = DI::args()->get(1);
$dimen = 3;
}
else {
$dimen = 3;
}
$o .= '<h3>' . DI::l10n()->t('3D Tic-Tac-Toe') . '</h3><br />';
@ -70,6 +71,7 @@ class tictac {
private $dimen;
private $first_move = true;
private $handicap = 0;
private $mefirst;
private $yours;
private $mine;
private $winning_play;
@ -161,10 +163,10 @@ class tictac {
];
function __construct($dimen,$handicap,$mefirst,$yours,$mine) {
$this->dimen = 3;
$this->handicap = (($handicap) ? 1 : 0);
$this->mefirst = (($mefirst) ? 1 : 0);
function __construct($dimen, $handicap, $mefirst, $yours, $mine) {
$this->dimen = $dimen;
$this->handicap = $handicap ? 1 : 0;
$this->mefirst = $mefirst ? 1 : 0;
$this->yours = str_replace('XXX','',$yours);
$this->mine = $mine;
$this->you = $this->parse_moves('you');
@ -175,6 +177,7 @@ class tictac {
}
function play() {
$o = '';
if($this->first_move) {
if(rand(0,1) == 1) {
@ -226,6 +229,8 @@ class tictac {
}
function parse_moves($player) {
$str = '';
if($player == 'me')
$str = $this->mine;
if($player == 'you')
@ -629,7 +634,7 @@ function winning_move() {
function draw_board() {
if(! strlen($this->yours))
$this->yours = 'XXX';
$o .= "<form action=\"tictac/{$this->handicap}/{$this->mefirst}/{$this->dimen}/{$this->yours}/{$this->mine}\" method=\"post\" />";
$o = "<form action=\"tictac/{$this->handicap}/{$this->mefirst}/{$this->dimen}/{$this->yours}/{$this->mine}\" method=\"post\" />";
for($x = 0; $x < $this->dimen; $x ++) {
$o .= '<table>';
for($y = 0; $y < $this->dimen; $y ++) {

View file

@ -14,7 +14,6 @@ use Friendica\Content\Text\NPF;
use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Config\Util\ConfigFileManager;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
use Friendica\Core\System;
@ -60,12 +59,12 @@ function tumblr_install()
Hook::register('check_item_notification', __FILE__, 'tumblr_check_item_notification');
Hook::register('probe_detect', __FILE__, 'tumblr_probe_detect');
Hook::register('item_by_link', __FILE__, 'tumblr_item_by_link');
Logger::info('installed tumblr');
DI::logger()->info('installed tumblr');
}
function tumblr_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('tumblr'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('tumblr'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function tumblr_check_item_notification(array &$notification_data)
@ -121,16 +120,16 @@ function tumblr_item_by_link(array &$hookData)
return;
}
Logger::debug('Found tumblr post', ['url' => $hookData['uri'], 'blog' => $matches[1], 'id' => $matches[2]]);
DI::logger()->debug('Found tumblr post', ['url' => $hookData['uri'], 'blog' => $matches[1], 'id' => $matches[2]]);
$parameters = ['id' => $matches[2], 'reblog_info' => false, 'notes_info' => false, 'npf' => false];
$result = tumblr_get($hookData['uid'], 'blog/' . $matches[1] . '/posts', $parameters);
if ($result->meta->status > 399) {
Logger::notice('Error fetching status', ['meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'blog' => $matches[1], 'id' => $matches[2]]);
DI::logger()->notice('Error fetching status', ['meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'blog' => $matches[1], 'id' => $matches[2]]);
return [];
}
Logger::debug('Got post', ['blog' => $matches[1], 'id' => $matches[2], 'result' => $result->response->posts]);
DI::logger()->debug('Got post', ['blog' => $matches[1], 'id' => $matches[2], 'result' => $result->response->posts]);
if (!empty($result->response->posts)) {
$hookData['item_id'] = tumblr_process_post($result->response->posts[0], $hookData['uid'], Item::PR_FETCHED);
Item::incrementInbound(Protocol::TUMBLR);
@ -159,20 +158,20 @@ function tumblr_follow(array &$hook_data)
return;
}
Logger::debug('Check if contact is Tumblr', ['url' => $hook_data['url']]);
DI::logger()->debug('Check if contact is Tumblr', ['url' => $hook_data['url']]);
$fields = tumblr_get_contact_by_url($hook_data['url'], $uid);
if (empty($fields)) {
Logger::debug('Contact is not a Tumblr contact', ['url' => $hook_data['url']]);
DI::logger()->debug('Contact is not a Tumblr contact', ['url' => $hook_data['url']]);
return;
}
$result = tumblr_post($uid, 'user/follow', ['url' => $fields['url']]);
if ($result->meta->status <= 399) {
$hook_data['contact'] = $fields;
Logger::debug('Successfully start following', ['url' => $fields['url']]);
DI::logger()->debug('Successfully start following', ['url' => $fields['url']]);
} else {
Logger::notice('Following failed', ['meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'url' => $fields['url']]);
DI::logger()->notice('Following failed', ['meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'url' => $fields['url']]);
}
}
@ -392,12 +391,17 @@ function tumblr_settings_post(array &$b)
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'tumblr', 'import', intval($_POST['tumblr_import']));
$max_tags = DI::config()->get('tumblr', 'max_tags') ?? TUMBLR_DEFAULT_MAXIMUM_TAGS;
$tags = [];
foreach (explode(',', $_POST['tags']) as $tag) {
if (count($tags) < $max_tags) {
$tags[] = trim($tag, ' #');
}
}
$tags = array_slice(
array_filter(
array_map(
function($tag) { return trim($tag, ' #');},
explode(',', $_POST['tags']) ?: []
)
),
0,
$max_tags,
);
DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'tumblr', 'tags', $tags);
}
@ -415,11 +419,11 @@ function tumblr_cron()
if ($last) {
$next = $last + ($poll_interval * 60);
if ($next > time()) {
Logger::notice('poll interval not reached');
DI::logger()->notice('poll interval not reached');
return;
}
}
Logger::notice('cron_start');
DI::logger()->notice('cron_start');
$abandon_days = intval(DI::config()->get('system', 'account_abandon_days'));
if ($abandon_days < 1) {
@ -432,30 +436,30 @@ function tumblr_cron()
foreach ($pconfigs as $pconfig) {
if ($abandon_days != 0) {
if (!DBA::exists('user', ["`uid` = ? AND `login_date` >= ?", $pconfig['uid'], $abandon_limit])) {
Logger::notice('abandoned account: timeline from user will not be imported', ['user' => $pconfig['uid']]);
DI::logger()->notice('abandoned account: timeline from user will not be imported', ['user' => $pconfig['uid']]);
continue;
}
}
Logger::notice('importing timeline - start', ['user' => $pconfig['uid']]);
DI::logger()->notice('importing timeline - start', ['user' => $pconfig['uid']]);
tumblr_fetch_dashboard($pconfig['uid'], $last);
tumblr_fetch_tags($pconfig['uid'], $last);
Logger::notice('importing timeline - done', ['user' => $pconfig['uid']]);
DI::logger()->notice('importing timeline - done', ['user' => $pconfig['uid']]);
}
$last_clean = DI::keyValue()->get('tumblr_last_clean');
if (empty($last_clean) || ($last_clean + 86400 < time())) {
Logger::notice('Start contact cleanup');
DI::logger()->notice('Start contact cleanup');
$contacts = DBA::select('account-user-view', ['id', 'pid'], ["`network` = ? AND `uid` != ? AND `rel` = ?", Protocol::TUMBLR, 0, Contact::NOTHING]);
while ($contact = DBA::fetch($contacts)) {
Worker::add(Worker::PRIORITY_LOW, 'MergeContact', $contact['pid'], $contact['id'], 0);
}
DBA::close($contacts);
DI::keyValue()->set('tumblr_last_clean', time());
Logger::notice('Contact cleanup done');
DI::logger()->notice('Contact cleanup done');
}
Logger::notice('cron_end');
DI::logger()->notice('cron_end');
DI::keyValue()->set('tumblr_last_poll', time());
}
@ -478,7 +482,7 @@ function tumblr_hook_fork(array &$b)
if (DI::pConfig()->get($post['uid'], 'tumblr', 'import')) {
// Don't post if it isn't a reply to a tumblr post
if (($post['gravity'] != Item::GRAVITY_PARENT) && !Post::exists(['id' => $post['parent'], 'network' => Protocol::TUMBLR])) {
Logger::notice('No tumblr parent found', ['item' => $post['id']]);
DI::logger()->notice('No tumblr parent found', ['item' => $post['id']]);
$b['execute'] = false;
return;
}
@ -524,21 +528,25 @@ function tumblr_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['gravity'] != Item::GRAVITY_PARENT) {
Logger::debug('Got comment', ['item' => $b]);
DI::logger()->debug('Got comment', ['item' => $b]);
$parent = tumblr_get_post_from_uri($b['thr-parent']);
if (empty($parent)) {
Logger::notice('No tumblr post', ['thr-parent' => $b['thr-parent']]);
DI::logger()->notice('No tumblr post', ['thr-parent' => $b['thr-parent']]);
return;
}
Logger::debug('Parent found', ['parent' => $parent]);
DI::logger()->debug('Parent found', ['parent' => $parent]);
$page = tumblr_get_page($b['uid']);
if ($b['gravity'] == Item::GRAVITY_COMMENT) {
Logger::notice('Commenting is not supported (yet)');
DI::logger()->notice('Commenting is not supported (yet)');
} else {
if (($b['verb'] == Activity::LIKE) && !$b['deleted']) {
$params = ['id' => $parent['id'], 'reblog_key' => $parent['reblog_key']];
@ -562,12 +570,12 @@ function tumblr_send(array &$b)
}
if ($result->meta->status < 400) {
Logger::info('Successfully performed activity', ['verb' => $b['verb'], 'deleted' => $b['deleted'], 'meta' => $result->meta, 'response' => $result->response]);
DI::logger()->info('Successfully performed activity', ['verb' => $b['verb'], 'deleted' => $b['deleted'], 'meta' => $result->meta, 'response' => $result->response]);
if (!$b['deleted'] && !empty($result->response->id_string)) {
Item::update(['extid' => 'tumblr::' . $result->response->id_string], ['guid' => $b['guid']]);
}
} else {
Logger::notice('Error while performing activity', ['verb' => $b['verb'], 'deleted' => $b['deleted'], 'meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'params' => $params]);
DI::logger()->notice('Error while performing activity', ['verb' => $b['verb'], 'deleted' => $b['deleted'], 'meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'params' => $params]);
}
}
return;
@ -665,9 +673,9 @@ function tumblr_send_legacy(array $b)
$result = tumblr_post($b['uid'], 'blog/' . $page . '/post', $params);
if ($result->meta->status < 400) {
Logger::info('Success (legacy)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response]);
DI::logger()->info('Success (legacy)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response]);
} else {
Logger::notice('Error posting blog (legacy)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'params' => $params]);
DI::logger()->notice('Error posting blog (legacy)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'params' => $params]);
}
}
@ -676,7 +684,7 @@ function tumblr_send_npf(array $post): bool
$page = tumblr_get_page($post['uid']);
if (empty($page)) {
Logger::notice('Missing page, post will not be send to Tumblr.', ['uid' => $post['uid'], 'page' => $page, 'id' => $post['id']]);
DI::logger()->notice('Missing page, post will not be send to Tumblr.', ['uid' => $post['uid'], 'page' => $page, 'id' => $post['id']]);
// "true" is returned, since the legacy function will fail as well.
return true;
}
@ -707,10 +715,10 @@ function tumblr_send_npf(array $post): bool
$result = tumblr_post($post['uid'], 'blog/' . $page . '/posts', $params);
if ($result->meta->status < 400) {
Logger::info('Success (NPF)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response]);
DI::logger()->info('Success (NPF)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response]);
return true;
} else {
Logger::notice('Error posting blog (NPF)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'params' => $params]);
DI::logger()->notice('Error posting blog (NPF)', ['blog' => $page, 'meta' => $result->meta, 'response' => $result->response, 'errors' => $result->errors, 'params' => $params]);
return false;
}
}
@ -743,14 +751,25 @@ function tumblr_fetch_tags(int $uid, int $last_poll)
}
foreach (DI::pConfig()->get($uid, 'tumblr', 'tags') ?? [] as $tag) {
// Tumblr will return an error for queries on empty tag
if (!$tag) {
continue;
}
$data = tumblr_get($uid, 'tagged', ['tag' => $tag]);
if (!is_array($data->response)) {
DI::logger()->warning('Unexpected Tumblr response format', ['uid' => $uid, 'url' => 'tagged', 'parameters' => ['tag' => $tag], 'data' => $data]);
continue;
}
foreach (array_reverse($data->response) as $post) {
$id = tumblr_process_post($post, $uid, Item::PR_TAG, $last_poll);
if (!empty($id)) {
Logger::debug('Tag post imported', ['tag' => $tag, 'id' => $id]);
DI::logger()->debug('Tag post imported', ['tag' => $tag, 'id' => $id]);
$post = Post::selectFirst(['uri-id'], ['id' => $id]);
$stored = Post\Category::storeFileByURIId($post['uri-id'], $uid, Post\Category::SUBCRIPTION, $tag);
Logger::debug('Stored tag subscription for user', ['uri-id' => $post['uri-id'], 'uid' => $uid, 'tag' => $tag, 'stored' => $stored]);
DI::logger()->debug('Stored tag subscription for user', ['uri-id' => $post['uri-id'], 'uid' => $uid, 'tag' => $tag, 'stored' => $stored]);
Item::incrementInbound(Protocol::TUMBLR);
}
}
@ -775,8 +794,8 @@ function tumblr_fetch_dashboard(int $uid, int $last_poll)
$dashboard = tumblr_get($uid, 'user/dashboard', $parameters);
if ($dashboard->meta->status > 399) {
Logger::notice('Error fetching dashboard', ['meta' => $dashboard->meta, 'response' => $dashboard->response, 'errors' => $dashboard->errors]);
return [];
DI::logger()->notice('Error fetching dashboard', ['meta' => $dashboard->meta, 'response' => $dashboard->response, 'errors' => $dashboard->errors]);
return;
}
if (empty($dashboard->response->posts)) {
@ -788,7 +807,7 @@ function tumblr_fetch_dashboard(int $uid, int $last_poll)
$last = $post->id;
}
Logger::debug('Importing post', ['uid' => $uid, 'created' => date(DateTimeFormat::MYSQL, $post->timestamp), 'id' => $post->id_string]);
DI::logger()->debug('Importing post', ['uid' => $uid, 'created' => date(DateTimeFormat::MYSQL, $post->timestamp), 'id' => $post->id_string]);
tumblr_process_post($post, $uid, Item::PR_NONE, $last_poll);
Item::incrementInbound(Protocol::TUMBLR);
@ -1063,7 +1082,7 @@ function tumblr_get_type_replacement(array $data, string $plink): string
}
default:
Logger::notice('Unknown type', ['type' => $data['type'], 'data' => $data, 'plink' => $plink]);
DI::logger()->notice('Unknown type', ['type' => $data['type'], 'data' => $data, 'plink' => $plink]);
$body = '';
}
@ -1118,9 +1137,9 @@ function tumblr_get_contact(stdClass $blog, int $uid): array
$cid = $contact['id'];
Contact::update($fields, ['id' => $cid], true);
}
Logger::debug('Get user contact', ['id' => $cid, 'uid' => $uid, 'update' => $update]);
DI::logger()->debug('Get user contact', ['id' => $cid, 'uid' => $uid, 'update' => $update]);
} else {
Logger::debug('Get public contact', ['id' => $cid, 'uid' => $uid, 'update' => $update]);
DI::logger()->debug('Get public contact', ['id' => $cid, 'uid' => $uid, 'update' => $update]);
}
if (!empty($avatar)) {
@ -1156,13 +1175,13 @@ function tumblr_get_contact_fields(stdClass $blog, int $uid, bool $update): arra
];
if (!$update) {
Logger::debug('Got contact fields', ['uid' => $uid, 'url' => $fields['url']]);
DI::logger()->debug('Got contact fields', ['uid' => $uid, 'url' => $fields['url']]);
return $fields;
}
$info = tumblr_get($uid, 'blog/' . $blog->uuid . '/info');
if ($info->meta->status > 399) {
Logger::notice('Error fetching blog info', ['meta' => $info->meta, 'response' => $info->response, 'errors' => $info->errors]);
DI::logger()->notice('Error fetching blog info', ['meta' => $info->meta, 'response' => $info->response, 'errors' => $info->errors]);
return $fields;
}
Item::incrementInbound(Protocol::TUMBLR);
@ -1184,7 +1203,7 @@ function tumblr_get_contact_fields(stdClass $blog, int $uid, bool $update): arra
$fields['header'] = $info->response->blog->theme->header_image_focused;
Logger::debug('Got updated contact fields', ['uid' => $uid, 'url' => $fields['url']]);
DI::logger()->debug('Got updated contact fields', ['uid' => $uid, 'url' => $fields['url']]);
return $fields;
}
@ -1226,7 +1245,7 @@ function tumblr_get_blogs(int $uid): array
{
$userinfo = tumblr_get($uid, 'user/info');
if ($userinfo->meta->status > 399) {
Logger::notice('Error fetching blogs', ['meta' => $userinfo->meta, 'response' => $userinfo->response, 'errors' => $userinfo->errors]);
DI::logger()->notice('Error fetching blogs', ['meta' => $userinfo->meta, 'response' => $userinfo->response, 'errors' => $userinfo->errors]);
return [];
}
@ -1282,15 +1301,15 @@ function tumblr_get_contact_by_url(string $url, int $uid): ?array
return null;
}
Logger::debug('Update Tumblr blog data', ['url' => $url, 'blog' => $blog, 'uid' => $uid]);
DI::logger()->debug('Update Tumblr blog data', ['url' => $url, 'blog' => $blog, 'uid' => $uid]);
$info = tumblr_get($uid, 'blog/' . $blog . '/info');
if ($info->meta->status > 399) {
Logger::notice('Error fetching blog info', ['meta' => $info->meta, 'response' => $info->response, 'errors' => $info->errors, 'blog' => $blog, 'uid' => $uid]);
DI::logger()->notice('Error fetching blog info', ['meta' => $info->meta, 'response' => $info->response, 'errors' => $info->errors, 'blog' => $blog, 'uid' => $uid]);
return null;
}
Logger::debug('Got data', ['blog' => $blog, 'meta' => $info->meta]);
DI::logger()->debug('Got data', ['blog' => $blog, 'meta' => $info->meta]);
Item::incrementInbound(Protocol::TUMBLR);
$baseurl = 'https://tumblr.com';
@ -1419,7 +1438,7 @@ function tumblr_get_token(int $uid, string $code = ''): string
$refresh_token = DI::pConfig()->get($uid, 'tumblr', 'refresh_token');
if (empty($code) && !empty($access_token) && ($expires_at > (time()))) {
Logger::debug('Got token', ['uid' => $uid, 'expires_at' => date('c', $expires_at)]);
DI::logger()->debug('Got token', ['uid' => $uid, 'expires_at' => date('c', $expires_at)]);
return $access_token;
}
@ -1431,11 +1450,11 @@ function tumblr_get_token(int $uid, string $code = ''): string
if (empty($refresh_token) && empty($code)) {
$result = tumblr_exchange_token($uid);
if (empty($result->refresh_token)) {
Logger::info('Invalid result while exchanging token', ['uid' => $uid]);
DI::logger()->info('Invalid result while exchanging token', ['uid' => $uid]);
return '';
}
$expires_at = time() + $result->expires_in;
Logger::debug('Updated token from OAuth1 to OAuth2', ['uid' => $uid, 'expires_at' => date('c', $expires_at)]);
DI::logger()->debug('Updated token from OAuth1 to OAuth2', ['uid' => $uid, 'expires_at' => date('c', $expires_at)]);
} else {
if (!empty($code)) {
$parameters['code'] = $code;
@ -1447,18 +1466,18 @@ function tumblr_get_token(int $uid, string $code = ''): string
$curlResult = DI::httpClient()->post('https://api.tumblr.com/v2/oauth2/token', $parameters);
if (!$curlResult->isSuccess()) {
Logger::info('Error fetching token', ['uid' => $uid, 'code' => $code, 'result' => $curlResult->getBodyString(), 'parameters' => $parameters]);
DI::logger()->info('Error fetching token', ['uid' => $uid, 'code' => $code, 'result' => $curlResult->getBodyString(), 'parameters' => $parameters]);
return '';
}
$result = json_decode($curlResult->getBodyString());
if (empty($result)) {
Logger::info('Invalid result when updating token', ['uid' => $uid]);
DI::logger()->info('Invalid result when updating token', ['uid' => $uid]);
return '';
}
$expires_at = time() + $result->expires_in;
Logger::debug('Renewed token', ['uid' => $uid, 'expires_at' => date('c', $expires_at)]);
DI::logger()->debug('Renewed token', ['uid' => $uid, 'expires_at' => date('c', $expires_at)]);
}
DI::pConfig()->set($uid, 'tumblr', 'access_token', $result->access_token);
@ -1502,7 +1521,7 @@ function tumblr_exchange_token(int $uid): stdClass
$response = $client->post('oauth2/exchange', ['auth' => 'oauth']);
return json_decode($response->getBody()->getContents());
} catch (RequestException $exception) {
Logger::notice('Exchange failed', ['code' => $exception->getCode(), 'message' => $exception->getMessage()]);
DI::logger()->notice('Exchange failed', ['code' => $exception->getCode(), 'message' => $exception->getMessage()]);
return new stdClass;
}
}

View file

@ -38,7 +38,6 @@
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\Plaintext;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Core\Worker;
use Friendica\DI;
@ -67,7 +66,7 @@ function twitter_install()
function twitter_load_config(ConfigFileManager $loader)
{
DI::app()->getConfigCache()->load($loader->loadAddonConfig('twitter'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('twitter'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function twitter_jot_nets(array &$jotnets_fields)
@ -215,9 +214,13 @@ function twitter_post_hook(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
$b['body'] = Post\Media::addAttachmentsToBody($b['uri-id'], DI::contentItem()->addSharedPost($b));
Logger::notice('twitter post invoked', ['id' => $b['id'], 'guid' => $b['guid']]);
DI::logger()->notice('twitter post invoked', ['id' => $b['id'], 'guid' => $b['guid']]);
DI::pConfig()->load($b['uid'], 'twitter');
@ -227,17 +230,17 @@ function twitter_post_hook(array &$b)
$access_secret = DI::pConfig()->get($b['uid'], 'twitter', 'access_secret');
if (empty($api_key) || empty($api_secret) || empty($access_token) || empty($access_secret)) {
Logger::info('Missing keys, secrets or tokens.');
DI::logger()->info('Missing keys, secrets or tokens.');
return;
}
$msgarr = Plaintext::getPost($b, 280, true, BBCode::TWITTER);
Logger::debug('Got plaintext', ['id' => $b['id'], 'message' => $msgarr]);
DI::logger()->debug('Got plaintext', ['id' => $b['id'], 'message' => $msgarr]);
$media_ids = [];
if (!empty($msgarr['images']) || !empty($msgarr['remote_images'])) {
Logger::info('Got images', ['id' => $b['id'], 'images' => $msgarr['images'] ?? []]);
DI::logger()->info('Got images', ['id' => $b['id'], 'images' => $msgarr['images'] ?? []]);
$retrial = Worker::getRetrial();
if ($retrial > 4) {
@ -250,7 +253,7 @@ function twitter_post_hook(array &$b)
try {
$media_ids[] = twitter_upload_image($b['uid'], $image, $retrial);
} catch (RequestException $exception) {
Logger::warning('Error while uploading image', ['image' => $image, 'code' => $exception->getCode(), 'message' => $exception->getMessage()]);
DI::logger()->warning('Error while uploading image', ['image' => $image, 'code' => $exception->getCode(), 'message' => $exception->getMessage()]);
Worker::defer();
return;
}
@ -259,13 +262,13 @@ function twitter_post_hook(array &$b)
$in_reply_to_tweet_id = 0;
Logger::debug('Post message', ['id' => $b['id'], 'parts' => count($msgarr['parts'])]);
DI::logger()->debug('Post message', ['id' => $b['id'], 'parts' => count($msgarr['parts'])]);
foreach ($msgarr['parts'] as $key => $part) {
try {
$id = twitter_post_status($b['uid'], $part, $media_ids, $in_reply_to_tweet_id);
Logger::info('twitter_post send', ['part' => $key, 'id' => $b['id'], 'result' => $id]);
DI::logger()->info('twitter_post send', ['part' => $key, 'id' => $b['id'], 'result' => $id]);
} catch (RequestException $exception) {
Logger::warning('Error while posting message', ['part' => $key, 'id' => $b['id'], 'code' => $exception->getCode(), 'message' => $exception->getMessage()]);
DI::logger()->warning('Error while posting message', ['part' => $key, 'id' => $b['id'], 'code' => $exception->getCode(), 'message' => $exception->getMessage()]);
$status = [
'code' => $exception->getCode(),
'reason' => $exception->getResponse()->getReasonPhrase(),
@ -319,9 +322,9 @@ function twitter_upload_image(int $uid, array $image, int $retrial)
$picturedata = $picture->asString();
$new_size = strlen($picturedata);
Logger::info('Uploading', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size, 'image' => $image]);
DI::logger()->info('Uploading', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size, 'image' => $image]);
$media = twitter_post($uid, 'https://upload.twitter.com/1.1/media/upload.json', 'form_params', ['media' => base64_encode($picturedata)]);
Logger::info('Uploading done', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size, 'image' => $image]);
DI::logger()->info('Uploading done', ['uid' => $uid, 'retrial' => $retrial, 'height' => $new_height, 'width' => $new_width, 'size' => $new_size, 'orig-height' => $height, 'orig-width' => $width, 'orig-size' => $size, 'image' => $image]);
if (isset($media->media_id_string)) {
$media_id = $media->media_id_string;
@ -334,10 +337,10 @@ function twitter_upload_image(int $uid, array $image, int $retrial)
]
];
$ret = twitter_post($uid, 'https://upload.twitter.com/1.1/media/metadata/create.json', 'json', $data);
Logger::info('Metadata create', ['uid' => $uid, 'data' => $data, 'return' => $ret]);
DI::logger()->info('Metadata create', ['uid' => $uid, 'data' => $data, 'return' => $ret]);
}
} else {
Logger::error('Failed upload', ['uid' => $uid, 'size' => strlen($picturedata), 'image' => $image['url'], 'return' => $media]);
DI::logger()->error('Failed upload', ['uid' => $uid, 'size' => strlen($picturedata), 'image' => $image['url'], 'return' => $media]);
throw new Exception('Failed upload of ' . $image['url']);
}
@ -373,7 +376,7 @@ function twitter_post(int $uid, string $url, string $type, array $data): stdClas
DI::pConfig()->set($uid, 'twitter', 'last_status', $status);
$content = json_decode($body) ?? new stdClass;
Logger::debug('Success', ['content' => $content]);
DI::logger()->debug('Success', ['content' => $content]);
return $content;
}
@ -402,7 +405,7 @@ function twitter_test_connection(int $uid)
'content' => $response->getBody()->getContents()
];
DI::pConfig()->set(1, 'twitter', 'last_status', $status);
Logger::info('Test successful', ['uid' => $uid]);
DI::logger()->info('Test successful', ['uid' => $uid]);
} catch (RequestException $exception) {
$status = [
'code' => $exception->getCode(),
@ -410,6 +413,6 @@ function twitter_test_connection(int $uid)
'content' => $exception->getMessage()
];
DI::pConfig()->set(1, 'twitter', 'last_status', $status);
Logger::info('Test failed', ['uid' => $uid]);
DI::logger()->info('Test failed', ['uid' => $uid]);
}
}

View file

@ -7,7 +7,6 @@
* Author: Matthias Ebers <https://loma.ml/profile/one>
*/
use Friendica\App;
use Friendica\Content\Smilies;
use Friendica\Core\Hook;

View file

@ -7,7 +7,6 @@
*
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;

View file

@ -52,7 +52,7 @@ class WebDavConfig implements ICanConfigureStorage
$this->config = $config;
$this->client = $client;
$this->authOptions = null;
$this->authOptions = [];
if (!empty($this->config->get('webdav', 'username'))) {
$this->authOptions = [

View file

@ -8,11 +8,10 @@
use Friendica\Addon\webdav_storage\src\WebDav;
use Friendica\Addon\webdav_storage\src\WebDavConfig;
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\DI;
function webdav_storage_install($a)
function webdav_storage_install()
{
Hook::register('storage_instance' , __FILE__, 'webdav_storage_instance');
Hook::register('storage_config' , __FILE__, 'webdav_storage_config');

View file

@ -7,7 +7,6 @@
* Author: Tobias Diekershoff <https://f.diekershoff.de/profile/tobias>
*/
use Friendica\App;
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;

View file

@ -9,7 +9,6 @@
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
use Friendica\Core\Hook;
use Friendica\Core\Logger;
use Friendica\Core\Renderer;
use Friendica\Database\DBA;
use Friendica\DI;
@ -156,6 +155,10 @@ function wppost_send(array &$b)
return;
}
if (Item::isGroupPost($b['uri-id'])) {
return;
}
if ($b['gravity'] != Item::GRAVITY_PARENT) {
return;
}
@ -257,11 +260,13 @@ function wppost_send(array &$b)
EOT;
Logger::debug('wppost: data: ' . $xml);
DI::logger()->debug('wppost: data: ' . $xml);
$x = '';
if ($wp_blog !== 'test') {
$x = DI::httpClient()->post($wp_blog, $xml)->getBodyString();
}
Logger::info('posted to wordpress: ' . (($x) ? $x : ''));
DI::logger()->info('posted to wordpress: ' . $x);
}
}

202
xmppchat/README.md Normal file
View file

@ -0,0 +1,202 @@
# XMPP Chat Addon for Friendica
Embeds a fully-featured XMPP webchat client (Converse.js) into your Friendica instance.
## Features
- **Full XMPP chat UI** via Converse.js
- **Multi-User Chat (MUC)** support
- **Message Archive Management** (XEP-0313) for chat history
- **Stream Management** (XEP-0198) for reliable connections
- **Optional OMEMO** end-to-end encryption
- **WebSocket & BOSH** transport support
- Overlayed chat widget (minimizable)
- Desktop notifications
- File sharing (when XMPP server supports XEP-0363)
## Requirements
### XMPP Server
You need an XMPP server with:
- **WebSocket** support (recommended) or **BOSH** (HTTP binding)
- Enabled modules:
- `mod_websocket` or `mod_bosh`
- `mod_mam` (Message Archive Management)
- `mod_smacks` (Stream Management)
- `mod_carbons` (Message Carbons for multi-device sync)
- `mod_http_upload` (for file sharing)
- Optional: `mod_omemo` (for OMEMO encryption)
**Example for Prosody** (`/etc/prosody/prosody.cfg.lua`):
```lua
modules_enabled = {
"websocket";
"bosh";
"mam";
"smacks";
"carbons";
"http_upload";
"csi"; -- Client State Indication
"vcard4";
"bookmarks";
}
-- WebSocket configuration
consider_websocket_secure = true
cross_domain_websocket = true
-- HTTP upload limits
http_upload_file_size_limit = 10485760 -- 10 MB
http_upload_expire_after = 60 * 60 * 24 * 7 -- 1 week
```
Ensure your firewall allows:
- Port 5281 (WebSocket/BOSH over HTTPS)
- Port 5222 (XMPP client connections)
### DNS/SSL
For WebSocket over TLS (wss://), you need:
- Valid SSL certificate for your XMPP domain
- DNS records pointing to your XMPP server
## Security Considerations
### Auto-Login
The `auto_login` option is **disabled by default** and requires:
- XMPP usernames matching Friendica usernames
- Separate password management (do NOT reuse Friendica passwords!)
- Consider using:
- **SASL EXTERNAL** with client certificates
- **OAuth tokens** via `mod_auth_external`
- **Anonymous login** for public chat rooms
### User Passwords
**Custom XMPP credentials** are stored per-user in the database:
- Passwords are base64-encoded (basic obfuscation)
- Users should use **separate XMPP passwords**, not their Friendica password
### OMEMO Encryption
To enable end-to-end encryption:
1. Set `enable_omemo => true` in config (or via Admin UI)
2. Ensure Converse.js OMEMO plugin is loaded (CDN version 10.1.6+ includes it)
3. Users must verify device fingerprints manually in the chat UI
4. First connection with OMEMO may take longer due to key generation
5. OMEMO requires:
- Modern browser with WebCrypto API support
- Server support for PEP (XEP-0163) and device list storage
- All chat participants using OMEMO-capable clients
**OMEMO Features in this addon:**
- Automatic device key management
- Multi-device synchronization
- Encrypted message storage (MAM)
- Trust-on-first-use (TOFU) model
- Manual fingerprint verification UI
### Content Security Policy
If you use strict CSP headers, whitelist:
- `cdn.conversejs.org` (for Converse.js assets)
- Your XMPP server domain (for WebSocket/BOSH connections)
## Usage
### For Users
#### Using Your Own XMPP Account
1. Go to **Settings → Addon Settings → XMPP Chat**
2. Enable "Use Custom XMPP Account"
3. Enter your XMPP address (JID), e.g., `user@jabber.org` or `myname@conversations.im`
4. Enter your XMPP password
5. Save settings
6. Reload any page - you'll be automatically logged into the chat
**You can use any XMPP account from any server!** No need to create an account on the Friendica instance's XMPP server.
#### Using the Chat Widget
1. Click the chat icon in bottom-right corner
2. If you haven't configured custom credentials, enter XMPP username@domain and password
3. Chat with contacts or join group rooms (MUCs)
4. Chat state persists across page navigation
### Joining Group Chats
To join a multi-user chat room:
1. Click the "+" icon in Converse.js
2. Select "Join a chat room"
3. Enter room JID: `room@conference.example.org`
4. Choose a nickname
### Managing Bookmarks
Converse.js supports XEP-0048 bookmarks:
- Bookmarked rooms appear in your sidebar
- Auto-join on login (optional)
## Troubleshooting
### Chat widget not appearing
- Check browser console for errors
- Verify `enabled => true` in config
- Ensure `websocket_url` or `bosh_url` is set
- Check Friendica logs: `tail -f friendica.log | grep xmppchat`
### Cannot connect to XMPP server
- Test WebSocket endpoint manually:
```bash
wscat -c wss://xmpp.example.org:5281/xmpp-websocket
```
- Verify firewall rules allow port 5281
- Check Prosody logs: `tail -f /var/log/prosody/prosody.log`
- Ensure SSL certificate is valid
### Messages not loading from history
- Verify `mod_mam` is enabled on server
- Check `enable_mam => true` in Friendica config
- MAM requires XMPP server storage backend (SQL recommended)
### OMEMO not working
- Ensure all participants have OMEMO-capable clients
- Verify device trust (fingerprint verification)
- Check for conflicting security plugins
## Performance Tips
- Use **WebSocket** (faster than BOSH)
- Enable **Stream Management** (`mod_smacks`)
- Limit **MAM page size** (default: 50 messages)
- Use **Client State Indication** (`mod_csi`) to reduce traffic when inactive
## Compatibility
- **XMPP Servers**: Prosody, ejabberd, Openfire
- **Browsers**: Modern browsers with WebSocket support
## License
Converse.js is licensed under MPL 2.0.
## Documentation
- Converse.js Documentation: https://conversejs.org/docs/html/
- XMPP Standards: https://xmpp.org/extensions/

View file

@ -0,0 +1,36 @@
{{*
* XMPP Chat Admin Configuration Template
* SPDX-License-Identifier: AGPL-3.0-or-later
*}}
<p>
{{$page_intro}}
</p>
<h4>{{$connection_title}}</h4>
{{include file="field_input.tpl" field=$websocket_url}}
{{include file="field_input.tpl" field=$bosh_url}}
{{include file="field_input.tpl" field=$domain}}
<h4>{{$auth_title}}</h4>
{{include file="field_checkbox.tpl" field=$auto_login}}
{{include file="field_checkbox.tpl" field=$allow_anonymous}}
<h4>{{$features_title}}</h4>
{{include file="field_checkbox.tpl" field=$enable_mam}}
{{include file="field_checkbox.tpl" field=$enable_smacks}}
{{include file="field_checkbox.tpl" field=$enable_omemo}}
<h4>{{$chatrooms_title}}</h4>
{{include file="field_input.tpl" field=$default_muc}}
<p class="help-block">
<strong>{{$help_omemo}}:</strong> {{$help_omemo_text}}
<br>
<strong>{{$help_muc}}:</strong> {{$help_muc_text}}
<br>
<strong>{{$help_anon}}:</strong> {{$help_anon_text}}
</p>
<div class="submit">
<input type="submit" name="page_site" value="{{$submit}}" />
</div>

View file

@ -0,0 +1,34 @@
{{*
* XMPP Chat User Settings Template
* SPDX-License-Identifier: AGPL-3.0-or-later
*}}
<p class="info-message">
{{$info}}
</p>
{{include file="field_checkbox.tpl" field=$user_enabled}}
{{include file="field_checkbox.tpl" field=$use_custom}}
<div id="xmppchat-custom-fields" {{if !$use_custom.2}}style="display:none;"{{/if}}>
{{include file="field_input.tpl" field=$custom_jid}}
{{include file="field_password.tpl" field=$custom_password}}
{{include file="field_input.tpl" field=$custom_websocket}}
{{include file="field_input.tpl" field=$custom_bosh}}
<p class="settings-help-text">
<strong>{{$security_title}}:</strong> {{$security_text}}
</p>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var checkbox = document.getElementById('id_use_custom');
var customFields = document.getElementById('xmppchat-custom-fields');
if (checkbox && customFields) {
checkbox.addEventListener('change', function() {
customFields.style.display = this.checked ? 'block' : 'none';
});
}
});
</script>

View file

@ -0,0 +1,61 @@
{{*
* XMPP Chat Widget Template (Converse.js)
* SPDX-License-Identifier: AGPL-3.0-or-later
*}}
<link rel="stylesheet" href="addon/xmppchat/vendor/converse.min.css">
<style>
.media {
display: block;
}
</style>
<div id="conversejs-container"></div>
<script src="addon/xmppchat/vendor/converse.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var converseConfig = {
{{if $websocket_url}}
websocket_url: '{{$websocket_url}}',
{{/if}}
{{if $bosh_url}}
bosh_service_url: '{{$bosh_url}}',
{{/if}}
view_mode: 'overlayed',
{{if $allow_anonymous}}
authentication: 'anonymous',
auto_login: false,
{{else if $auto_login && $jid}}
authentication: 'login',
auto_login: true,
jid: '{{$jid}}',
{{if $password}}
password: '{{$password}}',
{{/if}}
{{else}}
authentication: 'login',
auto_login: false,
{{/if}}
show_controlbox_by_default: false,
enable_mam: {{$enable_mam}},
enable_smacks: {{$enable_smacks}},
message_archiving: 'always',
muc_respect_autojoin: true,
{{if $enable_omemo}}
whitelisted_plugins: ['converse-omemo'],
trusted: true,
allow_message_corrections: 'all',
{{/if}}
{{if $default_muc}}
auto_join_rooms: [
{ jid: '{{$default_muc}}', nick: '{{$jid}}' }
],
{{/if}}
theme: 'concord',
allow_non_roster_messaging: true,
show_desktop_notifications: true,
play_sounds: false,
notification_icon: '/images/friendica.svg'
};
converse.initialize(converseConfig);
});
</script>

50
xmppchat/vendor/converse.min.css vendored Normal file

File diff suppressed because one or more lines are too long

10
xmppchat/vendor/converse.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,47 @@
<?php
/**
* XMPP Chat Addon Configuration
*
* Copy this file to config/xmppchat.config.php and adjust the values
*/
return [
'xmppchat' => [
// Enable/disable the chat widget
'enabled' => false,
// XMPP server WebSocket URL (preferred)
// Example: 'wss://xmpp.example.org:5281/xmpp-websocket'
'websocket_url' => '',
// XMPP server BOSH URL (fallback)
// Example: 'https://xmpp.example.org/http-bind'
'bosh_url' => '',
// XMPP domain
// Example: 'example.org'
'domain' => '',
// Attempt auto-login with Friendica credentials
// WARNING: This requires matching XMPP accounts and secure password handling
// Consider using SASL EXTERNAL or OAuth tokens instead
'auto_login' => false,
// Allow anonymous login (users can join without XMPP account)
// Requires server support for anonymous authentication
'allow_anonymous' => false,
// Enable Message Archive Management (XEP-0313)
'enable_mam' => true,
// Enable Stream Management (XEP-0198) for connection reliability
'enable_smacks' => true,
// Enable OMEMO encryption (XEP-0384) for end-to-end encryption
'enable_omemo' => false,
// Default chat room to auto-join on login
// Example: 'lobby@conference.example.org'
'default_muc' => '',
],
];

210
xmppchat/xmppchat.php Normal file
View file

@ -0,0 +1,210 @@
<?php
/**
* Name: XMPP Chat
* Description: Embeds Converse.js XMPP webchat client into Friendica
* Version: 1.0
* Author: Friendica Community
* License: AGPL-3.0-or-later
*/
use Friendica\Core\Hook;
use Friendica\Core\Renderer;
use Friendica\DI;
use Friendica\Core\Config\Util\ConfigFileManager;
function xmppchat_install()
{
Hook::register('load_config', 'addon/xmppchat/xmppchat.php', 'xmppchat_load_config');
Hook::register('footer', 'addon/xmppchat/xmppchat.php', 'xmppchat_footer');
Hook::register('addon_settings', 'addon/xmppchat/xmppchat.php', 'xmppchat_addon_settings');
Hook::register('addon_settings_post', 'addon/xmppchat/xmppchat.php', 'xmppchat_addon_settings_post');
DI::logger()->notice("installed xmppchat addon");
}
function xmppchat_addon_admin_post()
{
DI::config()->set('xmppchat', 'websocket_url', trim($_POST['websocket_url'] ?? ''));
DI::config()->set('xmppchat', 'bosh_url', trim($_POST['bosh_url'] ?? ''));
DI::config()->set('xmppchat', 'domain', trim($_POST['domain'] ?? ''));
DI::config()->set('xmppchat', 'auto_login', !empty($_POST['auto_login']));
DI::config()->set('xmppchat', 'enable_mam', !empty($_POST['enable_mam']));
DI::config()->set('xmppchat', 'enable_smacks', !empty($_POST['enable_smacks']));
DI::config()->set('xmppchat', 'enable_omemo', !empty($_POST['enable_omemo']));
DI::config()->set('xmppchat', 'allow_anonymous', !empty($_POST['allow_anonymous']));
DI::config()->set('xmppchat', 'default_muc', trim($_POST['default_muc'] ?? ''));
}
function xmppchat_addon_admin(string &$o)
{
$t = Renderer::getMarkupTemplate('admin.tpl', 'addon/xmppchat/');
$o = Renderer::replaceMacros($t, [
'$page_intro' => DI::l10n()->t('Configure the Converse.js XMPP webchat integration. Requires an XMPP server with WebSocket or BOSH support.'),
'$connection_title' => DI::l10n()->t('Connection Settings'),
'$auth_title' => DI::l10n()->t('Authentication'),
'$features_title' => DI::l10n()->t('Features'),
'$chatrooms_title' => DI::l10n()->t('Chat Rooms'),
'$help_omemo' => DI::l10n()->t('OMEMO Encryption'),
'$help_omemo_text' => DI::l10n()->t('Requires users to verify device fingerprints. May increase initial connection time.'),
'$help_muc' => DI::l10n()->t('Default Chat Room'),
'$help_muc_text' => DI::l10n()->t('Users will automatically join this room on login. Format: roomname@conference.example.org'),
'$help_anon' => DI::l10n()->t('Anonymous Login'),
'$help_anon_text' => DI::l10n()->t('Allows users to join chat rooms without XMPP accounts. Requires server support for anonymous authentication.'),
'$submit' => DI::l10n()->t('Save Settings'),
'$websocket_url' => ['websocket_url', DI::l10n()->t('WebSocket URL'), DI::config()->get('xmppchat', 'websocket_url'), DI::l10n()->t('XMPP WebSocket endpoint (e.g., wss://xmpp.example.org:5281/xmpp-websocket)')],
'$bosh_url' => ['bosh_url', DI::l10n()->t('BOSH URL'), DI::config()->get('xmppchat', 'bosh_url'), DI::l10n()->t('XMPP BOSH endpoint for fallback (e.g., https://xmpp.example.org/http-bind)')],
'$domain' => ['domain', DI::l10n()->t('XMPP Domain'), DI::config()->get('xmppchat', 'domain'), DI::l10n()->t('XMPP server domain (e.g., example.org)')],
'$auto_login' => ['auto_login', DI::l10n()->t('Auto-Login'), DI::config()->get('xmppchat', 'auto_login', false), DI::l10n()->t('Attempt automatic login using Friendica username (requires matching XMPP accounts)')],
'$enable_mam' => ['enable_mam', DI::l10n()->t('Enable Message Archive'), DI::config()->get('xmppchat', 'enable_mam', true), DI::l10n()->t('Enable XEP-0313 Message Archive Management for chat history')],
'$enable_smacks' => ['enable_smacks', DI::l10n()->t('Enable Stream Management'), DI::config()->get('xmppchat', 'enable_smacks', true), DI::l10n()->t('Enable XEP-0198 Stream Management for reliable connections')],
'$enable_omemo' => ['enable_omemo', DI::l10n()->t('Enable OMEMO Encryption'), DI::config()->get('xmppchat', 'enable_omemo', false), DI::l10n()->t('Enable XEP-0384 OMEMO end-to-end encryption')],
'$allow_anonymous' => ['allow_anonymous', DI::l10n()->t('Allow Anonymous Login'), DI::config()->get('xmppchat', 'allow_anonymous', false), DI::l10n()->t('Allow users to join chat rooms without authentication')],
'$default_muc' => ['default_muc', DI::l10n()->t('Default Chat Room'), DI::config()->get('xmppchat', 'default_muc'), DI::l10n()->t('Auto-join this MUC room on login (e.g., lobby@conference.example.org)')],
]);
}
function xmppchat_addon_settings(array &$data)
{
if (!DI::userSession()->getLocalUserId()) {
return;
}
$uid = DI::userSession()->getLocalUserId();
$custom_jid = DI::pConfig()->get($uid, 'xmppchat', 'custom_jid');
$custom_password = DI::pConfig()->get($uid, 'xmppchat', 'custom_password');
$use_custom = DI::pConfig()->get($uid, 'xmppchat', 'use_custom', false);
$user_enabled = DI::pConfig()->get($uid, 'xmppchat', 'enabled', DI::config()->get('xmppchat', 'enabled', false));
$custom_websocket = DI::pConfig()->get($uid, 'xmppchat', 'custom_websocket_url');
$custom_bosh = DI::pConfig()->get($uid, 'xmppchat', 'custom_bosh_url');
$t = Renderer::getMarkupTemplate('settings.tpl', 'addon/xmppchat/');
$html = Renderer::replaceMacros($t, [
'$title' => DI::l10n()->t('XMPP Chat Settings'),
'$submit' => DI::l10n()->t('Save Settings'),
'$info' => DI::l10n()->t('You can connect with any XMPP account from any server. Leave password empty to keep the existing one.'),
'$security_title' => DI::l10n()->t('Security Note'),
'$security_text' => DI::l10n()->t('Your password is stored encrypted on the server. We recommend using a separate password for XMPP.'),
'$user_enabled' => ['enabled', DI::l10n()->t('Enable XMPP Chat'), $user_enabled, DI::l10n()->t('Show the chat widget for your account')],
'$use_custom' => ['use_custom', DI::l10n()->t('Use Custom XMPP Account'), $use_custom, DI::l10n()->t('Enable to use your own XMPP account from any server')],
'$custom_jid' => ['custom_jid', DI::l10n()->t('XMPP Address (JID)'), $custom_jid, DI::l10n()->t('Your full XMPP address (e.g., user@example.org or user@other-server.com)')],
'$custom_password' => ['custom_password', DI::l10n()->t('XMPP Password'), '', DI::l10n()->t('Your XMPP account password (stored encrypted)')],
'$custom_websocket' => ['custom_websocket_url', DI::l10n()->t('WebSocket URL'), $custom_websocket, DI::l10n()->t('XMPP WebSocket endpoint for your account (e.g., wss://xmpp.example.org:5281/xmpp-websocket)')],
'$custom_bosh' => ['custom_bosh_url', DI::l10n()->t('BOSH URL'), $custom_bosh, DI::l10n()->t('XMPP BOSH endpoint for your account (e.g., https://xmpp.example.org/http-bind)')],
]);
$data = [
'addon' => 'xmppchat',
'title' => DI::l10n()->t('XMPP Chat'),
'html' => $html,
];
}
function xmppchat_addon_settings_post(array &$b)
{
if (!DI::userSession()->getLocalUserId()) {
return;
}
$uid = DI::userSession()->getLocalUserId();
if (!empty($b['xmppchat-submit'])) {
DI::pConfig()->set($uid, 'xmppchat', 'enabled', !empty($b['enabled']));
DI::pConfig()->set($uid, 'xmppchat', 'use_custom', !empty($b['use_custom']));
DI::pConfig()->set($uid, 'xmppchat', 'custom_jid', trim($b['custom_jid'] ?? ''));
DI::pConfig()->set($uid, 'xmppchat', 'custom_websocket_url', trim($b['custom_websocket_url'] ?? ''));
DI::pConfig()->set($uid, 'xmppchat', 'custom_bosh_url', trim($b['custom_bosh_url'] ?? ''));
// Only update password if provided
if (!empty($b['custom_password'])) {
// Note: In production, use proper encryption (e.g., openssl_encrypt)
// For now, store base64-encoded (NOT SECURE - just for demonstration)
$encrypted_password = base64_encode($b['custom_password']);
DI::pConfig()->set($uid, 'xmppchat', 'custom_password', $encrypted_password);
}
}
}
function xmppchat_load_config(ConfigFileManager $loader)
{
DI::appHelper()->getConfigCache()->load($loader->loadAddonConfig('xmppchat'), \Friendica\Core\Config\ValueObject\Cache::SOURCE_STATIC);
}
function xmppchat_footer(string &$body)
{
DI::logger()->debug("xmppchat: footer hook called");
// Only show the widget for authenticated users who enabled it in their settings
if (!DI::userSession()->isAuthenticated()) {
return;
}
$uid = DI::userSession()->getLocalUserId();
$user_enabled = DI::pConfig()->get($uid, 'xmppchat', 'enabled', false);
if (!$user_enabled) {
return;
}
// Load global features/settings
$domain = DI::config()->get('xmppchat', 'domain');
$auto_login = DI::config()->get('xmppchat', 'auto_login', false);
$enable_mam = DI::config()->get('xmppchat', 'enable_mam', true);
$enable_smacks = DI::config()->get('xmppchat', 'enable_smacks', true);
$enable_omemo = DI::config()->get('xmppchat', 'enable_omemo', false);
$allow_anonymous = DI::config()->get('xmppchat', 'allow_anonymous', false);
$default_muc = DI::config()->get('xmppchat', 'default_muc');
// Determine whether to use custom user endpoints or global ones
$use_custom = DI::pConfig()->get($uid, 'xmppchat', 'use_custom', false);
$jid = '';
$password = '';
$websocket_url = null;
$bosh_url = null;
if ($use_custom) {
// User explicitly chose a custom account: use their endpoints and credentials only
$websocket_url = DI::pConfig()->get($uid, 'xmppchat', 'custom_websocket_url');
$bosh_url = DI::pConfig()->get($uid, 'xmppchat', 'custom_bosh_url');
$jid = DI::pConfig()->get($uid, 'xmppchat', 'custom_jid');
$encrypted_password = DI::pConfig()->get($uid, 'xmppchat', 'custom_password');
if ($encrypted_password) {
$password = base64_decode($encrypted_password);
}
// If the user selected a custom account but didn't provide endpoints, don't attempt to connect
if (empty($websocket_url) && empty($bosh_url)) {
DI::logger()->warning("xmppchat: user $uid selected custom XMPP account but no websocket or bosh URL provided");
return;
}
} else {
// Use global endpoints
$websocket_url = DI::config()->get('xmppchat', 'websocket_url');
$bosh_url = DI::config()->get('xmppchat', 'bosh_url');
if (empty($websocket_url) && empty($bosh_url)) {
DI::logger()->warning("xmppchat: No websocket_url or bosh_url configured globally");
return;
}
// Auto-login using Friendica username if configured
if ($auto_login) {
$nickname = DI::session()->get('nickname');
if ($nickname && $domain) {
$jid = $nickname . '@' . $domain;
}
}
}
$tpl = Renderer::getMarkupTemplate('xmppchat.tpl', 'addon/xmppchat/');
$chat_html = Renderer::replaceMacros($tpl, [
'$websocket_url' => $websocket_url,
'$bosh_url' => $bosh_url,
'$jid' => $jid,
'$password' => $password,
'$auto_login' => $auto_login,
'$allow_anonymous' => $allow_anonymous,
'$enable_mam' => $enable_mam ? 'true' : 'false',
'$enable_smacks' => $enable_smacks ? 'true' : 'false',
'$enable_omemo' => $enable_omemo ? 'true' : 'false',
'$default_muc' => $default_muc,
]);
$body .= $chat_html;
}