summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Prodromou <evan@status.net>2009-10-02 15:27:55 -0400
committerEvan Prodromou <evan@status.net>2009-10-02 15:27:55 -0400
commitb3b3af9a2eff10c272bb213eccd3dd3060bc5830 (patch)
treeff0ae9108bcb085015a8e9f286963ad9fe58c13c
parent51ac34e80c5a99008b1a945b2c00b6dbfdde1529 (diff)
parent5309910b9b4dd2533ff5b2190f90bf415fd20113 (diff)
Merge branch '0.8.x' into deleteuser
-rw-r--r--.gitignore3
-rw-r--r--EVENTS.txt20
-rw-r--r--README487
-rw-r--r--actions/accesstoken.php22
-rw-r--r--actions/all.php40
-rw-r--r--actions/allrss.php26
-rw-r--r--actions/api.php73
-rw-r--r--actions/attachment.php30
-rw-r--r--actions/attachment_ajax.php18
-rw-r--r--actions/attachment_thumbnail.php18
-rw-r--r--actions/avatarbynickname.php22
-rw-r--r--actions/avatarsettings.php51
-rw-r--r--actions/block.php22
-rw-r--r--actions/blockedfromgroup.php26
-rw-r--r--actions/confirmaddress.php24
-rw-r--r--actions/conversation.php32
-rw-r--r--actions/deletenotice.php14
-rw-r--r--actions/disfavor.php22
-rw-r--r--actions/doc.php22
-rw-r--r--actions/editgroup.php31
-rw-r--r--actions/emailsettings.php42
-rw-r--r--actions/facebookhome.php6
-rw-r--r--actions/facebookinvite.php6
-rw-r--r--actions/facebooklogin.php6
-rw-r--r--actions/facebookremove.php6
-rw-r--r--actions/facebooksettings.php6
-rw-r--r--actions/favor.php22
-rw-r--r--actions/favorited.php25
-rw-r--r--actions/favoritesrss.php28
-rw-r--r--actions/featured.php22
-rw-r--r--actions/file.php6
-rw-r--r--actions/finishaddopenid.php18
-rw-r--r--actions/finishopenidlogin.php16
-rw-r--r--actions/finishremotesubscribe.php8
-rw-r--r--actions/foaf.php20
-rw-r--r--actions/groupblock.php18
-rw-r--r--actions/groupbyid.php20
-rw-r--r--actions/groupdesignsettings.php22
-rw-r--r--actions/grouplogo.php43
-rw-r--r--actions/groupmembers.php34
-rw-r--r--actions/grouprss.php25
-rw-r--r--actions/groups.php20
-rw-r--r--actions/groupsearch.php31
-rw-r--r--actions/groupunblock.php18
-rw-r--r--actions/imsettings.php24
-rw-r--r--actions/inbox.php18
-rw-r--r--actions/invite.php16
-rw-r--r--actions/joingroup.php18
-rw-r--r--actions/leavegroup.php18
-rw-r--r--actions/login.php38
-rw-r--r--actions/logout.php22
-rw-r--r--actions/makeadmin.php18
-rw-r--r--actions/microsummary.php22
-rw-r--r--actions/newgroup.php20
-rw-r--r--actions/newmessage.php26
-rw-r--r--actions/newnotice.php85
-rw-r--r--actions/noticesearch.php36
-rw-r--r--actions/noticesearchrss.php27
-rw-r--r--actions/nudge.php24
-rw-r--r--actions/oembed.php (renamed from actions/twitapioembed.php)81
-rw-r--r--actions/openidlogin.php16
-rw-r--r--actions/openidsettings.php30
-rw-r--r--actions/opensearch.php24
-rw-r--r--actions/othersettings.php28
-rw-r--r--actions/outbox.php18
-rw-r--r--actions/passwordsettings.php28
-rw-r--r--actions/peoplesearch.php36
-rw-r--r--actions/peopletag.php22
-rw-r--r--actions/postnotice.php6
-rw-r--r--actions/profilesettings.php32
-rw-r--r--actions/public.php56
-rw-r--r--actions/publicrss.php26
-rw-r--r--actions/publictagcloud.php23
-rw-r--r--actions/publicxrds.php22
-rw-r--r--actions/recoverpassword.php6
-rw-r--r--actions/register.php52
-rw-r--r--actions/remotesubscribe.php20
-rw-r--r--actions/replies.php35
-rw-r--r--actions/repliesrss.php9
-rw-r--r--actions/requesttoken.php24
-rw-r--r--actions/showfavorites.php66
-rw-r--r--actions/showgroup.php43
-rw-r--r--actions/showmessage.php18
-rw-r--r--actions/shownotice.php36
-rw-r--r--actions/showstream.php41
-rw-r--r--actions/smssettings.php30
-rw-r--r--actions/subedit.php6
-rw-r--r--actions/subscribe.php6
-rw-r--r--actions/subscribers.php24
-rw-r--r--actions/subscriptions.php44
-rw-r--r--actions/sup.php6
-rw-r--r--actions/tag.php19
-rw-r--r--actions/tagother.php6
-rw-r--r--actions/tagrss.php9
-rw-r--r--actions/twitapiaccount.php6
-rw-r--r--actions/twitapiblocks.php6
-rw-r--r--actions/twitapidirect_messages.php6
-rw-r--r--actions/twitapifavorites.php32
-rw-r--r--actions/twitapifriendships.php12
-rw-r--r--actions/twitapigroups.php253
-rw-r--r--actions/twitapihelp.php6
-rw-r--r--actions/twitapinotifications.php6
-rw-r--r--actions/twitapisearchatom.php20
-rw-r--r--actions/twitapisearchjson.php18
-rw-r--r--actions/twitapistatuses.php29
-rw-r--r--actions/twitapistatusnet.php (renamed from actions/twitapilaconica.php)40
-rw-r--r--actions/twitapitags.php37
-rw-r--r--actions/twitapitrends.php18
-rw-r--r--actions/twitapiusers.php6
-rw-r--r--actions/twitterauthorization.php201
-rw-r--r--actions/twittersettings.php411
-rw-r--r--actions/unblock.php22
-rw-r--r--actions/unsubscribe.php45
-rw-r--r--actions/updateprofile.php8
-rw-r--r--actions/userauthorization.php14
-rw-r--r--actions/userbyid.php22
-rw-r--r--actions/userdesignsettings.php22
-rw-r--r--actions/usergroups.php20
-rw-r--r--actions/userrss.php11
-rw-r--r--actions/xrds.php22
-rw-r--r--classes/Design.php101
-rw-r--r--classes/File.php24
-rw-r--r--classes/File_oembed.php6
-rw-r--r--classes/File_redirection.php10
-rw-r--r--classes/File_thumbnail.php6
-rw-r--r--classes/File_to_post.php6
-rw-r--r--classes/Foreign_link.php34
-rw-r--r--classes/Group_alias.php6
-rw-r--r--classes/Group_block.php6
-rw-r--r--classes/Memcached_DataObject.php75
-rw-r--r--classes/Notice.php193
-rw-r--r--classes/Notice_inbox.php6
-rw-r--r--classes/Notice_tag.php4
-rw-r--r--classes/Profile.php6
-rw-r--r--classes/Profile_block.php6
-rw-r--r--classes/Remote_profile.php6
-rw-r--r--classes/Session.php23
-rw-r--r--classes/Status_network.php10
-rw-r--r--classes/Subscription.php6
-rw-r--r--classes/User.php20
-rw-r--r--classes/User_group.php41
-rw-r--r--classes/laconica.ini500
-rw-r--r--classes/status_network.ini18
-rw-r--r--classes/statusnet.ini516
-rw-r--r--classes/statusnet.links.ini (renamed from classes/laconica.links.ini)0
-rw-r--r--config.php.sample51
-rw-r--r--db/074to080_pg.sql108
-rw-r--r--db/notice_source.sql4
-rw-r--r--db/sms_carrier.sql3
-rw-r--r--db/statusnet.sql (renamed from db/laconica.sql)0
-rw-r--r--db/statusnet_pg.sql (renamed from db/laconica_pg.sql)1068
-rw-r--r--doc-src/about2
-rw-r--r--doc-src/bookmarklet4
-rw-r--r--doc-src/contact4
-rw-r--r--doc-src/faq4
-rw-r--r--doc-src/groups2
-rw-r--r--doc-src/help4
-rw-r--r--doc-src/im13
-rw-r--r--doc-src/openmublog4
-rw-r--r--doc-src/sms30
-rw-r--r--doc-src/source8
-rw-r--r--extlib/Auth/OpenID/BigMath.php2
-rw-r--r--extlib/Auth/Yadis/XML.php2
-rw-r--r--extlib/OAuth.php5
-rw-r--r--extlib/PEAR.php2
-rw-r--r--extlib/Services/oEmbed.php10
-rw-r--r--extlib/Stomp.php2
-rw-r--r--extlib/htmLawed/htmLawed.php715
-rw-r--r--extlib/htmLawed/htmLawedTest.php592
-rw-r--r--extlib/htmLawed/htmLawed_README.htm1979
-rw-r--r--extlib/htmLawed/htmLawed_README.txt1600
-rw-r--r--extlib/htmLawed/htmLawed_TESTCASE.txt370
-rw-r--r--extlib/php-gettext/AUTHORS3
-rw-r--r--extlib/php-gettext/COPYING340
-rw-r--r--extlib/php-gettext/ChangeLog144
-rw-r--r--extlib/php-gettext/README189
-rw-r--r--extlib/php-gettext/gettext.inc318
-rw-r--r--extlib/php-gettext/gettext.php358
-rw-r--r--extlib/php-gettext/streams.php167
-rw-r--r--htaccess.sample2
-rw-r--r--index.php78
-rw-r--r--install.php467
-rw-r--r--js/facebookapp.js4
-rw-r--r--js/identica-badge.js16
-rw-r--r--js/jcrop/jquery.Jcrop.go.js8
-rw-r--r--js/jcrop/jquery.Jcrop.min.js163
-rw-r--r--js/jcrop/jquery.Jcrop.pack.js8
-rw-r--r--js/userdesign.go.js41
-rw-r--r--js/util.js66
-rw-r--r--lib/Shorturl_api.php6
-rw-r--r--lib/accountsettingsaction.php28
-rw-r--r--lib/action.php156
-rw-r--r--lib/arraywrapper.php10
-rw-r--r--lib/attachmentlist.php33
-rw-r--r--lib/attachmentnoticesection.php18
-rw-r--r--lib/attachmenttagcloudsection.php18
-rw-r--r--lib/blockform.php22
-rw-r--r--lib/channel.php6
-rw-r--r--lib/clienterroraction.php63
-rw-r--r--lib/clientexception.php18
-rw-r--r--lib/command.php111
-rw-r--r--lib/commandinterpreter.php28
-rw-r--r--lib/common.php76
-rw-r--r--lib/connectsettingsaction.php54
-rw-r--r--lib/currentuserdesignaction.php55
-rw-r--r--lib/daemon.php6
-rw-r--r--lib/dberroraction.php20
-rw-r--r--lib/dbqueuemanager.php10
-rw-r--r--lib/deleteaction.php14
-rw-r--r--lib/designsettings.php49
-rw-r--r--lib/disfavorform.php22
-rw-r--r--lib/error.php34
-rw-r--r--lib/event.php22
-rw-r--r--lib/facebookaction.php53
-rw-r--r--lib/facebookutil.php251
-rw-r--r--lib/favorform.php22
-rw-r--r--lib/featureduserssection.php18
-rw-r--r--lib/feed.php20
-rw-r--r--lib/feedlist.php22
-rw-r--r--lib/form.php22
-rw-r--r--lib/galleryaction.php11
-rw-r--r--lib/groupdesignaction.php48
-rw-r--r--lib/groupeditform.php22
-rw-r--r--lib/grouplist.php18
-rw-r--r--lib/groupminilist.php18
-rw-r--r--lib/groupnav.php22
-rw-r--r--lib/groupsbymemberssection.php18
-rw-r--r--lib/groupsbypostssection.php18
-rw-r--r--lib/groupsection.php18
-rw-r--r--lib/grouptagcloudsection.php18
-rw-r--r--lib/htmloutputter.php102
-rw-r--r--lib/imagefile.php22
-rw-r--r--lib/jabber.php16
-rw-r--r--lib/joinform.php22
-rw-r--r--lib/jsonsearchresultslist.php28
-rw-r--r--lib/language.php10
-rw-r--r--lib/leaveform.php22
-rw-r--r--lib/logingroupnav.php36
-rw-r--r--lib/mail.php91
-rw-r--r--lib/mailbox.php48
-rw-r--r--lib/messageform.php22
-rw-r--r--lib/microid.php18
-rw-r--r--lib/noticeform.php33
-rw-r--r--lib/noticelist.php93
-rw-r--r--lib/noticesection.php18
-rw-r--r--lib/nudgeform.php22
-rw-r--r--lib/oauthclient.php225
-rw-r--r--lib/oauthstore.php8
-rw-r--r--lib/omb.php14
-rw-r--r--lib/openid.php6
-rw-r--r--lib/ownerdesignaction.php49
-rw-r--r--lib/parallelizingdaemon.php229
-rw-r--r--lib/personalgroupnav.php22
-rw-r--r--lib/personaltagcloudsection.php18
-rw-r--r--lib/ping.php12
-rw-r--r--lib/plugin.php20
-rw-r--r--lib/popularnoticesection.php18
-rw-r--r--lib/profileaction.php20
-rw-r--r--lib/profilelist.php20
-rw-r--r--lib/profileminilist.php18
-rw-r--r--lib/profilesection.php20
-rw-r--r--lib/publicgroupnav.php20
-rw-r--r--lib/queuehandler.php13
-rw-r--r--lib/queuemanager.php12
-rw-r--r--lib/router.php82
-rw-r--r--lib/rssaction.php20
-rw-r--r--lib/search_engines.php8
-rw-r--r--lib/searchaction.php22
-rw-r--r--lib/searchgroupnav.php18
-rw-r--r--lib/section.php18
-rw-r--r--lib/servererroraction.php44
-rw-r--r--lib/serverexception.php18
-rw-r--r--lib/settingsaction.php18
-rw-r--r--lib/snapshot.php24
-rw-r--r--lib/stompqueuemanager.php12
-rw-r--r--lib/subgroupnav.php18
-rw-r--r--lib/subpeopletagcloudsection.php18
-rw-r--r--lib/subs.php6
-rw-r--r--lib/subscribeform.php22
-rw-r--r--lib/subscriberspeopleselftagcloudsection.php18
-rw-r--r--lib/subscriberspeopletagcloudsection.php18
-rw-r--r--lib/subscriptionlist.php20
-rw-r--r--lib/subscriptionspeopleselftagcloudsection.php18
-rw-r--r--lib/subscriptionspeopletagcloudsection.php18
-rw-r--r--lib/tagcloudsection.php18
-rw-r--r--lib/theme.php14
-rw-r--r--lib/topposterssection.php18
-rw-r--r--lib/twitter.php432
-rw-r--r--lib/twitterapi.php312
-rw-r--r--lib/twitterbasicauthclient.php236
-rw-r--r--lib/twitteroauthclient.php229
-rw-r--r--lib/unblockform.php22
-rw-r--r--lib/unqueuemanager.php16
-rw-r--r--lib/unsubscribeform.php22
-rw-r--r--lib/util.php260
-rw-r--r--lib/webcolor.php12
-rw-r--r--lib/widget.php22
-rw-r--r--lib/xmloutputter.php22
-rw-r--r--lib/xmlstringer.php18
-rw-r--r--lib/xmppqueuehandler.php24
-rw-r--r--lighttpd.conf.example2
-rw-r--r--locale/bg_BG/LC_MESSAGES/laconica.mobin97725 -> 0 bytes
-rw-r--r--locale/bg_BG/LC_MESSAGES/statusnet.mobin0 -> 89338 bytes
-rw-r--r--locale/bg_BG/LC_MESSAGES/statusnet.po (renamed from locale/bg_BG/LC_MESSAGES/laconica.po)24
-rw-r--r--locale/ca_ES/LC_MESSAGES/statusnet.mo (renamed from locale/ca_ES/LC_MESSAGES/laconica.mo)bin84537 -> 84543 bytes
-rw-r--r--locale/ca_ES/LC_MESSAGES/statusnet.po (renamed from locale/ca_ES/LC_MESSAGES/laconica.po)14
-rw-r--r--locale/cs_CZ/LC_MESSAGES/laconica.mobin38699 -> 0 bytes
-rw-r--r--locale/cs_CZ/LC_MESSAGES/statusnet.mobin0 -> 28419 bytes
-rw-r--r--locale/cs_CZ/LC_MESSAGES/statusnet.po (renamed from locale/cs_CZ/LC_MESSAGES/laconica.po)12
-rw-r--r--locale/de_DE/LC_MESSAGES/laconica.mobin84573 -> 0 bytes
-rw-r--r--locale/de_DE/LC_MESSAGES/statusnet.mobin0 -> 59656 bytes
-rw-r--r--locale/de_DE/LC_MESSAGES/statusnet.po (renamed from locale/de_DE/LC_MESSAGES/laconica.po)14
-rw-r--r--locale/el_GR/LC_MESSAGES/statusnet.mo (renamed from locale/el_GR/LC_MESSAGES/laconica.mo)bin7230 -> 7230 bytes
-rw-r--r--locale/el_GR/LC_MESSAGES/statusnet.po (renamed from locale/el_GR/LC_MESSAGES/laconica.po)10
-rw-r--r--locale/en_GB/LC_MESSAGES/statusnet.mo (renamed from locale/en_GB/LC_MESSAGES/laconica.mo)bin78515 -> 77405 bytes
-rw-r--r--locale/en_GB/LC_MESSAGES/statusnet.po (renamed from locale/en_GB/LC_MESSAGES/laconica.po)16
-rw-r--r--locale/es/LC_MESSAGES/laconica.mobin83466 -> 0 bytes
-rw-r--r--locale/es/LC_MESSAGES/statusnet.mobin0 -> 71978 bytes
-rw-r--r--locale/es/LC_MESSAGES/statusnet.po (renamed from locale/es/LC_MESSAGES/laconica.po)14
-rw-r--r--locale/fi/LC_MESSAGES/statusnet.mo (renamed from locale/fi/LC_MESSAGES/laconica.mo)bin86002 -> 86008 bytes
-rw-r--r--locale/fi/LC_MESSAGES/statusnet.po (renamed from locale/fi/LC_MESSAGES/laconica.po)14
-rw-r--r--locale/fr_FR/LC_MESSAGES/laconica.mobin86456 -> 0 bytes
-rw-r--r--locale/fr_FR/LC_MESSAGES/statusnet.mobin0 -> 83964 bytes
-rw-r--r--locale/fr_FR/LC_MESSAGES/statusnet.po (renamed from locale/fr_FR/LC_MESSAGES/laconica.po)46
-rw-r--r--locale/he_IL/LC_MESSAGES/laconica.mobin31405 -> 0 bytes
-rw-r--r--locale/he_IL/LC_MESSAGES/statusnet.mobin0 -> 31408 bytes
-rw-r--r--locale/he_IL/LC_MESSAGES/statusnet.po (renamed from locale/he_IL/LC_MESSAGES/laconica.po)20
-rw-r--r--locale/it_IT/LC_MESSAGES/laconica.mobin83394 -> 0 bytes
-rw-r--r--locale/it_IT/LC_MESSAGES/statusnet.mobin0 -> 80186 bytes
-rw-r--r--locale/it_IT/LC_MESSAGES/statusnet.po (renamed from locale/it_IT/LC_MESSAGES/laconica.po)22
-rw-r--r--locale/ja_JP/LC_MESSAGES/laconica.mobin46644 -> 0 bytes
-rw-r--r--locale/ja_JP/LC_MESSAGES/statusnet.mobin0 -> 37594 bytes
-rw-r--r--locale/ja_JP/LC_MESSAGES/statusnet.po (renamed from locale/ja_JP/LC_MESSAGES/laconica.po)16
-rw-r--r--locale/ko_KR/LC_MESSAGES/statusnet.mo (renamed from locale/ko_KR/LC_MESSAGES/laconica.mo)bin88923 -> 88929 bytes
-rw-r--r--locale/ko_KR/LC_MESSAGES/statusnet.po (renamed from locale/ko_KR/LC_MESSAGES/laconica.po)12
-rw-r--r--locale/mk_MK/LC_MESSAGES/laconica.mobin37725 -> 0 bytes
-rw-r--r--locale/mk_MK/LC_MESSAGES/statusnet.mobin0 -> 37731 bytes
-rw-r--r--locale/mk_MK/LC_MESSAGES/statusnet.po (renamed from locale/mk_MK/LC_MESSAGES/laconica.po)20
-rw-r--r--locale/nb_NO/LC_MESSAGES/laconica.mobin19769 -> 0 bytes
-rw-r--r--locale/nb_NO/LC_MESSAGES/statusnet.mobin0 -> 14685 bytes
-rw-r--r--locale/nb_NO/LC_MESSAGES/statusnet.po (renamed from locale/nb_NO/LC_MESSAGES/laconica.po)12
-rw-r--r--locale/nl_NL/LC_MESSAGES/laconica.mobin63575 -> 0 bytes
-rw-r--r--locale/nl_NL/LC_MESSAGES/statusnet.mobin0 -> 56796 bytes
-rw-r--r--locale/nl_NL/LC_MESSAGES/statusnet.po (renamed from locale/nl_NL/LC_MESSAGES/laconica.po)12
-rw-r--r--locale/nn_NO/LC_MESSAGES/statusnet.mo (renamed from locale/nn_NO/LC_MESSAGES/laconica.mo)bin80322 -> 80329 bytes
-rw-r--r--locale/nn_NO/LC_MESSAGES/statusnet.po (renamed from locale/nn_NO/LC_MESSAGES/laconica.po)18
-rw-r--r--locale/pl_PL/LC_MESSAGES/laconica.mobin49768 -> 0 bytes
-rw-r--r--locale/pl_PL/LC_MESSAGES/statusnet.mobin0 -> 38812 bytes
-rw-r--r--locale/pl_PL/LC_MESSAGES/statusnet.po (renamed from locale/pl_PL/LC_MESSAGES/laconica.po)16
-rw-r--r--locale/pt/LC_MESSAGES/laconica.mobin25415 -> 0 bytes
-rw-r--r--locale/pt/LC_MESSAGES/statusnet.mobin0 -> 22701 bytes
-rw-r--r--locale/pt/LC_MESSAGES/statusnet.po (renamed from locale/pt/LC_MESSAGES/laconica.po)10
-rw-r--r--locale/pt_BR/LC_MESSAGES/laconica.mobin83647 -> 0 bytes
-rw-r--r--locale/pt_BR/LC_MESSAGES/statusnet.mobin0 -> 76797 bytes
-rw-r--r--locale/pt_BR/LC_MESSAGES/statusnet.po (renamed from locale/pt_BR/LC_MESSAGES/laconica.po)16
-rw-r--r--locale/ru_RU/LC_MESSAGES/statusnet.mo (renamed from locale/ru_RU/LC_MESSAGES/laconica.mo)bin109415 -> 109421 bytes
-rw-r--r--locale/ru_RU/LC_MESSAGES/statusnet.po (renamed from locale/ru_RU/LC_MESSAGES/laconica.po)16
-rw-r--r--locale/statusnet.po (renamed from locale/laconica.po)22
-rw-r--r--locale/sv_SE/LC_MESSAGES/laconica.mobin69740 -> 0 bytes
-rw-r--r--locale/sv_SE/LC_MESSAGES/statusnet.mobin0 -> 54299 bytes
-rw-r--r--locale/sv_SE/LC_MESSAGES/statusnet.po (renamed from locale/sv_SE/LC_MESSAGES/laconica.po)12
-rw-r--r--locale/te_IN/LC_MESSAGES/laconica.mobin43726 -> 0 bytes
-rw-r--r--locale/te_IN/LC_MESSAGES/statusnet.mobin0 -> 29270 bytes
-rw-r--r--locale/te_IN/LC_MESSAGES/statusnet.po (renamed from locale/te_IN/LC_MESSAGES/laconica.po)18
-rw-r--r--locale/tr_TR/LC_MESSAGES/laconica.mobin27594 -> 0 bytes
-rw-r--r--locale/tr_TR/LC_MESSAGES/statusnet.mobin0 -> 27598 bytes
-rw-r--r--locale/tr_TR/LC_MESSAGES/statusnet.po (renamed from locale/tr_TR/LC_MESSAGES/laconica.po)14
-rw-r--r--locale/uk_UA/LC_MESSAGES/statusnet.mo (renamed from locale/uk_UA/LC_MESSAGES/laconica.mo)bin109630 -> 109628 bytes
-rw-r--r--locale/uk_UA/LC_MESSAGES/statusnet.po (renamed from locale/uk_UA/LC_MESSAGES/laconica.po)18
-rw-r--r--locale/vi_VN/LC_MESSAGES/laconica.mobin78720 -> 0 bytes
-rw-r--r--locale/vi_VN/LC_MESSAGES/statusnet.mobin0 -> 50650 bytes
-rw-r--r--locale/vi_VN/LC_MESSAGES/statusnet.po (renamed from locale/vi_VN/LC_MESSAGES/laconica.po)20
-rw-r--r--locale/zh_CN/LC_MESSAGES/laconica.mobin76518 -> 0 bytes
-rw-r--r--locale/zh_CN/LC_MESSAGES/statusnet.mobin0 -> 63488 bytes
-rw-r--r--locale/zh_CN/LC_MESSAGES/statusnet.po (renamed from locale/zh_CN/LC_MESSAGES/laconica.po)14
-rw-r--r--locale/zh_TW/LC_MESSAGES/statusnet.mo (renamed from locale/zh_TW/LC_MESSAGES/laconica.mo)bin11939 -> 11931 bytes
-rw-r--r--locale/zh_TW/LC_MESSAGES/statusnet.po (renamed from locale/zh_TW/LC_MESSAGES/laconica.po)12
-rw-r--r--plugins/Autocomplete/Autocomplete.js37
-rw-r--r--plugins/Autocomplete/AutocompletePlugin.php65
-rw-r--r--plugins/Autocomplete/autocomplete.php136
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/changelog.txt20
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.css48
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.js759
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.min.js15
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js13
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/lib/jquery.ajaxQueue.js116
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/lib/jquery.bgiframe.min.js10
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/lib/jquery.js3558
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/lib/thickbox-compressed.js10
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/lib/thickbox.css163
-rw-r--r--plugins/Autocomplete/jquery-autocomplete/todo166
-rw-r--r--plugins/Autocomplete/readme.txt8
-rw-r--r--plugins/BlogspamNetPlugin.php20
-rw-r--r--plugins/Comet/CometPlugin.php18
-rw-r--r--plugins/FBConnect/FBCLoginGroupNav.php22
-rw-r--r--plugins/FBConnect/FBCSettingsNav.php22
-rw-r--r--plugins/FBConnect/FBC_XDReceiver.php11
-rw-r--r--plugins/FBConnect/FBConnectAuth.php75
-rw-r--r--plugins/FBConnect/FBConnectLogin.php4
-rw-r--r--plugins/FBConnect/FBConnectPlugin.css8
-rw-r--r--plugins/FBConnect/FBConnectPlugin.php57
-rw-r--r--plugins/FBConnect/FBConnectSettings.php24
-rw-r--r--plugins/FBConnect/README33
-rw-r--r--plugins/GoogleAnalyticsPlugin.php18
-rw-r--r--plugins/InfiniteScroll/InfiniteScrollPlugin.php46
-rw-r--r--plugins/InfiniteScroll/ajax-loader.gifbin0 -> 10819 bytes
-rw-r--r--plugins/InfiniteScroll/infinitescroll.js15
-rw-r--r--plugins/InfiniteScroll/jquery.infinitescroll.js261
-rw-r--r--plugins/InfiniteScroll/jquery.infinitescroll.min.js8
-rw-r--r--plugins/InfiniteScroll/readme.txt6
-rw-r--r--plugins/LinkbackPlugin.php35
-rw-r--r--plugins/Meteor/MeteorPlugin.php18
-rw-r--r--plugins/Meteor/meteorupdater.js5
-rw-r--r--plugins/PiwikAnalyticsPlugin.php44
-rw-r--r--plugins/Realtime/RealtimePlugin.php195
-rw-r--r--plugins/Realtime/icon_external.gifbin0 -> 90 bytes
-rw-r--r--plugins/Realtime/jquery.getUrlParam.js72
-rw-r--r--plugins/Realtime/realtimeupdate.js125
-rw-r--r--plugins/TemplatePlugin.php23
-rw-r--r--plugins/WikiHashtagsPlugin.php20
-rw-r--r--plugins/recaptcha/LICENSE22
-rw-r--r--plugins/recaptcha/README23
-rw-r--r--plugins/recaptcha/recaptcha.php104
-rw-r--r--plugins/recaptcha/recaptchalib.php277
-rwxr-xr-xscripts/allsites.php4
-rw-r--r--scripts/commandline.inc6
-rw-r--r--scripts/createsim.php142
-rw-r--r--scripts/decache.php4
-rwxr-xr-xscripts/delete_status_network.sh2
-rwxr-xr-xscripts/enjitqueuehandler.php4
-rwxr-xr-xscripts/facebookqueuehandler.php4
-rwxr-xr-xscripts/fixup_conversations.php4
-rwxr-xr-xscripts/fixup_hashtags.php7
-rwxr-xr-xscripts/fixup_inboxes.php7
-rwxr-xr-xscripts/fixup_notices_rendered.php7
-rwxr-xr-xscripts/fixup_replies.php7
-rwxr-xr-x[-rw-r--r--]scripts/fixup_utf8.php8
-rwxr-xr-xscripts/getpiddir.php4
-rwxr-xr-xscripts/getvaliddaemons.php13
-rwxr-xr-xscripts/inbox_users.php4
-rwxr-xr-xscripts/jabberqueuehandler.php4
-rwxr-xr-xscripts/maildaemon.php13
-rwxr-xr-xscripts/ombqueuehandler.php4
-rw-r--r--scripts/pingqueuehandler.php4
-rwxr-xr-xscripts/publicqueuehandler.php4
-rwxr-xr-xscripts/rebuilddb_psql.sh6
-rw-r--r--scripts/reportsnapshot.php4
-rw-r--r--scripts/sessiongc.php36
-rwxr-xr-xscripts/setpassword.php4
-rwxr-xr-xscripts/setup_status_network.sh4
-rw-r--r--scripts/showcache.php4
-rwxr-xr-xscripts/sitemap.php4
-rwxr-xr-xscripts/smsqueuehandler.php4
-rwxr-xr-xscripts/sphinx-cron.sh6
-rwxr-xr-xscripts/sphinx-indexer.sh6
-rwxr-xr-xscripts/startdaemons.sh6
-rw-r--r--scripts/statusnet.spec (renamed from scripts/laconica.spec)36
-rwxr-xr-xscripts/stopdaemons.sh8
-rwxr-xr-xscripts/synctwitterfriends.php286
-rw-r--r--scripts/triminboxes.php4
-rwxr-xr-xscripts/twitterqueuehandler.php4
-rwxr-xr-xscripts/twitterstatusfetcher.php339
-rw-r--r--scripts/uncache_users.php4
-rwxr-xr-xscripts/update_pot.sh2
-rwxr-xr-xscripts/update_translations.php21
-rwxr-xr-xscripts/xmppconfirmhandler.php4
-rwxr-xr-xscripts/xmppdaemon.php4
-rw-r--r--sphinx.conf.sample2
-rw-r--r--tests/HashTagDetectionTests.php47
-rw-r--r--tests/URLDetectionTest.php269
-rw-r--r--theme/base/css/display.css62
-rw-r--r--theme/base/css/ie6.css3
-rw-r--r--theme/base/css/jquery.Jcrop.css20
-rw-r--r--theme/base/css/mobile.css6
-rw-r--r--theme/base/css/print.css8
-rw-r--r--theme/base/images/icons/icon_atom.pngbin820 -> 807 bytes
-rw-r--r--theme/base/images/icons/icon_rss.pngbin777 -> 763 bytes
-rw-r--r--theme/biz/css/base.css33
-rw-r--r--theme/biz/css/display.css118
-rw-r--r--theme/biz/logo.pngbin2228 -> 6389 bytes
-rw-r--r--theme/cloudy/css/display.css54
-rw-r--r--theme/cloudy/css/ie.css24
-rw-r--r--theme/cloudy/logo.pngbin2228 -> 6389 bytes
-rw-r--r--theme/default/css/display.css24
-rw-r--r--theme/default/default-avatar-mini.pngbin646 -> 512 bytes
-rw-r--r--theme/default/default-avatar-profile.pngbin2853 -> 2234 bytes
-rw-r--r--theme/default/default-avatar-stream.pngbin1487 -> 1146 bytes
-rw-r--r--theme/default/logo.pngbin2228 -> 6389 bytes
-rw-r--r--theme/h4ck3r/css/base.css8
-rw-r--r--theme/h4ck3r/css/display.css8
-rw-r--r--theme/h4ck3r/logo.pngbin2228 -> 6389 bytes
-rw-r--r--theme/identica/css/display.css24
-rw-r--r--theme/identica/default-avatar-mini.pngbin646 -> 512 bytes
-rw-r--r--theme/identica/default-avatar-profile.pngbin2853 -> 2234 bytes
-rw-r--r--theme/identica/default-avatar-stream.pngbin1487 -> 1146 bytes
-rw-r--r--theme/identica/logo.pngbin4988 -> 4044 bytes
-rw-r--r--theme/otalk/css/base.css8
-rw-r--r--theme/otalk/css/display.css8
-rw-r--r--theme/pigeonthoughts/css/base.css38
-rw-r--r--theme/pigeonthoughts/css/display.css16
-rw-r--r--theme/pigeonthoughts/logo.pngbin2228 -> 6389 bytes
-rw-r--r--theme/readme.txt6
-rw-r--r--tpl/index.php6
503 files changed, 22516 insertions, 6224 deletions
diff --git a/.gitignore b/.gitignore
index f4c2bba5f..1cde3a625 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ avatar/*
background/*
files/*
file/*
+local/*
_darcs/*
logs/*
config.php
@@ -23,4 +24,4 @@ config-*.php
good-config.php
lac08.log
php.log
-config.php.*
+
diff --git a/EVENTS.txt b/EVENTS.txt
index 2c43469d4..68cb28603 100644
--- a/EVENTS.txt
+++ b/EVENTS.txt
@@ -20,10 +20,16 @@ StartShowStyles: Showing Style links; good place to add UA style resets
EndShowStyles: End showing Style links; good place to add custom styles
- $action: the current action
-StartShowLaconicaStyles: Showing Laconica Style links
+StartShowStatusNetStyles: Showing StatusNet Style links
- $action: the current action
-EndShowLaconicaStyles: End showing Laconica Style links; good place to add handheld or JavaScript dependant styles
+EndShowStatusNetStyles: End showing StatusNet Style links; good place to add handheld or JavaScript dependant styles
+- $action: the current action
+
+StartShowLaconicaStyles: backwards compatibility; deprecated
+- $action: the current action
+
+EndShowLaconicaStyles: backwards compatibility; deprecated
- $action: the current action
StartShowUAStyles: Showing custom UA Style links
@@ -45,10 +51,16 @@ StartShowJQueryScripts: Showing JQuery script links (use this to link to e.g. Go
EndShowJQueryScripts: End showing JQuery script links
- $action: the current action
-StartShowLaconicaScripts: Showing Laconica script links (use this to link to a CDN or something)
+StartShowStatusNetScripts: Showing StatusNet script links (use this to link to a CDN or something)
+- $action: the current action
+
+EndShowStatusNetScripts: End showing StatusNet script links
+- $action: the current action
+
+StartShowLaconicaScripts: backwards compatibility; deprecated
- $action: the current action
-EndShowLaconicaScripts: End showing Laconica script links
+EndShowLaconicaScripts: backwards compatibility; deprecated
- $action: the current action
StartShowSections: Start the list of sections in the sidebar
diff --git a/README b/README
index 0bf1319c6..756219981 100644
--- a/README
+++ b/README
@@ -2,41 +2,47 @@
README
------
-Laconica 0.8.0 ("Shiny Happy People")
-15 July 2009
+StatusNet 0.8.1 ("Second Guessing")
+26 Aug 2009
-This is the README file for Laconica, the Open Source microblogging
-platform. It includes installation instructions, descriptions of
-options you can set, warnings, tips, and general info for
-administrators. Information on using Laconica can be found in the
+This is the README file for StatusNet (formerly Laconica), the Open
+Source microblogging platform. It includes installation instructions,
+descriptions of options you can set, warnings, tips, and general info
+for administrators. Information on using StatusNet can be found in the
"doc" subdirectory or in the "help" section on-line.
About
=====
-Laconica (pronounced "luh-KAWN-ih-kuh") is a Free and Open Source
-microblogging platform. It helps people in a community, company or
-group to exchange short (140 character) messages over the Web. Users
-can choose which people to "follow" and receive only their friends' or
-colleagues' status messages. It provides a similar service to sites
-like Twitter, Jaiku and Plurk.
+StatusNet (formerly Laconica) is a Free and Open Source microblogging
+platform. It helps people in a community, company or group to exchange
+short (140 character) messages over the Web. Users can choose which
+people to "follow" and receive only their friends' or colleagues'
+status messages. It provides a similar service to sites like Twitter,
+Jaiku, Yammer, and Plurk.
With a little work, status messages can be sent to mobile phones,
instant messenger programs (GTalk/Jabber), and specially-designed
desktop clients that support the Twitter API.
-Laconica supports an open standard called OpenMicroBlogging
+StatusNet supports an open standard called OpenMicroBlogging
<http://openmicroblogging.org/> that lets users on different Web sites
or in different companies subscribe to each others' notices. It
enables a distributed social network spread all across the Web.
-Laconica was originally developed for the Open Software Service,
+StatusNet was originally developed for the Open Software Service,
Identi.ca <http://identi.ca/>. It is shared with you in hope that you
too make an Open Software Service available to your users. To learn
more, please see the Open Software Service Definition 1.1:
http://www.opendefinition.org/ossd
+StatusNet, Inc. <http://status.net/> also offers this software as a
+Web service, requiring no installation on your part. The software run
+on status.net is identical to the software available for download, so
+you can move back and forth between a hosted version or a version
+installed on your own servers.
+
License
=======
@@ -56,11 +62,11 @@ License along with this program, in the file "COPYING". If not, see
IMPORTANT NOTE: The GNU Affero General Public License (AGPL) has
*different requirements* from the "regular" GPL. In particular, if
- you make modifications to the Laconica source code on your server,
+ you make modifications to the StatusNet source code on your server,
you *MUST MAKE AVAILABLE* the modified version of the source code
to your users under the same license. This is a legal requirement
of using the software, and if you do not wish to share your
- modifications, *YOU MAY NOT INSTALL LACONICA*.
+ modifications, *YOU MAY NOT INSTALL STATUSNET*.
Additional library software has been made available in the 'extlib'
directory. All of it is Free Software and can be distributed under
@@ -71,62 +77,49 @@ for additional terms.
New this version
================
-This is a major feature release since version 0.7.4, released May 31
-2009. Notable changes this version:
-
-- Support for a hosted service (status network). Multiple sites can
- share the same codebase but use different databases.
-- OEmbed. Links to pages that support OEmbed (http://www.oembed.com/)
- become popup links, and the media are shown in a special lightbox.
-- File attachments. Users can attach files of the size and type approved
- by an administrator, and a shortened link will be included in the
- notice.
-- Related notices are organized into conversations, with each reply a
- branch in a tree. Conversations have pages and are linked to from each
- notice in the conversation.
-- User designs. Users can specify colours and backgrounds
- for their profile pages and other "personal" pages.
-- Group designs. Group administrators can specify similar designs for
- group profiles and related pages.
-- Site designs. Site authors can specify a design (background and
- colors) for the site.
-- New themes. Five new themes are added to the base release; these show
- off the flexibility of Laconica's theming system.
-- Statistics. Public sites will periodically send usage statistics,
- configuration options, and dependency information to Laconica dev site.
- This will help us understand how the software is used and plan future
- versions of the software.
-- Additional hooks. The hooks and plugins system introduced in 0.7.x was
- expanded with additional points of access.
-- Facebook Connect. A new plugin allows logging in with Facebook Connect
- (http://developers.facebook.com/connect.php).
-- A session handler. A new optional session handler class to manage PHP
- sessions reliably and quickly for large sites.
-- STOMP queuing. Queue management for offline daemons has been
- abstracted with three concrete instances. A new interface that should
- work with STOMP servers like ActiveMQ and RabbitMQ is available, which
- should make things scale better.
-- Group block. Group admins can block users from joining or posting to
- a group.
-- Group aliases. Groups can be referred to with aliases, additional
- names. For example, "!yul" and "!montreal" can be the same group.
-- Bidirectional Twitter bridge. Users can read the tweets their Twitter
- friends post on Twitter.
-- Adaptation of WordPress.com Terms of Service (http://en.wordpress.com/tos/)
- as default TOS for Laconica sites.
-- Better command-line handling for scripts, including standard options
- and ability to set hostname and path from the command line.
-- An experimental plugin to use Meteor (http://www.meteorserver.org/)
- for "real-time" updates.
-- A new framework for "real-time" updates, making it easier to develop
- plugins for different browser-based update modes.
-- RSS 2.0 and Atom feeds for groups.
-- RSS 2.0 and Atom feeds for tags.
-- Attachments can be sent by email.
-- Attachments are encoded as enclosures in RSS 2.0 and Atom.
-- Notices with attachments display in Facebook as media inline.
-
-- Many, many bug fixes.
+This is a minor feature and bugfix release since version 0.8.0,
+released Jul 15 2009. Notable changes this version:
+
+- Laconica has been renamed StatusNet. With a few minor compatibility
+ exceptions, all references to "Laconica" in code, documentation
+ and comments were changed to "StatusNet".
+- A new plugin to support "infinite scroll".
+- A new plugin to support reCaptcha <http://recaptcha.net>.
+- Better logging of server errors.
+- Add an Openid-only mode for authentication.
+- 'lite' parameter for some Twitter API methods.
+- A new plugin to auto-complete nicknames for @-replies.
+- Configuration options to disable OpenID, SMS, Twitter, post-by-email, and IM.
+- Support for lighttpd <http://lighttpd.org/> using 404-based
+ rewrites.
+- Support for using Twitter's OAuth authentication as a client.
+- First version of the groups API.
+- Can configure a site-wide design, including background image and
+ colors.
+- Improved algorithm for replies and conversations, making
+ conversation trees more accurate and useful.
+- Add a script to create a simulation database for testing/debugging.
+- Sanitize HTML for OEmbed.
+- Improved queue management for DB-based queuing.
+- More complete URL detection.
+- Hashtags now support full Unicode character set.
+- Notice inboxes are now garbage-collected on a regular basis
+ at notice-write time.
+- PiwikAnalyticsPlugin updated for latest Piwik interface.
+- Attachment and notice pages can be embedded with OEmbed
+ <http://www.oembed.com>.
+- Failed authentication is logged.
+- PostgreSQL schema and support brought up-to-date with 0.8.x features.
+- The installer works with PostgreSQL as well as MySQL.
+- RSS 1.0 feeds use HTTP Basic authentication in private mode.
+- Many, many bug fixes, particularly with performance.
+- Better (=working) garbage collection for old sessions.
+- Better (=working) search queries.
+- Some cleanup of HTML output.
+- Better error handling when updating Facebook.
+- Considerably better performance when using replication for API
+ calls.
+- Initial unit tests.
Prerequisites
=============
@@ -137,7 +130,7 @@ run correctly.
- PHP 5.2.3+. It may be possible to run this software on earlier
versions of PHP, but many of the functions used are only available
in PHP 5.2 or above.
-- MySQL 5.x. The Laconica database is stored, by default, in a MySQL
+- MySQL 5.x. The StatusNet database is stored, by default, in a MySQL
server. It has been primarily tested on 5.x servers, although it may
be possible to install on earlier (or later!) versions. The server
*must* support the MyISAM storage engine -- the default for most
@@ -153,6 +146,7 @@ Your PHP installation must include the following PHP extensions:
- GD. For scaling down avatar images.
- mbstring. For handling Unicode (UTF-8) encoded strings.
- gettext. For multiple languages. Default on many PHP installs.
+- tidy. Used to clean up HTML/URLs for the URL shortener to consume.
For some functionality, you will also need the following extensions:
@@ -206,7 +200,7 @@ and the URLs are listed here for your convenience.
as of this writing the version of this library that is available in
the extlib directory is *significantly different* from the upstream
version (patches have been submitted). Upgrading to the upstream
- version may render your Laconica site unable to send or receive XMPP
+ version may render your StatusNet site unable to send or receive XMPP
messages.
- Facebook library. Used for the Facebook application.
- PEAR Services_oEmbed. Used for some multimedia integration.
@@ -215,7 +209,7 @@ and the URLs are listed here for your convenience.
- PEAR Net_URL2 is an oEmbed dependency.
- Console_GetOpt for parsing command-line options.
-A design goal of Laconica is that the basic Web functionality should
+A design goal of StatusNet is that the basic Web functionality should
work on even the most restrictive commercial hosting services.
However, additional functionality, such as receiving messages by
Jabber/GTalk, require that you be able to run long-running processes
@@ -225,15 +219,15 @@ that you be able to install a mail filter in your mail server.
Installation
============
-Installing the basic Laconica Web component is relatively easy,
+Installing the basic StatusNet Web component is relatively easy,
especially if you've previously installed PHP/MySQL packages.
1. Unpack the tarball you downloaded on your Web server. Usually a
command like this will work:
- tar zxf laconica-0.8.0.tar.gz
+ tar zxf statusnet-0.8.1.tar.gz
- ...which will make a laconica-0.8.0 subdirectory in your current
+ ...which will make a statusnet-0.8.1 subdirectory in your current
directory. (If you don't have shell access on your Web server, you
may have to unpack the tarball on your local computer and FTP the
files to the server.)
@@ -241,11 +235,11 @@ especially if you've previously installed PHP/MySQL packages.
2. Move the tarball to a directory of your choosing in your Web root
directory. Usually something like this will work:
- mv laconica-0.8.0 /var/www/mublog
+ mv statusnet-0.8.1 /var/www/mublog
- This will make your Laconica instance available in the mublog path of
+ This will make your StatusNet instance available in the mublog path of
your server, like "http://example.net/mublog". "microblog" or
- "laconica" might also be good path names. If you know how to
+ "statusnet" might also be good path names. If you know how to
configure virtual hosts on your web server, you can try setting up
"http://micro.example.net/" or the like.
@@ -276,9 +270,9 @@ especially if you've previously installed PHP/MySQL packages.
5. Create a database to hold your microblog data. Something like this
should work:
- mysqladmin -u "username" --password="password" create laconica
+ mysqladmin -u "username" --password="password" create statusnet
- Note that Laconica must have its own database; you can't share the
+ Note that StatusNet must have its own database; you can't share the
database with another program. You can name it whatever you want,
though.
@@ -286,11 +280,11 @@ especially if you've previously installed PHP/MySQL packages.
a tool like PHPAdmin to create a database. Check your hosting
service's documentation for how to create a new MySQL database.)
-6. Create a new database account that Laconica will use to access the
+6. Create a new database account that StatusNet will use to access the
database. If you have shell access, this will probably work from the
MySQL shell:
- GRANT ALL on laconica.*
+ GRANT ALL on statusnet.*
TO 'lacuser'@'localhost'
IDENTIFIED BY 'lacpassword';
@@ -298,7 +292,7 @@ especially if you've previously installed PHP/MySQL packages.
username and password. You may want to test logging in to MySQL as
this new user.
-7. In a browser, navigate to the Laconica install script; something like:
+7. In a browser, navigate to the StatusNet install script; something like:
http://yourserver.example.com/mublog/install.php
@@ -316,7 +310,7 @@ especially if you've previously installed PHP/MySQL packages.
Fancy URLs
----------
-By default, Laconica will use URLs that include the main PHP program's
+By default, StatusNet will use URLs that include the main PHP program's
name in them. For example, a user's home profile might be
found at:
@@ -336,7 +330,7 @@ fancy URLs, you must either have Apache 2.x with .htaccess enabled and
mod_redirect enabled, -OR- know how to configure "url redirection" in
your server.
-1. Copy the htaccess.sample file to .htaccess in your Laconica
+1. Copy the htaccess.sample file to .htaccess in your StatusNet
directory. Note: if you have control of your server's httpd.conf or
similar configuration files, it can greatly improve performance to
import the .htaccess file into your conf file instead. If you're
@@ -344,8 +338,8 @@ your server.
just leaving the .htaccess file.
2. Change the "RewriteBase" in the new .htaccess file to be the URL path
- to your Laconica installation on your server. Typically this will
- be the path to your Laconica directory relative to your Web root.
+ to your StatusNet installation on your server. Typically this will
+ be the path to your StatusNet directory relative to your Web root.
3. Add or uncomment or change a line in your config.php file so it says:
@@ -380,7 +374,7 @@ to start and stop the sphinx search daemon.
SMS
---
-Laconica supports a cheap-and-dirty system for sending update messages
+StatusNet supports a cheap-and-dirty system for sending update messages
to mobile phones and for receiving updates from the mobile. Instead of
sending through the SMS network itself, which is costly and requires
buy-in from the wireless carriers, it simply piggybacks on the email
@@ -395,10 +389,10 @@ converted to a notice and stored in the DB.
For this to work, there *must* be a domain or sub-domain for which all
(or most) incoming email can pass through the incoming mail filter.
-1. Run the SQL script carrier.sql in your Laconica database. This will
+1. Run the SQL script carrier.sql in your StatusNet database. This will
usually work:
- mysql -u "lacuser" --password="lacpassword" laconica < db/carrier.sql
+ mysql -u "lacuser" --password="lacpassword" statusnet < db/carrier.sql
This will populate your database with a list of wireless carriers
that support email SMS gateways.
@@ -412,7 +406,7 @@ For this to work, there *must* be a domain or sub-domain for which all
2. Edit /etc/aliases on your mail server and add the following line:
- *: /path/to/laconica/scripts/maildaemon.php
+ *: /path/to/statusnet/scripts/maildaemon.php
3. Run whatever code you need to to update your aliases database. For
many mail servers (Postfix, Exim, Sendmail), this should work:
@@ -428,8 +422,8 @@ For this to work, there *must* be a domain or sub-domain for which all
At this point, post-by-email and post-by-SMS-gateway should work. Note
that if your mail server is on a different computer from your email
-server, you'll need to have a full installation of Laconica, a working
-config.php, and access to the Laconica database from the mail server.
+server, you'll need to have a full installation of StatusNet, a working
+config.php, and access to the StatusNet database from the mail server.
XMPP
----
@@ -449,7 +443,7 @@ well.
similar. Alternately, your "update JID" can be registered on a
publicly-available XMPP service, like jabber.org or GTalk.
- Laconica will not register the JID with your chosen XMPP server;
+ StatusNet will not register the JID with your chosen XMPP server;
you need to do this manually, with an XMPP client like Gajim,
Telepathy, or Pidgin.im.
@@ -465,7 +459,7 @@ can really slow down your site; it may cause posting to timeout.
NOTE: stream_select(), a crucial function for network programming, is
broken on PHP 5.2.x less than 5.2.6 on amd64-based servers. We don't
-work around this bug in Laconica; current recommendation is to move
+work around this bug in StatusNet; current recommendation is to move
off of amd64 to another server.
Public feed
@@ -488,7 +482,7 @@ consider setting up queues and daemons.
Queues and daemons
------------------
-Some activities that Laconica needs to do, like broadcast OMB, SMS,
+Some activities that StatusNet needs to do, like broadcast OMB, SMS,
and XMPP messages, can be 'queued' and done by off-line bots instead.
For this to work, you must be able to run long-running offline
processes, either on your main Web server or on another server you
@@ -499,7 +493,7 @@ server is probably a good idea for high-volume sites.
1. You'll need the "CLI" (command-line interface) version of PHP
installed on whatever server you use.
-2. If you're using a separate server for queues, install Laconica
+2. If you're using a separate server for queues, install StatusNet
somewhere on the server. You don't need to worry about the
.htaccess file, but make sure that your config.php file is close
to, or identical to, your Web server's version.
@@ -516,7 +510,7 @@ server is probably a good idea for high-volume sites.
4. On the queues server, run the command scripts/startdaemons.sh. It
needs as a parameter the install path; if you run it from the
- Laconica dir, "." should suffice.
+ StatusNet dir, "." should suffice.
This will run eight (for now) queue handlers:
@@ -548,39 +542,67 @@ All the daemons write their process IDs (pids) to /var/run/ by
default. This can be useful for starting, stopping, and monitoring the
daemons.
-With version 0.8.0, it's now possible to use a STOMP server instead of
+Since version 0.8.0, it's now possible to use a STOMP server instead of
our kind of hacky home-grown DB-based queue solution. See the "queues"
config section below for how to configure to use STOMP. As of this
writing, the software has been tested with ActiveMQ (
-Twitter Friends Syncing
------------------------
+Twitter Bridge
+--------------
+
+* OAuth
+
+As of 0.8.1, OAuth is used to to access protected resources on Twitter
+instead of HTTP Basic Auth. To use Twitter bridging you will need
+to register your instance of StatusNet as an application on Twitter
+(http://twitter.com/apps), and update the following variables in your
+config.php with the consumer key and secret Twitter generates for you:
+
+ $config['twitter']['consumer_key'] = 'YOURKEY';
+ $config['twitter']['consumer_secret'] = 'YOURSECRET';
+
+When registering your application with Twitter set the type to "Browser"
+and your Callback URL to:
+
+ http://example.org/mublog/twitter/authorization
+
+The default access type should be, "Read & Write".
+
+* Importing statuses from Twitter
-As of Laconica 0.6.3, users may set a flag in their settings ("Subscribe
-to my Twitter friends here" under the Twitter tab) to have Laconica
-attempt to locate and subscribe to "friends" (people they "follow") on
-Twitter who also have accounts on your Laconica system, and who have
-previously set up a link for automatically posting notices to Twitter.
+To allow your users to import their friends' Twitter statuses, you will
+need to enable the bidirectional Twitter bridge in config.php:
-Optionally, there is a script (./scripts/synctwitterfriends.php), meant
-to be run periodically from a job scheduler (e.g.: cron under Unix), to
-look for new additions to users' friends lists. Note that the friends
-syncing only subscribes users to each other, it does not unsubscribe
-users when they stop following each other on Twitter.
+ $config['twitterbridge']['enabled'] = true;
-Sample cron job:
+and run the TwitterStatusFetcher daemon (scripts/twitterstatusfetcher.php).
+Additionally, you will want to set the integration source variable,
+which will keep notices posted to Twitter via StatusNet from looping
+back. The integration source should be set to the name of your
+application, exactly as you specified it on the settings page for your
+StatusNet application on Twitter, e.g.:
-# Update Twitter friends subscriptions every half hour
-0,30 * * * * /path/to/php /path/to/laconica/scripts/synctwitterfriends.php>&/dev/null
+ $config['integration']['source'] = 'YourApp';
+
+* Twitter Friends Syncing
+
+Users may set a flag in their settings ("Subscribe to my Twitter friends
+here" under the Twitter tab) to have StatusNet attempt to locate and
+subscribe to "friends" (people they "follow") on Twitter who also have
+accounts on your StatusNet system, and who have previously set up a link
+for automatically posting notices to Twitter.
+
+As of 0.8.0, this is no longer accomplished via a cron job. Instead you
+must run the SyncTwitterFriends daemon (scripts/synctwitterfreinds.php).
Built-in Facebook Application
-----------------------------
-Laconica's Facebook application allows your users to automatically
+StatusNet's Facebook application allows your users to automatically
update their Facebook statuses with their latest notices, invite
their friends to use the app (and thus your site), view their notice
timelines, and post notices -- all from within Facebook. The application
-is built into Laconica and runs on your host. For automatic Facebook
+is built into StatusNet and runs on your host. For automatic Facebook
status updating to work you will need to enable queuing and run the
facebookqueuehandler.php daemon (see the "Queues and daemons" section
above).
@@ -601,13 +623,13 @@ key and secret, e.g.:
In Facebook's application editor, specify the following URLs for your app:
-- Callback URL: http://example.net/mublog/facebook/
-- Post-Remove URL: http://example.net/mublog/facebook/remove
+- Canvas Callback URL: http://example.net/mublog/facebook/
+- Post-Remove Callback URL: http://example.net/mublog/facebook/remove
- Post-Add Redirect URL: http://apps.facebook.com/yourapp/
-- Canvas URL: http://apps.facebook.com/yourapp/
+- Canvas Page URL: http://apps.facebook.com/yourapp/
(Replace 'example.net' with your host's URL, 'mublog' with the path
-to your Laconica installation, and 'yourapp' with the name of the
+to your StatusNet installation, and 'yourapp' with the name of the
Facebook application you created.)
Additionally, Choose "Web" for Application type in the Advanced tab.
@@ -616,9 +638,9 @@ In the "Canvas setting" section, choose the "FBML" for Render Method,
Everything else can be left with default values.
*For more detailed instructions please see the installation guide on the
-Laconica wiki:
+StatusNet wiki:
- http://laconi.ca/trac/wiki/FacebookApplication
+ http://status.net/trac/wiki/FacebookApplication
Sitemaps
--------
@@ -626,11 +648,11 @@ Sitemaps
Sitemap files <http://sitemaps.org/> are a very nice way of telling
search engines and other interested bots what's available on your site
and what's changed recently. You can generate sitemap files for your
-Laconica instance.
+StatusNet instance.
-1. Choose your sitemap URL layout. Laconica creates a number of
+1. Choose your sitemap URL layout. StatusNet creates a number of
sitemap XML files for different parts of your site. You may want to
- put these in a sub-directory of your Laconica directory to avoid
+ put these in a sub-directory of your StatusNet directory to avoid
clutter. The sitemap index file tells the search engines and other
bots where to find all the sitemap files; it *must* be in the main
installation directory or higher. Both types of file must be
@@ -660,7 +682,7 @@ to these resources.
Themes
------
-There are two themes shipped with this version of Laconica: "identica",
+There are two themes shipped with this version of StatusNet: "identica",
which is what the Identi.ca site uses, and "default", which is a good
basis for other sites.
@@ -691,28 +713,28 @@ default-avatar-mini.png: Ditto ditto, but 24x24. For subscriptions
You may want to start by copying the files from the default theme to
your own directory.
-NOTE: the HTML generated by Laconica changed *radically* between
+NOTE: the HTML generated by StatusNet changed *radically* between
version 0.6.x and 0.7.x. Older themes will need signification
modification to use the new output format.
Translation
-----------
-Translations in Laconica use the gettext system <http://www.gnu.org/software/gettext/>.
+Translations in StatusNet use the gettext system <http://www.gnu.org/software/gettext/>.
Theoretically, you can add your own sub-directory to the locale/
subdirectory to add a new language to your system. You'll need to
compile the ".po" files into ".mo" files, however.
-Contributions of translation information to Laconica are very easy:
-you can use the Web interface at http://laconi.ca/pootle/ to add one
+Contributions of translation information to StatusNet are very easy:
+you can use the Web interface at http://status.net/pootle/ to add one
or a few or lots of new translations -- or even new languages. You can
also download more up-to-date .po files there, if you so desire.
Backups
-------
-There is no built-in system for doing backups in Laconica. You can make
-backups of a working Laconica system by backing up the database and
+There is no built-in system for doing backups in StatusNet. You can make
+backups of a working StatusNet system by backing up the database and
the Web directory. To backup the database use mysqldump <http://ur1.ca/7xo>
and to backup the Web directory, try tar.
@@ -736,20 +758,20 @@ to users on a remote site. (Or not... it's not well tested.) The
Upgrading
=========
-IMPORTANT NOTE: Laconica 0.7.4 introduced a fix for some
+IMPORTANT NOTE: StatusNet 0.7.4 introduced a fix for some
incorrectly-stored international characters ("UTF-8"). For new
installations, it will now store non-ASCII characters correctly.
However, older installations will have the incorrect storage, and will
consequently show up "wrong" in browsers. See below for how to deal
with this situation.
-If you've been using Laconica 0.7, 0.6, 0.5 or lower, or if you've
+If you've been using StatusNet 0.7, 0.6, 0.5 or lower, or if you've
been tracking the "git" version of the software, you will probably
want to upgrade and keep your existing data. There is no automated
-upgrade procedure in Laconica 0.8.0. Try these step-by-step
+upgrade procedure in StatusNet 0.8.1. Try these step-by-step
instructions; read to the end first before trying them.
-0. Download Laconica and set up all the prerequisites as if you were
+0. Download StatusNet and set up all the prerequisites as if you were
doing a new install.
1. Make backups of both your database and your Web directory. UNDER NO
CIRCUMSTANCES should you try to do an upgrade without a known-good
@@ -766,14 +788,17 @@ instructions; read to the end first before trying them.
maildaemon.php file, and running something like "newaliases".
5. Once all writing processes to your site are turned off, make a
final backup of the Web directory and database.
-6. Move your Laconica directory to a backup spot, like "mublog.bak".
-7. Unpack your Laconica 0.8.0 tarball and move it to "mublog" or
+6. Move your StatusNet directory to a backup spot, like "mublog.bak".
+7. Unpack your StatusNet 0.8.1 tarball and move it to "mublog" or
wherever your code used to be.
8. Copy the config.php file and avatar directory from your old
directory to your new directory.
9. Copy htaccess.sample to .htaccess in the new directory. Change the
RewriteBase to use the correct path.
-10. Rebuild the database. NOTE: this step is destructive and cannot be
+10. Rebuild the database. (You can safely skip this step and go to #12
+ if you're upgrading from another 0.8.x version).
+
+ NOTE: this step is destructive and cannot be
reversed. YOU CAN EASILY DESTROY YOUR SITE WITH THIS STEP. Don't
do it without a known-good backup!
@@ -782,14 +807,14 @@ instructions; read to the end first before trying them.
mysql -u<rootuser> -p<rootpassword> <database> db/074to080.sql
- Otherwise, go to your Laconica directory and AFTER YOU MAKE A
+ Otherwise, go to your StatusNet directory and AFTER YOU MAKE A
BACKUP run the rebuilddb.sh script like this:
- ./scripts/rebuilddb.sh rootuser rootpassword database db/laconica.sql
+ ./scripts/rebuilddb.sh rootuser rootpassword database db/statusnet.sql
Here, rootuser and rootpassword are the username and password for a
user who can drop and create databases as well as tables; typically
- that's _not_ the user Laconica runs as. Note that rebuilddb.sh drops
+ that's _not_ the user StatusNet runs as. Note that rebuilddb.sh drops
your database and rebuilds it; if there is an error you have no
database. Make sure you have a backup.
For PostgreSQL databases there is an equivalent, rebuilddb_psql.sh,
@@ -806,8 +831,8 @@ the fixup_* scripts in the scripts directories. These will store some
precooked data in the DB. All upgraders should check out the inboxes
options below.
-NOTE: the database definition file, stoica.ini, has been renamed to
-laconica.ini (since this is the recommended database name). If you
+NOTE: the database definition file, laconica.ini, has been renamed to
+statusnet.ini (since this is the recommended database name). If you
have a line in your config.php pointing to the old name, you'll need
to update it.
@@ -843,13 +868,16 @@ problem.
3. When fixup_inboxes is finished, you can set the enabled flag to
'true'.
+NOTE: As of version 0.8.1 notice inboxes are automatically trimmed back
+ to ~1000 notices every once in a while.
+
NOTE: we will drop support for non-inboxed sites in the 0.9.x version
-of Laconica. It's time to switch now!
+of StatusNet. It's time to switch now!
UTF-8 Database
--------------
-Laconica 0.7.4 introduced a fix for some incorrectly-stored
+StatusNet 0.7.4 introduced a fix for some incorrectly-stored
international characters ("UTF-8"). This fix is not
backwards-compatible; installations from before 0.7.4 will show
non-ASCII characters of old notices incorrectly. This section explains
@@ -872,19 +900,19 @@ what to do.
Configuration options
=====================
-The main configuration file for Laconica (excepting configurations for
-dependency software) is config.php in your Laconica directory. If you
+The main configuration file for StatusNet (excepting configurations for
+dependency software) is config.php in your StatusNet directory. If you
edit any other file in the directory, like lib/common.php (where most
of the defaults are defined), you will lose your configuration options
in any upgrade, and you will wish that you had been more careful.
Starting with version 0.7.1, you can put config files in the
-/etc/laconica/ directory on your server, if it exists. Config files
+/etc/statusnet/ directory on your server, if it exists. Config files
will be included in this order:
-* /etc/laconica/laconica.php - server-wide config
-* /etc/laconica/<servername>.php - for a virtual host
-* /etc/laconica/<servername>_<pathname>.php - for a path
+* /etc/statusnet/statusnet.php - server-wide config
+* /etc/statusnet/<servername>.php - for a virtual host
+* /etc/statusnet/<servername>_<pathname>.php - for a path
* INSTALLDIR/config.php - for a particular implementation
Almost all configuration options are made through a two-dimensional
@@ -907,7 +935,7 @@ path: The path part of your site's URLs, like 'mublog' or ''
(installed in root).
fancy: whether or not your site uses fancy URLs (see Fancy URLs
section above). Default is false.
-logfile: full path to a file for Laconica to save logging
+logfile: full path to a file for StatusNet to save logging
information to. You may want to use this if you don't have
access to syslog.
logdebug: whether to log additional debug info like backtraces on
@@ -940,6 +968,8 @@ closed: If set to 'true', will disallow registration on your site.
the service, *then* set this variable to 'true'.
inviteonly: If set to 'true', will only allow registration if the user
was invited by an existing user.
+openidonly: If set to 'true', will only allow registrations and logins
+ through OpenID.
private: If set to 'true', anonymous users will be redirected to the
'login' page. Also, API methods that normally require no
authentication will require it. Note that this does not turn
@@ -964,9 +994,6 @@ sslserver: use an alternate server name for SSL URLs, like
shorturllength: Length of URL at which URLs in a message exceeding 140
characters will be sent to the user's chosen
shortening service.
-design: a default design (colors and background) for the site.
- Sub-items are: backgroundcolor, contentcolor, sidebarcolor,
- textcolor, linkcolor, backgroundimage, disposition.
dupelimit: minimum time allowed for one person to say the same thing
twice. Default 60s. Anything lower is considered a user
or UI error.
@@ -978,14 +1005,14 @@ This section is a reference to the configuration options for
DB_DataObject (see <http://ur1.ca/7xp>). The ones that you may want to
set are listed below for clarity.
-database: a DSN (Data Source Name) for your Laconica database. This is
+database: a DSN (Data Source Name) for your StatusNet database. This is
in the format 'protocol://username:password@hostname/databasename',
where 'protocol' is 'mysql' or 'mysqli' (or possibly 'postgresql', if you
really know what you're doing), 'username' is the username,
'password' is the password, and etc.
-ini_yourdbname: if your database is not named 'laconica', you'll need
+ini_yourdbname: if your database is not named 'statusnet', you'll need
to set this to point to the location of the
- laconica.ini file. Note that the real name of your database
+ statusnet.ini file. Note that the real name of your database
should go in there, not literally 'yourdbname'.
db_driver: You can try changing this to 'MDB2' to use the other driver
type for DB_DataObject, but note that it breaks the OpenID
@@ -1013,11 +1040,11 @@ utf8: whether to talk to the database in UTF-8 mode. This is the default
syslog
------
-By default, Laconica sites log error messages to the syslog facility.
+By default, StatusNet sites log error messages to the syslog facility.
(You can override this using the 'logfile' parameter described above).
-appname: The name that Laconica uses to log messages. By default it's
- "laconica", but if you have more than one installation on the
+appname: The name that StatusNet uses to log messages. By default it's
+ "statusnet", but if you have more than one installation on the
server, you may want to change the name for each instance so
you can track log messages more easily.
priority: level to log at. Currently ignored.
@@ -1076,9 +1103,9 @@ This is for configuring nicknames in the service.
blacklist: an array of strings for usernames that may not be
registered. A default array exists for strings that are
- used by Laconica (e.g. 'doc', 'main', 'avatar', 'theme')
+ used by StatusNet (e.g. 'doc', 'main', 'avatar', 'theme')
but you may want to add others if you have other software
- installed in a subdirectory of Laconica or if you just
+ installed in a subdirectory of StatusNet or if you just
don't want certain words used as usernames.
featured: an array of nicknames of 'featured' users of the site.
Can be useful to draw attention to well-known users, or
@@ -1151,7 +1178,7 @@ host: some XMPP domains are served by machines with a different
hostname. (For example, @gmail.com GTalk users connect to
talk.google.com). Set this to the correct hostname if that's the
case with your server.
-encryption: Whether to encrypt the connection between Laconica and the
+encryption: Whether to encrypt the connection between StatusNet and the
XMPP server. Defaults to true, but you can get
considerably better performance turning it off if you're
connecting to a server on the same machine or on a
@@ -1170,6 +1197,14 @@ For configuring invites.
enabled: Whether to allow users to send invites. Default true.
+openid
+------
+
+For configuring OpenID.
+
+enabled: Whether to allow users to register and login using OpenID. Default
+ true.
+
tag
---
@@ -1217,7 +1252,7 @@ base: memcached uses key-value pairs to store data. We build long,
base of the key is usually a simplified version of the site name
(like "Identi.ca" => "identica"), but you can overwrite this if
you need to. You can safely ignore it if you only have one
- Laconica site using your memcached server.
+ StatusNet site using your memcached server.
port: Port to connect to; defaults to 11211.
sphinx
@@ -1231,13 +1266,37 @@ enabled: Set to true to enable. Default false.
server: a string with the hostname of the sphinx server.
port: an integer with the port number of the sphinx server.
+emailpost
+---------
+
+For post-by-email.
+
+enabled: Whether to enable post-by-email. Defaults to true. You will
+ also need to set up maildaemon.php.
+
+sms
+---
+
+For SMS integration.
+
+enabled: Whether to enable SMS integration. Defaults to true. Queues
+ should also be enabled.
+
+twitter
+-------
+
+For Twitter integration
+
+enabled: Whether to enable Twitter integration. Defaults to true.
+ Queues should also be enabled.
+
integration
-----------
A catch-all for integration with other systems.
source: The name to use for the source of posts to Twitter. Defaults
- to 'laconica', but if you request your own source name from
+ to 'statusnet', but if you request your own source name from
Twitter <http://twitter.com/help/request_source>, you can use
that here instead. Status updates on Twitter will then have
links to your site.
@@ -1294,11 +1353,11 @@ snapshot
--------
The software will, by default, send statistical snapshots about the
-local installation to a stats server on the laconi.ca Web site. This
+local installation to a stats server on the status.net Web site. This
data is used by the developers to prioritize development decisions. No
identifying data about users or organizations is collected. The data
is available to the public for review. Participating in this survey
-helps Laconica developers take your needs into account when updating
+helps StatusNet developers take your needs into account when updating
the software.
run: string indicating when to run the statistics. Values can be 'web'
@@ -1309,7 +1368,7 @@ frequency: if run value is 'web', how often to report statistics.
Measured in Web hits; depends on how active your site is.
Default is 10000 -- that is, one report every 10000 Web hits,
on average.
-reporturl: URL to post statistics to. Defaults to Laconica developers'
+reporturl: URL to post statistics to. Defaults to StatusNet developers'
report system, but if they go evil or disappear you may
need to update this to another value. Note: if you
don't want to report stats, it's much better to
@@ -1432,10 +1491,24 @@ notify third-party servers of updates.
notify: an array of URLs for ping endpoints. Default is the empty
array (no notification).
+design
+------
+
+Default design (colors and background) for the site. Actual appearance
+depends on the theme. Null values mean to use the theme defaults.
+
+backgroundcolor: Hex color of the site background.
+contentcolor: Hex color of the content area background.
+sidebarcolor: Hex color of the sidebar background.
+textcolor: Hex color of all non-link text.
+linkcolor: Hex color of all links.
+backgroundimage: Image to use for the background.
+disposition: Flags for whether or not to tile the background image.
+
Plugins
=======
-Beginning with the 0.7.x branch, Laconica has supported a simple but
+Beginning with the 0.7.x branch, StatusNet has supported a simple but
powerful plugin architecture. Important events in the code are named,
like 'StartNoticeSave', and other software can register interest
in those events. When the events happen, the other software is called
@@ -1471,7 +1544,7 @@ can enable a plugin with the following line in config.php:
This will look for and load files named 'ExamplePlugin.php' or
'Example/ExamplePlugin.php' either in the plugins/ directory (for
-plugins that ship with Laconica) or in the local/ directory (for
+plugins that ship with StatusNet) or in the local/ directory (for
plugins you write yourself or that you get from somewhere else) or
local/plugins/.
@@ -1480,24 +1553,24 @@ Plugins are documented in their own directories.
Troubleshooting
===============
-The primary output for Laconica is syslog, unless you configured a
+The primary output for StatusNet is syslog, unless you configured a
separate logfile. This is probably the first place to look if you're
-getting weird behaviour from Laconica.
+getting weird behaviour from StatusNet.
-If you're tracking the unstable version of Laconica in the git
+If you're tracking the unstable version of StatusNet in the git
repository (see below), and you get a compilation error ("unexpected
T_STRING") in the browser, check to see that you don't have any
conflicts in your code.
-If you upgraded to Laconica 0.7.4 without reading the "Notice inboxes"
-section above, and all your users' 'Personal' tabs are empty, read the
-"Notice inboxes" section above.
+If you upgraded to StatusNet 0.8.1 without reading the "Notice
+inboxes" section above, and all your users' 'Personal' tabs are empty,
+read the "Notice inboxes" section above.
Myths
=====
-These are some myths you may see on the Web about Laconica.
-Documentation from the core team about Laconica has been pretty
+These are some myths you may see on the Web about StatusNet.
+Documentation from the core team about StatusNet has been pretty
sparse, so some backtracking and guesswork resulted in some incorrect
assumptions.
@@ -1509,7 +1582,7 @@ assumptions.
- "Edit dataobject.ini with the following settings..." dataobject.ini
is a development file for the DB_DataObject framework and is not
- used by the running software. It was removed from the Laconica
+ used by the running software. It was removed from the StatusNet
distribution because its presence was confusing. Do not bother
configuring dataobject.ini, and do not put your database username
and password into the file on a production Web server; unscrupulous
@@ -1519,45 +1592,55 @@ Unstable version
================
If you're adventurous or impatient, you may want to install the
-development version of Laconica. To get it, use the git version
+development version of StatusNet. To get it, use the git version
control tool <http://git-scm.com/> like so:
- git clone http://laconi.ca/software/laconica.git
+ git clone git@gitorious.org:statusnet/mainline.git
+
+This is the version of the software that runs on Identi.ca and the
+status.net hosted service. Using it is a mixed bag. On the positive
+side, it usually includes the latest security and bug fix patches. On
+the downside, it may also include changes that require admin
+intervention (like running a script or even raw SQL!) that may not be
+documented yet. It may be a good idea to test this version before
+installing it on your production machines.
To keep it up-to-date, use 'git pull'. Watch for conflicts!
Further information
===================
-There are several ways to get more information about Laconica.
+There are several ways to get more information about StatusNet.
-* There is a mailing list for Laconica developers and admins at
- http://mail.laconi.ca/mailman/listinfo/laconica-dev
-* The #laconica IRC channel on freenode.net <http://www.freenode.net/>.
-* The Laconica wiki, http://laconi.ca/trac/
+* There is a mailing list for StatusNet developers and admins at
+ http://mail.status.net/mailman/listinfo/statusnet-dev
+* The #statusnet IRC channel on freenode.net <http://www.freenode.net/>.
+* The StatusNet wiki, http://status.net/wiki/
+* The StatusNet blog, http://status.net/blog/
+* The StatusNet status update, <http://status.status.net/status> (!)
Feedback
========
* Microblogging messages to http://identi.ca/evan are very welcome.
-* Laconica's Trac server has a bug tracker for any defects you may find,
- or ideas for making things better. http://laconi.ca/trac/
-* e-mail to evan@identi.ca will usually be read and responded to very
+* StatusNet's Trac server has a bug tracker for any defects you may find,
+ or ideas for making things better. http://status.net/trac/
+* e-mail to evan@status.net will usually be read and responded to very
quickly, unless the question is really hard.
Credits
=======
The following is an incomplete list of developers who've worked on
-Laconi.ca. Apologies for any oversight; please let evan@identi.ca know
+StatusNet. Apologies for any oversight; please let evan@status.net know
if anyone's been overlooked in error.
-* Evan Prodromou, founder and lead developer, Control Yourself, Inc.
-* Zach Copley, Control Yourself, Inc.
-* Earle Martin, Control Yourself, Inc.
-* Marie-Claude Doyon, designer, Control Yourself, Inc.
-* Sarven Capadisli, Control Yourself, Inc.
-* Robin Millette, Control Yourself, Inc.
+* Evan Prodromou, founder and lead developer, StatusNet, Inc.
+* Zach Copley, StatusNet, Inc.
+* Earle Martin, StatusNet, Inc.
+* Marie-Claude Doyon, designer, StatusNet, Inc.
+* Sarven Capadisli, StatusNet, Inc.
+* Robin Millette, StatusNet, Inc.
* Ciaran Gultnieks
* Michael Landers
* Ori Avtalion
@@ -1589,6 +1672,6 @@ if anyone's been overlooked in error.
* Craig Andrews
Thanks also to the developers of our upstream library code and to the
-thousands of people who have tried out Identi.ca, installed Laconi.ca,
+thousands of people who have tried out Identi.ca, installed StatusNet,
told their friends, and built the Open Microblogging network to what
it is today.
diff --git a/actions/accesstoken.php b/actions/accesstoken.php
index 2a8cd1713..c99aaeded 100644
--- a/actions/accesstoken.php
+++ b/actions/accesstoken.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/omb.php';
* Access token class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AccesstokenAction extends Action
{
diff --git a/actions/all.php b/actions/all.php
index f06ead2a8..bfde3a7e4 100644
--- a/actions/all.php
+++ b/actions/all.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/lib/personalgroupnav.php';
require_once INSTALLDIR.'/lib/noticelist.php';
@@ -25,11 +25,31 @@ require_once INSTALLDIR.'/lib/feedlist.php';
class AllAction extends ProfileAction
{
+ var $notice;
+
function isReadOnly($args)
{
return true;
}
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $cur = common_current_user();
+
+ if (!empty($cur) && $cur->id == $this->user->id) {
+ $this->notice = $this->user->noticeInbox(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+ } else {
+ $this->notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+ }
+
+ if($this->page > 1 && $this->notice->N == 0){
+ $this->serverError(_('No such page'),$code=404);
+ }
+
+ return true;
+ }
+
function handle($args)
{
parent::handle($args);
@@ -88,7 +108,9 @@ class AllAction extends ProfileAction
}
}
else {
- $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
+ $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin',
+ $this->user->nickname);
}
$this->elementStart('div', 'guide');
@@ -98,15 +120,7 @@ class AllAction extends ProfileAction
function showContent()
{
- $cur = common_current_user();
-
- if (!empty($cur) && $cur->id == $this->user->id) {
- $notice = $this->user->noticeInbox(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
- } else {
- $notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
- }
-
- $nl = new NoticeList($notice, $this);
+ $nl = new NoticeList($this->notice, $this);
$cnt = $nl->show();
diff --git a/actions/allrss.php b/actions/allrss.php
index 885a67f61..57efb73f0 100644
--- a/actions/allrss.php
+++ b/actions/allrss.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,11 +41,11 @@ require_once INSTALLDIR.'/lib/rssaction.php';
* Formatting of RSS handled by Rss10Action
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AllrssAction extends Rss10Action
{
@@ -115,8 +115,8 @@ class AllrssAction extends Rss10Action
'link' => common_local_url('all',
array('nickname' =>
$user->nickname)),
- 'description' => sprintf(_('Feed for friends of %s'),
- $user->nickname));
+ 'description' => sprintf(_('Updates from %1$s and friends on %2$s!'),
+ $user->nickname, common_config('site', 'name')));
return $c;
}
diff --git a/actions/api.php b/actions/api.php
index 8b92889f8..3705d035c 100644
--- a/actions/api.php
+++ b/actions/api.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class ApiAction extends Action
{
@@ -27,6 +27,8 @@ class ApiAction extends Action
var $api_arg;
var $api_method;
var $api_action;
+ var $auth_user;
+ var $auth_pw;
function handle($args)
{
@@ -35,6 +37,7 @@ class ApiAction extends Action
$this->api_action = $this->arg('apiaction');
$method = $this->arg('method');
$argument = $this->arg('argument');
+ $this->basic_auth_process_header();
if (isset($argument)) {
$cmdext = explode('.', $argument);
@@ -50,16 +53,16 @@ class ApiAction extends Action
}
if ($this->requires_auth()) {
- if (!isset($_SERVER['PHP_AUTH_USER'])) {
+ if (!isset($this->auth_user)) {
# This header makes basic auth go
- header('WWW-Authenticate: Basic realm="Laconica API"');
+ header('WWW-Authenticate: Basic realm="StatusNet API"');
# If the user hits cancel -- bam!
$this->show_basic_auth_error();
} else {
- $nickname = $_SERVER['PHP_AUTH_USER'];
- $password = $_SERVER['PHP_AUTH_PW'];
+ $nickname = $this->auth_user;
+ $password = $this->auth_pw;
$user = common_check_user($nickname, $password);
if ($user) {
@@ -76,8 +79,8 @@ class ApiAction extends Action
} else {
// Caller might give us a username even if not required
- if (isset($_SERVER['PHP_AUTH_USER'])) {
- $user = User::staticGet('nickname', $_SERVER['PHP_AUTH_USER']);
+ if (isset($this->auth_user)) {
+ $user = User::staticGet('nickname', $this->auth_user);
if ($user) {
$this->user = $user;
}
@@ -125,29 +128,36 @@ class ApiAction extends Action
'users/show',
'help/test',
'help/downtime_schedule',
- 'laconica/version',
- 'laconica/config',
- 'laconica/wadl',
+ 'statusnet/version',
+ 'statusnet/config',
+ 'statusnet/wadl',
'tags/timeline',
'oembed/oembed',
+ 'groups/show',
+ 'groups/timeline',
+ 'groups/list_all',
+ 'groups/membership',
+ 'groups/is_member',
'groups/timeline');
static $bareauth = array('statuses/user_timeline',
'statuses/friends_timeline',
+ 'statuses/home_timeline',
'statuses/friends',
'statuses/replies',
'statuses/mentions',
'statuses/followers',
'favorites/favorites',
- 'friendships/show');
+ 'friendships/show',
+ 'groups/list_groups');
$fullname = "$this->api_action/$this->api_method";
- // If the site is "private", all API methods except laconica/config
+ // If the site is "private", all API methods except statusnet/config
// need authentication
if (common_config('site', 'private')) {
- return $fullname != 'laconica/config' || false;
+ return $fullname != 'statusnet/config' || false;
}
// bareauth: only needs auth if without an argument or query param specifying user
@@ -197,6 +207,39 @@ class ApiAction extends Action
}
}
+ function basic_auth_process_header()
+ {
+ if(isset($_SERVER['AUTHORIZATION']) || isset($_SERVER['HTTP_AUTHORIZATION']))
+ {
+ $authorization_header = isset($_SERVER['HTTP_AUTHORIZATION'])?$_SERVER['HTTP_AUTHORIZATION']:$_SERVER['AUTHORIZATION'];
+ }
+
+ if(isset($_SERVER['PHP_AUTH_USER']))
+ {
+ $this->auth_user = $_SERVER['PHP_AUTH_USER'];
+ $this->auth_pw = $_SERVER['PHP_AUTH_PW'];
+ }
+ elseif ( isset($authorization_header) && strstr(substr($authorization_header, 0,5),'Basic') )
+ {
+ // decode the HTTP_AUTHORIZATION header on php-cgi server self
+ // on fcgid server the header name is AUTHORIZATION
+
+ $auth_hash = base64_decode( substr($authorization_header, 6) );
+ list($this->auth_user, $this->auth_pw) = explode(':', $auth_hash);
+
+ // set all to NULL on a empty basic auth request
+ if($this->auth_user == "") {
+ $this->auth_user = NULL;
+ $this->auth_pw = NULL;
+ }
+ }
+ else
+ {
+ $this->auth_user = NULL;
+ $this->auth_pw = NULL;
+ }
+ }
+
function show_basic_auth_error()
{
header('HTTP/1.1 401 Unauthorized');
diff --git a/actions/attachment.php b/actions/attachment.php
index c6a5d0d52..6981354d1 100644
--- a/actions/attachment.php
+++ b/actions/attachment.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Show notice attachments
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/attachmentlist.php';
* Show notice attachments
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AttachmentAction extends Action
@@ -103,18 +103,18 @@ class AttachmentAction extends Action
$this->element('link',array('rel'=>'alternate',
'type'=>'application/json+oembed',
'href'=>common_local_url(
- 'api',
- array('apiaction'=>'oembed','method'=>'oembed.json'),
- array('url'=>
+ 'oembed',
+ array(),
+ array('format'=>'json', 'url'=>
common_local_url('attachment',
array('attachment' => $this->attachment->id)))),
'title'=>'oEmbed'),null);
$this->element('link',array('rel'=>'alternate',
'type'=>'text/xml+oembed',
'href'=>common_local_url(
- 'api',
- array('apiaction'=>'oembed','method'=>'oembed.xml'),
- array('url'=>
+ 'oembed',
+ array(),
+ array('format'=>'xml','url'=>
common_local_url('attachment',
array('attachment' => $this->attachment->id)))),
'title'=>'oEmbed'),null);
diff --git a/actions/attachment_ajax.php b/actions/attachment_ajax.php
index 4caa159f3..1e0728075 100644
--- a/actions/attachment_ajax.php
+++ b/actions/attachment_ajax.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Show notice attachments
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/actions/attachment.php';
* Show notice attachments
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class Attachment_ajaxAction extends AttachmentAction
diff --git a/actions/attachment_thumbnail.php b/actions/attachment_thumbnail.php
index 248d16e38..7d0ac97a6 100644
--- a/actions/attachment_thumbnail.php
+++ b/actions/attachment_thumbnail.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Show notice attachments
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/actions/attachment.php';
* Show notice attachments
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class Attachment_thumbnailAction extends AttachmentAction
diff --git a/actions/avatarbynickname.php b/actions/avatarbynickname.php
index 3e615261f..537950792 100644
--- a/actions/avatarbynickname.php
+++ b/actions/avatarbynickname.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -36,11 +36,11 @@ if (!defined('LACONICA')) {
* Retrieve user avatar by nickname action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AvatarbynicknameAction extends Action
{
diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php
index c2bb35a39..ded419dd7 100644
--- a/actions/avatarsettings.php
+++ b/actions/avatarsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Upload an avatar
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -42,12 +42,12 @@ define('MAX_ORIGINAL', 480);
* We use jCrop plugin for jQuery to crop the image after upload.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AvatarsettingsAction extends AccountSettingsAction
@@ -362,13 +362,13 @@ class AvatarsettingsAction extends AccountSettingsAction
$profile = $user->getProfile();
$avatar = $profile->getOriginalAvatar();
- $avatar->delete();
+ if($avatar) $avatar->delete();
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
- $avatar->delete();
+ if($avatar) $avatar->delete();
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
- $avatar->delete();
+ if($avatar) $avatar->delete();
$avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
- $avatar->delete();
+ if($avatar) $avatar->delete();
$this->showForm(_('Avatar deleted.'), true);
}
@@ -382,13 +382,7 @@ class AvatarsettingsAction extends AccountSettingsAction
function showStylesheets()
{
parent::showStylesheets();
- $jcropStyle =
- common_path('theme/base/css/jquery.Jcrop.css?version='.LACONICA_VERSION);
-
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => $jcropStyle,
- 'media' => 'screen, projection, tv'));
+ $this->cssLink('css/jquery.Jcrop.css','base','screen, projection, tv');
}
/**
@@ -402,13 +396,10 @@ class AvatarsettingsAction extends AccountSettingsAction
parent::showScripts();
if ($this->mode == 'crop') {
- $jcropPack = common_path('js/jcrop/jquery.Jcrop.pack.js');
- $jcropGo = common_path('js/jcrop/jquery.Jcrop.go.js');
-
- $this->element('script', array('type' => 'text/javascript',
- 'src' => $jcropPack));
- $this->element('script', array('type' => 'text/javascript',
- 'src' => $jcropGo));
+ $this->script('js/jcrop/jquery.Jcrop.min.js');
+ $this->script('js/jcrop/jquery.Jcrop.go.js');
}
+
+ $this->autofocus('avatarfile');
}
}
diff --git a/actions/block.php b/actions/block.php
index 06f92254e..408f16434 100644
--- a/actions/block.php
+++ b/actions/block.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -36,11 +36,11 @@ if (!defined('LACONICA')) {
* Block a user action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class BlockAction extends Action
{
diff --git a/actions/blockedfromgroup.php b/actions/blockedfromgroup.php
index 5c1eab354..ca4a711cb 100644
--- a/actions/blockedfromgroup.php
+++ b/actions/blockedfromgroup.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of group members
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* List of profiles blocked from this group
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class BlockedfromgroupAction extends GroupDesignAction
@@ -190,11 +190,11 @@ class GroupBlockListItem extends ProfileListItem
* Form for unblocking a user from a group
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see UnblockForm
*/
diff --git a/actions/confirmaddress.php b/actions/confirmaddress.php
index 725c1f1e3..201694286 100644
--- a/actions/confirmaddress.php
+++ b/actions/confirmaddress.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Confirm an address
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Confirm
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ if (!defined('LACONICA')) {
* accepts those codes.
*
* @category Confirm
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ConfirmaddressAction extends Action
@@ -67,7 +67,11 @@ class ConfirmaddressAction extends Action
parent::handle($args);
if (!common_logged_in()) {
common_set_returnto($this->selfUrl());
- common_redirect(common_local_url('login'));
+ if (!common_config('site', 'openidonly')) {
+ common_redirect(common_local_url('login'));
+ } else {
+ common_redirect(common_local_url('openidlogin'));
+ }
return;
}
$code = $this->trimmed('code');
diff --git a/actions/conversation.php b/actions/conversation.php
index c8755ba6e..900a724ef 100644
--- a/actions/conversation.php
+++ b/actions/conversation.php
@@ -5,13 +5,13 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -27,7 +27,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ require_once INSTALLDIR.'/lib/noticelist.php';
* Conversation tree in the browser
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ConversationAction extends Action
@@ -129,10 +129,10 @@ class ConversationAction extends Action
* The widget class for displaying a hierarchical list of notices.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ConversationTree extends NoticeList
@@ -167,6 +167,8 @@ class ConversationTree extends NoticeList
function _buildTree()
{
+ $cnt = 0;
+
$this->tree = array();
$this->table = array();
@@ -248,10 +250,10 @@ class ConversationTree extends NoticeList
* Special class of NoticeListItem for use inside conversation trees.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ConversationTreeItem extends NoticeListItem
diff --git a/actions/deletenotice.php b/actions/deletenotice.php
index e733f9650..3d040f2fa 100644
--- a/actions/deletenotice.php
+++ b/actions/deletenotice.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Class for deleting a notice
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/actions/disfavor.php b/actions/disfavor.php
index 02e01d6e0..6269f1bd2 100644
--- a/actions/disfavor.php
+++ b/actions/disfavor.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ require_once INSTALLDIR.'/lib/favorform.php';
* Disfavor class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class DisfavorAction extends Action
{
diff --git a/actions/doc.php b/actions/doc.php
index 54ae13803..68295234c 100644
--- a/actions/doc.php
+++ b/actions/doc.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,11 +37,11 @@ if (!defined('LACONICA')) {
* Documentation class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class DocAction extends Action
{
diff --git a/actions/editgroup.php b/actions/editgroup.php
index 6aa6f8b11..b8dac31cb 100644
--- a/actions/editgroup.php
+++ b/actions/editgroup.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Edit an existing group
*
@@ -20,16 +20,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ if (!defined('LACONICA')) {
* This is the form for adding a new group
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class EditgroupAction extends GroupDesignAction
@@ -160,6 +160,12 @@ class EditgroupAction extends GroupDesignAction
}
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('nickname');
+ }
+
function trySave()
{
$cur = common_current_user();
@@ -244,7 +250,6 @@ class EditgroupAction extends GroupDesignAction
$this->group->homepage = $homepage;
$this->group->description = $description;
$this->group->location = $location;
- $this->group->created = common_sql_now();
$result = $this->group->update($orig);
diff --git a/actions/emailsettings.php b/actions/emailsettings.php
index 634388fdd..6eff06c0d 100644
--- a/actions/emailsettings.php
+++ b/actions/emailsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Settings for email
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/accountsettingsaction.php';
* Settings for email
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
@@ -71,6 +71,12 @@ class EmailsettingsAction extends AccountSettingsAction
return _('Manage how you get email from %%site.name%%.');
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('email');
+ }
+
/**
* Content area of the page
*
@@ -122,7 +128,7 @@ class EmailsettingsAction extends AccountSettingsAction
}
$this->elementEnd('fieldset');
- if ($user->email) {
+ if (common_config('emailpost', 'enabled') && $user->email) {
$this->elementStart('fieldset', array('id' => 'settings_email_incoming'));
$this->element('legend',_('Incoming email'));
if ($user->incomingemail) {
@@ -173,11 +179,13 @@ class EmailsettingsAction extends AccountSettingsAction
_('Allow friends to nudge me and send me an email.'),
$user->emailnotifynudge);
$this->elementEnd('li');
- $this->elementStart('li');
- $this->checkbox('emailpost',
- _('I want to post notices by email.'),
- $user->emailpost);
- $this->elementEnd('li');
+ if (common_config('emailpost', 'enabled')) {
+ $this->elementStart('li');
+ $this->checkbox('emailpost',
+ _('I want to post notices by email.'),
+ $user->emailpost);
+ $this->elementEnd('li');
+ }
$this->elementStart('li');
$this->checkbox('emailmicroid',
_('Publish a MicroID for my email address.'),
diff --git a/actions/facebookhome.php b/actions/facebookhome.php
index 6d8d0745d..70f205205 100644
--- a/actions/facebookhome.php
+++ b/actions/facebookhome.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/lib/facebookaction.php';
diff --git a/actions/facebookinvite.php b/actions/facebookinvite.php
index f43d04e27..6dfc9d688 100644
--- a/actions/facebookinvite.php
+++ b/actions/facebookinvite.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/actions/facebooklogin.php b/actions/facebooklogin.php
index aa86cfbc0..8ac2477ab 100644
--- a/actions/facebooklogin.php
+++ b/actions/facebooklogin.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/facebookaction.php');
diff --git a/actions/facebookremove.php b/actions/facebookremove.php
index 9ca7a77a8..ae231c0fb 100644
--- a/actions/facebookremove.php
+++ b/actions/facebookremove.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/lib/facebookaction.php';
diff --git a/actions/facebooksettings.php b/actions/facebooksettings.php
index c3b364743..84bdde910 100644
--- a/actions/facebooksettings.php
+++ b/actions/facebooksettings.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/lib/facebookaction.php';
diff --git a/actions/favor.php b/actions/favor.php
index fe51e34a2..2aeb1da61 100644
--- a/actions/favor.php
+++ b/actions/favor.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ require_once INSTALLDIR.'/lib/disfavorform.php';
* Favor class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FavorAction extends Action
{
diff --git a/actions/favorited.php b/actions/favorited.php
index 156c7a700..5ba508cdf 100644
--- a/actions/favorited.php
+++ b/actions/favorited.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of popular notices
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -42,11 +42,11 @@ require_once INSTALLDIR.'/lib/noticelist.php';
* is measured by
*
* @category Personal
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FavoritedAction extends Action
@@ -153,7 +153,8 @@ class FavoritedAction extends Action
$message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.');
}
else {
- $message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!');
+ $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to add a notice to your favorites!'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
}
$this->elementStart('div', 'guide');
diff --git a/actions/favoritesrss.php b/actions/favoritesrss.php
index c439a9a62..2d5ce9854 100644
--- a/actions/favoritesrss.php
+++ b/actions/favoritesrss.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,12 +41,12 @@ require_once INSTALLDIR.'/lib/rssaction.php';
* Formatting of RSS handled by Rss10Action
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FavoritesrssAction extends Rss10Action
{
@@ -111,8 +111,8 @@ class FavoritesrssAction extends Rss10Action
'link' => common_local_url('showfavorites',
array('nickname' =>
$user->nickname)),
- 'description' => sprintf(_('Feed of favorite notices of %s'),
- $user->nickname));
+ 'description' => sprintf(_('Updates favored by %1$s on %2$s!'),
+ $user->nickname, common_config('site', 'name')));
return $c;
}
diff --git a/actions/featured.php b/actions/featured.php
index 04365687d..39bf09d8f 100644
--- a/actions/featured.php
+++ b/actions/featured.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of featured users
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ require_once INSTALLDIR.'/lib/publicgroupnav.php';
* List of featured users
*
* @category Public
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FeaturedAction extends Action
diff --git a/actions/file.php b/actions/file.php
index 8310e48df..10c59a961 100644
--- a/actions/file.php
+++ b/actions/file.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/actions/shownotice.php');
diff --git a/actions/finishaddopenid.php b/actions/finishaddopenid.php
index 32bceecfd..b6de4f244 100644
--- a/actions/finishaddopenid.php
+++ b/actions/finishaddopenid.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Complete adding an OpenID
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ require_once INSTALLDIR.'/lib/openid.php';
* Handle the return from an OpenID verification
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FinishaddopenidAction extends Action
diff --git a/actions/finishopenidlogin.php b/actions/finishopenidlogin.php
index ff0b35218..9ac036985 100644
--- a/actions/finishopenidlogin.php
+++ b/actions/finishopenidlogin.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/openid.php');
@@ -30,7 +30,9 @@ class FinishopenidloginAction extends Action
function handle($args)
{
parent::handle($args);
- if (common_is_real_login()) {
+ if (!common_config('openid', 'enabled')) {
+ common_redirect(common_local_url('login'));
+ } else if (common_is_real_login()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$token = $this->trimmed('token');
@@ -217,7 +219,7 @@ class FinishopenidloginAction extends Action
if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64,
- 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
+ 'format' => NICKNAME_FMT))) {
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
return;
}
@@ -389,7 +391,7 @@ class FinishopenidloginAction extends Action
{
if (!Validate::string($str, array('min_length' => 1,
'max_length' => 64,
- 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
+ 'format' => NICKNAME_FMT))) {
return false;
}
if (!User::allowed_nickname($str)) {
@@ -410,7 +412,7 @@ class FinishopenidloginAction extends Action
}
}
- # We try to use an OpenID URL as a legal Laconica user name in this order
+ # We try to use an OpenID URL as a legal StatusNet user name in this order
# 1. Plain hostname, like http://evanp.myopenid.com/
# 2. One element in path, like http://profile.typekey.com/EvanProdromou/
# or http://getopenid.com/evanprodromou
diff --git a/actions/finishremotesubscribe.php b/actions/finishremotesubscribe.php
index 5c764aeb0..871bc3d2d 100644
--- a/actions/finishremotesubscribe.php
+++ b/actions/finishremotesubscribe.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/omb.php');
@@ -284,7 +284,7 @@ class FinishremotesubscribeAction extends Action
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(),
- array('User-Agent: Laconica/' . LACONICA_VERSION));
+ array('User-Agent: StatusNet/' . STATUSNET_VERSION));
common_debug('got result: "'.print_r($result,true).'"', __FILE__);
diff --git a/actions/foaf.php b/actions/foaf.php
index b481b2437..356393304 100644
--- a/actions/foaf.php
+++ b/actions/foaf.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
define('LISTENER', 1);
define('LISTENEE', -1);
@@ -146,8 +146,10 @@ class FoafAction extends Action
while ($sub->fetch()) {
if ($sub->token) {
$other = Remote_profile::staticGet('id', $sub->subscriber);
+ $profile = Profile::staticGet('id', $sub->subscriber);
} else {
$other = User::staticGet('id', $sub->subscriber);
+ $profile = Profile::staticGet('id', $sub->subscriber);
}
if (!$other) {
common_debug('Got a bad subscription: '.print_r($sub,true));
@@ -158,12 +160,15 @@ class FoafAction extends Action
} else {
$person[$other->uri] = array(LISTENER,
$other->id,
- $other->nickname,
+ $profile->nickname,
(empty($sub->token)) ? 'User' : 'Remote_profile');
}
$other->free();
$other = null;
unset($other);
+ $profile->free();
+ $profile = null;
+ unset($profile);
}
}
@@ -254,8 +259,10 @@ class FoafAction extends Action
while ($sub->fetch()) {
if (!empty($sub->token)) {
$other = Remote_profile::staticGet('id', $sub->subscribed);
+ $profile = Profile::staticGet('id', $sub->subscribed);
} else {
$other = User::staticGet('id', $sub->subscribed);
+ $profile = Profile::staticGet('id', $sub->subscribed);
}
if (empty($other)) {
common_debug('Got a bad subscription: '.print_r($sub,true));
@@ -264,11 +271,14 @@ class FoafAction extends Action
$this->element('sioc:follows', array('rdf:resource' => $other->uri.'#acct'));
$person[$other->uri] = array(LISTENEE,
$other->id,
- $other->nickname,
+ $profile->nickname,
(empty($sub->token)) ? 'User' : 'Remote_profile');
$other->free();
$other = null;
unset($other);
+ $profile->free();
+ $profile = null;
+ unset($profile);
}
}
diff --git a/actions/groupblock.php b/actions/groupblock.php
index ce2c6c144..979a56a81 100644
--- a/actions/groupblock.php
+++ b/actions/groupblock.php
@@ -5,13 +5,13 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -27,7 +27,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Block a user from a group
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupblockAction extends Action
diff --git a/actions/groupbyid.php b/actions/groupbyid.php
index 7d327d56c..52cfaddfc 100644
--- a/actions/groupbyid.php
+++ b/actions/groupbyid.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Permalink for group
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -42,10 +42,10 @@ require_once INSTALLDIR.'/lib/feedlist.php';
* an URL with the ID in it as the permanent identifier.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupbyidAction extends Action
diff --git a/actions/groupdesignsettings.php b/actions/groupdesignsettings.php
index bb01243c6..cd86e3b05 100644
--- a/actions/groupdesignsettings.php
+++ b/actions/groupdesignsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Change user password
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ require_once INSTALLDIR . '/lib/designsettings.php';
* Saves a design for a given group
*
* @category Settings
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupDesignSettingsAction extends DesignSettingsAction
diff --git a/actions/grouplogo.php b/actions/grouplogo.php
index 8f6158dac..63ba769c7 100644
--- a/actions/grouplogo.php
+++ b/actions/grouplogo.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Upload an avatar
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -42,12 +42,12 @@ define('MAX_ORIGINAL', 480);
* We use jCrop plugin for jQuery to crop the image after upload.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GrouplogoAction extends GroupDesignAction
@@ -428,13 +428,7 @@ class GrouplogoAction extends GroupDesignAction
function showStylesheets()
{
parent::showStylesheets();
- $jcropStyle =
- common_path('theme/base/css/jquery.Jcrop.css?version='.LACONICA_VERSION);
-
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => $jcropStyle,
- 'media' => 'screen, projection, tv'));
+ $this->cssLink('css/jquery.Jcrop.css','base','screen, projection, tv');
}
/**
@@ -448,14 +442,11 @@ class GrouplogoAction extends GroupDesignAction
parent::showScripts();
if ($this->mode == 'crop') {
- $jcropPack = common_path('js/jcrop/jquery.Jcrop.pack.js');
- $jcropGo = common_path('js/jcrop/jquery.Jcrop.go.js');
-
- $this->element('script', array('type' => 'text/javascript',
- 'src' => $jcropPack));
- $this->element('script', array('type' => 'text/javascript',
- 'src' => $jcropGo));
+ $this->script('js/jcrop/jquery.Jcrop.min.js');
+ $this->script('js/jcrop/jquery.Jcrop.go.js');
}
+
+ $this->autofocus('avatarfile');
}
function showLocalNav()
diff --git a/actions/groupmembers.php b/actions/groupmembers.php
index 14256526a..dcbdd3759 100644
--- a/actions/groupmembers.php
+++ b/actions/groupmembers.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of group members
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ require_once INSTALLDIR.'/lib/publicgroupnav.php';
* List of group members
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupmembersAction extends GroupDesignAction
@@ -220,11 +220,11 @@ class GroupMemberListItem extends ProfileListItem
* Form for blocking a user from a group
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see BlockForm
*/
@@ -348,11 +348,11 @@ class GroupBlockForm extends Form
* Form for making a user an admin for a group
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class MakeAdminForm extends Form
diff --git a/actions/grouprss.php b/actions/grouprss.php
index 2bdcaafb2..70c1ded48 100644
--- a/actions/grouprss.php
+++ b/actions/grouprss.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Group main page
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ define('MEMBERS_PER_SECTION', 27);
* Group RSS feed
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class groupRssAction extends Rss10Action
@@ -132,9 +132,10 @@ class groupRssAction extends Rss10Action
$c = array('url' => common_local_url('grouprss',
array('nickname' =>
$group->nickname)),
- 'title' => $group->nickname,
+ 'title' => sprintf(_('%s timeline'), $group->nickname),
'link' => common_local_url('showgroup', array('nickname' => $group->nickname)),
- 'description' => sprintf(_('Microblog by %s group'), $group->nickname));
+ 'description' => sprintf(_('Updates from members of %1$s on %2$s!'),
+ $group->nickname, common_config('site', 'name')));
return $c;
}
diff --git a/actions/groups.php b/actions/groups.php
index 3d62843ed..10a1d5964 100644
--- a/actions/groups.php
+++ b/actions/groups.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Latest groups information
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ require_once INSTALLDIR.'/lib/grouplist.php';
* Show the latest groups on the site
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupsAction extends Action
diff --git a/actions/groupsearch.php b/actions/groupsearch.php
index c50466ce6..be15efc47 100644
--- a/actions/groupsearch.php
+++ b/actions/groupsearch.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ if (!defined('LACONICA')) {
* Group search action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupsearchAction extends SearchAction
{
@@ -82,7 +82,8 @@ class GroupsearchAction extends SearchAction
$message = _('If you can\'t find the group you\'re looking for, you can [create it](%%action.newgroup%%) yourself.');
}
else {
- $message = _('Why not [register an account](%%action.register%%) and [create the group](%%action.newgroup%%) yourself!');
+ $message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and [create the group](%%%%action.newgroup%%%%) yourself!'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
}
$this->elementStart('div', 'guide');
$this->raw(common_markup_to_html($message));
@@ -90,6 +91,12 @@ class GroupsearchAction extends SearchAction
$user_group->free();
}
}
+
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('q');
+ }
}
class GroupSearchResults extends GroupList
diff --git a/actions/groupunblock.php b/actions/groupunblock.php
index 6beb46352..dd6b15c26 100644
--- a/actions/groupunblock.php
+++ b/actions/groupunblock.php
@@ -5,13 +5,13 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -27,7 +27,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Unlock a user from a group
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupunblockAction extends Action
diff --git a/actions/imsettings.php b/actions/imsettings.php
index e0f5ede3a..f57933b43 100644
--- a/actions/imsettings.php
+++ b/actions/imsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Settings for Jabber/XMPP integration
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ require_once INSTALLDIR.'/lib/jabber.php';
* Settings for Jabber/XMPP integration
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see SettingsAction
*/
@@ -84,6 +84,12 @@ class ImsettingsAction extends ConnectSettingsAction
function showContent()
{
+ if (!common_config('xmpp', 'enabled')) {
+ $this->element('div', array('class' => 'error'),
+ _('IM is not available.'));
+ return;
+ }
+
$user = common_current_user();
$this->elementStart('form', array('method' => 'post',
'id' => 'form_settings_im',
diff --git a/actions/inbox.php b/actions/inbox.php
index f14ba631f..6cb7f9e15 100644
--- a/actions/inbox.php
+++ b/actions/inbox.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* action handler for message inbox
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Message
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/mailbox.php';
* action handler for message inbox
*
* @category Message
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see MailboxAction
*/
diff --git a/actions/invite.php b/actions/invite.php
index bdea4807d..9fa6a76f6 100644
--- a/actions/invite.php
+++ b/actions/invite.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class InviteAction extends CurrentUserDesignAction
{
@@ -98,6 +98,12 @@ class InviteAction extends CurrentUserDesignAction
$this->showPage();
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('addresses');
+ }
+
function title()
{
if ($this->mode == 'sent') {
@@ -216,7 +222,7 @@ class InviteAction extends CurrentUserDesignAction
$recipients = array($email);
$headers['From'] = mail_notify_from();
- $headers['To'] = $email;
+ $headers['To'] = trim($email);
$headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename);
$body = sprintf(_("%1\$s has invited you to join them on %2\$s (%3\$s).\n\n".
@@ -235,7 +241,7 @@ class InviteAction extends CurrentUserDesignAction
common_root_url(),
$personal,
common_local_url('showstream', array('nickname' => $user->nickname)),
- common_local_url('register', array('code' => $invite->code)));
+ common_local_url((!common_config('site', 'openidonly')) ? 'register' : 'openidlogin', array('code' => $invite->code)));
mail_send($recipients, $headers, $body);
}
diff --git a/actions/joingroup.php b/actions/joingroup.php
index 0e4f96eaf..0209dd43f 100644
--- a/actions/joingroup.php
+++ b/actions/joingroup.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Join a group
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ if (!defined('LACONICA')) {
* for users.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class JoingroupAction extends Action
diff --git a/actions/leavegroup.php b/actions/leavegroup.php
index 215ccd901..60b22e147 100644
--- a/actions/leavegroup.php
+++ b/actions/leavegroup.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Leave a group
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ if (!defined('LACONICA')) {
* for users.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class LeavegroupAction extends Action
diff --git a/actions/login.php b/actions/login.php
index 50de83f6f..ac8c40c3e 100644
--- a/actions/login.php
+++ b/actions/login.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Login form
*
@@ -20,14 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Login
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +36,11 @@ if (!defined('LACONICA')) {
* Login form
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class LoginAction extends Action
@@ -65,6 +67,8 @@ class LoginAction extends Action
*
* Switches on request method; either shows the form or handles its input.
*
+ * Checks if only OpenID is allowed and redirects to openidlogin if so.
+ *
* @param array $args $_REQUEST data
*
* @return void
@@ -73,7 +77,9 @@ class LoginAction extends Action
function handle($args)
{
parent::handle($args);
- if (common_is_real_login()) {
+ if (common_config('site', 'openidonly')) {
+ common_redirect(common_local_url('openidlogin'));
+ } else if (common_is_real_login()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->checkLogin();
@@ -158,6 +164,12 @@ class LoginAction extends Action
$this->showPage();
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('nickname');
+ }
+
/**
* Title of the page
*
@@ -247,11 +259,15 @@ class LoginAction extends Action
return _('For security reasons, please re-enter your ' .
'user name and password ' .
'before changing your settings.');
- } else {
+ } else if (common_config('openid', 'enabled')) {
return _('Login with your username and password. ' .
'Don\'t have a username yet? ' .
'[Register](%%action.register%%) a new account, or ' .
'try [OpenID](%%action.openidlogin%%). ');
+ } else {
+ return _('Login with your username and password. ' .
+ 'Don\'t have a username yet? ' .
+ '[Register](%%action.register%%) a new account.');
}
}
diff --git a/actions/logout.php b/actions/logout.php
index 3fcfb4f4e..298b2a484 100644
--- a/actions/logout.php
+++ b/actions/logout.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/openid.php';
* Logout action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class LogoutAction extends Action
{
diff --git a/actions/makeadmin.php b/actions/makeadmin.php
index 6fc2cf9ab..2dfddebc2 100644
--- a/actions/makeadmin.php
+++ b/actions/makeadmin.php
@@ -5,13 +5,13 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -27,7 +27,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Make another user an admin of a group
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class MakeadminAction extends Action
diff --git a/actions/microsummary.php b/actions/microsummary.php
index 6884a919a..5c01a9ce0 100644
--- a/actions/microsummary.php
+++ b/actions/microsummary.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -36,11 +36,11 @@ if (!defined('LACONICA')) {
* Microsummary action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class MicrosummaryAction extends Action
{
diff --git a/actions/newgroup.php b/actions/newgroup.php
index 0289e77c2..01cb636aa 100644
--- a/actions/newgroup.php
+++ b/actions/newgroup.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Add a new group
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ if (!defined('LACONICA')) {
* This is the form for adding a new group
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class NewgroupAction extends Action
diff --git a/actions/newmessage.php b/actions/newmessage.php
index 52d4899ba..828a339cf 100644
--- a/actions/newmessage.php
+++ b/actions/newmessage.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Handler for posting new messages
*
@@ -20,16 +20,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,12 +37,12 @@ if (!defined('LACONICA')) {
* Action for posting new direct messages
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class NewmessageAction extends Action
diff --git a/actions/newnotice.php b/actions/newnotice.php
index e254eac49..6e3720e09 100644
--- a/actions/newnotice.php
+++ b/actions/newnotice.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Handler for posting new notices
*
@@ -20,16 +20,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,12 +39,12 @@ require_once INSTALLDIR.'/lib/noticelist.php';
* Action for posting new notices
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class NewnoticeAction extends Action
@@ -91,8 +91,8 @@ class NewnoticeAction extends Action
// is losts when size is exceeded
if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) {
$this->clientError(sprintf(_('The server was unable to handle ' .
- 'that much POST data (%s bytes) due to its current configuration.'),
- $_SERVER['CONTENT_LENGTH']));
+ 'that much POST data (%s bytes) due to its current configuration.'),
+ $_SERVER['CONTENT_LENGTH']));
}
parent::handle($args);
@@ -130,7 +130,7 @@ class NewnoticeAction extends Action
$hint = '';
}
$this->clientError(sprintf(
- _('%s is not a supported filetype on this server.'), $filetype) . $hint);
+ _('%s is not a supported filetype on this server.'), $filetype) . $hint);
}
function isRespectsQuota($user) {
@@ -190,37 +190,37 @@ class NewnoticeAction extends Action
if (isset($_FILES['attach']['error'])) {
switch ($_FILES['attach']['error']) {
- case UPLOAD_ERR_NO_FILE:
- // no file uploaded, nothing to do
- break;
+ case UPLOAD_ERR_NO_FILE:
+ // no file uploaded, nothing to do
+ break;
- case UPLOAD_ERR_OK:
- $mimetype = $this->getUploadedFileType();
- if (!$this->isRespectsQuota($user)) {
- die('clientError() should trigger an exception before reaching here.');
- }
- break;
+ case UPLOAD_ERR_OK:
+ $mimetype = $this->getUploadedFileType();
+ if (!$this->isRespectsQuota($user)) {
+ die('clientError() should trigger an exception before reaching here.');
+ }
+ break;
- case UPLOAD_ERR_INI_SIZE:
- $this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
+ case UPLOAD_ERR_INI_SIZE:
+ $this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.'));
- case UPLOAD_ERR_FORM_SIZE:
- $this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
+ case UPLOAD_ERR_FORM_SIZE:
+ $this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.'));
- case UPLOAD_ERR_PARTIAL:
- $this->clientError(_('The uploaded file was only partially uploaded.'));
+ case UPLOAD_ERR_PARTIAL:
+ $this->clientError(_('The uploaded file was only partially uploaded.'));
- case UPLOAD_ERR_NO_TMP_DIR:
- $this->clientError(_('Missing a temporary folder.'));
+ case UPLOAD_ERR_NO_TMP_DIR:
+ $this->clientError(_('Missing a temporary folder.'));
- case UPLOAD_ERR_CANT_WRITE:
- $this->clientError(_('Failed to write file to disk.'));
+ case UPLOAD_ERR_CANT_WRITE:
+ $this->clientError(_('Failed to write file to disk.'));
- case UPLOAD_ERR_EXTENSION:
- $this->clientError(_('File upload stopped by extension.'));
+ case UPLOAD_ERR_EXTENSION:
+ $this->clientError(_('File upload stopped by extension.'));
- default:
- die('Should never reach here.');
+ default:
+ die('Should never reach here.');
}
}
@@ -233,7 +233,7 @@ class NewnoticeAction extends Action
$fileRecord = $this->storeFile($filename, $mimetype);
$fileurl = common_local_url('attachment',
- array('attachment' => $fileRecord->id));
+ array('attachment' => $fileRecord->id));
// not sure this is necessary -- Zach
$this->maybeAddRedir($fileRecord->id, $fileurl);
@@ -367,7 +367,7 @@ class NewnoticeAction extends Action
File_to_post::processNew($filerec->id, $notice->id);
$this->maybeAddRedir($filerec->id,
- common_local_url('file', array('notice' => $notice->id)));
+ common_local_url('file', array('notice' => $notice->id)));
}
/**
@@ -431,13 +431,14 @@ class NewnoticeAction extends Action
$content = $this->trimmed('status_textarea');
if (!$content) {
$replyto = $this->trimmed('replyto');
+ $inreplyto = $this->trimmed('inreplyto');
$profile = Profile::staticGet('nickname', $replyto);
if ($profile) {
$content = '@' . $profile->nickname . ' ';
}
}
- $notice_form = new NoticeForm($this, '', $content);
+ $notice_form = new NoticeForm($this, '', $content, null, $inreplyto);
$notice_form->show();
}
diff --git a/actions/noticesearch.php b/actions/noticesearch.php
index 49b473d9e..69dcd1a46 100644
--- a/actions/noticesearch.php
+++ b/actions/noticesearch.php
@@ -5,15 +5,15 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ require_once INSTALLDIR.'/lib/searchaction.php';
* Notice search action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
* @todo common parent for people and content search?
*/
class NoticesearchAction extends SearchAction
@@ -121,7 +121,9 @@ class NoticesearchAction extends SearchAction
$message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
}
else {
- $message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
+ $message = sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin',
+ urlencode($q));
}
$this->elementStart('div', 'guide');
@@ -135,6 +137,12 @@ class NoticesearchAction extends SearchAction
$this->pagination($page > 1, $cnt > NOTICES_PER_PAGE,
$page, 'noticesearch', array('q' => $q));
}
+
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('q');
+ }
}
class SearchNoticeList extends NoticeList {
@@ -190,7 +198,7 @@ class SearchNoticeListItem extends NoticeListItem {
$result = preg_replace($pattern, '<strong>\\1</strong>', $text);
/* Remove highlighting from inside links, loop incase multiple highlights in links */
- $pattern = '/(href="[^"]*)<strong>('.$options.')<\/strong>([^"]*")/iU';
+ $pattern = '/(\w+="[^"]*)<strong>('.$options.')<\/strong>([^"]*")/iU';
do {
$result = preg_replace($pattern, '\\1\\2\\3', $result, -1, $count);
} while ($count);
diff --git a/actions/noticesearchrss.php b/actions/noticesearchrss.php
index 2a4b2060d..f59ad7962 100644
--- a/actions/noticesearchrss.php
+++ b/actions/noticesearchrss.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ require_once INSTALLDIR.'/lib/rssaction.php';
* Formatting of RSS handled by Rss10Action
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class NoticesearchrssAction extends Rss10Action
{
@@ -86,9 +86,10 @@ class NoticesearchrssAction extends Rss10Action
{
$q = $this->trimmed('q');
$c = array('url' => common_local_url('noticesearchrss', array('q' => $q)),
- 'title' => common_config('site', 'name') . sprintf(_(' Search Stream for "%s"'), $q),
+ 'title' => sprintf(_('Updates with "%s"'), $q),
'link' => common_local_url('noticesearch', array('q' => $q)),
- 'description' => sprintf(_('All updates matching search term "%s"'), $q));
+ 'description' => sprintf(_('Updates matching search term "%1$s" on %2$s!'),
+ $q, common_config('site', 'name')));
return $c;
}
diff --git a/actions/nudge.php b/actions/nudge.php
index 78c0ee566..cf5f773e7 100644
--- a/actions/nudge.php
+++ b/actions/nudge.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,12 +39,12 @@ require_once INSTALLDIR.'/lib/mail.php';
* Nudge a user action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class NudgeAction extends Action
{
diff --git a/actions/twitapioembed.php b/actions/oembed.php
index 3019e5878..e287b6ae2 100644
--- a/actions/twitapioembed.php
+++ b/actions/oembed.php
@@ -1,8 +1,8 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
- * Laconica-only extensions to the Twitter-like API
+ * StatusNet-only extensions to the Twitter-like API
*
* PHP version 5
*
@@ -20,43 +20,37 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Twitter
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
-require_once INSTALLDIR.'/lib/twitterapi.php';
-
/**
* Oembed provider implementation
*
* This class handles all /main/oembed(.xml|.json)/ requests.
*
* @category oEmbed
- * @package Laconica
+ * @package StatusNet
* @author Craig Andrews <candrews@integralblue.com>
- * @copyright 2008 Control Yourself, Inc.
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-class TwitapioembedAction extends TwitterapiAction
+class OembedAction extends Action
{
- function oembed($args, $apidata)
+ function handle($args)
{
- parent::handle($args);
-
common_debug("in oembed api action");
- $this->auth_user = $apidata['user'];
-
$url = $args['url'];
if( substr(strtolower($url),0,strlen(common_root_url())) == strtolower(common_root_url()) ){
$path = substr($url,strlen(common_root_url()));
@@ -131,8 +125,7 @@ class TwitapioembedAction extends TwitterapiAction
default:
$this->serverError(_("$path not supported for oembed requests"), 501);
}
-
- switch($apidata['content-type']){
+ switch($args['format']){
case 'xml':
$this->init_document('xml');
$this->elementStart('oembed');
@@ -151,12 +144,11 @@ class TwitapioembedAction extends TwitterapiAction
if($oembed['thumbnail_url']) $this->element('thumbnail_url',null,$oembed['thumbnail_url']);
if($oembed['thumbnail_width']) $this->element('thumbnail_width',null,$oembed['thumbnail_width']);
if($oembed['thumbnail_height']) $this->element('thumbnail_height',null,$oembed['thumbnail_height']);
-
$this->elementEnd('oembed');
$this->end_document('xml');
break;
- case 'json':
+ case 'json': case '':
$this->init_document('json');
print(json_encode($oembed));
$this->end_document('json');
@@ -164,10 +156,51 @@ class TwitapioembedAction extends TwitterapiAction
default:
$this->serverError(_('content type ' . $apidata['content-type'] . ' not supported'), 501);
}
-
}else{
$this->serverError(_('Only ' . common_root_url() . ' urls over plain http please'), 404);
}
}
-}
+ function init_document($type)
+ {
+ switch ($type) {
+ case 'xml':
+ header('Content-Type: application/xml; charset=utf-8');
+ $this->startXML();
+ break;
+ case 'json':
+ header('Content-Type: application/json; charset=utf-8');
+
+ // Check for JSONP callback
+ $callback = $this->arg('callback');
+ if ($callback) {
+ print $callback . '(';
+ }
+ break;
+ default:
+ $this->serverError(_('Not a supported data format.'), 501);
+ break;
+ }
+ }
+
+ function end_document($type='xml')
+ {
+ switch ($type) {
+ case 'xml':
+ $this->endXML();
+ break;
+ case 'json':
+ // Check for JSONP callback
+ $callback = $this->arg('callback');
+ if ($callback) {
+ print ')';
+ }
+ break;
+ default:
+ $this->serverError(_('Not a supported data format.'), 501);
+ break;
+ }
+ return;
+ }
+
+}
diff --git a/actions/openidlogin.php b/actions/openidlogin.php
index a8d052096..9b7deefb6 100644
--- a/actions/openidlogin.php
+++ b/actions/openidlogin.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/openid.php');
@@ -26,7 +26,9 @@ class OpenidloginAction extends Action
function handle($args)
{
parent::handle($args);
- if (common_is_real_login()) {
+ if (!common_config('openid', 'enabled')) {
+ common_redirect(common_local_url('login'));
+ } else if (common_is_real_login()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$openid_url = $this->trimmed('openid_url');
@@ -84,6 +86,12 @@ class OpenidloginAction extends Action
}
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('openid_url');
+ }
+
function title()
{
return _('OpenID Login');
diff --git a/actions/openidsettings.php b/actions/openidsettings.php
index 5f59ebc01..30725fc1b 100644
--- a/actions/openidsettings.php
+++ b/actions/openidsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Settings for OpenID
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ require_once INSTALLDIR.'/lib/openid.php';
* Lets users add, edit and delete OpenIDs from their account
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class OpenidsettingsAction extends AccountSettingsAction
@@ -72,6 +72,12 @@ class OpenidsettingsAction extends AccountSettingsAction
' Manage your associated OpenIDs from here.');
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('openid_url');
+ }
+
/**
* Show the form for OpenID management
*
@@ -82,6 +88,12 @@ class OpenidsettingsAction extends AccountSettingsAction
function showContent()
{
+ if (!common_config('openid', 'enabled')) {
+ $this->element('div', array('class' => 'error'),
+ _('OpenID is not available.'));
+ return;
+ }
+
$user = common_current_user();
$this->elementStart('form', array('method' => 'post',
diff --git a/actions/opensearch.php b/actions/opensearch.php
index 4fe95c93b..d5e6698f3 100644
--- a/actions/opensearch.php
+++ b/actions/opensearch.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ if (!defined('LACONICA')) {
* Formatting of RSS handled by Rss10Action
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class OpensearchAction extends Action
{
@@ -66,7 +66,7 @@ class OpensearchAction extends Action
$type = 'noticesearch';
$short_name = _('Notice Search');
}
- header('Content-Type: text/html');
+ header('Content-Type: application/opensearchdescription+xml');
$this->startXML();
$this->elementStart('OpenSearchDescription', array('xmlns' => 'http://a9.com/-/spec/opensearch/1.1/'));
$short_name = common_config('site', 'name').' '.$short_name;
diff --git a/actions/othersettings.php b/actions/othersettings.php
index 1277f8052..f898e2207 100644
--- a/actions/othersettings.php
+++ b/actions/othersettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Miscellaneous settings
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Robin Millette <millette@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Robin Millette <millette@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ require_once INSTALLDIR.'/lib/accountsettingsaction.php';
* Currently this just manages URL shortening.
*
* @category Settings
- * @package Laconica
- * @author Robin Millette <millette@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Robin Millette <millette@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class OthersettingsAction extends AccountSettingsAction
@@ -71,6 +71,12 @@ class OthersettingsAction extends AccountSettingsAction
return _('Manage various other options.');
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('urlshorteningservice');
+ }
+
/**
* Content area of the page
*
diff --git a/actions/outbox.php b/actions/outbox.php
index a875e9ad9..537fad3ef 100644
--- a/actions/outbox.php
+++ b/actions/outbox.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* action handler for message inbox
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Message
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/mailbox.php';
* action handler for message outbox
*
* @category Message
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see MailboxAction
*/
diff --git a/actions/passwordsettings.php b/actions/passwordsettings.php
index bdce61035..cd4beac3f 100644
--- a/actions/passwordsettings.php
+++ b/actions/passwordsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Change user password
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/accountsettingsaction.php';
* Change password
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class PasswordsettingsAction extends AccountSettingsAction
@@ -69,6 +69,12 @@ class PasswordsettingsAction extends AccountSettingsAction
return _('Change your password.');
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('oldpassword');
+ }
+
/**
* Content area of the page
*
diff --git a/actions/peoplesearch.php b/actions/peoplesearch.php
index 60ddb6a82..38135ecbd 100644
--- a/actions/peoplesearch.php
+++ b/actions/peoplesearch.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ require_once INSTALLDIR.'/lib/profilelist.php';
* People search action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class PeoplesearchAction extends SearchAction
{
@@ -85,6 +85,12 @@ class PeoplesearchAction extends SearchAction
$profile->free();
}
}
+
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('q');
+ }
}
/**
@@ -93,11 +99,11 @@ class PeoplesearchAction extends SearchAction
* Derivative of ProfileList with specialization for highlighting search terms.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see PeoplesearchAction
*/
diff --git a/actions/peopletag.php b/actions/peopletag.php
index dd3c1c089..6dbbc9261 100644
--- a/actions/peopletag.php
+++ b/actions/peopletag.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Action for showing profiles self-tagged with a given tag
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/profilelist.php';
* This class outputs a paginated list of profiles self-tagged with a given tag
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Action
*/
diff --git a/actions/postnotice.php b/actions/postnotice.php
index eb2d63b61..e775ca17e 100644
--- a/actions/postnotice.php
+++ b/actions/postnotice.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/omb.php');
diff --git a/actions/profilesettings.php b/actions/profilesettings.php
index fb847680b..2d66e9946 100644
--- a/actions/profilesettings.php
+++ b/actions/profilesettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Change profile settings
*
@@ -20,15 +20,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +39,12 @@ require_once INSTALLDIR.'/lib/accountsettingsaction.php';
* Change profile settings
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ProfilesettingsAction extends AccountSettingsAction
@@ -70,6 +72,12 @@ class ProfilesettingsAction extends AccountSettingsAction
'so people know more about you.');
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('nickname');
+ }
+
/**
* Content area of the page
*
@@ -189,7 +197,7 @@ class ProfilesettingsAction extends AccountSettingsAction
// Some validation
if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64,
- 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
+ 'format' => NICKNAME_FMT))) {
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
return;
} else if (!User::allowed_nickname($nickname)) {
diff --git a/actions/public.php b/actions/public.php
index ef9ef0d1a..d426648f3 100644
--- a/actions/public.php
+++ b/actions/public.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Action for displaying the public stream
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -43,10 +43,10 @@ define('MAX_PUBLIC_PAGE', 100);
* Action for displaying the public stream
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see PublicrssAction
* @see PublicxrdsAction
@@ -59,6 +59,7 @@ class PublicAction extends Action
*/
var $page = null;
+ var $notice;
function isReadOnly($args)
{
@@ -84,6 +85,18 @@ class PublicAction extends Action
common_set_returnto($this->selfUrl());
+ $this->notice = Notice::publicStream(($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1);
+
+ if (!$this->notice) {
+ $this->serverError(_('Could not retrieve public stream.'));
+ return;
+ }
+
+ if($this->page > 1 && $this->notice->N == 0){
+ $this->serverError(_('No such page'),$code=404);
+ }
+
return true;
}
@@ -183,7 +196,8 @@ class PublicAction extends Action
}
else {
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
- $message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
+ $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post!'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
}
}
@@ -203,15 +217,7 @@ class PublicAction extends Action
function showContent()
{
- $notice = Notice::publicStream(($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1);
-
- if (!$notice) {
- $this->serverError(_('Could not retrieve public stream.'));
- return;
- }
-
- $nl = new NoticeList($notice, $this);
+ $nl = new NoticeList($this->notice, $this);
$cnt = $nl->show();
@@ -229,7 +235,7 @@ class PublicAction extends Action
// $top->show();
$pop = new PopularNoticeSection($this);
$pop->show();
- $gbp = new GroupsByPostsSection($this);
+ $gbp = new GroupsByMembersSection($this);
$gbp->show();
$feat = new FeaturedUsersSection($this);
$feat->show();
@@ -238,12 +244,14 @@ class PublicAction extends Action
function showAnonymousMessage()
{
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
- $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
- '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))');
+ $m = sprintf(_('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
+ 'based on the Free Software [StatusNet](http://status.net/) tool. ' .
+ '[Join now](%%%%action.%s%%%%) to share notices about yourself with friends, family, and colleagues! ' .
+ '([Read more](%%%%doc.help%%%%))'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
} else {
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool.');
+ 'based on the Free Software [StatusNet](http://status.net/) tool.');
}
$this->elementStart('div', array('id' => 'anon_notice'));
$this->raw(common_markup_to_html($m));
diff --git a/actions/publicrss.php b/actions/publicrss.php
index 7e8df9625..593888b9f 100644
--- a/actions/publicrss.php
+++ b/actions/publicrss.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,11 +41,11 @@ require_once INSTALLDIR.'/lib/rssaction.php';
* Formatting of RSS handled by Rss10Action
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class PublicrssAction extends Rss10Action
{
@@ -86,9 +86,9 @@ class PublicrssAction extends Rss10Action
{
$c = array(
'url' => common_local_url('publicrss')
- , 'title' => sprintf(_('%s Public Stream'), common_config('site', 'name'))
+ , 'title' => sprintf(_('%s public timeline'), common_config('site', 'name'))
, 'link' => common_local_url('public')
- , 'description' => sprintf(_('All updates for %s'), common_config('site', 'name')));
+ , 'description' => sprintf(_('%s updates from everyone!'), common_config('site', 'name')));
return $c;
}
diff --git a/actions/publictagcloud.php b/actions/publictagcloud.php
index e9f33d58b..60bb53e27 100644
--- a/actions/publictagcloud.php
+++ b/actions/publictagcloud.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Public tag cloud for notices
*
@@ -20,16 +20,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
+ * @package StatusNet
* @author Mike Cochrane <mikec@mikenz.geek.nz>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Evan Prodromou <evan@status.net>
* @copyright 2008 Mike Cochrane
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
define('TAGS_PER_PAGE', 100);
@@ -37,12 +37,12 @@ define('TAGS_PER_PAGE', 100);
* Public tag cloud for notices
*
* @category Personal
- * @package Laconica
+ * @package StatusNet
* @author Mike Cochrane <mikec@mikenz.geek.nz>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Evan Prodromou <evan@status.net>
* @copyright 2008 Mike Cochrane
- * @copyright 2008-2009 Control Yourself, Inc.
- * @link http://laconi.ca/
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @link http://status.net/
*/
class PublictagcloudAction extends Action
@@ -72,7 +72,8 @@ class PublictagcloudAction extends Action
$message .= _('Be the first to post one!');
}
else {
- $message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
+ $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and be the first to post one!'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
}
$this->elementStart('div', 'guide');
diff --git a/actions/publicxrds.php b/actions/publicxrds.php
index 0a1421550..209a10e3d 100644
--- a/actions/publicxrds.php
+++ b/actions/publicxrds.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ require_once INSTALLDIR.'/lib/openid.php';
* Public XRDS for OpenID
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @todo factor out similarities with XrdsAction
*/
diff --git a/actions/recoverpassword.php b/actions/recoverpassword.php
index 721edea7f..9776c1fb4 100644
--- a/actions/recoverpassword.php
+++ b/actions/recoverpassword.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
# You have 24 hours to claim your password
diff --git a/actions/register.php b/actions/register.php
index dcbbbdb6a..eefbc340a 100644
--- a/actions/register.php
+++ b/actions/register.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Register a new user account
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Login
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* An action for registering a new user account
*
* @category Login
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class RegisterAction extends Action
@@ -116,6 +116,8 @@ class RegisterAction extends Action
*
* Checks if registration is closed and shows an error if so.
*
+ * Checks if only OpenID is allowed and redirects to openidlogin if so.
+ *
* @param array $args $_REQUEST data
*
* @return void
@@ -127,6 +129,8 @@ class RegisterAction extends Action
if (common_config('site', 'closed')) {
$this->clientError(_('Registration not allowed.'));
+ } else if (common_config('site', 'openidonly')) {
+ common_redirect(common_local_url('openidlogin'));
} else if (common_logged_in()) {
$this->clientError(_('Already logged in.'));
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
@@ -136,6 +140,12 @@ class RegisterAction extends Action
}
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('nickname');
+ }
+
/**
* Try to register a user
*
@@ -325,14 +335,22 @@ class RegisterAction extends Action
} else if ($this->error) {
$this->element('p', 'error', $this->error);
} else {
- $instr =
- common_markup_to_html(_('With this form you can create '.
- ' a new account. ' .
- 'You can then post notices and '.
- 'link up to friends and colleagues. '.
- '(Have an [OpenID](http://openid.net/)? ' .
- 'Try our [OpenID registration]'.
- '(%%action.openidlogin%%)!)'));
+ if (common_config('openid', 'enabled')) {
+ $instr =
+ common_markup_to_html(_('With this form you can create '.
+ ' a new account. ' .
+ 'You can then post notices and '.
+ 'link up to friends and colleagues. '.
+ '(Have an [OpenID](http://openid.net/)? ' .
+ 'Try our [OpenID registration]'.
+ '(%%action.openidlogin%%)!)'));
+ } else {
+ $instr =
+ common_markup_to_html(_('With this form you can create '.
+ ' a new account. ' .
+ 'You can then post notices and '.
+ 'link up to friends and colleagues.'));
+ }
$this->elementStart('div', 'instructions');
$this->raw($instr);
diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php
index e658f8d37..374392d4a 100644
--- a/actions/remotesubscribe.php
+++ b/actions/remotesubscribe.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/omb.php');
@@ -71,11 +71,13 @@ class RemotesubscribeAction extends Action
if ($this->err) {
$this->element('div', 'error', $this->err);
} else {
- $inst = _('To subscribe, you can [login](%%action.login%%),' .
- ' or [register](%%action.register%%) a new ' .
- ' account. If you already have an account ' .
- ' on a [compatible microblogging site](%%doc.openmublog%%), ' .
- ' enter your profile URL below.');
+ $inst = sprintf(_('To subscribe, you can [login](%%%%action.%s%%%%),' .
+ ' or [register](%%%%action.%s%%%%) a new ' .
+ ' account. If you already have an account ' .
+ ' on a [compatible microblogging site](%%doc.openmublog%%), ' .
+ ' enter your profile URL below.'),
+ (!common_config('site','openidonly')) ? 'login' : 'openidlogin',
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
$output = common_markup_to_html($inst);
$this->elementStart('div', 'instructions');
$this->raw($output);
@@ -321,7 +323,7 @@ class RemotesubscribeAction extends Action
$result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(),
- array('User-Agent: Laconica/' . LACONICA_VERSION));
+ array('User-Agent: StatusNet/' . STATUSNET_VERSION));
if ($result->status != 200) {
return null;
}
diff --git a/actions/replies.php b/actions/replies.php
index d7ed440e9..cca430230 100644
--- a/actions/replies.php
+++ b/actions/replies.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of replies
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,15 +39,16 @@ require_once INSTALLDIR.'/lib/feedlist.php';
* List of replies
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class RepliesAction extends OwnerDesignAction
{
var $page = null;
+ var $notice;
/**
* Prepare the object
@@ -84,6 +85,13 @@ class RepliesAction extends OwnerDesignAction
common_set_returnto($this->selfUrl());
+ $this->notice = $this->user->getReplies(($this->page-1) * NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1);
+
+ if($this->page > 1 && $this->notice->N == 0){
+ $this->serverError(_('No such page'),$code=404);
+ }
+
return true;
}
@@ -159,10 +167,7 @@ class RepliesAction extends OwnerDesignAction
function showContent()
{
- $notice = $this->user->getReplies(($this->page-1) * NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1);
-
- $nl = new NoticeList($notice, $this);
+ $nl = new NoticeList($this->notice, $this);
$cnt = $nl->show();
if (0 === $cnt) {
@@ -187,7 +192,9 @@ class RepliesAction extends OwnerDesignAction
}
}
else {
- $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
+ $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin',
+ $this->user->nickname);
}
$this->elementStart('div', 'guide');
diff --git a/actions/repliesrss.php b/actions/repliesrss.php
index a87e2870d..c71c9226f 100644
--- a/actions/repliesrss.php
+++ b/actions/repliesrss.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/rssaction.php');
@@ -68,7 +68,8 @@ class RepliesrssAction extends Rss10Action
'link' => common_local_url('replies',
array('nickname' =>
$user->nickname)),
- 'description' => sprintf(_('Feed for replies to %s'), $user->nickname));
+ 'description' => sprintf(_('Replies to %1$s on %2$s!'),
+ $user->nickname, common_config('site', 'name')));
return $c;
}
diff --git a/actions/requesttoken.php b/actions/requesttoken.php
index 8d1e3f004..a17efcdd5 100644
--- a/actions/requesttoken.php
+++ b/actions/requesttoken.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ require_once INSTALLDIR.'/lib/omb.php';
* Request token action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class RequesttokenAction extends Action
{
@@ -72,7 +72,7 @@ class RequesttokenAction extends Action
$req = OAuthRequest::from_request('POST', common_local_url('requesttoken'));
$server = omb_oauth_server();
$token = $server->fetch_request_token($req);
- print $token;
+ print $token.'&omb_version='.OMB_VERSION_01;
} catch (OAuthException $e) {
$this->serverError($e->getMessage());
}
diff --git a/actions/showfavorites.php b/actions/showfavorites.php
index 8efe9d30a..0f7a66330 100644
--- a/actions/showfavorites.php
+++ b/actions/showfavorites.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of replies
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ require_once INSTALLDIR.'/lib/feedlist.php';
* List of replies
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ShowfavoritesAction extends OwnerDesignAction
@@ -114,6 +114,29 @@ class ShowfavoritesAction extends OwnerDesignAction
common_set_returnto($this->selfUrl());
+ $cur = common_current_user();
+
+ if (!empty($cur) && $cur->id == $this->user->id) {
+
+ // Show imported/gateway notices as well as local if
+ // the user is looking at his own favorites
+
+ $this->notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1, true);
+ } else {
+ $this->notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
+ NOTICES_PER_PAGE + 1, false);
+ }
+
+ if (empty($this->notice)) {
+ $this->serverError(_('Could not retrieve favorite notices.'));
+ return;
+ }
+
+ if($this->page > 1 && $this->notice->N == 0){
+ $this->serverError(_('No such page'),$code=404);
+ }
+
return true;
}
@@ -173,7 +196,9 @@ class ShowfavoritesAction extends OwnerDesignAction
}
}
else {
- $message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to thier favorites :)'), $this->user->nickname);
+ $message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.%s%%%%) and then post something interesting they would add to their favorites :)'),
+ $this->user->nickname,
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
}
$this->elementStart('div', 'guide');
@@ -191,26 +216,7 @@ class ShowfavoritesAction extends OwnerDesignAction
function showContent()
{
- $cur = common_current_user();
-
- if (!empty($cur) && $cur->id == $this->user->id) {
-
- // Show imported/gateway notices as well as local if
- // the user is looking at his own favorites
-
- $notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1, true);
- } else {
- $notice = $this->user->favoriteNotices(($this->page-1)*NOTICES_PER_PAGE,
- NOTICES_PER_PAGE + 1, false);
- }
-
- if (empty($notice)) {
- $this->serverError(_('Could not retrieve favorite notices.'));
- return;
- }
-
- $nl = new NoticeList($notice, $this);
+ $nl = new NoticeList($this->notice, $this);
$cnt = $nl->show();
if (0 == $cnt) {
diff --git a/actions/showgroup.php b/actions/showgroup.php
index 32ec674a9..8157ee3c8 100644
--- a/actions/showgroup.php
+++ b/actions/showgroup.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Group main page
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,10 +41,10 @@ define('MEMBERS_PER_SECTION', 27);
* Group main page
*
* @category Group
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ShowgroupAction extends GroupDesignAction
@@ -130,8 +130,18 @@ class ShowgroupAction extends GroupDesignAction
$this->group = User_group::staticGet('nickname', $nickname);
if (!$this->group) {
- $this->clientError(_('No such group'), 404);
- return false;
+ $alias = Group_alias::staticGet('alias', $nickname);
+ if ($alias) {
+ $args = array('id' => $alias->group_id);
+ if ($this->page != 1) {
+ $args['page'] = $this->page;
+ }
+ common_redirect(common_local_url('groupbyid', $args), 301);
+ return false;
+ } else {
+ $this->clientError(_('No such group'), 404);
+ return false;
+ }
}
common_set_returnto($this->selfUrl());
@@ -438,13 +448,14 @@ class ShowgroupAction extends GroupDesignAction
{
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
+ 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' .
'short messages about their life and interests. '.
- '[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
- $this->group->nickname);
+ '[Join now](%%%%action.%s%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
+ $this->group->nickname,
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
} else {
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
+ 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' .
'short messages about their life and interests. '),
$this->group->nickname);
}
diff --git a/actions/showmessage.php b/actions/showmessage.php
index 4fcaadbe8..db757948b 100644
--- a/actions/showmessage.php
+++ b/actions/showmessage.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Show a single message
*
@@ -20,13 +20,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ require_once INSTALLDIR.'/lib/mailbox.php';
* // XXX: It is totally weird how this works!
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ShowmessageAction extends MailboxAction
diff --git a/actions/shownotice.php b/actions/shownotice.php
index 8f73dc824..3bc52b2db 100644
--- a/actions/shownotice.php
+++ b/actions/shownotice.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Show a single notice
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ require_once INSTALLDIR.'/lib/feedlist.php';
* Show a single notice
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ShownoticeAction extends OwnerDesignAction
@@ -97,8 +97,8 @@ class ShownoticeAction extends OwnerDesignAction
$this->user = User::staticGet('id', $this->profile->id);
- if (empty($this->user)) {
- $this->serverError(_('Not a local notice'), 500);
+ if (! $this->notice->is_local) {
+ common_redirect($this->notice->uri);
return false;
}
@@ -190,7 +190,7 @@ class ShownoticeAction extends OwnerDesignAction
{
parent::handle($args);
- if ($this->notice->is_local == 0) {
+ if ($this->notice->is_local == Notice::REMOTE_OMB) {
if (!empty($this->notice->url)) {
common_redirect($this->notice->url, 301);
} else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
@@ -278,16 +278,16 @@ class ShownoticeAction extends OwnerDesignAction
$this->element('link',array('rel'=>'alternate',
'type'=>'application/json+oembed',
'href'=>common_local_url(
- 'api',
- array('apiaction'=>'oembed','method'=>'oembed.json'),
- array('url'=>$this->notice->uri)),
+ 'oembed',
+ array(),
+ array('format'=>'json','url'=>$this->notice->uri)),
'title'=>'oEmbed'),null);
$this->element('link',array('rel'=>'alternate',
'type'=>'text/xml+oembed',
'href'=>common_local_url(
- 'api',
- array('apiaction'=>'oembed','method'=>'oembed.xml'),
- array('url'=>$this->notice->uri)),
+ 'oembed',
+ array(),
+ array('format'=>'xml','url'=>$this->notice->uri)),
'title'=>'oEmbed'),null);
}
}
diff --git a/actions/showstream.php b/actions/showstream.php
index cd5d4bb70..89285b13c 100644
--- a/actions/showstream.php
+++ b/actions/showstream.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* User profile page
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -48,10 +48,10 @@ require_once INSTALLDIR.'/lib/feedlist.php';
* to subscriptions and stuff, etc.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ShowstreamAction extends ProfileAction
@@ -358,7 +358,9 @@ class ShowstreamAction extends ProfileAction
}
}
else {
- $message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
+ $message .= sprintf(_('Why not [register an account](%%%%action.%s%%%%) and then nudge %s or post a notice to his or her attention.'),
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin',
+ $this->user->nickname);
}
$this->elementStart('div', 'guide');
@@ -378,20 +380,27 @@ class ShowstreamAction extends ProfileAction
$this->showEmptyListMessage();
}
+ $args = array('nickname' => $this->user->nickname);
+ if (!empty($this->tag))
+ {
+ $args['tag'] = $this->tag;
+ }
$this->pagination($this->page>1, $cnt>NOTICES_PER_PAGE, $this->page,
- 'showstream', array('nickname' => $this->user->nickname));
+ 'showstream', $args);
}
function showAnonymousMessage()
{
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
- '[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
- $this->user->nickname, $this->user->nickname);
+ 'based on the Free Software [StatusNet](http://status.net/) tool. ' .
+ '[Join now](%%%%action.%s%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
+ $this->user->nickname,
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin',
+ $this->user->nickname);
} else {
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. '),
+ 'based on the Free Software [StatusNet](http://status.net/) tool. '),
$this->user->nickname, $this->user->nickname);
}
$this->elementStart('div', array('id' => 'anon_notice'));
diff --git a/actions/smssettings.php b/actions/smssettings.php
index 922bab9a4..672abcef8 100644
--- a/actions/smssettings.php
+++ b/actions/smssettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Settings for SMS
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/connectsettingsaction.php';
* Settings for SMS
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see SettingsAction
*/
@@ -69,6 +69,12 @@ class SmssettingsAction extends ConnectSettingsAction
return _('You can receive SMS messages through email from %%site.name%%.');
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('sms');
+ }
+
/**
* Content area of the page
*
@@ -80,6 +86,12 @@ class SmssettingsAction extends ConnectSettingsAction
function showContent()
{
+ if (!common_config('sms', 'enabled')) {
+ $this->element('div', array('class' => 'error'),
+ _('SMS is not available.'));
+ return;
+ }
+
$user = common_current_user();
$this->elementStart('form', array('method' => 'post',
diff --git a/actions/subedit.php b/actions/subedit.php
index 2e1bf5538..cf6589e50 100644
--- a/actions/subedit.php
+++ b/actions/subedit.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class SubeditAction extends Action
{
diff --git a/actions/subscribe.php b/actions/subscribe.php
index 15b89a312..4c46806e4 100644
--- a/actions/subscribe.php
+++ b/actions/subscribe.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class SubscribeAction extends Action
{
diff --git a/actions/subscribers.php b/actions/subscribers.php
index 66ac00fb1..f7d08d9d0 100644
--- a/actions/subscribers.php
+++ b/actions/subscribers.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List a user's subscribers
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Social
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -36,10 +36,10 @@ if (!defined('LACONICA')) {
* List a user's subscribers
*
* @category Social
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubscribersAction extends GalleryAction
@@ -111,7 +111,9 @@ class SubscribersAction extends GalleryAction
}
}
else {
- $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname);
+ $message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.%s%%%%) and be the first?'),
+ $this->user->nickname,
+ (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
}
$this->elementStart('div', 'guide');
diff --git a/actions/subscriptions.php b/actions/subscriptions.php
index 42bdae10f..cc7b38ee4 100644
--- a/actions/subscriptions.php
+++ b/actions/subscriptions.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of a user's subscriptions
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Social
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -36,13 +36,13 @@ if (!defined('LACONICA')) {
* A list of the user's subscriptions
*
* @category Social
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class SubscriptionsAction extends GalleryAction
{
@@ -107,6 +107,12 @@ class SubscriptionsAction extends GalleryAction
array('nickname' => $this->user->nickname));
}
+ function showScripts()
+ {
+ parent::showScripts();
+ $this->autofocus('tag');
+ }
+
function showEmptyListMessage()
{
if (common_logged_in()) {
@@ -174,14 +180,26 @@ class SubscriptionsListItem extends SubscriptionListItem
return;
}
+ if (!common_config('xmpp', 'enabled') && !common_config('sms', 'enabled')) {
+ return;
+ }
+
$this->out->elementStart('form', array('id' => 'subedit-' . $this->profile->id,
'method' => 'post',
'class' => 'form_subscription_edit',
'action' => common_local_url('subedit')));
$this->out->hidden('token', common_session_token());
$this->out->hidden('profile', $this->profile->id);
- $this->out->checkbox('jabber', _('Jabber'), $sub->jabber);
- $this->out->checkbox('sms', _('SMS'), $sub->sms);
+ if (common_config('xmpp', 'enabled')) {
+ $this->out->checkbox('jabber', _('Jabber'), $sub->jabber);
+ } else {
+ $this->out->hidden('jabber', $sub->jabber);
+ }
+ if (common_config('sms', 'enabled')) {
+ $this->out->checkbox('sms', _('SMS'), $sub->sms);
+ } else {
+ $this->out->hidden('sms', $sub->sms);
+ }
$this->out->submit('save', _('Save'));
$this->out->elementEnd('form');
return;
diff --git a/actions/sup.php b/actions/sup.php
index a5b665562..5daf0a1c1 100644
--- a/actions/sup.php
+++ b/actions/sup.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class SupAction extends Action
{
diff --git a/actions/tag.php b/actions/tag.php
index 020399d9e..f0ab30308 100644
--- a/actions/tag.php
+++ b/actions/tag.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,10 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class TagAction extends Action
{
+
+ var $notice;
+
function prepare($args)
{
parent::prepare($args);
@@ -42,6 +45,12 @@ class TagAction extends Action
common_set_returnto($this->selfUrl());
+ $this->notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
+
+ if($this->page > 1 && $this->notice->N == 0){
+ $this->serverError(_('No such page'),$code=404);
+ }
+
return true;
}
@@ -94,9 +103,7 @@ class TagAction extends Action
function showContent()
{
- $notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1);
-
- $nl = new NoticeList($notice, $this);
+ $nl = new NoticeList($this->notice, $this);
$cnt = $nl->show();
diff --git a/actions/tagother.php b/actions/tagother.php
index 96246f799..c3f43be8b 100644
--- a/actions/tagother.php
+++ b/actions/tagother.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/settingsaction.php');
diff --git a/actions/tagrss.php b/actions/tagrss.php
index f69374fca..75cbfa274 100644
--- a/actions/tagrss.php
+++ b/actions/tagrss.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/rssaction.php');
@@ -61,7 +61,8 @@ class TagrssAction extends Rss10Action
$c = array('url' => common_local_url('tagrss', array('tag' => $tagname)),
'title' => $tagname,
'link' => common_local_url('tagrss', array('tag' => $tagname)),
- 'description' => sprintf(_('Microblog tagged with %s'), $tagname));
+ 'description' => sprintf(_('Updates tagged with %1$s on %2$s!'),
+ $tagname, common_config('site', 'name')));
return $c;
}
diff --git a/actions/twitapiaccount.php b/actions/twitapiaccount.php
index f2a7534a2..93c8443c9 100644
--- a/actions/twitapiaccount.php
+++ b/actions/twitapiaccount.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/actions/twitapiblocks.php b/actions/twitapiblocks.php
index d8e72efb1..ed17946ae 100644
--- a/actions/twitapiblocks.php
+++ b/actions/twitapiblocks.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php
index bd27e9d20..dbe55804b 100644
--- a/actions/twitapidirect_messages.php
+++ b/actions/twitapidirect_messages.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/actions/twitapifavorites.php b/actions/twitapifavorites.php
index 8256668f3..f8943fe2d 100644
--- a/actions/twitapifavorites.php
+++ b/actions/twitapifavorites.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -207,32 +207,10 @@ class TwitapifavoritesAction extends TwitterapiAction
$other = User::staticGet('id', $notice->profile_id);
if ($other && $other->id != $user->id) {
if ($other->email && $other->emailnotifyfav) {
- $this->notify_mail($other, $user, $notice);
+ mail_notify_fave($other, $user, $notice);
}
# XXX: notify by IM
# XXX: notify by SMS
}
}
-
- function notify_mail($other, $user, $notice)
- {
- $profile = $user->getProfile();
- $bestname = $profile->getBestName();
- $subject = sprintf(_('%s added your notice as a favorite'), $bestname);
- $body = sprintf(_("%1\$s just added your notice from %2\$s as one of their favorites.\n\n" .
- "In case you forgot, you can see the text of your notice here:\n\n" .
- "%3\$s\n\n" .
- "You can see the list of %1\$s's favorites here:\n\n" .
- "%4\$s\n\n" .
- "Faithfully yours,\n" .
- "%5\$s\n"),
- $bestname,
- common_exact_date($notice->created),
- common_local_url('shownotice', array('notice' => $notice->id)),
- common_local_url('showfavorites', array('nickname' => $user->nickname)),
- common_config('site', 'name'));
-
- mail_to_user($other, $subject, $body);
- }
-
-} \ No newline at end of file
+}
diff --git a/actions/twitapifriendships.php b/actions/twitapifriendships.php
index 5fb55e9ff..eea8945c3 100644
--- a/actions/twitapifriendships.php
+++ b/actions/twitapifriendships.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -99,6 +99,12 @@ class TwitapifriendshipsAction extends TwitterapiAction
$other = $this->get_profile($id);
$user = $apidata['user']; // Alwyas the auth user
+ if ($user->id == $other->id) {
+ $this->clientError(_("You cannot unfollow yourself!"),
+ 403, $apidata['content-type']);
+ return;
+ }
+
$sub = new Subscription();
$sub->subscriber = $user->id;
$sub->subscribed = $other->id;
diff --git a/actions/twitapigroups.php b/actions/twitapigroups.php
index 71a0776f4..4deb1b764 100644
--- a/actions/twitapigroups.php
+++ b/actions/twitapigroups.php
@@ -1,8 +1,8 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
- * Laconica extensions to the Twitter-like API for groups
+ * StatusNet extensions to the Twitter-like API for groups
*
* PHP version 5
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Twitter
- * @package Laconica
- * @author Craig Andrews
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,20 +37,143 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
/**
* Group-specific API methods
*
- * This class handles Laconica group API methods.
+ * This class handles StatusNet group API methods.
*
* @category Twitter
- * @package Laconica
- * @author Craig Andrews
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class TwitapigroupsAction extends TwitterapiAction
{
+ function list_groups($args, $apidata)
+ {
+ parent::handle($args);
+
+ common_debug("in groups api action");
+
+ $this->auth_user = $apidata['user'];
+ $user = $this->get_user($apidata['api_arg'], $apidata);
+
+ if (empty($user)) {
+ $this->clientError('Not Found', 404, $apidata['content-type']);
+ return;
+ }
+
+ $page = (int)$this->arg('page', 1);
+ $count = (int)$this->arg('count', 20);
+ $max_id = (int)$this->arg('max_id', 0);
+ $since_id = (int)$this->arg('since_id', 0);
+ $since = $this->arg('since');
+ $group = $user->getGroups(($page-1)*$count,
+ $count, $since_id, $max_id, $since);
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s's groups"), $user->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:Groups";
+ $link = common_root_url();
+ $subtitle = sprintf(_("groups %s is a member of on %s"), $user->nickname, $sitename);
+
+ switch($apidata['content-type']) {
+ case 'xml':
+ $this->show_xml_groups($group);
+ break;
+ case 'rss':
+ $this->show_rss_groups($group, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() . 'api/statusnet/groups/list/' . $user->id . '.atom';
+ $this->show_atom_groups($group, $title, $id, $link,
+ $subtitle, $selfuri);
+ break;
+ case 'json':
+ $this->show_json_groups($group);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ function list_all($args, $apidata)
+ {
+ parent::handle($args);
+
+ common_debug("in groups api action");
+
+ $page = (int)$this->arg('page', 1);
+ $count = (int)$this->arg('count', 20);
+ $max_id = (int)$this->arg('max_id', 0);
+ $since_id = (int)$this->arg('since_id', 0);
+ $since = $this->arg('since');
+
+ /* TODO:
+ Use the $page, $count, $max_id, $since_id, and $since parameters
+ */
+ $group = new User_group();
+ $group->orderBy('created DESC');
+ $group->find();
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s groups"), $sitename);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:Groups";
+ $link = common_root_url();
+ $subtitle = sprintf(_("groups on %s"), $sitename);
+
+ switch($apidata['content-type']) {
+ case 'xml':
+ $this->show_xml_groups($group);
+ break;
+ case 'rss':
+ $this->show_rss_groups($group, $title, $link, $subtitle);
+ break;
+ case 'atom':
+ $selfuri = common_root_url() . 'api/statusnet/groups/list_all.atom';
+ $this->show_atom_groups($group, $title, $id, $link,
+ $subtitle, $selfuri);
+ break;
+ case 'json':
+ $this->show_json_groups($group);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ break;
+ }
+ }
+
+ function show($args, $apidata)
+ {
+ parent::handle($args);
+
+ common_debug("in groups api action");
+
+ $this->auth_user = $apidata['user'];
+ $group = $this->get_group($apidata['api_arg'], $apidata);
+
+ if (empty($group)) {
+ $this->clientError('Not Found', 404, $apidata['content-type']);
+ return;
+ }
+
+ switch($apidata['content-type']) {
+ case 'xml':
+ $this->show_single_xml_group($group);
+ break;
+ case 'json':
+ $this->show_single_json_group($group);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ }
+ }
+
function timeline($args, $apidata)
{
parent::handle($args);
@@ -88,20 +211,19 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
$this->show_xml_timeline($notice);
break;
case 'rss':
- $this->show_rss_timeline($notice, $title, $link,
- $subtitle, $suplink);
+ $this->show_rss_timeline($notice, $title, $link, $subtitle);
break;
case 'atom':
if (isset($apidata['api_arg'])) {
$selfuri = common_root_url() .
- 'api/laconica/groups/timeline/' .
+ 'api/statusnet/groups/timeline/' .
$apidata['api_arg'] . '.atom';
} else {
$selfuri = common_root_url() .
- 'api/laconica/groups/timeline.atom';
+ 'api/statusnet/groups/timeline.atom';
}
$this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, $suplink, $selfuri);
+ $subtitle, null, $selfuri);
break;
case 'json':
$this->show_json_timeline($notice);
@@ -111,4 +233,97 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
}
}
+ function membership($args, $apidata)
+ {
+ parent::handle($args);
+
+ common_debug("in groups api action");
+
+ $this->auth_user = $apidata['user'];
+ $group = $this->get_group($apidata['api_arg'], $apidata);
+
+ if (empty($group)) {
+ $this->clientError('Not Found', 404, $apidata['content-type']);
+ return;
+ }
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("Members of %s group"), $group->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:GroupMembership:".$group->id;
+ $link = common_local_url('showgroup',
+ array('nickname' => $group->nickname));
+ $subtitle = sprintf(_('Members of %1$s on %2$s'),
+ $group->nickname, $sitename);
+
+ $page = (int)$this->arg('page', 1);
+ $count = (int)$this->arg('count', 20);
+ $max_id = (int)$this->arg('max_id', 0);
+ $since_id = (int)$this->arg('since_id', 0);
+ $since = $this->arg('since');
+
+ $member = $group->getMembers(($page-1)*$count,
+ $count, $since_id, $max_id, $since);
+
+ switch($apidata['content-type']) {
+ case 'xml':
+ $this->show_twitter_xml_users($member);
+ break;
+ //TODO implement the RSS and ATOM content types
+ /*case 'rss':
+ $this->show_rss_users($member, $title, $link, $subtitle);
+ break;*/
+ /*case 'atom':
+ if (isset($apidata['api_arg'])) {
+ $selfuri = common_root_url() .
+ 'api/statusnet/groups/membership/' .
+ $apidata['api_arg'] . '.atom';
+ } else {
+ $selfuri = common_root_url() .
+ 'api/statusnet/groups/membership.atom';
+ }
+ $this->show_atom_users($member, $title, $id, $link,
+ $subtitle, null, $selfuri);
+ break;*/
+ case 'json':
+ $this->show_json_users($member);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ }
+ }
+
+ function is_member($args, $apidata)
+ {
+ parent::handle($args);
+
+ common_debug("in groups api action");
+
+ $this->auth_user = $apidata['user'];
+ $group = User_group::staticGet($args['group_id']);
+ if(! $group){
+ $this->clientError(_('Group not found'), $code = 500);
+ }
+ $user = User::staticGet('id', $args['user_id']);
+ if(! $user){
+ $this->clientError(_('User not found'), $code = 500);
+ }
+
+ $is_member=$user->isMember($group);
+
+ switch($apidata['content-type']) {
+ case 'xml':
+ $this->init_document('xml');
+ $this->element('is_member', null, $is_member);
+ $this->end_document('xml');
+ break;
+ case 'json':
+ $this->init_document('json');
+ $this->show_json_objects(array('is_member'=>$is_member));
+ $this->end_document('json');
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ }
+ }
}
diff --git a/actions/twitapihelp.php b/actions/twitapihelp.php
index dab2b34f9..81381620e 100644
--- a/actions/twitapihelp.php
+++ b/actions/twitapihelp.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/actions/twitapinotifications.php b/actions/twitapinotifications.php
index 09b11766b..0653e69ab 100644
--- a/actions/twitapinotifications.php
+++ b/actions/twitapinotifications.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/twitterapi.php');
diff --git a/actions/twitapisearchatom.php b/actions/twitapisearchatom.php
index 3678213c3..2f587d604 100644
--- a/actions/twitapisearchatom.php
+++ b/actions/twitapisearchatom.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Action for showing Twitter-like Atom search results
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,10 +41,10 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
* RSS10Action.
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see TwitterapiAction
*/
@@ -227,7 +227,7 @@ class TwitapisearchatomAction extends TwitterapiAction
$server = common_config('site', 'server');
$sitename = common_config('site', 'name');
- // XXX: Use xmlns:laconica instead?
+ // XXX: Use xmlns:statusnet instead?
$this->elementStart('feed',
array('xmlns' => 'http://www.w3.org/2005/Atom',
diff --git a/actions/twitapisearchjson.php b/actions/twitapisearchjson.php
index 27a717bfc..c628ee624 100644
--- a/actions/twitapisearchjson.php
+++ b/actions/twitapisearchjson.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Action for showing Twitter-like JSON search results
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
* Action handler for Twitter-compatible API search
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see TwitterapiAction
*/
diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php
index c9943698d..41887a68f 100644
--- a/actions/twitapistatuses.php
+++ b/actions/twitapistatuses.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -136,6 +136,11 @@ class TwitapistatusesAction extends TwitterapiAction
}
+ function home_timeline($args, $apidata)
+ {
+ call_user_func(array($this, 'friends_timeline'), $args, $apidata);
+ }
+
function user_timeline($args, $apidata)
{
parent::handle($args);
@@ -292,7 +297,7 @@ class TwitapistatusesAction extends TwitterapiAction
$source, 1, $reply_to);
if (is_string($notice)) {
- $this->serverError($notice);
+ $this->serverError($notice, 500, $apidata['content-type']);
return;
}
@@ -449,7 +454,8 @@ class TwitapistatusesAction extends TwitterapiAction
function friends($args, $apidata)
{
parent::handle($args);
- return $this->subscriptions($apidata, 'subscribed', 'subscriber');
+ $includeStatuses=! (boolean) $args['lite'];
+ return $this->subscriptions($apidata, 'subscribed', 'subscriber', false, $includeStatuses);
}
function friendsIDs($args, $apidata)
@@ -461,7 +467,8 @@ class TwitapistatusesAction extends TwitterapiAction
function followers($args, $apidata)
{
parent::handle($args);
- return $this->subscriptions($apidata, 'subscriber', 'subscribed');
+ $includeStatuses=! (boolean) $args['lite'];
+ return $this->subscriptions($apidata, 'subscriber', 'subscribed', false, $includeStatuses);
}
function followersIDs($args, $apidata)
@@ -470,7 +477,7 @@ class TwitapistatusesAction extends TwitterapiAction
return $this->subscriptions($apidata, 'subscriber', 'subscribed', true);
}
- function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false)
+ function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false, $includeStatuses=true)
{
$this->auth_user = $apidata['user'];
$user = $this->get_user($apidata['api_arg'], $apidata);
@@ -526,26 +533,26 @@ class TwitapistatusesAction extends TwitterapiAction
if ($onlyIDs) {
$this->showIDs($others, $type);
} else {
- $this->show_profiles($others, $type);
+ $this->show_profiles($others, $type, $includeStatuses);
}
$this->end_document($type);
}
- function show_profiles($profiles, $type)
+ function show_profiles($profiles, $type, $includeStatuses)
{
switch ($type) {
case 'xml':
$this->elementStart('users', array('type' => 'array'));
foreach ($profiles as $profile) {
- $this->show_profile($profile);
+ $this->show_profile($profile,$type,null,$includeStatuses);
}
$this->elementEnd('users');
break;
case 'json':
$arrays = array();
foreach ($profiles as $profile) {
- $arrays[] = $this->twitter_user_array($profile, true);
+ $arrays[] = $this->twitter_user_array($profile, $includeStatuses);
}
print json_encode($arrays);
break;
diff --git a/actions/twitapilaconica.php b/actions/twitapistatusnet.php
index 442fdbcef..490f11dce 100644
--- a/actions/twitapilaconica.php
+++ b/actions/twitapistatusnet.php
@@ -1,8 +1,8 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
- * Laconica-only extensions to the Twitter-like API
+ * StatusNet-only extensions to the Twitter-like API
*
* PHP version 5
*
@@ -20,40 +20,40 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Twitter
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/twitterapi.php';
/**
- * Laconica-specific API methods
+ * StatusNet-specific API methods
*
- * This class handles all /laconica/ API methods.
+ * This class handles all /statusnet/ API methods.
*
* @category Twitter
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-class TwitapilaconicaAction extends TwitterapiAction
+class TwitapistatusnetAction extends TwitterapiAction
{
/**
* A version stamp for the API
*
- * Returns a version number for this version of Laconica, which
+ * Returns a version number for this version of StatusNet, which
* should make things a bit easier for upgrades.
- * URL: http://identi.ca/api/laconica/version.(xml|json)
+ * URL: http://identi.ca/api/statusnet/version.(xml|json)
* Formats: xml, json
*
* @param array $args Web arguments
@@ -70,12 +70,12 @@ class TwitapilaconicaAction extends TwitterapiAction
switch ($apidata['content-type']) {
case 'xml':
$this->init_document('xml');
- $this->element('version', null, LACONICA_VERSION);
+ $this->element('version', null, STATUSNET_VERSION);
$this->end_document('xml');
break;
case 'json':
$this->init_document('json');
- print '"'.LACONICA_VERSION.'"';
+ print '"'.STATUSNET_VERSION.'"';
$this->end_document('json');
break;
default:
@@ -87,9 +87,9 @@ class TwitapilaconicaAction extends TwitterapiAction
* Dump of configuration variables
*
* Gives a full dump of configuration variables for this instance
- * of Laconica, minus variables that may be security-sensitive (like
+ * of StatusNet, minus variables that may be security-sensitive (like
* passwords).
- * URL: http://identi.ca/api/laconica/config.(xml|json)
+ * URL: http://identi.ca/api/statusnet/config.(xml|json)
* Formats: xml, json
*
* @param array $args Web arguments
diff --git a/actions/twitapitags.php b/actions/twitapitags.php
index 5c8527530..0bcc55d37 100644
--- a/actions/twitapitags.php
+++ b/actions/twitapitags.php
@@ -1,8 +1,8 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
- * Laconica extensions to the Twitter-like API for groups
+ * StatusNet extensions to the Twitter-like API for groups
*
* PHP version 5
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Twitter
- * @package Laconica
- * @author Craig Andrews
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,15 +37,15 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
/**
* Group-specific API methods
*
- * This class handles Laconica group API methods.
+ * This class handles StatusNet group API methods.
*
* @category Twitter
- * @package Laconica
- * @author Craig Andrews
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class TwitapitagsAction extends TwitterapiAction
@@ -88,20 +88,19 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
$this->show_xml_timeline($notice);
break;
case 'rss':
- $this->show_rss_timeline($notice, $title, $link,
- $subtitle, $suplink);
+ $this->show_rss_timeline($notice, $title, $link, $subtitle);
break;
case 'atom':
if (isset($apidata['api_arg'])) {
$selfuri = common_root_url() .
- 'api/laconica/tags/timeline/' .
+ 'api/statusnet/tags/timeline/' .
$apidata['api_arg'] . '.atom';
} else {
$selfuri = common_root_url() .
- 'api/laconica/tags/timeline.atom';
+ 'api/statusnet/tags/timeline.atom';
}
$this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, $suplink, $selfuri);
+ $subtitle, null, $selfuri);
break;
case 'json':
$this->show_json_timeline($notice);
diff --git a/actions/twitapitrends.php b/actions/twitapitrends.php
index c73d89446..83ab28f35 100644
--- a/actions/twitapitrends.php
+++ b/actions/twitapitrends.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* List of replies
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
* Returns the top ten queries that are currently trending
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see TwitterapiAction
*/
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
index fea41b397..703fa6754 100644
--- a/actions/twitapiusers.php
+++ b/actions/twitapiusers.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/actions/twitterauthorization.php b/actions/twitterauthorization.php
new file mode 100644
index 000000000..630ac426f
--- /dev/null
+++ b/actions/twitterauthorization.php
@@ -0,0 +1,201 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class for doing OAuth authentication against Twitter
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category TwitterauthorizationAction
+ * @package StatusNet
+ * @author Zach Copely <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class TwitterauthorizationAction extends Action
+{
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $this->oauth_token = $this->arg('oauth_token');
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $args is ignored since it's now passed in in prepare()
+ *
+ * @return nothing
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if (!common_logged_in()) {
+ $this->clientError(_('Not logged in.'), 403);
+ }
+
+ $user = common_current_user();
+ $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
+
+ // If there's already a foreign link record, it means we already
+ // have an access token, and this is unecessary. So go back.
+
+ if (isset($flink)) {
+ common_redirect(common_local_url('twittersettings'));
+ }
+
+ // $this->oauth_token is only populated once Twitter authorizes our
+ // request token. If it's empty we're at the beginning of the auth
+ // process
+
+ if (empty($this->oauth_token)) {
+ $this->authorizeRequestToken();
+ } else {
+ $this->saveAccessToken();
+ }
+ }
+
+ /**
+ * Asks Twitter for a request token, and then redirects to Twitter
+ * to authorize it.
+ *
+ * @return nothing
+ */
+ function authorizeRequestToken()
+ {
+ try {
+
+ // Get a new request token and authorize it
+
+ $client = new TwitterOAuthClient();
+ $req_tok =
+ $client->getRequestToken(TwitterOAuthClient::$requestTokenURL);
+
+ // Sock the request token away in the session temporarily
+
+ $_SESSION['twitter_request_token'] = $req_tok->key;
+ $_SESSION['twitter_request_token_secret'] = $req_tok->secret;
+
+ $auth_link = $client->getAuthorizeLink($req_tok);
+
+ } catch (TwitterOAuthClientException $e) {
+ $msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
+ $e->getCode(), $e->getMessage());
+ $this->serverError(_('Couldn\'t link your Twitter account.'));
+ }
+
+ common_redirect($auth_link);
+ }
+
+ /**
+ * Called when Twitter returns an authorized request token. Exchanges
+ * it for an access token and stores it.
+ *
+ * @return nothing
+ */
+ function saveAccessToken()
+ {
+
+ // Check to make sure Twitter returned the same request
+ // token we sent them
+
+ if ($_SESSION['twitter_request_token'] != $this->oauth_token) {
+ $this->serverError(_('Couldn\'t link your Twitter account.'));
+ }
+
+ try {
+
+ $client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
+ $_SESSION['twitter_request_token_secret']);
+
+ // Exchange the request token for an access token
+
+ $atok = $client->getAccessToken(TwitterOAuthClient::$accessTokenURL);
+
+ // Test the access token and get the user's Twitter info
+
+ $client = new TwitterOAuthClient($atok->key, $atok->secret);
+ $twitter_user = $client->verifyCredentials();
+
+ } catch (OAuthClientException $e) {
+ $msg = sprintf('OAuth client cURL error - code: %1$s, msg: %2$s',
+ $e->getCode(), $e->getMessage());
+ $this->serverError(_('Couldn\'t link your Twitter account.'));
+ }
+
+ // Save the access token and Twitter user info
+
+ $this->saveForeignLink($atok, $twitter_user);
+
+ // Clean up the the mess we made in the session
+
+ unset($_SESSION['twitter_request_token']);
+ unset($_SESSION['twitter_request_token_secret']);
+
+ common_redirect(common_local_url('twittersettings'));
+ }
+
+ /**
+ * Saves a Foreign_link between Twitter user and local user,
+ * which includes the access token and secret.
+ *
+ * @param OAuthToken $access_token the access token to save
+ * @param mixed $twitter_user twitter API user object
+ *
+ * @return nothing
+ */
+ function saveForeignLink($access_token, $twitter_user)
+ {
+ $user = common_current_user();
+
+ $flink = new Foreign_link();
+
+ $flink->user_id = $user->id;
+ $flink->foreign_id = $twitter_user->id;
+ $flink->service = TWITTER_SERVICE;
+
+ $creds = TwitterOAuthClient::packToken($access_token);
+
+ $flink->credentials = $creds;
+ $flink->created = common_sql_now();
+
+ // Defaults: noticesync on, everything else off
+
+ $flink->set_flags(true, false, false, false);
+
+ $flink_id = $flink->insert();
+
+ if (empty($flink_id)) {
+ common_log_db_error($flink, 'INSERT', __FILE__);
+ $this->serverError(_('Couldn\'t link your Twitter account.'));
+ }
+
+ save_twitter_user($twitter_user->id, $twitter_user->screen_name);
+ }
+
+}
+
diff --git a/actions/twittersettings.php b/actions/twittersettings.php
index 2b742788e..89169941e 100644
--- a/actions/twittersettings.php
+++ b/actions/twittersettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Settings for Twitter integration
*
@@ -20,30 +20,28 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
require_once INSTALLDIR.'/lib/connectsettingsaction.php';
require_once INSTALLDIR.'/lib/twitter.php';
-define('SUBSCRIPTIONS', 80);
-
/**
* Settings for Twitter integration
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see SettingsAction
*/
@@ -69,22 +67,27 @@ class TwittersettingsAction extends ConnectSettingsAction
function getInstructions()
{
- return _('Add your Twitter account to automatically send '.
- ' your notices to Twitter, ' .
- 'and subscribe to Twitter friends already here.');
+ return _('Connect your Twitter account to share your updates ' .
+ 'with your Twitter friends and vice-versa.');
}
/**
* Content area of the page
*
* Shows a form for associating a Twitter account with this
- * Laconica account. Also lets the user set preferences.
+ * StatusNet account. Also lets the user set preferences.
*
* @return void
*/
function showContent()
{
+ if (!common_config('twitter', 'enabled')) {
+ $this->element('div', array('class' => 'error'),
+ _('Twitter is not available.'));
+ return;
+ }
+
$user = common_current_user();
$profile = $user->getProfile();
@@ -93,7 +96,7 @@ class TwittersettingsAction extends ConnectSettingsAction
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
- if ($flink) {
+ if (!empty($flink)) {
$fuser = $flink->getForeignUser();
}
@@ -102,192 +105,86 @@ class TwittersettingsAction extends ConnectSettingsAction
'class' => 'form_settings',
'action' =>
common_local_url('twittersettings')));
- $this->elementStart('fieldset', array('id' => 'settings_twitter_account'));
- $this->element('legend', null, _('Twitter Account'));
+
$this->hidden('token', common_session_token());
- if ($fuser) {
+
+ $this->elementStart('fieldset', array('id' => 'settings_twitter_account'));
+
+ if (empty($fuser)) {
$this->elementStart('ul', 'form_data');
- $this->elementStart('li', array('id' => 'settings_twitter_remove'));
- $this->element('span', 'twitter_user', $fuser->nickname);
- $this->element('a', array('href' => $fuser->uri), $fuser->uri);
- $this->element('p', 'form_note',
- _('Current verified Twitter account.'));
- $this->hidden('flink_foreign_id', $flink->foreign_id);
+ $this->elementStart('li', array('id' => 'settings_twitter_login_button'));
+ $this->element('a', array('href' => common_local_url('twitterauthorization')),
+ 'Connect my Twitter account');
$this->elementEnd('li');
$this->elementEnd('ul');
- $this->submit('remove', _('Remove'));
+
+ $this->elementEnd('fieldset');
} else {
+ $this->element('legend', null, _('Twitter account'));
+ $this->elementStart('p', array('id' => 'form_confirmed'));
+ $this->element('a', array('href' => $fuser->uri), $fuser->nickname);
+ $this->elementEnd('p');
+ $this->element('p', 'form_note',
+ _('Connected Twitter account'));
+
+ $this->submit('remove', _('Remove'));
+
+ $this->elementEnd('fieldset');
+
+ $this->elementStart('fieldset', array('id' => 'settings_twitter_preferences'));
+
+ $this->element('legend', null, _('Preferences'));
$this->elementStart('ul', 'form_data');
- $this->elementStart('li', array('id' => 'settings_twitter_login'));
- $this->input('twitter_username', _('Twitter user name'),
- ($this->arg('twitter_username')) ?
- $this->arg('twitter_username') :
- $profile->nickname,
- _('No spaces, please.')); // hey, it's what Twitter says
+ $this->elementStart('li');
+ $this->checkbox('noticesend',
+ _('Automatically send my notices to Twitter.'),
+ ($flink) ?
+ ($flink->noticesync & FOREIGN_NOTICE_SEND) :
+ true);
$this->elementEnd('li');
$this->elementStart('li');
- $this->password('twitter_password', _('Twitter password'));
- $this->elementend('li');
- $this->elementEnd('ul');
- }
- $this->elementEnd('fieldset');
-
- $this->elementStart('fieldset',
- array('id' => 'settings_twitter_preferences'));
- $this->element('legend', null, _('Preferences'));
-
- $this->elementStart('ul', 'form_data');
- $this->elementStart('li');
- $this->checkbox('noticesend',
- _('Automatically send my notices to Twitter.'),
- ($flink) ?
- ($flink->noticesync & FOREIGN_NOTICE_SEND) :
- true);
- $this->elementEnd('li');
- $this->elementStart('li');
- $this->checkbox('replysync',
- _('Send local "@" replies to Twitter.'),
- ($flink) ?
- ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) :
- true);
- $this->elementEnd('li');
- $this->elementStart('li');
- $this->checkbox('friendsync',
- _('Subscribe to my Twitter friends here.'),
- ($flink) ?
- ($flink->friendsync & FOREIGN_FRIEND_RECV) :
- false);
- $this->elementEnd('li');
-
- if (common_config('twitterbridge','enabled')) {
+ $this->checkbox('replysync',
+ _('Send local "@" replies to Twitter.'),
+ ($flink) ?
+ ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) :
+ true);
+ $this->elementEnd('li');
$this->elementStart('li');
- $this->checkbox('noticerecv',
- _('Import my Friends Timeline.'),
+ $this->checkbox('friendsync',
+ _('Subscribe to my Twitter friends here.'),
($flink) ?
- ($flink->noticesync & FOREIGN_NOTICE_RECV) :
+ ($flink->friendsync & FOREIGN_FRIEND_RECV) :
false);
$this->elementEnd('li');
- } else {
- // preserve setting even if bidrection bridge toggled off
- if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
- $this->hidden('noticerecv', true, 'noticerecv');
- }
- }
-
- $this->elementEnd('ul');
- if ($flink) {
- $this->submit('save', _('Save'));
- } else {
- $this->submit('add', _('Add'));
- }
- $this->elementEnd('fieldset');
-
- $this->showTwitterSubscriptions();
-
- $this->elementEnd('form');
- }
-
- /**
- * Gets some of the user's Twitter friends
- *
- * Gets the number of Twitter friends that are on this
- * instance of Laconica.
- *
- * @return array array of User objects
- */
-
- function subscribedTwitterUsers()
- {
-
- $current_user = common_current_user();
-
- $qry = 'SELECT "user".* ' .
- 'FROM subscription ' .
- 'JOIN "user" ON subscription.subscribed = "user".id ' .
- 'JOIN foreign_link ON foreign_link.user_id = "user".id ' .
- 'WHERE subscriber = %d ' .
- 'ORDER BY "user".nickname';
-
- $user = new User();
-
- $user->query(sprintf($qry, $current_user->id));
-
- $users = array();
-
- while ($user->fetch()) {
-
- // Don't include the user's own self-subscription
- if ($user->id != $current_user->id) {
- $users[] = clone($user);
- }
- }
-
- return $users;
- }
-
- /**
- * Show user's Twitter friends
- *
- * Gets the number of Twitter friends that are on this
- * instance of Laconica, and shows their mini-avatars.
- *
- * @return void
- */
-
- function showTwitterSubscriptions()
- {
-
- $friends = $this->subscribedTwitterUsers();
-
- $friends_count = count($friends);
-
- if ($friends_count > 0) {
- $this->elementStart('div', array('id' => 'entity_subscriptions',
- 'class' => 'section'));
- $this->element('h2', null, _('Twitter Friends'));
- $this->elementStart('ul', 'entities users xoxo');
-
- for ($i = 0; $i < min($friends_count, SUBSCRIPTIONS); $i++) {
-
- $other = Profile::staticGet($friends[$i]->id);
-
- if (!$other) {
- common_log_db_error($subs, 'SELECT', __FILE__);
- continue;
- }
-
- $this->elementStart('li', 'vcard');
- $this->elementStart('a', array('title' => ($other->fullname) ?
- $other->fullname :
- $other->nickname,
- 'href' => $other->profileurl,
- 'class' => 'url'));
-
- $avatar = $other->getAvatar(AVATAR_MINI_SIZE);
-
- $avatar_url = ($avatar) ?
- $avatar->displayUrl() :
- Avatar::defaultImage(AVATAR_MINI_SIZE);
-
- $this->element('img', array('src' => $avatar_url,
- 'width' => AVATAR_MINI_SIZE,
- 'height' => AVATAR_MINI_SIZE,
- 'class' => 'avatar photo',
- 'alt' => ($other->fullname) ?
- $other->fullname :
- $other->nickname));
-
- $this->element('span', 'fn nickname', $other->nickname);
- $this->elementEnd('a');
+ if (common_config('twitterbridge','enabled')) {
+ $this->elementStart('li');
+ $this->checkbox('noticerecv',
+ _('Import my Friends Timeline.'),
+ ($flink) ?
+ ($flink->noticesync & FOREIGN_NOTICE_RECV) :
+ false);
$this->elementEnd('li');
+ } else {
+ // preserve setting even if bidrection bridge toggled off
+ if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
+ $this->hidden('noticerecv', true, 'noticerecv');
+ }
}
$this->elementEnd('ul');
- $this->elementEnd('div');
+ if ($flink) {
+ $this->submit('save', _('Save'));
+ } else {
+ $this->submit('add', _('Add'));
+ }
+
+ $this->elementEnd('fieldset');
}
+
+ $this->elementEnd('form');
}
/**
@@ -303,7 +200,6 @@ class TwittersettingsAction extends ConnectSettingsAction
function handlePost()
{
-
// CSRF protection
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
@@ -314,8 +210,6 @@ class TwittersettingsAction extends ConnectSettingsAction
if ($this->arg('save')) {
$this->savePreferences();
- } else if ($this->arg('add')) {
- $this->addTwitterAccount();
} else if ($this->arg('remove')) {
$this->removeTwitterAccount();
} else {
@@ -324,82 +218,6 @@ class TwittersettingsAction extends ConnectSettingsAction
}
/**
- * Associate a Twitter account with the user's account
- *
- * Validates post input; verifies it against Twitter; and if
- * successful stores in the database.
- *
- * @return void
- */
-
- function addTwitterAccount()
- {
- $screen_name = $this->trimmed('twitter_username');
- $password = $this->trimmed('twitter_password');
- $noticesend = $this->boolean('noticesend');
- $noticerecv = $this->boolean('noticerecv');
- $replysync = $this->boolean('replysync');
- $friendsync = $this->boolean('friendsync');
-
- if (!Validate::string($screen_name,
- array('min_length' => 1,
- 'max_length' => 15,
- 'format' => VALIDATE_NUM.VALIDATE_ALPHA.'_'))) {
- $this->showForm(_('Username must have only numbers, '.
- 'upper- and lowercase letters, '.
- 'and underscore (_). 15 chars max.'));
- return;
- }
-
- if (!$this->verifyCredentials($screen_name, $password)) {
- $this->showForm(_('Could not verify your Twitter credentials!'));
- return;
- }
-
- $twit_user = twitter_user_info($screen_name, $password);
-
- if (!$twit_user) {
- $this->showForm(sprintf(_('Unable to retrieve account information '.
- 'For "%s" from Twitter.'),
- $screen_name));
- return;
- }
-
- if (!save_twitter_user($twit_user->id, $screen_name)) {
- $this->showForm(_('Unable to save your Twitter settings!'));
- return;
- }
-
- $user = common_current_user();
-
- $flink = new Foreign_link();
-
- $flink->user_id = $user->id;
- $flink->foreign_id = $twit_user->id;
- $flink->service = TWITTER_SERVICE;
- $flink->credentials = $password;
- $flink->created = common_sql_now();
-
- $flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
-
- $flink_id = $flink->insert();
-
- if (!$flink_id) {
- common_log_db_error($flink, 'INSERT', __FILE__);
- $this->showForm(_('Unable to save your Twitter settings!'));
- return;
- }
-
- if ($friendsync) {
- save_twitter_friends($user, $twit_user->id, $screen_name, $password);
- $flink->last_friendsync = common_sql_now();
- $flink->update();
- }
-
- $this->showForm(_('Twitter settings saved.'), true);
- }
-
- /**
* Disassociate an existing Twitter account from this account
*
* @return void
@@ -408,20 +226,11 @@ class TwittersettingsAction extends ConnectSettingsAction
function removeTwitterAccount()
{
$user = common_current_user();
-
- $flink = Foreign_link::getByUserID($user->id, 1);
-
- $flink_foreign_id = $this->arg('flink_foreign_id');
-
- // Maybe an old tab open...?
- if ($flink->foreign_id != $flink_foreign_id) {
- $this->showForm(_('That is not your Twitter account.'));
- return;
- }
+ $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
$result = $flink->delete();
- if (!$result) {
+ if (empty($result)) {
common_log_db_error($flink, 'DELETE', __FILE__);
$this->serverError(_('Couldn\'t remove Twitter user.'));
return;
@@ -444,32 +253,16 @@ class TwittersettingsAction extends ConnectSettingsAction
$replysync = $this->boolean('replysync');
$user = common_current_user();
+ $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
- $flink = Foreign_link::getByUserID($user->id, 1);
-
- if (!$flink) {
+ if (empty($flink)) {
common_log_db_error($flink, 'SELECT', __FILE__);
$this->showForm(_('Couldn\'t save Twitter preferences.'));
return;
}
- $twitter_id = $flink->foreign_id;
- $password = $flink->credentials;
-
- $fuser = $flink->getForeignUser();
-
- if (!$fuser) {
- common_log_db_error($fuser, 'SELECT', __FILE__);
- $this->showForm(_('Couldn\'t save Twitter preferences.'));
- return;
- }
-
- $screen_name = $fuser->nickname;
-
$original = clone($flink);
-
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
-
$result = $flink->update($original);
if ($result === false) {
@@ -478,45 +271,7 @@ class TwittersettingsAction extends ConnectSettingsAction
return;
}
- if ($friendsync) {
- save_twitter_friends($user, $flink->foreign_id, $screen_name, $password);
- }
-
$this->showForm(_('Twitter preferences saved.'), true);
}
- /**
- * Verifies a username and password against Twitter's API
- *
- * @param string $screen_name Twitter user name
- * @param string $password Twitter password
- *
- * @return boolean success flag
- */
-
- function verifyCredentials($screen_name, $password)
- {
- $uri = 'http://twitter.com/account/verify_credentials.json';
-
- $data = get_twitter_data($uri, $screen_name, $password);
-
- if (!$data) {
- return false;
- }
-
- $user = json_decode($data);
-
- if (!$user) {
- return false;
- }
-
- $twitter_id = $user->id;
-
- if ($twitter_id) {
- return $twitter_id;
- }
-
- return false;
- }
-
}
diff --git a/actions/unblock.php b/actions/unblock.php
index 05d57c60d..dc28d5d54 100644
--- a/actions/unblock.php
+++ b/actions/unblock.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -36,11 +36,11 @@ if (!defined('LACONICA')) {
* Unblock a user action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class UnblockAction extends Action
{
diff --git a/actions/unsubscribe.php b/actions/unsubscribe.php
index 19275041a..4a5863489 100644
--- a/actions/unsubscribe.php
+++ b/actions/unsubscribe.php
@@ -1,7 +1,18 @@
<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+/**
+ * Unsubscribe handler
+ *
+ * PHP version 5
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ *
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,6 +28,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Unsubscribe handler
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://status.net/
+ */
class UnsubscribeAction extends Action
{
@@ -31,16 +56,18 @@ class UnsubscribeAction extends Action
$user = common_current_user();
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
- common_redirect(common_local_url('subscriptions', array('nickname' => $user->nickname)));
+ common_redirect(common_local_url('subscriptions',
+ array('nickname' => $user->nickname)));
return;
}
- # CSRF protection
+ /* Use a session token for CSRF protection. */
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
- $this->clientError(_('There was a problem with your session token. Try again, please.'));
+ $this->clientError(_('There was a problem with your session token. ' .
+ 'Try again, please.'));
return;
}
@@ -53,7 +80,7 @@ class UnsubscribeAction extends Action
$other = Profile::staticGet('id', $other_id);
- if (!$other_id) {
+ if (!$other) {
$this->clientError(_('No profile with that id.'));
return;
}
@@ -76,8 +103,8 @@ class UnsubscribeAction extends Action
$this->elementEnd('body');
$this->elementEnd('html');
} else {
- common_redirect(common_local_url('subscriptions', array('nickname' =>
- $user->nickname)),
+ common_redirect(common_local_url('subscriptions',
+ array('nickname' => $user->nickname)),
303);
}
}
diff --git a/actions/updateprofile.php b/actions/updateprofile.php
index d8b62fb09..9a4cf8e46 100644
--- a/actions/updateprofile.php
+++ b/actions/updateprofile.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/omb.php');
@@ -79,7 +79,7 @@ class UpdateprofileAction extends Action
$nickname = $req->get_parameter('omb_listenee_nickname');
if ($nickname && !Validate::string($nickname, array('min_length' => 1,
'max_length' => 64,
- 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
+ 'format' => NICKNAME_FMT))) {
$this->clientError(_('Nickname must have only lowercase letters and numbers and no spaces.'));
return false;
}
diff --git a/actions/userauthorization.php b/actions/userauthorization.php
index 8dc2c808d..a9ac1f256 100644
--- a/actions/userauthorization.php
+++ b/actions/userauthorization.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/omb.php');
define('TIMESTAMP_THRESHOLD', 300);
@@ -47,7 +47,11 @@ class UserauthorizationAction extends Action
# Go log in, and then come back
common_set_returnto($_SERVER['REQUEST_URI']);
- common_redirect(common_local_url('login'));
+ if (!common_config('site', 'openidonly')) {
+ common_redirect(common_local_url('login'));
+ } else {
+ common_redirect(common_local_url('openidlogin'));
+ }
return;
}
@@ -481,7 +485,7 @@ class UserauthorizationAction extends Action
$nickname = $_GET['omb_listenee_nickname'];
if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64,
- 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
+ 'format' => NICKNAME_FMT))) {
throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
}
$profile = $_GET['omb_listenee_profile'];
diff --git a/actions/userbyid.php b/actions/userbyid.php
index 8b686ae10..802bcb081 100644
--- a/actions/userbyid.php
+++ b/actions/userbyid.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,11 +37,11 @@ if (!defined('LACONICA')) {
* User by ID action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class UserbyidAction extends Action
{
diff --git a/actions/userdesignsettings.php b/actions/userdesignsettings.php
index d7949951a..568c1d624 100644
--- a/actions/userdesignsettings.php
+++ b/actions/userdesignsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Change user password
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ require_once INSTALLDIR . '/lib/designsettings.php';
* Saves a design for a given user
*
* @category Settings
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class UserDesignSettingsAction extends DesignSettingsAction
diff --git a/actions/usergroups.php b/actions/usergroups.php
index 7ead6e6e4..84e105153 100644
--- a/actions/usergroups.php
+++ b/actions/usergroups.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* User groups information
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ require_once INSTALLDIR.'/lib/grouplist.php';
* Show the groups a user belongs to
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class UsergroupsAction extends OwnerDesignAction
diff --git a/actions/userrss.php b/actions/userrss.php
index 8a940865f..fa6d588cd 100644
--- a/actions/userrss.php
+++ b/actions/userrss.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/rssaction.php');
@@ -88,9 +88,10 @@ class UserrssAction extends Rss10Action
$c = array('url' => common_local_url('userrss',
array('nickname' =>
$user->nickname)),
- 'title' => $user->nickname,
+ 'title' => sprintf(_('%s timeline'), $user->nickname),
'link' => $profile->profileurl,
- 'description' => sprintf(_('Microblog by %s'), $user->nickname));
+ 'description' => sprintf(_('Updates from %1$s on %2$s!'),
+ $user->nickname, common_config('site', 'name')));
return $c;
}
diff --git a/actions/xrds.php b/actions/xrds.php
index 9327a3c83..def10e4cf 100644
--- a/actions/xrds.php
+++ b/actions/xrds.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,11 +39,11 @@ require_once INSTALLDIR.'/lib/omb.php';
* XRDS for OpenID
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class XrdsAction extends Action
{
diff --git a/classes/Design.php b/classes/Design.php
index 0927fcda7..89ae50c8c 100644
--- a/classes/Design.php
+++ b/classes/Design.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - the distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -55,26 +55,38 @@ class Design extends Memcached_DataObject
function showCSS($out)
{
- try {
+ $css = '';
- $bgcolor = new WebColor($this->backgroundcolor);
- $ccolor = new WebColor($this->contentcolor);
- $sbcolor = new WebColor($this->sidebarcolor);
- $tcolor = new WebColor($this->textcolor);
- $lcolor = new WebColor($this->linkcolor);
+ $bgcolor = Design::toWebColor($this->backgroundcolor);
- } catch (WebColorException $e) {
- // This shouldn't happen
- common_log(LOG_ERR, "Unable to create color for design $id.",
- __FILE__);
+ if (!empty($bgcolor)) {
+ $css .= 'body { background-color: #' . $bgcolor->hexValue() . ' }' . "\n";
}
- $css = 'body { background-color: #' . $bgcolor->hexValue() . ' }' . "\n";
- $css .= '#content, #site_nav_local_views .current a { background-color: #';
- $css .= $ccolor->hexValue() . '} '."\n";
- $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . ' }' . "\n";
- $css .= 'html body { color: #'. $tcolor->hexValue() . ' }'. "\n";
- $css .= 'a { color: #' . $lcolor->hexValue() . ' }' . "\n";
+ $ccolor = Design::toWebColor($this->contentcolor);
+
+ if (!empty($ccolor)) {
+ $css .= '#content, #site_nav_local_views .current a { background-color: #';
+ $css .= $ccolor->hexValue() . '} '."\n";
+ }
+
+ $sbcolor = Design::toWebColor($this->sidebarcolor);
+
+ if (!empty($sbcolor)) {
+ $css .= '#aside_primary { background-color: #'. $sbcolor->hexValue() . ' }' . "\n";
+ }
+
+ $tcolor = Design::toWebColor($this->textcolor);
+
+ if (!empty($tcolor)) {
+ $css .= 'html body { color: #'. $tcolor->hexValue() . ' }'. "\n";
+ }
+
+ $lcolor = Design::toWebColor($this->linkcolor);
+
+ if (!empty($lcolor)) {
+ $css .= 'a { color: #' . $lcolor->hexValue() . ' }' . "\n";
+ }
if (!empty($this->backgroundimage) &&
$this->disposition & BACKGROUND_ON) {
@@ -88,8 +100,25 @@ class Design extends Memcached_DataObject
'); ' . $repeat . ' background-attachment:fixed; }' . "\n";
}
- $out->element('style', array('type' => 'text/css'), $css);
+ if (0 != mb_strlen($css)) {
+ $out->element('style', array('type' => 'text/css'), $css);
+ }
+ }
+
+ static function toWebColor($color)
+ {
+ if ($color == null) {
+ return null;
+ }
+ try {
+ return new WebColor($color);
+ } catch (WebColorException $e) {
+ // This shouldn't happen
+ common_log(LOG_ERR, "Unable to create web color for $color",
+ __FILE__);
+ return null;
+ }
}
static function filename($id, $extension, $extra=null)
@@ -152,4 +181,36 @@ class Design extends Memcached_DataObject
}
}
+ /**
+ * Return a design object based on the configured site design.
+ *
+ * @return Design a singleton design object for the site.
+ */
+
+ static function siteDesign()
+ {
+ static $siteDesign = null;
+
+ if (empty($siteDesign)) {
+
+ $siteDesign = new Design();
+
+ $attrs = array('backgroundcolor',
+ 'contentcolor',
+ 'sidebarcolor',
+ 'textcolor',
+ 'linkcolor',
+ 'backgroundimage',
+ 'disposition');
+
+ foreach ($attrs as $attr) {
+ $val = common_config('design', $attr);
+ if ($val !== false) {
+ $siteDesign->$attr = $val;
+ }
+ }
+ }
+
+ return $siteDesign;
+ }
}
diff --git a/classes/File.php b/classes/File.php
index 0c4fbf7e6..308d0a771 100644
--- a/classes/File.php
+++ b/classes/File.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
require_once INSTALLDIR.'/classes/File_redirection.php';
@@ -78,14 +78,14 @@ class File extends Memcached_DataObject
$file_id = $x->insert();
if (isset($redir_data['type'])
- && ('text/html' === substr($redir_data['type'], 0, 9))
+ && (('text/html' === substr($redir_data['type'], 0, 9) || 'application/xhtml+xml' === substr($redir_data['type'], 0, 21)))
&& ($oembed_data = File_oembed::_getOembed($given_url))) {
File_oembed::saveNew($oembed_data, $file_id);
}
return $x;
}
- function processNew($given_url, $notice_id) {
+ function processNew($given_url, $notice_id=null) {
if (empty($given_url)) return -1; // error, no url to process
$given_url = File_redirection::_canonUrl($given_url);
if (empty($given_url)) return -1; // error, no url to process
@@ -93,10 +93,10 @@ class File extends Memcached_DataObject
if (empty($file)) {
$file_redir = File_redirection::staticGet('url', $given_url);
if (empty($file_redir)) {
- common_debug("processNew() '$given_url' not a known redirect.\n");
$redir_data = File_redirection::where($given_url);
$redir_url = $redir_data['url'];
- if ($redir_url === $given_url) {
+ // TODO: max field length
+ if ($redir_url === $given_url || strlen($redir_url) > 255) {
$x = File::saveNew($redir_data, $given_url);
$file_id = $x->id;
} else {
@@ -114,10 +114,14 @@ class File extends Memcached_DataObject
if (empty($x)) {
$x = File::staticGet($file_id);
- if (empty($x)) die('Impossible!');
+ if (empty($x)) {
+ throw new ServerException("Robin thinks something is impossible.");
+ }
}
- File_to_post::processNew($file_id, $notice_id);
+ if (!empty($notice_id)) {
+ File_to_post::processNew($file_id, $notice_id);
+ }
return $x;
}
@@ -197,7 +201,7 @@ class File extends Memcached_DataObject
if(isset($this->filename)){
return true;
}
- $notEnclosureMimeTypes = array('text/html','application/xhtml+xml');
+ $notEnclosureMimeTypes = array('text/html','application/xhtml+xml',null);
$mimetype = strtolower($this->mimetype);
$semicolon = strpos($mimetype,';');
if($semicolon){
diff --git a/classes/File_oembed.php b/classes/File_oembed.php
index bbf112729..6be651815 100644
--- a/classes/File_oembed.php
+++ b/classes/File_oembed.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
diff --git a/classes/File_redirection.php b/classes/File_redirection.php
index d6fa0bcb6..76b18f672 100644
--- a/classes/File_redirection.php
+++ b/classes/File_redirection.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,13 +17,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
require_once INSTALLDIR.'/classes/File.php';
require_once INSTALLDIR.'/classes/File_oembed.php';
-define('USER_AGENT', 'Laconica user agent / file probe');
+define('USER_AGENT', 'StatusNet user agent / file probe');
/**
* Table Definition for file_redirection
@@ -182,7 +182,7 @@ class File_redirection extends Memcached_DataObject
}
}
- if (('ftp' == $p['scheme']) || ('http' == $p['scheme']) || ('https' == $p['scheme'])) {
+ if (('ftp' == $p['scheme']) || ('ftps' == $p['scheme']) || ('http' == $p['scheme']) || ('https' == $p['scheme'])) {
if (empty($p['host'])) return false;
if (empty($p['path'])) {
$out_url .= '/';
diff --git a/classes/File_thumbnail.php b/classes/File_thumbnail.php
index 0b09c6af8..f8b70356c 100644
--- a/classes/File_thumbnail.php
+++ b/classes/File_thumbnail.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
diff --git a/classes/File_to_post.php b/classes/File_to_post.php
index d35febb77..e3db91b20 100644
--- a/classes/File_to_post.php
+++ b/classes/File_to_post.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
diff --git a/classes/Foreign_link.php b/classes/Foreign_link.php
index c0b356ece..ae8c22fd8 100644
--- a/classes/Foreign_link.php
+++ b/classes/Foreign_link.php
@@ -29,34 +29,38 @@ class Foreign_link extends Memcached_DataObject
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
- // XXX: This only returns a 1->1 single obj mapping. Change? Or make
- // a getForeignUsers() that returns more than one? --Zach
static function getByUserID($user_id, $service)
{
+ if (empty($user_id) || empty($service)) {
+ return null;
+ }
+
$flink = new Foreign_link();
+
$flink->service = $service;
$flink->user_id = $user_id;
$flink->limit(1);
- if ($flink->find(true)) {
- return $flink;
- }
+ $result = $flink->find(true);
+
+ return empty($result) ? null : $flink;
- return null;
}
static function getByForeignID($foreign_id, $service)
{
- $flink = new Foreign_link();
- $flink->service = $service;
- $flink->foreign_id = $foreign_id;
- $flink->limit(1);
+ if (empty($foreign_id) || empty($service)) {
+ return null;
+ } else {
+ $flink = new Foreign_link();
+ $flink->service = $service;
+ $flink->foreign_id = $foreign_id;
+ $flink->limit(1);
- if ($flink->find(true)) {
- return $flink;
- }
+ $result = $flink->find(true);
- return null;
+ return empty($result) ? null : $flink;
+ }
}
function set_flags($noticesend, $noticerecv, $replysync, $friendsync)
@@ -66,7 +70,7 @@ class Foreign_link extends Memcached_DataObject
} else {
$this->noticesync &= ~FOREIGN_NOTICE_SEND;
}
-
+
if ($noticerecv) {
$this->noticesync |= FOREIGN_NOTICE_RECV;
} else {
diff --git a/classes/Group_alias.php b/classes/Group_alias.php
index e801e50e1..be3d0a6c6 100644
--- a/classes/Group_alias.php
+++ b/classes/Group_alias.php
@@ -2,8 +2,8 @@
/**
* Table Definition for group_alias
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
diff --git a/classes/Group_block.php b/classes/Group_block.php
index 7922c19a9..de2cf5f6e 100644
--- a/classes/Group_block.php
+++ b/classes/Group_block.php
@@ -2,8 +2,8 @@
/**
* Table Definition for group_block
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php
index f7cbb9d5b..9c2ac3e01 100644
--- a/classes/Memcached_DataObject.php
+++ b/classes/Memcached_DataObject.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
@@ -241,10 +241,19 @@ class Memcached_DataObject extends DB_DataObject
function _connect()
{
global $_DB_DATAOBJECT;
- $exists = !empty($this->_database_dsn_md5) &&
- isset($_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5]);
+
+ $sum = $this->_getDbDsnMD5();
+
+ if (!empty($_DB_DATAOBJECT['CONNECTIONS'][$sum]) &&
+ !PEAR::isError($_DB_DATAOBJECT['CONNECTIONS'][$sum])) {
+ $exists = true;
+ } else {
+ $exists = false;
+ }
+
$result = parent::_connect();
- if (!$exists) {
+
+ if ($result && !$exists) {
$DB = &$_DB_DATAOBJECT['CONNECTIONS'][$this->_database_dsn_md5];
if (common_config('db', 'type') == 'mysql' &&
common_config('db', 'utf8')) {
@@ -258,7 +267,61 @@ class Memcached_DataObject extends DB_DataObject
}
}
}
+
return $result;
}
+ // XXX: largely cadged from DB_DataObject
+
+ function _getDbDsnMD5()
+ {
+ if ($this->_database_dsn_md5) {
+ return $this->_database_dsn_md5;
+ }
+
+ $dsn = $this->_getDbDsn();
+
+ if (is_string($dsn)) {
+ $sum = md5($dsn);
+ } else {
+ /// support array based dsn's
+ $sum = md5(serialize($dsn));
+ }
+
+ return $sum;
+ }
+
+ function _getDbDsn()
+ {
+ global $_DB_DATAOBJECT;
+
+ if (empty($_DB_DATAOBJECT['CONFIG'])) {
+ DB_DataObject::_loadConfig();
+ }
+
+ $options = &$_DB_DATAOBJECT['CONFIG'];
+
+ // if the databse dsn dis defined in the object..
+
+ $dsn = isset($this->_database_dsn) ? $this->_database_dsn : null;
+
+ if (!$dsn) {
+
+ if (!$this->_database) {
+ $this->_database = isset($options["table_{$this->__table}"]) ? $options["table_{$this->__table}"] : null;
+ }
+
+ if ($this->_database && !empty($options["database_{$this->_database}"])) {
+ $dsn = $options["database_{$this->_database}"];
+ } else if (!empty($options['database'])) {
+ $dsn = $options['database'];
+ }
+ }
+
+ if (!$dsn) {
+ throw new Exception("No database name / dsn found anywhere");
+ }
+
+ return $dsn;
+ }
}
diff --git a/classes/Notice.php b/classes/Notice.php
index c2770edbe..7d0502626 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
/**
* Table Definition for notice
@@ -29,10 +29,6 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
define('NOTICE_CACHE_WINDOW', 61);
-define('NOTICE_LOCAL_PUBLIC', 1);
-define('NOTICE_REMOTE_OMB', 0);
-define('NOTICE_LOCAL_NONPUBLIC', -1);
-
define('MAX_BOXCARS', 128);
class Notice extends Memcached_DataObject
@@ -62,7 +58,11 @@ class Notice extends Memcached_DataObject
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
- const GATEWAY = -2;
+ /* Notice types */
+ const LOCAL_PUBLIC = 1;
+ const REMOTE_OMB = 0;
+ const LOCAL_NONPUBLIC = -1;
+ const GATEWAY = -2;
function getProfile()
{
@@ -102,15 +102,14 @@ class Notice extends Memcached_DataObject
if (!$count) {
return true;
}
-
+
//turn each into their canonical tag
//this is needed to remove dupes before saving e.g. #hash.tag = #hashtag
$hashtags = array();
for($i=0; $i<count($match[1]); $i++) {
- $hashtags[] = common_canonical_tag($match[1][$i]);
+ $hashtags[] = common_canonical_tag($match[1][$i]);
}
-
/* Add them to the database */
foreach(array_unique($hashtags) as $hashtag) {
/* elide characters we don't want in the tag */
@@ -135,7 +134,7 @@ class Notice extends Memcached_DataObject
}
static function saveNew($profile_id, $content, $source=null,
- $is_local=1, $reply_to=null, $uri=null, $created=null) {
+ $is_local=Notice::LOCAL_PUBLIC, $reply_to=null, $uri=null, $created=null) {
$profile = Profile::staticGet($profile_id);
@@ -178,34 +177,35 @@ class Notice extends Memcached_DataObject
if (($blacklist && in_array($profile_id, $blacklist)) ||
($source && $autosource && in_array($source, $autosource))) {
- $notice->is_local = -1;
+ $notice->is_local = Notice::LOCAL_NONPUBLIC;
} else {
$notice->is_local = $is_local;
}
- $notice->query('BEGIN');
-
- $notice->reply_to = $reply_to;
if (!empty($created)) {
$notice->created = $created;
} else {
$notice->created = common_sql_now();
}
+
$notice->content = $final;
$notice->rendered = common_render_content($final, $notice);
$notice->source = $source;
$notice->uri = $uri;
- if (!empty($reply_to)) {
- $reply_notice = Notice::staticGet('id', $reply_to);
- if (!empty($reply_notice)) {
- $notice->reply_to = $reply_to;
- $notice->conversation = $reply_notice->conversation;
- }
+ $notice->reply_to = self::getReplyTo($reply_to, $profile_id, $source, $final);
+
+ if (!empty($notice->reply_to)) {
+ $reply = Notice::staticGet('id', $notice->reply_to);
+ $notice->conversation = $reply->conversation;
}
if (Event::handle('StartNoticeSave', array(&$notice))) {
+ // XXX: some of these functions write to the DB
+
+ $notice->query('BEGIN');
+
$id = $notice->insert();
if (!$id) {
@@ -213,18 +213,33 @@ class Notice extends Memcached_DataObject
return _('Problem saving notice.');
}
- # Update the URI after the notice is in the database
- if (!$uri) {
- $orig = clone($notice);
+ // Update ID-dependent columns: URI, conversation
+
+ $orig = clone($notice);
+
+ $changed = false;
+
+ if (empty($uri)) {
$notice->uri = common_notice_uri($notice);
+ $changed = true;
+ }
+ // If it's not part of a conversation, it's
+ // the beginning of a new conversation.
+
+ if (empty($notice->conversation)) {
+ $notice->conversation = $notice->id;
+ $changed = true;
+ }
+
+ if ($changed) {
if (!$notice->update($orig)) {
common_log_db_error($notice, 'UPDATE', __FILE__);
return _('Problem saving notice.');
}
}
- # XXX: do we need to change this for remote users?
+ // XXX: do we need to change this for remote users?
$notice->saveReplies();
$notice->saveTags();
@@ -232,12 +247,6 @@ class Notice extends Memcached_DataObject
$notice->addToInboxes();
$notice->saveUrls();
- $orig2 = clone($notice);
- $notice->rendered = common_render_content($final, $notice);
- if (!$notice->update($orig2)) {
- common_log_db_error($notice, 'UPDATE', __FILE__);
- return _('Problem saving notice.');
- }
$notice->query('COMMIT');
@@ -290,9 +299,9 @@ class Notice extends Memcached_DataObject
$notice->profile_id = $profile_id;
$notice->content = $content;
if (common_config('db','type') == 'pgsql')
- $notice->whereAdd('extract(epoch from now() - created) < ' . common_config('site', 'dupelimit'));
+ $notice->whereAdd('extract(epoch from now() - created) < ' . common_config('site', 'dupelimit'));
else
- $notice->whereAdd('now() - created < ' . common_config('site', 'dupelimit'));
+ $notice->whereAdd('now() - created < ' . common_config('site', 'dupelimit'));
$cnt = $notice->count();
return ($cnt == 0);
@@ -489,7 +498,7 @@ class Notice extends Memcached_DataObject
function blowPublicCache($blowLast=false)
{
- if ($this->is_local == 1) {
+ if ($this->is_local == Notice::LOCAL_PUBLIC) {
$cache = common_memcache();
if ($cache) {
$cache->delete(common_cache_key('public'));
@@ -723,6 +732,10 @@ class Notice extends Memcached_DataObject
return new ArrayWrapper($notices);
} else {
$notice = new Notice();
+ if (empty($ids)) {
+ //if no IDs requested, just return the notice object
+ return $notice;
+ }
$notice->whereAdd('id in (' . implode(', ', $ids) . ')');
$notice->orderBy('id DESC');
@@ -755,10 +768,11 @@ class Notice extends Memcached_DataObject
}
if (common_config('public', 'localonly')) {
- $notice->whereAdd('is_local = 1');
+ $notice->whereAdd('is_local = ' . Notice::LOCAL_PUBLIC);
} else {
- # -1 == blacklisted
- $notice->whereAdd('is_local != -1');
+ # -1 == blacklisted, -2 == gateway (i.e. Twitter)
+ $notice->whereAdd('is_local !='. Notice::LOCAL_NONPUBLIC);
+ $notice->whereAdd('is_local !='. Notice::GATEWAY);
}
if ($since_id != 0) {
@@ -883,7 +897,8 @@ class Notice extends Memcached_DataObject
$qry .= '('.$id.', '.$this->id.', '.$source.", '".$this->created. "') ";
$cnt++;
if (rand() % NOTICE_INBOX_SOFT_LIMIT == 0) {
- Notice_inbox::gc($id);
+ // FIXME: Causes lag in replicated servers
+ // Notice_inbox::gc($id);
}
if ($cnt >= MAX_BOXCARS) {
$inbox = new Notice_inbox();
@@ -906,14 +921,14 @@ class Notice extends Memcached_DataObject
{
$user = new User();
- if(common_config('db','quote_identifiers'))
- $user_table = '"user"';
- else $user_table = 'user';
+ if(common_config('db','quote_identifiers'))
+ $user_table = '"user"';
+ else $user_table = 'user';
$qry =
'SELECT id ' .
- 'FROM '. $user_table .' JOIN subscription '.
- 'ON '. $user_table .'.id = subscription.subscriber ' .
+ 'FROM '. $user_table .' JOIN subscription '.
+ 'ON '. $user_table .'.id = subscription.subscriber ' .
'WHERE subscription.subscribed = %d ';
$user->query(sprintf($qry, $this->profile_id));
@@ -1031,16 +1046,6 @@ class Notice extends Memcached_DataObject
if (!$recipient) {
continue;
}
- if ($i == 0 && ($recipient->id != $sender->id) && !$this->reply_to) { // Don't save reply to self
- $reply_for = $recipient;
- $recipient_notice = $reply_for->getCurrentNotice();
- if ($recipient_notice) {
- $orig = clone($this);
- $this->reply_to = $recipient_notice->id;
- $this->conversation = $recipient_notice->conversation;
- $this->update($orig);
- }
- }
// Don't save replies from blocked profile to local user
$recipient_user = User::staticGet('id', $recipient->id);
if ($recipient_user && $recipient_user->hasBlocked($sender)) {
@@ -1087,14 +1092,6 @@ class Notice extends Memcached_DataObject
}
}
- // If it's not a reply, make it the root of a new conversation
-
- if (empty($this->conversation)) {
- $orig = clone($this);
- $this->conversation = $this->id;
- $this->update($orig);
- }
-
foreach (array_keys($replied) as $recipient) {
$user = User::staticGet('id', $recipient);
if ($user) {
@@ -1266,4 +1263,76 @@ class Notice extends Memcached_DataObject
return $ids;
}
+
+ /**
+ * Determine which notice, if any, a new notice is in reply to.
+ *
+ * For conversation tracking, we try to see where this notice fits
+ * in the tree. Rough algorithm is:
+ *
+ * if (reply_to is set and valid) {
+ * return reply_to;
+ * } else if ((source not API or Web) and (content starts with "T NAME" or "@name ")) {
+ * return ID of last notice by initial @name in content;
+ * }
+ *
+ * Note that all @nickname instances will still be used to save "reply" records,
+ * so the notice shows up in the mentioned users' "replies" tab.
+ *
+ * @param integer $reply_to ID passed in by Web or API
+ * @param integer $profile_id ID of author
+ * @param string $source Source tag, like 'web' or 'gwibber'
+ * @param string $content Final notice content
+ *
+ * @return integer ID of replied-to notice, or null for not a reply.
+ */
+
+ static function getReplyTo($reply_to, $profile_id, $source, $content)
+ {
+ static $lb = array('xmpp', 'mail', 'sms', 'omb');
+
+ // If $reply_to is specified, we check that it exists, and then
+ // return it if it does
+
+ if (!empty($reply_to)) {
+ $reply_notice = Notice::staticGet('id', $reply_to);
+ if (!empty($reply_notice)) {
+ return $reply_to;
+ }
+ }
+
+ // If it's not a "low bandwidth" source (one where you can't set
+ // a reply_to argument), we return. This is mostly web and API
+ // clients.
+
+ if (!in_array($source, $lb)) {
+ return null;
+ }
+
+ // Is there an initial @ or T?
+
+ if (preg_match('/^T ([A-Z0-9]{1,64}) /', $content, $match) ||
+ preg_match('/^@([a-z0-9]{1,64})\s+/', $content, $match)) {
+ $nickname = common_canonical_nickname($match[1]);
+ } else {
+ return null;
+ }
+
+ // Figure out who that is.
+
+ $sender = Profile::staticGet('id', $profile_id);
+ $recipient = common_relative_profile($sender, $nickname, common_sql_now());
+
+ if (empty($recipient)) {
+ return null;
+ }
+
+ // Get their last notice
+
+ $last = $recipient->getCurrentNotice();
+
+ if (!empty($last)) {
+ return $last->id;
+ }
+ }
}
diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php
index 2af34b1a4..d3e7853b1 100644
--- a/classes/Notice_inbox.php
+++ b/classes/Notice_inbox.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
diff --git a/classes/Notice_tag.php b/classes/Notice_tag.php
index 4e52ef269..02740280f 100644
--- a/classes/Notice_tag.php
+++ b/classes/Notice_tag.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/classes/Profile.php b/classes/Profile.php
index 0ee6fa657..463802b4e 100644
--- a/classes/Profile.php
+++ b/classes/Profile.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
/**
* Table Definition for profile
diff --git a/classes/Profile_block.php b/classes/Profile_block.php
index feadea42d..2d87edaa0 100644
--- a/classes/Profile_block.php
+++ b/classes/Profile_block.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
/**
* Table Definition for profile_block
diff --git a/classes/Remote_profile.php b/classes/Remote_profile.php
index 975852dd9..9f7bfeadc 100644
--- a/classes/Remote_profile.php
+++ b/classes/Remote_profile.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
/**
* Table Definition for remote_profile
diff --git a/classes/Session.php b/classes/Session.php
index ac80279c5..d641edbbe 100644
--- a/classes/Session.php
+++ b/classes/Session.php
@@ -2,8 +2,8 @@
/**
* Table Definition for session
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
@@ -108,11 +108,24 @@ class Session extends Memcached_DataObject
$epoch = common_sql_date(time() - $maxlifetime);
+ $ids = array();
+
$session = new Session();
$session->whereAdd('modified < "'.$epoch.'"');
- $result = $session->delete(DB_DATAOBJECT_WHEREADD_ONLY);
+ $session->selectAdd();
+ $session->selectAdd('id');
+
+ $session->find();
+
+ while ($session->fetch()) {
+ $ids[] = $session->id;
+ }
+
+ $session->free();
- self::logdeb("garbage collection result = $result");
+ foreach ($ids as $id) {
+ self::destroy($id);
+ }
}
static function setSaveHandler()
diff --git a/classes/Status_network.php b/classes/Status_network.php
index dbd722e88..fe4f0b0c5 100644
--- a/classes/Status_network.php
+++ b/classes/Status_network.php
@@ -2,8 +2,8 @@
/**
* Table Definition for status_network
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -19,7 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class Status_network extends DB_DataObject
{
@@ -54,7 +54,7 @@ class Status_network extends DB_DataObject
global $config;
$config['db']['database_'.$dbname] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname";
- $config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/statusnet.ini';
+ $config['db']['ini_'.$dbname] = INSTALLDIR.'/classes/status_network.ini';
$config['db']['table_status_network'] = $dbname;
self::$cache = new Memcache();
@@ -71,7 +71,7 @@ class Status_network extends DB_DataObject
}
static function cacheKey($k, $v) {
- return 'laconica:' . self::$base . ':status_network:'.$k.':'.$v;
+ return 'statusnet:' . self::$base . ':status_network:'.$k.':'.$v;
}
static function memGet($k, $v)
diff --git a/classes/Subscription.php b/classes/Subscription.php
index d4580fcba..fedfd5f19 100644
--- a/classes/Subscription.php
+++ b/classes/Subscription.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
/**
* Table Definition for subscription
diff --git a/classes/User.php b/classes/User.php
index 991e9c18f..ef8434292 100644
--- a/classes/User.php
+++ b/classes/User.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -120,11 +120,15 @@ class User extends Memcached_DataObject
function allowed_nickname($nickname)
{
// XXX: should already be validated for size, content, etc.
- static $blacklist = array('rss', 'xrds', 'doc', 'main',
- 'settings', 'notice', 'user',
- 'search', 'avatar', 'tag', 'tags',
- 'api', 'message', 'group', 'groups',
- 'local');
+
+ $blacklist = array();
+
+ //all directory and file names should be blacklisted
+ $d = dir(INSTALLDIR);
+ while (false !== ($entry = $d->read())) {
+ $blacklist[]=$entry;
+ }
+ $d->close();
$merged = array_merge($blacklist, common_config('nickname', 'blacklist'));
return !in_array($nickname, $merged);
}
diff --git a/classes/User_group.php b/classes/User_group.php
index b1ab1c2d3..ea19cbb97 100644
--- a/classes/User_group.php
+++ b/classes/User_group.php
@@ -297,4 +297,45 @@ class User_group extends Memcached_DataObject
return $ids;
}
+
+ function asAtomEntry($namespace=false, $source=false)
+ {
+ $xs = new XMLStringer(true);
+
+ if ($namespace) {
+ $attrs = array('xmlns' => 'http://www.w3.org/2005/Atom',
+ 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0');
+ } else {
+ $attrs = array();
+ }
+
+ $xs->elementStart('entry', $attrs);
+
+ if ($source) {
+ $xs->elementStart('source');
+ $xs->element('title', null, $profile->nickname . " - " . common_config('site', 'name'));
+ $xs->element('link', array('href' => $this->permalink()));
+ }
+
+ if ($source) {
+ $xs->elementEnd('source');
+ }
+
+ $xs->element('title', null, $this->nickname);
+ $xs->element('summary', null, $this->description);
+
+ $xs->element('link', array('rel' => 'alternate',
+ 'href' => $this->permalink()));
+
+ $xs->element('id', null, $this->permalink());
+
+ $xs->element('published', null, common_date_w3dtf($this->created));
+ $xs->element('updated', null, common_date_w3dtf($this->modified));
+
+ $xs->element('content', array('type' => 'html'), $this->description);
+
+ $xs->elementEnd('entry');
+
+ return $xs->getString();
+ }
}
diff --git a/classes/laconica.ini b/classes/laconica.ini
deleted file mode 100644
index 766bed75d..000000000
--- a/classes/laconica.ini
+++ /dev/null
@@ -1,500 +0,0 @@
-
-[avatar]
-profile_id = 129
-original = 17
-width = 129
-height = 129
-mediatype = 130
-filename = 2
-url = 2
-created = 142
-modified = 384
-
-[avatar__keys]
-profile_id = K
-width = K
-height = K
-url = U
-
-[confirm_address]
-code = 130
-user_id = 129
-address = 130
-address_extra = 130
-address_type = 130
-claimed = 14
-sent = 14
-modified = 384
-
-[confirm_address__keys]
-code = K
-
-[consumer]
-consumer_key = 130
-seed = 130
-created = 142
-modified = 384
-
-[consumer__keys]
-consumer_key = K
-
-[design]
-id = 129
-backgroundcolor = 1
-contentcolor = 1
-sidebarcolor = 1
-textcolor = 1
-linkcolor = 1
-backgroundimage = 2
-disposition = 17
-
-[design__keys]
-id = N
-
-[fave]
-notice_id = 129
-user_id = 129
-modified = 384
-
-[fave__keys]
-notice_id = K
-user_id = K
-
-[file]
-id = 129
-url = 2
-mimetype = 2
-size = 1
-title = 2
-date = 1
-protected = 1
-filename = 2
-modified = 384
-
-[file__keys]
-id = N
-
-[file_oembed]
-file_id = 129
-version = 2
-type = 2
-provider = 2
-provider_url = 2
-width = 1
-height = 1
-html = 34
-title = 2
-author_name = 2
-author_url = 2
-url = 2
-modified = 384
-
-[file_oembed__keys]
-file_id = K
-
-[file_redirection]
-url = 130
-file_id = 1
-redirections = 1
-httpcode = 1
-modified = 384
-
-[file_redirection__keys]
-url = K
-
-[file_thumbnail]
-file_id = 129
-url = 2
-width = 1
-height = 1
-modified = 384
-
-[file_thumbnail__keys]
-file_id = K
-url = U
-
-[file_to_post]
-file_id = 129
-post_id = 129
-modified = 384
-
-[file_to_post__keys]
-file_id = K
-post_id = K
-
-[foreign_link]
-user_id = 129
-foreign_id = 129
-service = 129
-credentials = 2
-noticesync = 145
-friendsync = 145
-profilesync = 145
-last_noticesync = 14
-last_friendsync = 14
-created = 142
-modified = 384
-
-[foreign_link__keys]
-user_id = K
-foreign_id = K
-service = K
-
-[foreign_service]
-id = 129
-name = 130
-description = 2
-created = 142
-modified = 384
-
-[foreign_service__keys]
-id = K
-name = U
-
-[foreign_subscription]
-service = 129
-subscriber = 129
-subscribed = 129
-created = 142
-
-[foreign_subscription__keys]
-service = K
-subscriber = K
-subscribed = K
-
-[foreign_user]
-id = 129
-service = 129
-uri = 130
-nickname = 2
-created = 142
-modified = 384
-
-[foreign_user__keys]
-id = K
-service = K
-uri = U
-
-[group_alias]
-alias = 130
-group_id = 129
-modified = 384
-
-[group_alias__keys]
-alias = K
-
-[group_block]
-group_id = 129
-blocked = 129
-blocker = 129
-modified = 384
-
-[group_block__keys]
-group_id = K
-blocked = K
-
-[group_inbox]
-group_id = 129
-notice_id = 129
-created = 142
-
-[group_inbox__keys]
-group_id = K
-notice_id = K
-
-[group_member]
-group_id = 129
-profile_id = 129
-is_admin = 17
-created = 142
-modified = 384
-
-[group_member__keys]
-group_id = K
-profile_id = K
-
-[invitation]
-code = 130
-user_id = 129
-address = 130
-address_type = 130
-created = 142
-
-[invitation__keys]
-code = K
-
-[message]
-id = 129
-uri = 2
-from_profile = 129
-to_profile = 129
-content = 2
-rendered = 34
-url = 2
-created = 142
-modified = 384
-source = 2
-
-[message__keys]
-id = N
-
-[nonce]
-consumer_key = 130
-tok = 2
-nonce = 130
-ts = 142
-created = 142
-modified = 384
-
-[nonce__keys]
-consumer_key = K
-nonce = K
-ts = K
-
-[notice]
-id = 129
-profile_id = 129
-uri = 2
-content = 2
-rendered = 34
-url = 2
-created = 142
-modified = 384
-reply_to = 1
-is_local = 17
-source = 2
-conversation = 1
-
-[notice__keys]
-id = N
-
-[notice_inbox]
-user_id = 129
-notice_id = 129
-created = 142
-source = 17
-
-[notice_inbox__keys]
-user_id = K
-notice_id = K
-
-[notice_source]
-code = 130
-name = 130
-url = 130
-created = 142
-modified = 384
-
-[notice_source__keys]
-code = K
-
-[notice_tag]
-tag = 130
-notice_id = 129
-created = 142
-
-[notice_tag__keys]
-tag = K
-notice_id = K
-
-[profile]
-id = 129
-nickname = 130
-fullname = 2
-profileurl = 2
-homepage = 2
-bio = 2
-location = 2
-created = 142
-modified = 384
-
-[profile__keys]
-id = N
-
-[profile_block]
-blocker = 129
-blocked = 129
-modified = 384
-
-[profile_block__keys]
-blocker = K
-blocked = K
-
-[profile_tag]
-tagger = 129
-tagged = 129
-tag = 130
-modified = 384
-
-[profile_tag__keys]
-tagger = K
-tagged = K
-tag = K
-
-[queue_item]
-notice_id = 129
-transport = 130
-created = 142
-claimed = 14
-
-[queue_item__keys]
-notice_id = K
-transport = K
-
-[related_group]
-group_id = 129
-related_group_id = 129
-created = 142
-
-[related_group__keys]
-group_id = K
-related_group_id = K
-
-[remember_me]
-code = 130
-user_id = 129
-modified = 384
-
-[remember_me__keys]
-code = K
-
-[remote_profile]
-id = 129
-uri = 2
-postnoticeurl = 2
-updateprofileurl = 2
-created = 142
-modified = 384
-
-[remote_profile__keys]
-id = K
-uri = U
-
-[reply]
-notice_id = 129
-profile_id = 129
-modified = 384
-replied_id = 1
-
-[reply__keys]
-notice_id = K
-profile_id = K
-
-[session]
-id = 130
-session_data = 34
-created = 142
-modified = 384
-
-[session__keys]
-id = K
-
-[sms_carrier]
-id = 129
-name = 2
-email_pattern = 130
-created = 142
-modified = 384
-
-[sms_carrier__keys]
-id = K
-name = U
-
-[subscription]
-subscriber = 129
-subscribed = 129
-jabber = 17
-sms = 17
-token = 2
-secret = 2
-created = 142
-modified = 384
-
-[subscription__keys]
-subscriber = K
-subscribed = K
-
-[token]
-consumer_key = 130
-tok = 130
-secret = 130
-type = 145
-state = 17
-created = 142
-modified = 384
-
-[token__keys]
-consumer_key = K
-tok = K
-
-[user]
-id = 129
-nickname = 2
-password = 2
-email = 2
-incomingemail = 2
-emailnotifysub = 17
-emailnotifyfav = 17
-emailnotifynudge = 17
-emailnotifymsg = 17
-emailnotifyattn = 17
-emailmicroid = 17
-language = 2
-timezone = 2
-emailpost = 17
-jabber = 2
-jabbernotify = 17
-jabberreplies = 17
-jabbermicroid = 17
-updatefrompresence = 17
-sms = 2
-carrier = 1
-smsnotify = 17
-smsreplies = 17
-smsemail = 2
-uri = 2
-autosubscribe = 17
-urlshorteningservice = 2
-inboxed = 17
-design_id = 1
-viewdesigns = 17
-created = 142
-modified = 384
-
-[user__keys]
-id = K
-nickname = U
-email = U
-incomingemail = U
-jabber = U
-sms = U
-uri = U
-
-[user_group]
-id = 129
-nickname = 2
-fullname = 2
-homepage = 2
-description = 2
-location = 2
-original_logo = 2
-homepage_logo = 2
-stream_logo = 2
-mini_logo = 2
-design_id = 1
-created = 142
-modified = 384
-
-[user_group__keys]
-id = N
-
-[user_openid]
-canonical = 130
-display = 130
-user_id = 129
-created = 142
-modified = 384
-
-[user_openid__keys]
-canonical = K
-display = U
diff --git a/classes/status_network.ini b/classes/status_network.ini
new file mode 100644
index 000000000..8123265e4
--- /dev/null
+++ b/classes/status_network.ini
@@ -0,0 +1,18 @@
+[status_network]
+nickname = 130
+hostname = 2
+pathname = 2
+dbhost = 2
+dbuser = 2
+dbpass = 2
+dbname = 2
+sitename = 2
+theme = 2
+logo = 2
+created = 142
+modified = 384
+
+[status_network__keys]
+nickname = K
+hostname = U
+pathname = U
diff --git a/classes/statusnet.ini b/classes/statusnet.ini
index 8123265e4..766bed75d 100644
--- a/classes/statusnet.ini
+++ b/classes/statusnet.ini
@@ -1,18 +1,500 @@
-[status_network]
+
+[avatar]
+profile_id = 129
+original = 17
+width = 129
+height = 129
+mediatype = 130
+filename = 2
+url = 2
+created = 142
+modified = 384
+
+[avatar__keys]
+profile_id = K
+width = K
+height = K
+url = U
+
+[confirm_address]
+code = 130
+user_id = 129
+address = 130
+address_extra = 130
+address_type = 130
+claimed = 14
+sent = 14
+modified = 384
+
+[confirm_address__keys]
+code = K
+
+[consumer]
+consumer_key = 130
+seed = 130
+created = 142
+modified = 384
+
+[consumer__keys]
+consumer_key = K
+
+[design]
+id = 129
+backgroundcolor = 1
+contentcolor = 1
+sidebarcolor = 1
+textcolor = 1
+linkcolor = 1
+backgroundimage = 2
+disposition = 17
+
+[design__keys]
+id = N
+
+[fave]
+notice_id = 129
+user_id = 129
+modified = 384
+
+[fave__keys]
+notice_id = K
+user_id = K
+
+[file]
+id = 129
+url = 2
+mimetype = 2
+size = 1
+title = 2
+date = 1
+protected = 1
+filename = 2
+modified = 384
+
+[file__keys]
+id = N
+
+[file_oembed]
+file_id = 129
+version = 2
+type = 2
+provider = 2
+provider_url = 2
+width = 1
+height = 1
+html = 34
+title = 2
+author_name = 2
+author_url = 2
+url = 2
+modified = 384
+
+[file_oembed__keys]
+file_id = K
+
+[file_redirection]
+url = 130
+file_id = 1
+redirections = 1
+httpcode = 1
+modified = 384
+
+[file_redirection__keys]
+url = K
+
+[file_thumbnail]
+file_id = 129
+url = 2
+width = 1
+height = 1
+modified = 384
+
+[file_thumbnail__keys]
+file_id = K
+url = U
+
+[file_to_post]
+file_id = 129
+post_id = 129
+modified = 384
+
+[file_to_post__keys]
+file_id = K
+post_id = K
+
+[foreign_link]
+user_id = 129
+foreign_id = 129
+service = 129
+credentials = 2
+noticesync = 145
+friendsync = 145
+profilesync = 145
+last_noticesync = 14
+last_friendsync = 14
+created = 142
+modified = 384
+
+[foreign_link__keys]
+user_id = K
+foreign_id = K
+service = K
+
+[foreign_service]
+id = 129
+name = 130
+description = 2
+created = 142
+modified = 384
+
+[foreign_service__keys]
+id = K
+name = U
+
+[foreign_subscription]
+service = 129
+subscriber = 129
+subscribed = 129
+created = 142
+
+[foreign_subscription__keys]
+service = K
+subscriber = K
+subscribed = K
+
+[foreign_user]
+id = 129
+service = 129
+uri = 130
+nickname = 2
+created = 142
+modified = 384
+
+[foreign_user__keys]
+id = K
+service = K
+uri = U
+
+[group_alias]
+alias = 130
+group_id = 129
+modified = 384
+
+[group_alias__keys]
+alias = K
+
+[group_block]
+group_id = 129
+blocked = 129
+blocker = 129
+modified = 384
+
+[group_block__keys]
+group_id = K
+blocked = K
+
+[group_inbox]
+group_id = 129
+notice_id = 129
+created = 142
+
+[group_inbox__keys]
+group_id = K
+notice_id = K
+
+[group_member]
+group_id = 129
+profile_id = 129
+is_admin = 17
+created = 142
+modified = 384
+
+[group_member__keys]
+group_id = K
+profile_id = K
+
+[invitation]
+code = 130
+user_id = 129
+address = 130
+address_type = 130
+created = 142
+
+[invitation__keys]
+code = K
+
+[message]
+id = 129
+uri = 2
+from_profile = 129
+to_profile = 129
+content = 2
+rendered = 34
+url = 2
+created = 142
+modified = 384
+source = 2
+
+[message__keys]
+id = N
+
+[nonce]
+consumer_key = 130
+tok = 2
+nonce = 130
+ts = 142
+created = 142
+modified = 384
+
+[nonce__keys]
+consumer_key = K
+nonce = K
+ts = K
+
+[notice]
+id = 129
+profile_id = 129
+uri = 2
+content = 2
+rendered = 34
+url = 2
+created = 142
+modified = 384
+reply_to = 1
+is_local = 17
+source = 2
+conversation = 1
+
+[notice__keys]
+id = N
+
+[notice_inbox]
+user_id = 129
+notice_id = 129
+created = 142
+source = 17
+
+[notice_inbox__keys]
+user_id = K
+notice_id = K
+
+[notice_source]
+code = 130
+name = 130
+url = 130
+created = 142
+modified = 384
+
+[notice_source__keys]
+code = K
+
+[notice_tag]
+tag = 130
+notice_id = 129
+created = 142
+
+[notice_tag__keys]
+tag = K
+notice_id = K
+
+[profile]
+id = 129
nickname = 130
-hostname = 2
-pathname = 2
-dbhost = 2
-dbuser = 2
-dbpass = 2
-dbname = 2
-sitename = 2
-theme = 2
-logo = 2
-created = 142
-modified = 384
-
-[status_network__keys]
-nickname = K
-hostname = U
-pathname = U
+fullname = 2
+profileurl = 2
+homepage = 2
+bio = 2
+location = 2
+created = 142
+modified = 384
+
+[profile__keys]
+id = N
+
+[profile_block]
+blocker = 129
+blocked = 129
+modified = 384
+
+[profile_block__keys]
+blocker = K
+blocked = K
+
+[profile_tag]
+tagger = 129
+tagged = 129
+tag = 130
+modified = 384
+
+[profile_tag__keys]
+tagger = K
+tagged = K
+tag = K
+
+[queue_item]
+notice_id = 129
+transport = 130
+created = 142
+claimed = 14
+
+[queue_item__keys]
+notice_id = K
+transport = K
+
+[related_group]
+group_id = 129
+related_group_id = 129
+created = 142
+
+[related_group__keys]
+group_id = K
+related_group_id = K
+
+[remember_me]
+code = 130
+user_id = 129
+modified = 384
+
+[remember_me__keys]
+code = K
+
+[remote_profile]
+id = 129
+uri = 2
+postnoticeurl = 2
+updateprofileurl = 2
+created = 142
+modified = 384
+
+[remote_profile__keys]
+id = K
+uri = U
+
+[reply]
+notice_id = 129
+profile_id = 129
+modified = 384
+replied_id = 1
+
+[reply__keys]
+notice_id = K
+profile_id = K
+
+[session]
+id = 130
+session_data = 34
+created = 142
+modified = 384
+
+[session__keys]
+id = K
+
+[sms_carrier]
+id = 129
+name = 2
+email_pattern = 130
+created = 142
+modified = 384
+
+[sms_carrier__keys]
+id = K
+name = U
+
+[subscription]
+subscriber = 129
+subscribed = 129
+jabber = 17
+sms = 17
+token = 2
+secret = 2
+created = 142
+modified = 384
+
+[subscription__keys]
+subscriber = K
+subscribed = K
+
+[token]
+consumer_key = 130
+tok = 130
+secret = 130
+type = 145
+state = 17
+created = 142
+modified = 384
+
+[token__keys]
+consumer_key = K
+tok = K
+
+[user]
+id = 129
+nickname = 2
+password = 2
+email = 2
+incomingemail = 2
+emailnotifysub = 17
+emailnotifyfav = 17
+emailnotifynudge = 17
+emailnotifymsg = 17
+emailnotifyattn = 17
+emailmicroid = 17
+language = 2
+timezone = 2
+emailpost = 17
+jabber = 2
+jabbernotify = 17
+jabberreplies = 17
+jabbermicroid = 17
+updatefrompresence = 17
+sms = 2
+carrier = 1
+smsnotify = 17
+smsreplies = 17
+smsemail = 2
+uri = 2
+autosubscribe = 17
+urlshorteningservice = 2
+inboxed = 17
+design_id = 1
+viewdesigns = 17
+created = 142
+modified = 384
+
+[user__keys]
+id = K
+nickname = U
+email = U
+incomingemail = U
+jabber = U
+sms = U
+uri = U
+
+[user_group]
+id = 129
+nickname = 2
+fullname = 2
+homepage = 2
+description = 2
+location = 2
+original_logo = 2
+homepage_logo = 2
+stream_logo = 2
+mini_logo = 2
+design_id = 1
+created = 142
+modified = 384
+
+[user_group__keys]
+id = N
+
+[user_openid]
+canonical = 130
+display = 130
+user_id = 129
+created = 142
+modified = 384
+
+[user_openid__keys]
+canonical = K
+display = U
diff --git a/classes/laconica.links.ini b/classes/statusnet.links.ini
index 95c63f3c0..95c63f3c0 100644
--- a/classes/laconica.links.ini
+++ b/classes/statusnet.links.ini
diff --git a/config.php.sample b/config.php.sample
index 57aa6a6c8..bd3776a47 100644
--- a/config.php.sample
+++ b/config.php.sample
@@ -1,7 +1,7 @@
<?php
/* -*- mode: php -*- */
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET')) { exit(1); }
// If you have downloaded libraries in random little places, you
// can add the paths here
@@ -13,11 +13,19 @@ if (!defined('LACONICA')) { exit(1); }
// options
// These are for configuring your URLs
-$config['site']['name'] = 'Just another Laconica microblog';
+$config['site']['name'] = 'Just another StatusNet microblog';
$config['site']['server'] = 'localhost';
-$config['site']['path'] = 'laconica';
+$config['site']['path'] = 'statusnet';
// $config['site']['fancy'] = false;
// $config['site']['theme'] = 'default';
+// Sets the site's default design values
+// $config['design']['backgroundcolor'] = '#F0F2F5';
+// $config['design']['contentcolor'] = '#FFFFFF';
+// $config['design']['sidebarcolor'] = '#CEE1E9';
+// $config['design']['textcolor'] = '#000000';
+// $config['design']['linkcolor'] = '#002E6E';
+// $config['design']['backgroundimage'] = null;
+// $config['design']['disposition'] = 1;
// To enable the built-in mobile style sheet, defaults to false.
// $config['site']['mobile'] = true;
// For contact email, defaults to $_SERVER["SERVER_ADMIN"]
@@ -30,13 +38,15 @@ $config['site']['path'] = 'laconica';
// $config['site']['closed'] = true;
// Only allow registration for people invited by another user
// $config['site']['inviteonly'] = true;
+// Only allow registrations and logins through OpenID
+// $config['site']['openidonly'] = true;
// Make the site invisible to non-logged-in users
// $config['site']['private'] = true;
// If you want logging sent to a file instead of syslog
-// $config['site']['logfile'] = '/tmp/laconica.log';
+// $config['site']['logfile'] = '/tmp/statusnet.log';
-// Change the syslog facility that Laconica logs to (default is LOG_USER)
+// Change the syslog facility that StatusNet logs to (default is LOG_USER)
// $config['syslog']['facility'] = LOG_LOCAL7;
// Enables extra log information, for example full details of PEAR DB errors
@@ -48,8 +58,8 @@ $config['site']['path'] = 'laconica';
// This is a PEAR DB DSN, see http://pear.php.net/manual/en/package.database.db.intro-dsn.php
// Set it to match your actual database
-$config['db']['database'] = 'mysql://laconica:microblog@localhost/laconica';
-// $config['db']['ini_your_db_name'] = $config['db']['schema_location'].'/laconica.ini';
+$config['db']['database'] = 'mysql://statusnet:microblog@localhost/statusnet';
+// $config['db']['ini_your_db_name'] = $config['db']['schema_location'].'/statusnet.ini';
// *** WARNING *** WARNING *** WARNING *** WARNING ***
// Setting debug to a non-zero value will expose your DATABASE PASSWORD to Web users.
// !!!!!! DO NOT SET THIS ON PRODUCTION SERVERS !!!!!! DB_DataObject's bug, btw, not
@@ -89,6 +99,9 @@ $config['sphinx']['port'] = 3312;
// $config['xmpp']['public'][] = 'someindexer@example.net';
// $config['xmpp']['debug'] = false;
+// Disable OpenID
+// $config['openid']['enabled'] = false;
+
// Turn off invites
// $config['invite']['enabled'] = false;
@@ -141,23 +154,32 @@ $config['sphinx']['port'] = 3312;
// using stomp requires an external message queue server
// $config['queue']['subsystem'] = 'stomp';
// $config['queue']['stomp_server'] = 'tcp://localhost:61613';
-// use different queue_basename for each laconica instance managed by the server
-// $config['queue']['queue_basename'] = 'laconica';
+// use different queue_basename for each statusnet instance managed by the server
+// $config['queue']['queue_basename'] = 'statusnet';
// The following customise the behaviour of the various daemons:
// $config['daemon']['piddir'] = '/var/run';
// $config['daemon']['user'] = false;
// $config['daemon']['group'] = false;
-// For installations with high traffic, laconica can use MemCached to cache
+// For installations with high traffic, statusnet can use MemCached to cache
// frequently requested information. Only enable the following if you have
// MemCached up and running:
// $config['memcached']['enabled'] = false;
// $config['memcached']['server'] = 'localhost';
// $config['memcached']['port'] = 11211;
-// Twitter integration source attribute. Note: default is Laconica
-// $config['integration']['source'] = 'Laconica';
+// Disable post-by-email
+// $config['emailpost']['enabled'] = false;
+
+// Disable SMS
+// $config['sms']['enabled'] = false;
+
+// Disable Twitter integration
+// $config['twitter']['enabled'] = false;
+
+// Twitter integration source attribute. Note: default is StatusNet
+// $config['integration']['source'] = 'StatusNet';
// Enable bidirectional Twitter bridge
//
@@ -165,6 +187,10 @@ $config['sphinx']['port'] = 3312;
//
// $config['twitterbridge']['enabled'] = true;
+// Twitter OAuth settings
+// $config['twitter']['consumer_key'] = 'YOURKEY';
+// $config['twitter']['consumer_secret'] = 'YOURSECRET';
+
// Edit throttling. Off by default. If turned on, you can only post 20 notices
// every 10 minutes. Admins may want to play with the settings to minimize inconvenience for
// real users without getting uncontrollable floods from spammers or runaway bots.
@@ -235,5 +261,6 @@ $config['sphinx']['port'] = 3312;
// $config['attachments']['user_quota'] = 50000000;
// $config['attachments']['monthly_quota'] = 15000000;
// $config['attachments']['uploads'] = true;
+// $config['attachments']['path'] = "/file/";
// $config['oohembed']['endpoint'] = 'http://oohembed.com/oohembed/';
diff --git a/db/074to080_pg.sql b/db/074to080_pg.sql
new file mode 100644
index 000000000..0a7171ae5
--- /dev/null
+++ b/db/074to080_pg.sql
@@ -0,0 +1,108 @@
+BEGIN;
+create sequence design_seq;
+create table design (
+ id bigint default nextval('design_seq') /* comment 'design ID'*/,
+ backgroundcolor integer /* comment 'main background color'*/ ,
+ contentcolor integer /*comment 'content area background color'*/ ,
+ sidebarcolor integer /*comment 'sidebar background color'*/ ,
+ textcolor integer /*comment 'text color'*/ ,
+ linkcolor integer /*comment 'link color'*/,
+ backgroundimage varchar(255) /*comment 'background image, if any'*/,
+ disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
+ primary key (id)
+);
+alter table "user"
+ add column design_id integer references design(id);
+alter table "user"
+ add column viewdesigns integer default 1;
+
+alter table notice add column
+ conversation integer references notice (id);
+
+create index notice_conversation_idx on notice(conversation);
+
+alter table foreign_user
+ alter column id TYPE bigint;
+
+alter table foreign_user alter column id set not null;
+
+alter table foreign_link
+ alter column foreign_id TYPE bigint;
+
+alter table user_group
+ add column design_id integer;
+
+/*attachments and URLs stuff */
+create sequence file_seq;
+create table file (
+ id bigint default nextval('file_seq') primary key /* comment 'unique identifier' */,
+ url varchar(255) unique,
+ mimetype varchar(50),
+ size integer,
+ title varchar(255),
+ date integer,
+ protected integer,
+ filename text /* comment 'if a local file, name of the file' */,
+ modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/
+);
+
+create sequence file_oembed_seq;
+create table file_oembed (
+ file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
+ version varchar(20),
+ type varchar(20),
+ provider varchar(50),
+ provider_url varchar(255),
+ width integer,
+ height integer,
+ html text,
+ title varchar(255),
+ author_name varchar(50),
+ author_url varchar(255),
+ url varchar(255)
+);
+
+create sequence file_redirection_seq;
+create table file_redirection (
+ url varchar(255) primary key,
+ file_id bigint,
+ redirections integer,
+ httpcode integer
+);
+
+create sequence file_thumbnail_seq;
+create table file_thumbnail (
+ file_id bigint primary key,
+ url varchar(255) unique,
+ width integer,
+ height integer
+);
+create sequence file_to_post_seq;
+create table file_to_post (
+ file_id bigint,
+ post_id bigint,
+
+ primary key (file_id, post_id)
+);
+
+
+create table group_block (
+ group_id integer not null /* comment 'group profile is blocked from' */ references user_group (id),
+ blocked integer not null /* comment 'profile that is blocked' */references profile (id),
+ blocker integer not null /* comment 'user making the block'*/ references "user" (id),
+ modified timestamp /* comment 'date of blocking'*/ ,
+
+ primary key (group_id, blocked)
+);
+
+create table group_alias (
+
+ alias varchar(64) /* comment 'additional nickname for the group'*/ ,
+ group_id integer not null /* comment 'group profile is blocked from'*/ references user_group (id),
+ modified timestamp /* comment 'date alias was created'*/,
+ primary key (alias)
+
+);
+create index group_alias_group_id_idx on group_alias (group_id);
+
+COMMIT; \ No newline at end of file
diff --git a/db/notice_source.sql b/db/notice_source.sql
index 983ea9150..2657763f4 100644
--- a/db/notice_source.sql
+++ b/db/notice_source.sql
@@ -21,7 +21,10 @@ VALUES
('identichat','identichat','http://identichat.prosody.im/', now()),
('IdentiFox','IdentiFox','http://www.bitbucket.org/uncryptic/identifox/', now()),
('identitwitch','IdentiTwitch','http://richfish.org/identitwitch/', now()),
+ ('Jiminy','Jiminy','http://code.google.com/p/jiminy/', now()),
('LaTwit','LaTwit','http://latwit.mac65.com/', now()),
+ ('LiveTweeter', 'LiveTweeter', 'http://addons.songbirdnest.com/addon/1204', now()),
+ ('livetweeter', 'livetweeter', 'http://addons.songbirdnest.com/addon/1204', now()),
('maisha', 'Maisha', 'http://maisha.grango.org/', now()),
('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()),
('Mobidentica', 'Mobidentica', 'http://www.substanceofcode.com/software/mobidentica/', now()),
@@ -34,6 +37,7 @@ VALUES
('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()),
('posty','Posty','http://spreadingfunkyness.com/posty/', now()),
('qtwitter','qTwitter','http://qtwitter.ayoy.net/', now()),
+ ('qwit', 'Qwit', 'http://code.google.com/p/qwit/', now()),
('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()),
('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()),
('rygh.no','rygh.no','http://rygh.no/', now()),
diff --git a/db/sms_carrier.sql b/db/sms_carrier.sql
index 055606f58..0e94df296 100644
--- a/db/sms_carrier.sql
+++ b/db/sms_carrier.sql
@@ -61,4 +61,5 @@ VALUES
(100113, 'T-Mobile Germany', '%s@t-mobile-sms.de', now()),
(100114, 'Vodafone Germany', '%s@vodafone-sms.de', now()),
(100115, 'E-Plus', '%s@smsmail.eplus.de', now()),
- (100116, 'Cellular South', '%s@csouth1.com', now());
+ (100116, 'Cellular South', '%s@csouth1.com', now()),
+ (100117, 'ChinaMobile (139)', '%s@139.com', now());
diff --git a/db/laconica.sql b/db/statusnet.sql
index 2c04f680a..2c04f680a 100644
--- a/db/laconica.sql
+++ b/db/statusnet.sql
diff --git a/db/laconica_pg.sql b/db/statusnet_pg.sql
index 31210fd1e..ad34720a2 100644
--- a/db/laconica_pg.sql
+++ b/db/statusnet_pg.sql
@@ -1,529 +1,539 @@
-/* local and remote users have profiles */
-
-create sequence profile_seq;
-create table profile (
- id bigint default nextval('profile_seq') primary key /* comment 'unique identifier' */,
- nickname varchar(64) not null /* comment 'nickname or username' */,
- fullname varchar(255) /* comment 'display name' */,
- profileurl varchar(255) /* comment 'URL, cached so we dont regenerate' */,
- homepage varchar(255) /* comment 'identifying URL' */,
- bio varchar(140) /* comment 'descriptive biography' */,
- location varchar(255) /* comment 'physical location' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- textsearch tsvector
-);
-create index profile_nickname_idx on profile using btree(nickname);
-
-create table avatar (
- profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id) ,
- original integer default 0 /* comment 'uploaded by user or generated?' */,
- width integer not null /* comment 'image width' */,
- height integer not null /* comment 'image height' */,
- mediatype varchar(32) not null /* comment 'file type' */,
- filename varchar(255) null /* comment 'local filename, if local' */,
- url varchar(255) unique /* comment 'avatar location' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- primary key(profile_id, width, height)
-);
-create index avatar_profile_id_idx on avatar using btree(profile_id);
-
-create sequence sms_carrier_seq;
-create table sms_carrier (
- id bigint default nextval('sms_carrier_seq') primary key /* comment 'primary key for SMS carrier' */,
- name varchar(64) unique /* comment 'name of the carrier' */,
- email_pattern varchar(255) not null /* comment 'sprintf pattern for making an email address from a phone number' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified ' */
-);
-
-create sequence design_seq;
-create table design (
- id bigint default nextval('design_seq') /* comment 'design ID'*/,
- backgroundcolor integer /* comment 'main background color'*/ ,
- contentcolor integer /*comment 'content area background color'*/ ,
- sidebarcolor integer /*comment 'sidebar background color'*/ ,
- textcolor integer /*comment 'text color'*/ ,
- linkcolor integer /*comment 'link color'*/,
- backgroundimage varchar(255) /*comment 'background image, if any'*/,
- disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
- primary key (id)
-);
-
-/* local users */
-
-create table "user" (
- id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
- nickname varchar(64) unique /* comment 'nickname or username, duped in profile' */,
- password varchar(255) /* comment 'salted password, can be null for OpenID users' */,
- email varchar(255) unique /* comment 'email address for password recovery etc.' */,
- incomingemail varchar(255) unique /* comment 'email address for post-by-email' */,
- emailnotifysub integer default 1 /* comment 'Notify by email of subscriptions' */,
- emailnotifyfav integer default 1 /* comment 'Notify by email of favorites' */,
- emailnotifynudge integer default 1 /* comment 'Notify by email of nudges' */,
- emailnotifymsg integer default 1 /* comment 'Notify by email of direct messages' */,
- emailnotifyattn integer default 1 /* command 'Notify by email of @-replies' */,
- emailmicroid integer default 1 /* comment 'whether to publish email microid' */,
- language varchar(50) /* comment 'preferred language' */,
- timezone varchar(50) /* comment 'timezone' */,
- emailpost integer default 1 /* comment 'Post by email' */,
- jabber varchar(255) unique /* comment 'jabber ID for notices' */,
- jabbernotify integer default 0 /* comment 'whether to send notices to jabber' */,
- jabberreplies integer default 0 /* comment 'whether to send notices to jabber on replies' */,
- jabbermicroid integer default 1 /* comment 'whether to publish xmpp microid' */,
- updatefrompresence integer default 0 /* comment 'whether to record updates from Jabber presence notices' */,
- sms varchar(64) unique /* comment 'sms phone number' */,
- carrier integer /* comment 'foreign key to sms_carrier' */ references sms_carrier (id) ,
- smsnotify integer default 0 /* comment 'whether to send notices to SMS' */,
- smsreplies integer default 0 /* comment 'whether to send notices to SMS on replies' */,
- smsemail varchar(255) /* comment 'built from sms and carrier' */,
- uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
- autosubscribe integer default 0 /* comment 'automatically subscribe to users who subscribe to us' */,
- urlshorteningservice varchar(50) default 'ur1.ca' /* comment 'service to use for auto-shortening URLs' */,
- inboxed integer default 0 /* comment 'has an inbox been created for this user?' */,
- design_id integer /* comment 'id of a design' */references design(id),
- viewdesigns integer default 1 /* comment 'whether to view user-provided designs'*/,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */
-
-);
-create index user_smsemail_idx on "user" using btree(smsemail);
-
-/* remote people */
-
-create table remote_profile (
- id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
- uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
- postnoticeurl varchar(255) /* comment 'URL we use for posting notices' */,
- updateprofileurl varchar(255) /* comment 'URL we use for updates to this profile' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */
-);
-
-create table subscription (
- subscriber integer not null /* comment 'profile listening' */,
- subscribed integer not null /* comment 'profile being listened to' */,
- jabber integer default 1 /* comment 'deliver jabber messages' */,
- sms integer default 1 /* comment 'deliver sms messages' */,
- token varchar(255) /* comment 'authorization token' */,
- secret varchar(255) /* comment 'token secret' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- primary key (subscriber, subscribed)
-);
-create index subscription_subscriber_idx on subscription using btree(subscriber);
-create index subscription_subscribed_idx on subscription using btree(subscribed);
-
-create sequence notice_seq;
-create table notice (
-
- id bigint default nextval('notice_seq') primary key /* comment 'unique identifier' */,
- profile_id integer not null /* comment 'who made the update' */ references profile (id) ,
- uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
- content varchar(140) /* comment 'update content' */,
- rendered text /* comment 'HTML version of the content' */,
- url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
- reply_to integer /* comment 'notice replied to (usually a guess)' */ references notice (id) ,
- is_local integer default 0 /* comment 'notice was generated by a user' */,
- source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */,
- conversation integer /*id of root notice in this conversation' */ references notice (id)
-
-
-/* FULLTEXT(content) */
-);
-create index notice_profile_id_idx on notice using btree(profile_id);
-create index notice_created_idx on notice using btree(created);
-
-create table notice_source (
- code varchar(32) primary key not null /* comment 'source code' */,
- name varchar(255) not null /* comment 'name of the source' */,
- url varchar(255) not null /* comment 'url to link to' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */
-);
-
-create table reply (
-
- notice_id integer not null /* comment 'notice that is the reply' */ references notice (id) ,
- profile_id integer not null /* comment 'profile replied to' */ references profile (id) ,
- modified timestamp /* comment 'date this record was modified' */,
- replied_id integer /* comment 'notice replied to (not used, see notice.reply_to)' */,
-
- primary key (notice_id, profile_id)
-
-);
-create index reply_notice_id_idx on reply using btree(notice_id);
-create index reply_profile_id_idx on reply using btree(profile_id);
-create index reply_replied_id_idx on reply using btree(replied_id);
-
-create table fave (
-
- notice_id integer not null /* comment 'notice that is the favorite' */ references notice (id),
- user_id integer not null /* comment 'user who likes this notice' */ references "user" (id) ,
- modified timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was modified' */,
- primary key (notice_id, user_id)
-
-);
-create index fave_notice_id_idx on fave using btree(notice_id);
-create index fave_user_id_idx on fave using btree(user_id);
-create index fave_modified_idx on fave using btree(modified);
-
-/* tables for OAuth */
-
-create table consumer (
- consumer_key varchar(255) primary key /* comment 'unique identifier, root URL' */,
- seed char(32) not null /* comment 'seed for new tokens by this consumer' */,
-
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */
-);
-
-create table token (
- consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */ references consumer (consumer_key),
- tok char(32) not null /* comment 'identifying value' */,
- secret char(32) not null /* comment 'secret value' */,
- type integer not null default 0 /* comment 'request or access' */,
- state integer default 0 /* comment 'for requests 0 = initial, 1 = authorized, 2 = used' */,
-
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- primary key (consumer_key, tok)
-);
-
-create table nonce (
- consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */,
- tok char(32) /* comment 'buggy old value, ignored' */,
- nonce char(32) null /* comment 'buggy old value, ignored */,
- ts integer not null /* comment 'timestamp sent' values are epoch, and only used internally */,
-
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- primary key (consumer_key, ts, nonce)
-);
-
-/* One-to-many relationship of user to openid_url */
-
-create table user_openid (
- canonical varchar(255) primary key /* comment 'Canonical true URL' */,
- display varchar(255) not null unique /* comment 'URL for viewing, may be different from canonical' */,
- user_id integer not null /* comment 'user owning this URL' */ references "user" (id) ,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */
-
-);
-create index user_openid_user_id_idx on user_openid using btree(user_id);
-
-/* These are used by JanRain OpenID library */
-
-create table oid_associations (
- server_url varchar(2047),
- handle varchar(255),
- secret bytea,
- issued integer,
- lifetime integer,
- assoc_type varchar(64),
- primary key (server_url, handle)
-);
-
-create table oid_nonces (
- server_url varchar(2047),
- "timestamp" integer,
- salt character(40),
- unique (server_url, "timestamp", salt)
-);
-
-create table confirm_address (
- code varchar(32) not null primary key /* comment 'good random code' */,
- user_id integer not null /* comment 'user who requested confirmation' */ references "user" (id),
- address varchar(255) not null /* comment 'address (email, Jabber, SMS, etc.)' */,
- address_extra varchar(255) not null default '' /* comment 'carrier ID, for SMS' */,
- address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms")' */,
- claimed timestamp /* comment 'date this was claimed for queueing' */,
- sent timestamp /* comment 'date this was sent for queueing' */,
- modified timestamp /* comment 'date this record was modified' */
-);
-
-create table remember_me (
- code varchar(32) not null primary key /* comment 'good random code' */,
- user_id integer not null /* comment 'user who is logged in' */ references "user" (id),
- modified timestamp /* comment 'date this record was modified' */
-);
-
-create table queue_item (
-
- notice_id integer not null /* comment 'notice queued' */ references notice (id) ,
- transport varchar(8) not null /* comment 'queue for what? "email", "jabber", "sms", "irc", ...' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- claimed timestamp /* comment 'date this item was claimed' */,
-
- primary key (notice_id, transport)
-
-);
-create index queue_item_created_idx on queue_item using btree(created);
-
-/* Hash tags */
-create table notice_tag (
- tag varchar( 64 ) not null /* comment 'hash tag associated with this notice' */,
- notice_id integer not null /* comment 'notice tagged' */ references notice (id) ,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
-
- primary key (tag, notice_id)
-);
-create index notice_tag_created_idx on notice_tag using btree(created);
-
-/* Synching with foreign services */
-
-create table foreign_service (
- id int not null primary key /* comment 'numeric key for service' */,
- name varchar(32) not null unique /* comment 'name of the service' */,
- description varchar(255) /* comment 'description' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */
-);
-
-create table foreign_user (
- id int not null unique /* comment 'unique numeric key on foreign service' */,
- service int not null /* comment 'foreign key to service' */ references foreign_service(id) ,
- uri varchar(255) not null unique /* comment 'identifying URI' */,
- nickname varchar(255) /* comment 'nickname on foreign service' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- primary key (id, service)
-);
-
-create table foreign_link (
- user_id int /* comment 'link to user on this system, if exists' */ references "user" (id),
- foreign_id int /* comment 'link' */ references foreign_user (id),
- service int not null /* comment 'foreign key to service' */ references foreign_service (id),
- credentials varchar(255) /* comment 'authc credentials, typically a password' */,
- noticesync int not null default 1 /* comment 'notice synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies' */,
- friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */,
- profilesync int not null default 1 /* comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming' */,
- last_noticesync timestamp default null /* comment 'last time notices were imported' */,
- last_friendsync timestamp default null /* comment 'last time friends were imported' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- primary key (user_id,foreign_id,service)
-);
-create index foreign_user_user_id_idx on foreign_link using btree(user_id);
-
-create table foreign_subscription (
- service int not null /* comment 'service where relationship happens' */ references foreign_service(id) ,
- subscriber int not null /* comment 'subscriber on foreign service' */ ,
- subscribed int not null /* comment 'subscribed user' */ ,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
-
- primary key (service, subscriber, subscribed)
-);
-create index foreign_subscription_subscriber_idx on foreign_subscription using btree(subscriber);
-create index foreign_subscription_subscribed_idx on foreign_subscription using btree(subscribed);
-
-create table invitation (
- code varchar(32) not null primary key /* comment 'random code for an invitation' */,
- user_id int not null /* comment 'who sent the invitation' */ references "user" (id),
- address varchar(255) not null /* comment 'invitation sent to' */,
- address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms") '*/,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */
-
-);
-create index invitation_address_idx on invitation using btree(address,address_type);
-create index invitation_user_id_idx on invitation using btree(user_id);
-
-create sequence message_seq;
-create table message (
-
- id bigint default nextval('message_seq') primary key /* comment 'unique identifier' */,
- uri varchar(255) unique /* comment 'universally unique identifier' */,
- from_profile integer not null /* comment 'who the message is from' */ references profile (id),
- to_profile integer not null /* comment 'who the message is to' */ references profile (id),
- content varchar(140) /* comment 'message content' */,
- rendered text /* comment 'HTML version of the content' */,
- url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
- source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
-
-);
-create index message_from_idx on message using btree(from_profile);
-create index message_to_idx on message using btree(to_profile);
-create index message_created_idx on message using btree(created);
-
-create table notice_inbox (
-
- user_id integer not null /* comment 'user receiving the message' */ references "user" (id),
- notice_id integer not null /* comment 'notice received' */ references notice (id),
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
- source integer default 1 /* comment 'reason it is in the inbox: 1=subscription' */,
-
- primary key (user_id, notice_id)
-);
-create index notice_inbox_notice_id_idx on notice_inbox using btree(notice_id);
-
-create table profile_tag (
- tagger integer not null /* comment 'user making the tag' */ references "user" (id),
- tagged integer not null /* comment 'profile tagged' */ references profile (id),
- tag varchar(64) not null /* comment 'hash tag associated with this notice' */,
- modified timestamp /* comment 'date the tag was added' */,
-
- primary key (tagger, tagged, tag)
-);
-create index profile_tag_modified_idx on profile_tag using btree(modified);
-create index profile_tag_tagger_tag_idx on profile_tag using btree(tagger,tag);
-
-create table profile_block (
-
- blocker integer not null /* comment 'user making the block' */ references "user" (id),
- blocked integer not null /* comment 'profile that is blocked' */ references profile (id),
- modified timestamp /* comment 'date of blocking' */,
-
- primary key (blocker, blocked)
-
-);
-
-create sequence user_group_seq;
-create table user_group (
-
- id bigint default nextval('user_group_seq') primary key /* comment 'unique identifier' */,
-
- nickname varchar(64) unique /* comment 'nickname for addressing' */,
- fullname varchar(255) /* comment 'display name' */,
- homepage varchar(255) /* comment 'URL, cached so we dont regenerate' */,
- description varchar(140) /* comment 'descriptive biography' */,
- location varchar(255) /* comment 'related physical location, if any' */,
-
- original_logo varchar(255) /* comment 'original size logo' */,
- homepage_logo varchar(255) /* comment 'homepage (profile) size logo' */,
- stream_logo varchar(255) /* comment 'stream-sized logo' */,
- mini_logo varchar(255) /* comment 'mini logo' */,
- design_id integer /*comment 'id of a design' */ references design(id),
-
-
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */
-
-);
-create index user_group_nickname_idx on user_group using btree(nickname);
-
-create table group_member (
-
- group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
- profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id),
- is_admin integer default 0 /* comment 'is this user an admin?' */,
-
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
- modified timestamp /* comment 'date this record was modified' */,
-
- primary key (group_id, profile_id)
-);
-
-create table related_group (
-
- group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id) ,
- related_group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
-
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
-
- primary key (group_id, related_group_id)
-
-);
-
-create table group_inbox (
- group_id integer not null /* comment 'group receiving the message' references user_group (id) */,
- notice_id integer not null /* comment 'notice received' references notice (id) */,
- created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
- primary key (group_id, notice_id)
-);
-create index group_inbox_created_idx on group_inbox using btree(created);
-
-
-/*attachments and URLs stuff */
-create sequence file_seq;
-create table file (
- id bigint default nextval('file_seq') primary key /* comment 'unique identifier' */,
- url varchar(255) unique,
- mimetype varchar(50),
- size integer,
- title varchar(255),
- date integer,
- protected integer,
- filename text /* comment 'if a local file, name of the file' */,
- modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/
-);
-
-create sequence file_oembed_seq;
-create table file_oembed (
- file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
- version varchar(20),
- type varchar(20),
- provider varchar(50),
- provider_url varchar(255),
- width integer,
- height integer,
- html text,
- title varchar(255),
- author_name varchar(50),
- author_url varchar(255),
- url varchar(255)
-);
-
-create sequence file_redirection_seq;
-create table file_redirection (
- url varchar(255) primary key,
- file_id bigint,
- redirections integer,
- httpcode integer
-);
-
-create sequence file_thumbnail_seq;
-create table file_thumbnail (
- file_id bigint primary key,
- url varchar(255) unique,
- width integer,
- height integer
-);
-
-create sequence file_to_post_seq;
-create table file_to_post (
- file_id bigint,
- post_id bigint,
-
- primary key (file_id, post_id)
-);
-
-create table group_block (
- group_id integer not null /* comment 'group profile is blocked from' */ references user_group (id),
- blocked integer not null /* comment 'profile that is blocked' */references profile (id),
- blocker integer not null /* comment 'user making the block'*/ references "user" (id),
- modified timestamp /* comment 'date of blocking'*/ ,
-
- primary key (group_id, blocked)
-);
-
-create table group_alias (
-
- alias varchar(64) /* comment 'additional nickname for the group'*/ ,
- group_id integer not null /* comment 'group profile is blocked from'*/ references user_group (id),
- modified timestamp /* comment 'date alias was created'*/,
- primary key (alias)
-
-);
-create index group_alias_group_id_idx on group_alias (group_id);
-
-
-/* Textsearch stuff */
-
-create index textsearch_idx on profile using gist(textsearch);
-create index noticecontent_idx on notice using gist(to_tsvector('english',content));
-create trigger textsearchupdate before insert or update on profile for each row
-execute procedure tsvector_update_trigger(textsearch, 'pg_catalog.english', nickname, fullname, location, bio, homepage);
-
+/* local and remote users have profiles */
+
+create sequence profile_seq;
+create table profile (
+ id bigint default nextval('profile_seq') primary key /* comment 'unique identifier' */,
+ nickname varchar(64) not null /* comment 'nickname or username' */,
+ fullname varchar(255) /* comment 'display name' */,
+ profileurl varchar(255) /* comment 'URL, cached so we dont regenerate' */,
+ homepage varchar(255) /* comment 'identifying URL' */,
+ bio varchar(140) /* comment 'descriptive biography' */,
+ location varchar(255) /* comment 'physical location' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ textsearch tsvector
+);
+create index profile_nickname_idx on profile using btree(nickname);
+
+create table avatar (
+ profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id) ,
+ original integer default 0 /* comment 'uploaded by user or generated?' */,
+ width integer not null /* comment 'image width' */,
+ height integer not null /* comment 'image height' */,
+ mediatype varchar(32) not null /* comment 'file type' */,
+ filename varchar(255) null /* comment 'local filename, if local' */,
+ url varchar(255) unique /* comment 'avatar location' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key(profile_id, width, height)
+);
+create index avatar_profile_id_idx on avatar using btree(profile_id);
+
+create sequence sms_carrier_seq;
+create table sms_carrier (
+ id bigint default nextval('sms_carrier_seq') primary key /* comment 'primary key for SMS carrier' */,
+ name varchar(64) unique /* comment 'name of the carrier' */,
+ email_pattern varchar(255) not null /* comment 'sprintf pattern for making an email address from a phone number' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified ' */
+);
+
+create sequence design_seq;
+create table design (
+ id bigint default nextval('design_seq') /* comment 'design ID'*/,
+ backgroundcolor integer /* comment 'main background color'*/ ,
+ contentcolor integer /*comment 'content area background color'*/ ,
+ sidebarcolor integer /*comment 'sidebar background color'*/ ,
+ textcolor integer /*comment 'text color'*/ ,
+ linkcolor integer /*comment 'link color'*/,
+ backgroundimage varchar(255) /*comment 'background image, if any'*/,
+ disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
+ primary key (id)
+);
+
+/* local users */
+
+create table "user" (
+ id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
+ nickname varchar(64) unique /* comment 'nickname or username, duped in profile' */,
+ password varchar(255) /* comment 'salted password, can be null for OpenID users' */,
+ email varchar(255) unique /* comment 'email address for password recovery etc.' */,
+ incomingemail varchar(255) unique /* comment 'email address for post-by-email' */,
+ emailnotifysub integer default 1 /* comment 'Notify by email of subscriptions' */,
+ emailnotifyfav integer default 1 /* comment 'Notify by email of favorites' */,
+ emailnotifynudge integer default 1 /* comment 'Notify by email of nudges' */,
+ emailnotifymsg integer default 1 /* comment 'Notify by email of direct messages' */,
+ emailnotifyattn integer default 1 /* command 'Notify by email of @-replies' */,
+ emailmicroid integer default 1 /* comment 'whether to publish email microid' */,
+ language varchar(50) /* comment 'preferred language' */,
+ timezone varchar(50) /* comment 'timezone' */,
+ emailpost integer default 1 /* comment 'Post by email' */,
+ jabber varchar(255) unique /* comment 'jabber ID for notices' */,
+ jabbernotify integer default 0 /* comment 'whether to send notices to jabber' */,
+ jabberreplies integer default 0 /* comment 'whether to send notices to jabber on replies' */,
+ jabbermicroid integer default 1 /* comment 'whether to publish xmpp microid' */,
+ updatefrompresence integer default 0 /* comment 'whether to record updates from Jabber presence notices' */,
+ sms varchar(64) unique /* comment 'sms phone number' */,
+ carrier integer /* comment 'foreign key to sms_carrier' */ references sms_carrier (id) ,
+ smsnotify integer default 0 /* comment 'whether to send notices to SMS' */,
+ smsreplies integer default 0 /* comment 'whether to send notices to SMS on replies' */,
+ smsemail varchar(255) /* comment 'built from sms and carrier' */,
+ uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+ autosubscribe integer default 0 /* comment 'automatically subscribe to users who subscribe to us' */,
+ urlshorteningservice varchar(50) default 'ur1.ca' /* comment 'service to use for auto-shortening URLs' */,
+ inboxed integer default 0 /* comment 'has an inbox been created for this user?' */,
+ design_id integer /* comment 'id of a design' */references design(id),
+ viewdesigns integer default 1 /* comment 'whether to view user-provided designs'*/,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+
+);
+create index user_smsemail_idx on "user" using btree(smsemail);
+
+/* remote people */
+
+create table remote_profile (
+ id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
+ uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+ postnoticeurl varchar(255) /* comment 'URL we use for posting notices' */,
+ updateprofileurl varchar(255) /* comment 'URL we use for updates to this profile' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+);
+
+create table subscription (
+ subscriber integer not null /* comment 'profile listening' */,
+ subscribed integer not null /* comment 'profile being listened to' */,
+ jabber integer default 1 /* comment 'deliver jabber messages' */,
+ sms integer default 1 /* comment 'deliver sms messages' */,
+ token varchar(255) /* comment 'authorization token' */,
+ secret varchar(255) /* comment 'token secret' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (subscriber, subscribed)
+);
+create index subscription_subscriber_idx on subscription using btree(subscriber);
+create index subscription_subscribed_idx on subscription using btree(subscribed);
+
+create sequence notice_seq;
+create table notice (
+
+ id bigint default nextval('notice_seq') primary key /* comment 'unique identifier' */,
+ profile_id integer not null /* comment 'who made the update' */ references profile (id) ,
+ uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+ content varchar(140) /* comment 'update content' */,
+ rendered text /* comment 'HTML version of the content' */,
+ url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+ reply_to integer /* comment 'notice replied to (usually a guess)' */ references notice (id) ,
+ is_local integer default 0 /* comment 'notice was generated by a user' */,
+ source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */,
+ conversation integer /*id of root notice in this conversation' */ references notice (id)
+
+
+/* FULLTEXT(content) */
+);
+create index notice_profile_id_idx on notice using btree(profile_id);
+create index notice_created_idx on notice using btree(created);
+
+create table notice_source (
+ code varchar(32) primary key not null /* comment 'source code' */,
+ name varchar(255) not null /* comment 'name of the source' */,
+ url varchar(255) not null /* comment 'url to link to' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+);
+
+create table reply (
+
+ notice_id integer not null /* comment 'notice that is the reply' */ references notice (id) ,
+ profile_id integer not null /* comment 'profile replied to' */ references profile (id) ,
+ modified timestamp /* comment 'date this record was modified' */,
+ replied_id integer /* comment 'notice replied to (not used, see notice.reply_to)' */,
+
+ primary key (notice_id, profile_id)
+
+);
+create index reply_notice_id_idx on reply using btree(notice_id);
+create index reply_profile_id_idx on reply using btree(profile_id);
+create index reply_replied_id_idx on reply using btree(replied_id);
+
+create table fave (
+
+ notice_id integer not null /* comment 'notice that is the favorite' */ references notice (id),
+ user_id integer not null /* comment 'user who likes this notice' */ references "user" (id) ,
+ modified timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was modified' */,
+ primary key (notice_id, user_id)
+
+);
+create index fave_notice_id_idx on fave using btree(notice_id);
+create index fave_user_id_idx on fave using btree(user_id);
+create index fave_modified_idx on fave using btree(modified);
+
+/* tables for OAuth */
+
+create table consumer (
+ consumer_key varchar(255) primary key /* comment 'unique identifier, root URL' */,
+ seed char(32) not null /* comment 'seed for new tokens by this consumer' */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+);
+
+create table token (
+ consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */ references consumer (consumer_key),
+ tok char(32) not null /* comment 'identifying value' */,
+ secret char(32) not null /* comment 'secret value' */,
+ type integer not null default 0 /* comment 'request or access' */,
+ state integer default 0 /* comment 'for requests 0 = initial, 1 = authorized, 2 = used' */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (consumer_key, tok)
+);
+
+create table nonce (
+ consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */,
+ tok char(32) /* comment 'buggy old value, ignored' */,
+ nonce char(32) null /* comment 'buggy old value, ignored */,
+ ts integer not null /* comment 'timestamp sent' values are epoch, and only used internally */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (consumer_key, ts, nonce)
+);
+
+/* One-to-many relationship of user to openid_url */
+
+create table user_openid (
+ canonical varchar(255) primary key /* comment 'Canonical true URL' */,
+ display varchar(255) not null unique /* comment 'URL for viewing, may be different from canonical' */,
+ user_id integer not null /* comment 'user owning this URL' */ references "user" (id) ,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+
+);
+create index user_openid_user_id_idx on user_openid using btree(user_id);
+
+/* These are used by JanRain OpenID library */
+
+create table oid_associations (
+ server_url varchar(2047),
+ handle varchar(255),
+ secret bytea,
+ issued integer,
+ lifetime integer,
+ assoc_type varchar(64),
+ primary key (server_url, handle)
+);
+
+create table oid_nonces (
+ server_url varchar(2047),
+ "timestamp" integer,
+ salt character(40),
+ unique (server_url, "timestamp", salt)
+);
+
+create table confirm_address (
+ code varchar(32) not null primary key /* comment 'good random code' */,
+ user_id integer not null /* comment 'user who requested confirmation' */ references "user" (id),
+ address varchar(255) not null /* comment 'address (email, Jabber, SMS, etc.)' */,
+ address_extra varchar(255) not null default '' /* comment 'carrier ID, for SMS' */,
+ address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms")' */,
+ claimed timestamp /* comment 'date this was claimed for queueing' */,
+ sent timestamp /* comment 'date this was sent for queueing' */,
+ modified timestamp /* comment 'date this record was modified' */
+);
+
+create table remember_me (
+ code varchar(32) not null primary key /* comment 'good random code' */,
+ user_id integer not null /* comment 'user who is logged in' */ references "user" (id),
+ modified timestamp /* comment 'date this record was modified' */
+);
+
+create table queue_item (
+
+ notice_id integer not null /* comment 'notice queued' */ references notice (id) ,
+ transport varchar(8) not null /* comment 'queue for what? "email", "jabber", "sms", "irc", ...' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ claimed timestamp /* comment 'date this item was claimed' */,
+
+ primary key (notice_id, transport)
+
+);
+create index queue_item_created_idx on queue_item using btree(created);
+
+/* Hash tags */
+create table notice_tag (
+ tag varchar( 64 ) not null /* comment 'hash tag associated with this notice' */,
+ notice_id integer not null /* comment 'notice tagged' */ references notice (id) ,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+
+ primary key (tag, notice_id)
+);
+create index notice_tag_created_idx on notice_tag using btree(created);
+
+/* Synching with foreign services */
+
+create table foreign_service (
+ id int not null primary key /* comment 'numeric key for service' */,
+ name varchar(32) not null unique /* comment 'name of the service' */,
+ description varchar(255) /* comment 'description' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+);
+
+create table foreign_user (
+ id int not null unique /* comment 'unique numeric key on foreign service' */,
+ service int not null /* comment 'foreign key to service' */ references foreign_service(id) ,
+ uri varchar(255) not null unique /* comment 'identifying URI' */,
+ nickname varchar(255) /* comment 'nickname on foreign service' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (id, service)
+);
+
+create table foreign_link (
+ user_id int /* comment 'link to user on this system, if exists' */ references "user" (id),
+ foreign_id int /* comment 'link' */ references foreign_user (id),
+ service int not null /* comment 'foreign key to service' */ references foreign_service (id),
+ credentials varchar(255) /* comment 'authc credentials, typically a password' */,
+ noticesync int not null default 1 /* comment 'notice synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies' */,
+ friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */,
+ profilesync int not null default 1 /* comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming' */,
+ last_noticesync timestamp default null /* comment 'last time notices were imported' */,
+ last_friendsync timestamp default null /* comment 'last time friends were imported' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (user_id,foreign_id,service)
+);
+create index foreign_user_user_id_idx on foreign_link using btree(user_id);
+
+create table foreign_subscription (
+ service int not null /* comment 'service where relationship happens' */ references foreign_service(id) ,
+ subscriber int not null /* comment 'subscriber on foreign service' */ ,
+ subscribed int not null /* comment 'subscribed user' */ ,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+
+ primary key (service, subscriber, subscribed)
+);
+create index foreign_subscription_subscriber_idx on foreign_subscription using btree(subscriber);
+create index foreign_subscription_subscribed_idx on foreign_subscription using btree(subscribed);
+
+create table invitation (
+ code varchar(32) not null primary key /* comment 'random code for an invitation' */,
+ user_id int not null /* comment 'who sent the invitation' */ references "user" (id),
+ address varchar(255) not null /* comment 'invitation sent to' */,
+ address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms") '*/,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */
+
+);
+create index invitation_address_idx on invitation using btree(address,address_type);
+create index invitation_user_id_idx on invitation using btree(user_id);
+
+create sequence message_seq;
+create table message (
+
+ id bigint default nextval('message_seq') primary key /* comment 'unique identifier' */,
+ uri varchar(255) unique /* comment 'universally unique identifier' */,
+ from_profile integer not null /* comment 'who the message is from' */ references profile (id),
+ to_profile integer not null /* comment 'who the message is to' */ references profile (id),
+ content varchar(140) /* comment 'message content' */,
+ rendered text /* comment 'HTML version of the content' */,
+ url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+ source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
+
+);
+create index message_from_idx on message using btree(from_profile);
+create index message_to_idx on message using btree(to_profile);
+create index message_created_idx on message using btree(created);
+
+create table notice_inbox (
+
+ user_id integer not null /* comment 'user receiving the message' */ references "user" (id),
+ notice_id integer not null /* comment 'notice received' */ references notice (id),
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
+ source integer default 1 /* comment 'reason it is in the inbox: 1=subscription' */,
+
+ primary key (user_id, notice_id)
+);
+create index notice_inbox_notice_id_idx on notice_inbox using btree(notice_id);
+
+create table profile_tag (
+ tagger integer not null /* comment 'user making the tag' */ references "user" (id),
+ tagged integer not null /* comment 'profile tagged' */ references profile (id),
+ tag varchar(64) not null /* comment 'hash tag associated with this notice' */,
+ modified timestamp /* comment 'date the tag was added' */,
+
+ primary key (tagger, tagged, tag)
+);
+create index profile_tag_modified_idx on profile_tag using btree(modified);
+create index profile_tag_tagger_tag_idx on profile_tag using btree(tagger,tag);
+
+create table profile_block (
+
+ blocker integer not null /* comment 'user making the block' */ references "user" (id),
+ blocked integer not null /* comment 'profile that is blocked' */ references profile (id),
+ modified timestamp /* comment 'date of blocking' */,
+
+ primary key (blocker, blocked)
+
+);
+
+create sequence user_group_seq;
+create table user_group (
+
+ id bigint default nextval('user_group_seq') primary key /* comment 'unique identifier' */,
+
+ nickname varchar(64) unique /* comment 'nickname for addressing' */,
+ fullname varchar(255) /* comment 'display name' */,
+ homepage varchar(255) /* comment 'URL, cached so we dont regenerate' */,
+ description varchar(140) /* comment 'descriptive biography' */,
+ location varchar(255) /* comment 'related physical location, if any' */,
+
+ original_logo varchar(255) /* comment 'original size logo' */,
+ homepage_logo varchar(255) /* comment 'homepage (profile) size logo' */,
+ stream_logo varchar(255) /* comment 'stream-sized logo' */,
+ mini_logo varchar(255) /* comment 'mini logo' */,
+ design_id integer /*comment 'id of a design' */ references design(id),
+
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+
+);
+create index user_group_nickname_idx on user_group using btree(nickname);
+
+create table group_member (
+
+ group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
+ profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id),
+ is_admin integer default 0 /* comment 'is this user an admin?' */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (group_id, profile_id)
+);
+
+create table related_group (
+
+ group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id) ,
+ related_group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+
+ primary key (group_id, related_group_id)
+
+);
+
+create table group_inbox (
+ group_id integer not null /* comment 'group receiving the message' references user_group (id) */,
+ notice_id integer not null /* comment 'notice received' references notice (id) */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
+ primary key (group_id, notice_id)
+);
+create index group_inbox_created_idx on group_inbox using btree(created);
+
+
+/*attachments and URLs stuff */
+create sequence file_seq;
+create table file (
+ id bigint default nextval('file_seq') primary key /* comment 'unique identifier' */,
+ url varchar(255) unique,
+ mimetype varchar(50),
+ size integer,
+ title varchar(255),
+ date integer,
+ protected integer,
+ filename text /* comment 'if a local file, name of the file' */,
+ modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/
+);
+
+create sequence file_oembed_seq;
+create table file_oembed (
+ file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
+ version varchar(20),
+ type varchar(20),
+ provider varchar(50),
+ provider_url varchar(255),
+ width integer,
+ height integer,
+ html text,
+ title varchar(255),
+ author_name varchar(50),
+ author_url varchar(255),
+ url varchar(255)
+);
+
+create sequence file_redirection_seq;
+create table file_redirection (
+ url varchar(255) primary key,
+ file_id bigint,
+ redirections integer,
+ httpcode integer
+);
+
+create sequence file_thumbnail_seq;
+create table file_thumbnail (
+ file_id bigint primary key,
+ url varchar(255) unique,
+ width integer,
+ height integer
+);
+
+create sequence file_to_post_seq;
+create table file_to_post (
+ file_id bigint,
+ post_id bigint,
+
+ primary key (file_id, post_id)
+);
+
+create table group_block (
+ group_id integer not null /* comment 'group profile is blocked from' */ references user_group (id),
+ blocked integer not null /* comment 'profile that is blocked' */references profile (id),
+ blocker integer not null /* comment 'user making the block'*/ references "user" (id),
+ modified timestamp /* comment 'date of blocking'*/ ,
+
+ primary key (group_id, blocked)
+);
+
+create table group_alias (
+
+ alias varchar(64) /* comment 'additional nickname for the group'*/ ,
+ group_id integer not null /* comment 'group profile is blocked from'*/ references user_group (id),
+ modified timestamp /* comment 'date alias was created'*/,
+ primary key (alias)
+
+);
+create index group_alias_group_id_idx on group_alias (group_id);
+
+create table session (
+
+ id varchar(32) primary key /* comment 'session ID'*/,
+ session_data text /* comment 'session data'*/,
+ created timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date this record was created'*/,
+ modified integer DEFAULT extract(epoch from CURRENT_TIMESTAMP) /* comment 'date this record was modified'*/
+);
+
+create index session_modified_idx on session (modified);
+
+
+/* Textsearch stuff */
+
+create index textsearch_idx on profile using gist(textsearch);
+create index noticecontent_idx on notice using gist(to_tsvector('english',content));
+create trigger textsearchupdate before insert or update on profile for each row
+execute procedure tsvector_update_trigger(textsearch, 'pg_catalog.english', nickname, fullname, location, bio, homepage);
+
diff --git a/doc-src/about b/doc-src/about
index 3036a51b9..21f4dbf15 100644
--- a/doc-src/about
+++ b/doc-src/about
@@ -1,6 +1,6 @@
%%site.name%% is a
[micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service
-based on the Free Software [Laconica](http://laconi.ca/) tool.
+based on the Free Software [StatusNet](http://status.net/) tool.
If you [register](%%action.register%%) for an account,
you can post small (140 chars or less) text notices
diff --git a/doc-src/bookmarklet b/doc-src/bookmarklet
index 6cd2c08f9..e5ded7702 100644
--- a/doc-src/bookmarklet
+++ b/doc-src/bookmarklet
@@ -2,6 +2,4 @@ A bookmarklet is a small piece of javascript code used as a bookmark. This one w
Drag-and-drop the following link to your bookmarks bar or right-click it and add it to your browser favorites to keep it handy.
-<MTMarkdownOptions output='raw'>
-<a href="javascript:var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=newnotice',l=d.location,e=encodeURIComponent,g=f+'&status_textarea=%22'+((e(s))?e(s):e(document.title))+'%22 from '+l.href;function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=800,height=570')){l.href=g;}}a();void(0);">Post to %%site.name%%</a>
-</MTMarkdownOptions>
+<a href="javascript:var%20d=document,w=window,e=w.getSelection,k=d.getSelection,x=d.selection,s=(e?e():(k)?k():(x?x.createRange().text:0)),f='http://%%site.server%%/%%site.path%%/index.php?action=newnotice',l=d.location,e=encodeURIComponent,g=f+'&amp;status_textarea=%22'+((e(s))?e(s):e(document.title))+'%22 from '+l.href;function%20a(){if(!w.open(g,'t','toolbar=0,resizable=0,scrollbars=1,status=1,width=800,height=570')){l.href=g;}}a();void(0);">Post to %%site.name%%</a>
diff --git a/doc-src/contact b/doc-src/contact
index a8efc456a..c63fcd01a 100644
--- a/doc-src/contact
+++ b/doc-src/contact
@@ -12,8 +12,8 @@ with "@" plus your user name.
Bugs
----
-If you think you've found a bug in the [Laconica](http://laconi.ca/) software,
-or if there's a new feature you'd like to see, add it into the [Laconica bug database](http://laconi.ca/PITS/HomePage). Don't forget to check the list of
+If you think you've found a bug in the [StatusNet](http://status.net/) software,
+or if there's a new feature you'd like to see, add it into the [StatusNet bug database](http://status.net/bugs/). Don't forget to check the list of
existing bugs to make sure it hasn't already been reported!
Email
diff --git a/doc-src/faq b/doc-src/faq
index 31582b9f0..6aadd2e60 100644
--- a/doc-src/faq
+++ b/doc-src/faq
@@ -26,7 +26,7 @@ presence. If you don't like how %%site.name%% works, you can take your data and
Where is feature X?
-------------------
-The software we run, [Laconica](http://laconi.ca/), is still in its early stages,
+The software we run, [StatusNet](http://status.net/), is still in its early stages,
and many features people expect from microblogging sites are not yet implemented. Some important ones that are expected "soon":
* More [AJAX](http://en.wikipedia.org/wiki/AJAX)-y interface
@@ -36,7 +36,7 @@ and many features people expect from microblogging sites are not yet implemented
* [Facebook](http://www.facebook.com/) integration
* Image, video, audio notices
-There is [a list of bugs and features](http://laconi.ca/trac/) that you may find
+There is [a list of bugs and features](http://status.net/trac/) that you may find
interesting. New ideas or complaints are very welcome.
diff --git a/doc-src/groups b/doc-src/groups
index 645390e0c..772ca9833 100644
--- a/doc-src/groups
+++ b/doc-src/groups
@@ -38,5 +38,5 @@ your phone or IM client if you've set them up to receive notices.
Remote groups
-------------
-While it's technically possible, this version of Laconica does not
+While it's technically possible, this version of StatusNet does not
support remote group membership.
diff --git a/doc-src/help b/doc-src/help
index 02cf0d14b..8d7acf63b 100644
--- a/doc-src/help
+++ b/doc-src/help
@@ -29,6 +29,6 @@ Here are some documents that you might find helpful in understanding
* [OpenID](%%doc.openid%%) - what OpenID is and how to use it with this service
* [OpenMicroBlogging](%%doc.openmublog%%) - subscribing to remote users
* [Privacy](%%doc.privacy%%) - %%site.name%%'s privacy policy
-* [Source](%%doc.source%%) - How to get the Laconica source code
-* [Badge](%%doc.badge%%) - How to put a Laconica badge on your blog or homepage
+* [Source](%%doc.source%%) - How to get the StatusNet source code
+* [Badge](%%doc.badge%%) - How to put a StatusNet badge on your blog or homepage
* [Bookmarklet](%%doc.bookmarklet%%) - Bookmarklet for posting Web pages \ No newline at end of file
diff --git a/doc-src/im b/doc-src/im
index da07f9fe7..631f6d9bb 100644
--- a/doc-src/im
+++ b/doc-src/im
@@ -32,4 +32,15 @@ currently-implemented commands:
you subscribe to.
* **off**: Turn off notifications. You'll no longer receive Jabber
notifications.
-
+* **stop**: Same as 'off'
+* **quit**: Same as 'off'
+* **help**: Show this help. List available Jabber/XMPP commands
+* **follow &lt;nickname&gt;**: Subscribe to &lt;nickname&gt;
+* **sub &lt;nickname&gt;**: Same as follow
+* **leave &lt;nickname&gt;**: Unsubscribe from &lt;nickname&gt;
+* **unsub &lt;nickname&gt;**: Same as leave
+* **d &lt;nickname&gt; &lt;text&gt;**: Send direct message to &lt;nickname&gt; with message body &lt;text&gt;
+* **get &lt;nickname&gt;**: Get last notice from &lt;nickname&gt;
+* **last &lt;nickname&gt;**: Same as 'get'
+* **whois &lt;nickname&gt;**: Get Profile info on &lt;nickname&gt;
+* **fav &lt;nickname&gt;**: Add user's last notice as a favorite
diff --git a/doc-src/openmublog b/doc-src/openmublog
index 6e3abee42..aec532b79 100644
--- a/doc-src/openmublog
+++ b/doc-src/openmublog
@@ -4,8 +4,8 @@ subscribe to notices by users of another service. The protocol, based on
[OAuth](http://oauth.net/), is open and free, and doesn't depend on any
central authority to maintain the federated microblogs.
-The [Laconica](http://laconi.ca/) software that runs %%site.name%% supports
-OpenMicroBlogging 0.1. Anyone can make a new installation of Laconica on their
+The [StatusNet](http://status.net/) software that runs %%site.name%% supports
+OpenMicroBlogging 0.1. Anyone can make a new installation of StatusNet on their
own servers, and users of that new installation can subscribe to notices from
%%site.name%%.
diff --git a/doc-src/sms b/doc-src/sms
index 1beb49786..1a3064318 100644
--- a/doc-src/sms
+++ b/doc-src/sms
@@ -44,24 +44,24 @@ You can use the following commands with %%site.name%%.
* on - turn on notifications
* off - turn off notifications
* help - show this help
-* follow <nickname> - subscribe to user
-* leave <nickname> - unsubscribe from user
-* d <nickname> <text> - direct message to user
-* get <nickname> - get last notice from user
-* whois <nickname> - get profile info on user
-* fav <nickname> - add user's last notice as a 'fave'
+* follow &lt;nickname&gt; - subscribe to user
+* leave &lt;nickname&gt; - unsubscribe from user
+* d &lt;nickname&gt; &lt;text&gt; - direct message to user
+* get &lt;nickname&gt; - get last notice from user
+* whois &lt;nickname&gt; - get profile info on user
+* fav &lt;nickname&gt; - add user's last notice as a 'fave'
* stats - get your stats
* stop - same as 'off'
* quit - same as 'off'
-* sub <nickname> - same as 'follow'
-* unsub <nickname> - same as 'leave'
-* last <nickname> - same as 'get'
-* on <nickname> - not yet implemented.
-* off <nickname> - not yet implemented.
-* nudge <nickname> - not yet implemented.
-* invite <phone number> - not yet implemented.
-* track <word> - not yet implemented.
-* untrack <word> - not yet implemented.
+* sub &lt;nickname&gt; - same as 'follow'
+* unsub &lt;nickname&gt; - same as 'leave'
+* last &lt;nickname&gt; - same as 'get'
+* on &lt;nickname&gt; - not yet implemented.
+* off &lt;nickname&gt; - not yet implemented.
+* nudge &lt;nickname&gt; - not yet implemented.
+* invite &lt;phone number&gt; - not yet implemented.
+* track &lt;word&gt; - not yet implemented.
+* untrack &lt;word&gt; - not yet implemented.
* track off - not yet implemented.
* untrack all - not yet implemented.
* tracks - not yet implemented.
diff --git a/doc-src/source b/doc-src/source
index 83debbe53..3ddd6203e 100644
--- a/doc-src/source
+++ b/doc-src/source
@@ -1,12 +1,12 @@
-This service uses a Free microblogging tool called **Laconica**.
-Laconica is available under the [GNU Affero General Public License
+This service uses a Free microblogging tool called **StatusNet**.
+StatusNet is available under the [GNU Affero General Public License
Version 3.0](http://www.fsf.org/licensing/licenses/agpl-3.0.html), a
Free Software license for network services.
You can get a copy of the software from the
-[Laconica](http://laconi.ca/) main site. The version of the software
+[StatusNet](http://status.net/) main site. The version of the software
that runs on *this* site is unmodified from that version. The site
also depends on certain libraries and other software; you can get
-those at the Laconica site, too.
+those at the StatusNet site, too.
diff --git a/extlib/Auth/OpenID/BigMath.php b/extlib/Auth/OpenID/BigMath.php
index 45104947d..b5fc627a0 100644
--- a/extlib/Auth/OpenID/BigMath.php
+++ b/extlib/Auth/OpenID/BigMath.php
@@ -376,7 +376,7 @@ function Auth_OpenID_detectMathLibrary($exts)
// Try to load dynamic modules.
if (!$loaded) {
foreach ($extension['modules'] as $module) {
- if (@dl($module . "." . PHP_SHLIB_SUFFIX)) {
+ if (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode') && @dl($module . "." . PHP_SHLIB_SUFFIX)) {
$loaded = true;
break;
}
diff --git a/extlib/Auth/Yadis/XML.php b/extlib/Auth/Yadis/XML.php
index 4854f12bb..7232d6cbd 100644
--- a/extlib/Auth/Yadis/XML.php
+++ b/extlib/Auth/Yadis/XML.php
@@ -349,7 +349,7 @@ function &Auth_Yadis_getXMLParser()
foreach ($extensions as $name => $params) {
if (!extension_loaded($name)) {
foreach ($params['libname'] as $libname) {
- if (@dl($libname)) {
+ if (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode') && @dl($libname)) {
$classname = $params['classname'];
}
}
diff --git a/extlib/OAuth.php b/extlib/OAuth.php
index 029166175..648627b57 100644
--- a/extlib/OAuth.php
+++ b/extlib/OAuth.php
@@ -199,7 +199,8 @@ class OAuthRequest {/*{{{*/
} else {
// collect request parameters from query string (GET) and post-data (POST) if appropriate (note: POST vars have priority)
$req_parameters = $_GET;
- if ($http_method == "POST" && @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") ) {
+ if ($http_method == "POST" &&
+ ( @strstr($request_headers["Content-Type"], "application/x-www-form-urlencoded") || @strstr($_ENV["CONTENT_TYPE"], "application/x-www-form-urlencoded") )) {
$req_parameters = array_merge($req_parameters, $_POST);
}
@@ -326,7 +327,7 @@ class OAuthRequest {/*{{{*/
public function get_normalized_http_url() {/*{{{*/
$parts = parse_url($this->http_url);
- $port = @$parts['port'];
+ $port = isset($parts['port']) ? $parts['port'] : null;
$scheme = $parts['scheme'];
$host = $parts['host'];
$path = @$parts['path'];
diff --git a/extlib/PEAR.php b/extlib/PEAR.php
index 4c24c6006..fcefa964a 100644
--- a/extlib/PEAR.php
+++ b/extlib/PEAR.php
@@ -746,7 +746,7 @@ class PEAR
{
if (!extension_loaded($ext)) {
// if either returns true dl() will produce a FATAL error, stop that
- if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1)) {
+ if ((ini_get('enable_dl') != 1) || (ini_get('safe_mode') == 1) || !function_exists('dl')) {
return false;
}
if (OS_WINDOWS) {
diff --git a/extlib/Services/oEmbed.php b/extlib/Services/oEmbed.php
index 7d507b6f6..0dc8f01b2 100644
--- a/extlib/Services/oEmbed.php
+++ b/extlib/Services/oEmbed.php
@@ -256,7 +256,7 @@ class Services_oEmbed
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (substr($code, 0, 1) != '2') {
- throw new Services_oEmbed_Exception('Non-200 code returned');
+ throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
}
curl_close($ch);
@@ -302,8 +302,8 @@ class Services_oEmbed
// Find all <link /> tags that have a valid oembed type set. We then
// extract the href attribute for each type.
- $regexp = '#<link([^>]*)type="' .
- '(application/json|text/xml)\+oembed"([^>]*)>#i';
+ $regexp = '#<link([^>]*)type[\s\n]*=[\s\n]*"' .
+ '(application/json|text/xml)\+oembed"([^>]*)>#im';
$m = $ret = array();
if (!preg_match_all($regexp, $body, $m)) {
@@ -314,7 +314,7 @@ class Services_oEmbed
foreach ($m[0] as $i => $link) {
$h = array();
- if (preg_match('/href="([^"]+)"/i', $link, $h)) {
+ if (preg_match('/[\s\n]+href[\s\n]*=[\s\n]*"([^"]+)"/im', $link, $h)) {
$ret[$m[2][$i]] = $h[1];
}
}
@@ -347,7 +347,7 @@ class Services_oEmbed
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (substr($code, 0, 1) != '2') {
- throw new Services_oEmbed_Exception('Non-200 code returned');
+ throw new Services_oEmbed_Exception('Non-200 code returned. Got code ' . $code);
}
return $result;
diff --git a/extlib/Stomp.php b/extlib/Stomp.php
index 9e1c97b3b..abd9cba62 100644
--- a/extlib/Stomp.php
+++ b/extlib/Stomp.php
@@ -454,7 +454,7 @@ class Stomp
*/
public function disconnect ()
{
- $header = array();
+ $headers = array();
if ($this->clientId != null) {
$headers["client-id"] = $this->clientId;
diff --git a/extlib/htmLawed/htmLawed.php b/extlib/htmLawed/htmLawed.php
new file mode 100644
index 000000000..17f6e98ca
--- /dev/null
+++ b/extlib/htmLawed/htmLawed.php
@@ -0,0 +1,715 @@
+<?php
+
+/*
+htmLawed 1.1.8.1, 16 July 2009
+Copyright Santosh Patnaik
+GPL v3 license
+A PHP Labware internal utility; www.bioinformatics.org/phplabware/internal_utilities/htmLawed
+
+See htmLawed_README.txt/htm
+*/
+
+function htmLawed($t, $C=1, $S=array()){
+$C = is_array($C) ? $C : array();
+if(!empty($C['valid_xhtml'])){
+ $C['elements'] = empty($C['elements']) ? '*-center-dir-font-isindex-menu-s-strike-u' : $C['elements'];
+ $C['make_tag_strict'] = isset($C['make_tag_strict']) ? $C['make_tag_strict'] : 2;
+ $C['xml:lang'] = isset($C['xml:lang']) ? $C['xml:lang'] : 2;
+}
+// config eles
+$e = array('a'=>1, 'abbr'=>1, 'acronym'=>1, 'address'=>1, 'applet'=>1, 'area'=>1, 'b'=>1, 'bdo'=>1, 'big'=>1, 'blockquote'=>1, 'br'=>1, 'button'=>1, 'caption'=>1, 'center'=>1, 'cite'=>1, 'code'=>1, 'col'=>1, 'colgroup'=>1, 'dd'=>1, 'del'=>1, 'dfn'=>1, 'dir'=>1, 'div'=>1, 'dl'=>1, 'dt'=>1, 'em'=>1, 'embed'=>1, 'fieldset'=>1, 'font'=>1, 'form'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'i'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'ins'=>1, 'isindex'=>1, 'kbd'=>1, 'label'=>1, 'legend'=>1, 'li'=>1, 'map'=>1, 'menu'=>1, 'noscript'=>1, 'object'=>1, 'ol'=>1, 'optgroup'=>1, 'option'=>1, 'p'=>1, 'param'=>1, 'pre'=>1, 'q'=>1, 'rb'=>1, 'rbc'=>1, 'rp'=>1, 'rt'=>1, 'rtc'=>1, 'ruby'=>1, 's'=>1, 'samp'=>1, 'script'=>1, 'select'=>1, 'small'=>1, 'span'=>1, 'strike'=>1, 'strong'=>1, 'sub'=>1, 'sup'=>1, 'table'=>1, 'tbody'=>1, 'td'=>1, 'textarea'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1, 'tt'=>1, 'u'=>1, 'ul'=>1, 'var'=>1); // 86/deprecated+embed+ruby
+if(!empty($C['safe'])){
+ unset($e['applet'], $e['embed'], $e['iframe'], $e['object'], $e['script']);
+}
+$x = !empty($C['elements']) ? str_replace(array("\n", "\r", "\t", ' '), '', $C['elements']) : '*';
+if($x == '-*'){$e = array();}
+elseif(strpos($x, '*') === false){$e = array_flip(explode(',', $x));}
+else{
+ if(isset($x[1])){
+ preg_match_all('`(?:^|-|\+)[^\-+]+?(?=-|\+|$)`', $x, $m, PREG_SET_ORDER);
+ for($i=count($m); --$i>=0;){$m[$i] = $m[$i][0];}
+ foreach($m as $v){
+ if($v[0] == '+'){$e[substr($v, 1)] = 1;}
+ if($v[0] == '-' && isset($e[($v = substr($v, 1))]) && !in_array('+'. $v, $m)){unset($e[$v]);}
+ }
+ }
+}
+$C['elements'] =& $e;
+// config attrs
+$x = !empty($C['deny_attribute']) ? str_replace(array("\n", "\r", "\t", ' '), '', $C['deny_attribute']) : '';
+$x = array_flip((isset($x[0]) && $x[0] == '*') ? explode('-', $x) : explode(',', $x. (!empty($C['safe']) ? ',on*' : '')));
+if(isset($x['on*'])){
+ unset($x['on*']);
+ $x += array('onblur'=>1, 'onchange'=>1, 'onclick'=>1, 'ondblclick'=>1, 'onfocus'=>1, 'onkeydown'=>1, 'onkeypress'=>1, 'onkeyup'=>1, 'onmousedown'=>1, 'onmousemove'=>1, 'onmouseout'=>1, 'onmouseover'=>1, 'onmouseup'=>1, 'onreset'=>1, 'onselect'=>1, 'onsubmit'=>1);
+}
+$C['deny_attribute'] = $x;
+// config URL
+$x = (isset($C['schemes'][2]) && strpos($C['schemes'], ':')) ? strtolower($C['schemes']) : 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https';
+$C['schemes'] = array();
+foreach(explode(';', str_replace(array(' ', "\t", "\r", "\n"), '', $x)) as $v){
+ $x = $x2 = null; list($x, $x2) = explode(':', $v, 2);
+ if($x2){$C['schemes'][$x] = array_flip(explode(',', $x2));}
+}
+if(!isset($C['schemes']['*'])){$C['schemes']['*'] = array('file'=>1, 'http'=>1, 'https'=>1,);}
+if(!empty($C['safe']) && empty($C['schemes']['style'])){$C['schemes']['style'] = array('nil'=>1);}
+$C['abs_url'] = isset($C['abs_url']) ? $C['abs_url'] : 0;
+if(!isset($C['base_url']) or !preg_match('`^[a-zA-Z\d.+\-]+://[^/]+/(.+?/)?$`', $C['base_url'])){
+ $C['base_url'] = $C['abs_url'] = 0;
+}
+// config rest
+$C['and_mark'] = empty($C['and_mark']) ? 0 : 1;
+$C['anti_link_spam'] = (isset($C['anti_link_spam']) && is_array($C['anti_link_spam']) && count($C['anti_link_spam']) == 2 && (empty($C['anti_link_spam'][0]) or hl_regex($C['anti_link_spam'][0])) && (empty($C['anti_link_spam'][1]) or hl_regex($C['anti_link_spam'][1]))) ? $C['anti_link_spam'] : 0;
+$C['anti_mail_spam'] = isset($C['anti_mail_spam']) ? $C['anti_mail_spam'] : 0;
+$C['balance'] = isset($C['balance']) ? (bool)$C['balance'] : 1;
+$C['cdata'] = isset($C['cdata']) ? $C['cdata'] : (empty($C['safe']) ? 3 : 0);
+$C['clean_ms_char'] = empty($C['clean_ms_char']) ? 0 : $C['clean_ms_char'];
+$C['comment'] = isset($C['comment']) ? $C['comment'] : (empty($C['safe']) ? 3 : 0);
+$C['css_expression'] = empty($C['css_expression']) ? 0 : 1;
+$C['hexdec_entity'] = isset($C['hexdec_entity']) ? $C['hexdec_entity'] : 1;
+$C['hook'] = (!empty($C['hook']) && function_exists($C['hook'])) ? $C['hook'] : 0;
+$C['hook_tag'] = (!empty($C['hook_tag']) && function_exists($C['hook_tag'])) ? $C['hook_tag'] : 0;
+$C['keep_bad'] = isset($C['keep_bad']) ? $C['keep_bad'] : 6;
+$C['lc_std_val'] = isset($C['lc_std_val']) ? (bool)$C['lc_std_val'] : 1;
+$C['make_tag_strict'] = isset($C['make_tag_strict']) ? $C['make_tag_strict'] : 1;
+$C['named_entity'] = isset($C['named_entity']) ? (bool)$C['named_entity'] : 1;
+$C['no_deprecated_attr'] = isset($C['no_deprecated_attr']) ? $C['no_deprecated_attr'] : 1;
+$C['parent'] = isset($C['parent'][0]) ? strtolower($C['parent']) : 'body';
+$C['show_setting'] = !empty($C['show_setting']) ? $C['show_setting'] : 0;
+$C['style_pass'] = empty($C['style_pass']) ? 0 : 1;
+$C['tidy'] = empty($C['tidy']) ? 0 : $C['tidy'];
+$C['unique_ids'] = isset($C['unique_ids']) ? $C['unique_ids'] : 1;
+$C['xml:lang'] = isset($C['xml:lang']) ? $C['xml:lang'] : 0;
+
+if(isset($GLOBALS['C'])){$reC = $GLOBALS['C'];}
+$GLOBALS['C'] = $C;
+$S = is_array($S) ? $S : hl_spec($S);
+if(isset($GLOBALS['S'])){$reS = $GLOBALS['S'];}
+$GLOBALS['S'] = $S;
+
+$t = preg_replace('`[\x00-\x08\x0b-\x0c\x0e-\x1f]`', '', $t);
+if($C['clean_ms_char']){
+ $x = array("\x7f"=>'', "\x80"=>'&#8364;', "\x81"=>'', "\x83"=>'&#402;', "\x85"=>'&#8230;', "\x86"=>'&#8224;', "\x87"=>'&#8225;', "\x88"=>'&#710;', "\x89"=>'&#8240;', "\x8a"=>'&#352;', "\x8b"=>'&#8249;', "\x8c"=>'&#338;', "\x8d"=>'', "\x8e"=>'&#381;', "\x8f"=>'', "\x90"=>'', "\x95"=>'&#8226;', "\x96"=>'&#8211;', "\x97"=>'&#8212;', "\x98"=>'&#732;', "\x99"=>'&#8482;', "\x9a"=>'&#353;', "\x9b"=>'&#8250;', "\x9c"=>'&#339;', "\x9d"=>'', "\x9e"=>'&#382;', "\x9f"=>'&#376;');
+ $x = $x + ($C['clean_ms_char'] == 1 ? array("\x82"=>'&#8218;', "\x84"=>'&#8222;', "\x91"=>'&#8216;', "\x92"=>'&#8217;', "\x93"=>'&#8220;', "\x94"=>'&#8221;') : array("\x82"=>'\'', "\x84"=>'"', "\x91"=>'\'', "\x92"=>'\'', "\x93"=>'"', "\x94"=>'"'));
+ $t = strtr($t, $x);
+}
+if($C['cdata'] or $C['comment']){$t = preg_replace_callback('`<!(?:(?:--.*?--)|(?:\[CDATA\[.*?\]\]))>`sm', 'hl_cmtcd', $t);}
+$t = preg_replace_callback('`&amp;([A-Za-z][A-Za-z0-9]{1,30}|#(?:[0-9]{1,8}|[Xx][0-9A-Fa-f]{1,7}));`', 'hl_ent', str_replace('&', '&amp;', $t));
+if($C['unique_ids'] && !isset($GLOBALS['hl_Ids'])){$GLOBALS['hl_Ids'] = array();}
+if($C['hook']){$t = $C['hook']($t, $C, $S);}
+if($C['show_setting'] && preg_match('`^[a-z][a-z0-9_]*$`i', $C['show_setting'])){
+ $GLOBALS[$C['show_setting']] = array('config'=>$C, 'spec'=>$S, 'time'=>microtime());
+}
+// main
+$t = preg_replace_callback('`<(?:(?:\s|$)|(?:[^>]*(?:>|$)))|>`m', 'hl_tag', $t);
+$t = $C['balance'] ? hl_bal($t, $C['keep_bad'], $C['parent']) : $t;
+$t = (($C['cdata'] or $C['comment']) && strpos($t, "\x01") !== false) ? str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05"), array('', '', '&', '<', '>'), $t) : $t;
+$t = $C['tidy'] ? hl_tidy($t, $C['tidy'], $C['parent']) : $t;
+unset($C, $e);
+if(isset($reC)){$GLOBALS['C'] = $reC;}
+if(isset($reS)){$GLOBALS['S'] = $reS;}
+return $t;
+// eof
+}
+
+function hl_attrval($t, $p){
+// check attr val against $S
+$o = 1; $l = strlen($t);
+foreach($p as $k=>$v){
+ switch($k){
+ case 'maxlen':if($l > $v){$o = 0;}
+ break; case 'minlen': if($l < $v){$o = 0;}
+ break; case 'maxval': if((float)($t) > $v){$o = 0;}
+ break; case 'minval': if((float)($t) < $v){$o = 0;}
+ break; case 'match': if(!preg_match($v, $t)){$o = 0;}
+ break; case 'nomatch': if(preg_match($v, $t)){$o = 0;}
+ break; case 'oneof':
+ $m = 0;
+ foreach(explode('|', $v) as $n){if($t == $n){$m = 1; break;}}
+ $o = $m;
+ break; case 'noneof':
+ $m = 1;
+ foreach(explode('|', $v) as $n){if($t == $n){$m = 0; break;}}
+ $o = $m;
+ break; default:
+ break;
+ }
+ if(!$o){break;}
+}
+return ($o ? $t : (isset($p['default']) ? $p['default'] : 0));
+// eof
+}
+
+function hl_bal($t, $do=1, $in='div'){
+// balance tags
+// by content
+$cB = array('blockquote'=>1, 'form'=>1, 'map'=>1, 'noscript'=>1); // Block
+$cE = array('area'=>1, 'br'=>1, 'col'=>1, 'embed'=>1, 'hr'=>1, 'img'=>1, 'input'=>1, 'isindex'=>1, 'param'=>1); // Empty
+$cF = array('button'=>1, 'del'=>1, 'div'=>1, 'dd'=>1, 'fieldset'=>1, 'iframe'=>1, 'ins'=>1, 'li'=>1, 'noscript'=>1, 'object'=>1, 'td'=>1, 'th'=>1); // Flow; later context-wise dynamic move of ins & del to $cI
+$cI = array('a'=>1, 'abbr'=>1, 'acronym'=>1, 'address'=>1, 'b'=>1, 'bdo'=>1, 'big'=>1, 'caption'=>1, 'cite'=>1, 'code'=>1, 'dfn'=>1, 'dt'=>1, 'em'=>1, 'font'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'i'=>1, 'kbd'=>1, 'label'=>1, 'legend'=>1, 'p'=>1, 'pre'=>1, 'q'=>1, 'rb'=>1, 'rt'=>1, 's'=>1, 'samp'=>1, 'small'=>1, 'span'=>1, 'strike'=>1, 'strong'=>1, 'sub'=>1, 'sup'=>1, 'tt'=>1, 'u'=>1, 'var'=>1); // Inline
+$cN = array('a'=>array('a'=>1), 'button'=>array('a'=>1, 'button'=>1, 'fieldset'=>1, 'form'=>1, 'iframe'=>1, 'input'=>1, 'label'=>1, 'select'=>1, 'textarea'=>1), 'fieldset'=>array('fieldset'=>1), 'form'=>array('form'=>1), 'label'=>array('label'=>1), 'noscript'=>array('script'=>1), 'pre'=>array('big'=>1, 'font'=>1, 'img'=>1, 'object'=>1, 'script'=>1, 'small'=>1, 'sub'=>1, 'sup'=>1), 'rb'=>array('ruby'=>1), 'rt'=>array('ruby'=>1)); // Illegal
+$cN2 = array_keys($cN);
+$cR = array('blockquote'=>1, 'dir'=>1, 'dl'=>1, 'form'=>1, 'map'=>1, 'menu'=>1, 'noscript'=>1, 'ol'=>1, 'optgroup'=>1, 'rbc'=>1, 'rtc'=>1, 'ruby'=>1, 'select'=>1, 'table'=>1, 'tbody'=>1, 'tfoot'=>1, 'thead'=>1, 'tr'=>1, 'ul'=>1);
+$cS = array('colgroup'=>array('col'=>1), 'dir'=>array('li'), 'dl'=>array('dd'=>1, 'dt'=>1), 'menu'=>array('li'=>1), 'ol'=>array('li'=>1), 'optgroup'=>array('option'=>1), 'option'=>array('#pcdata'=>1), 'rbc'=>array('rb'=>1), 'rp'=>array('#pcdata'=>1), 'rtc'=>array('rt'=>1), 'ruby'=>array('rb'=>1, 'rbc'=>1, 'rp'=>1, 'rt'=>1, 'rtc'=>1), 'select'=>array('optgroup'=>1, 'option'=>1), 'script'=>array('#pcdata'=>1), 'table'=>array('caption'=>1, 'col'=>1, 'colgroup'=>1, 'tfoot'=>1, 'tbody'=>1, 'tr'=>1, 'thead'=>1), 'tbody'=>array('tr'=>1), 'tfoot'=>array('tr'=>1), 'textarea'=>array('#pcdata'=>1), 'thead'=>array('tr'=>1), 'tr'=>array('td'=>1, 'th'=>1), 'ul'=>array('li'=>1)); // Specific - immediate parent-child
+$cO = array('address'=>array('p'=>1), 'applet'=>array('param'=>1), 'blockquote'=>array('script'=>1), 'fieldset'=>array('legend'=>1, '#pcdata'=>1), 'form'=>array('script'=>1), 'map'=>array('area'=>1), 'object'=>array('param'=>1, 'embed'=>1)); // Other
+$cT = array('colgroup'=>1, 'dd'=>1, 'dt'=>1, 'li'=>1, 'option'=>1, 'p'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1); // Omitable closing
+// block/inline type; ins & del both type; #pcdata: text
+$eB = array('address'=>1, 'blockquote'=>1, 'center'=>1, 'del'=>1, 'dir'=>1, 'dl'=>1, 'div'=>1, 'fieldset'=>1, 'form'=>1, 'ins'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'isindex'=>1, 'menu'=>1, 'noscript'=>1, 'ol'=>1, 'p'=>1, 'pre'=>1, 'table'=>1, 'ul'=>1);
+$eI = array('#pcdata'=>1, 'a'=>1, 'abbr'=>1, 'acronym'=>1, 'applet'=>1, 'b'=>1, 'bdo'=>1, 'big'=>1, 'br'=>1, 'button'=>1, 'cite'=>1, 'code'=>1, 'del'=>1, 'dfn'=>1, 'em'=>1, 'embed'=>1, 'font'=>1, 'i'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'ins'=>1, 'kbd'=>1, 'label'=>1, 'map'=>1, 'object'=>1, 'param'=>1, 'q'=>1, 'ruby'=>1, 's'=>1, 'samp'=>1, 'select'=>1, 'script'=>1, 'small'=>1, 'span'=>1, 'strike'=>1, 'strong'=>1, 'sub'=>1, 'sup'=>1, 'textarea'=>1, 'tt'=>1, 'u'=>1, 'var'=>1);
+$eN = array('a'=>1, 'big'=>1, 'button'=>1, 'fieldset'=>1, 'font'=>1, 'form'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'label'=>1, 'object'=>1, 'ruby'=>1, 'script'=>1, 'select'=>1, 'small'=>1, 'sub'=>1, 'sup'=>1, 'textarea'=>1); // Exclude from specific ele; $cN values
+$eO = array('area'=>1, 'caption'=>1, 'col'=>1, 'colgroup'=>1, 'dd'=>1, 'dt'=>1, 'legend'=>1, 'li'=>1, 'optgroup'=>1, 'option'=>1, 'rb'=>1, 'rbc'=>1, 'rp'=>1, 'rt'=>1, 'rtc'=>1, 'script'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'thead'=>1, 'th'=>1, 'tr'=>1); // Missing in $eB & $eI
+$eF = $eB + $eI;
+
+// $in sets allowed child
+$in = ((isset($eF[$in]) && $in != '#pcdata') or isset($eO[$in])) ? $in : 'div';
+if(isset($cE[$in])){
+ return (!$do ? '' : str_replace(array('<', '>'), array('&lt;', '&gt;'), $t));
+}
+if(isset($cS[$in])){$inOk = $cS[$in];}
+elseif(isset($cI[$in])){$inOk = $eI; $cI['del'] = 1; $cI['ins'] = 1;}
+elseif(isset($cF[$in])){$inOk = $eF; unset($cI['del'], $cI['ins']);}
+elseif(isset($cB[$in])){$inOk = $eB; unset($cI['del'], $cI['ins']);}
+if(isset($cO[$in])){$inOk = $inOk + $cO[$in];}
+if(isset($cN[$in])){$inOk = array_diff_assoc($inOk, $cN[$in]);}
+
+$t = explode('<', $t);
+$ok = $q = array(); // $q seq list of open non-empty ele
+ob_start();
+
+for($i=-1, $ci=count($t); ++$i<$ci;){
+ // allowed $ok in parent $p
+ if($ql = count($q)){
+ $p = array_pop($q);
+ $q[] = $p;
+ if(isset($cS[$p])){$ok = $cS[$p];}
+ elseif(isset($cI[$p])){$ok = $eI; $cI['del'] = 1; $cI['ins'] = 1;}
+ elseif(isset($cF[$p])){$ok = $eF; unset($cI['del'], $cI['ins']);}
+ elseif(isset($cB[$p])){$ok = $eB; unset($cI['del'], $cI['ins']);}
+ if(isset($cO[$p])){$ok = $ok + $cO[$p];}
+ if(isset($cN[$p])){$ok = array_diff_assoc($ok, $cN[$p]);}
+ }else{$ok = $inOk; unset($cI['del'], $cI['ins']);}
+ // bad tags, & ele content
+ if(isset($e) && ($do == 1 or (isset($ok['#pcdata']) && ($do == 3 or $do == 5)))){
+ echo '&lt;', $s, $e, $a, '&gt;';
+ }
+ if(isset($x[0])){
+ if($do < 3 or isset($ok['#pcdata'])){echo $x;}
+ elseif(strpos($x, "\x02\x04")){
+ foreach(preg_split('`(\x01\x02[^\x01\x02]+\x02\x01)`', $x, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $v){
+ echo (substr($v, 0, 2) == "\x01\x02" ? $v : ($do > 4 ? preg_replace('`\S`', '', $v) : ''));
+ }
+ }elseif($do > 4){echo preg_replace('`\S`', '', $x);}
+ }
+ // get markup
+ if(!preg_match('`^(/?)([a-zA-Z1-6]+)([^>]*)>(.*)`sm', $t[$i], $r)){$x = $t[$i]; continue;}
+ $s = null; $e = null; $a = null; $x = null; list($all, $s, $e, $a, $x) = $r;
+ // close tag
+ if($s){
+ if(isset($cE[$e]) or !in_array($e, $q)){continue;} // Empty/unopen
+ if($p == $e){array_pop($q); echo '</', $e, '>'; unset($e); continue;} // Last open
+ $add = ''; // Nesting - close open tags that need to be
+ for($j=-1, $cj=count($q); ++$j<$cj;){
+ if(($d = array_pop($q)) == $e){break;}
+ else{$add .= "</{$d}>";}
+ }
+ echo $add, '</', $e, '>'; unset($e); continue;
+ }
+ // open tag
+ // $cB ele needs $eB ele as child
+ if(isset($cB[$e]) && strlen(trim($x))){
+ $t[$i] = "{$e}{$a}>";
+ array_splice($t, $i+1, 0, 'div>'. $x); unset($e, $x); ++$ci; --$i; continue;
+ }
+ if((($ql && isset($cB[$p])) or (isset($cB[$in]) && !$ql)) && !isset($eB[$e]) && !isset($ok[$e])){
+ array_splice($t, $i, 0, 'div>'); unset($e, $x); ++$ci; --$i; continue;
+ }
+ // if no open ele, $in = parent; mostly immediate parent-child relation should hold
+ if(!$ql or !isset($eN[$e]) or !array_intersect($q, $cN2)){
+ if(!isset($ok[$e])){
+ if($ql && isset($cT[$p])){echo '</', array_pop($q), '>'; unset($e, $x); --$i;}
+ continue;
+ }
+ if(!isset($cE[$e])){$q[] = $e;}
+ echo '<', $e, $a, '>'; unset($e); continue;
+ }
+ // specific parent-child
+ if(isset($cS[$p][$e])){
+ if(!isset($cE[$e])){$q[] = $e;}
+ echo '<', $e, $a, '>'; unset($e); continue;
+ }
+ // nesting
+ $add = '';
+ $q2 = array();
+ for($k=-1, $kc=count($q); ++$k<$kc;){
+ $d = $q[$k];
+ $ok2 = array();
+ if(isset($cS[$d])){$q2[] = $d; continue;}
+ $ok2 = isset($cI[$d]) ? $eI : $eF;
+ if(isset($cO[$d])){$ok2 = $ok2 + $cO[$d];}
+ if(isset($cN[$d])){$ok2 = array_diff_assoc($ok2, $cN[$d]);}
+ if(!isset($ok2[$e])){
+ if(!$k && !isset($inOk[$e])){continue 2;}
+ $add = "</{$d}>";
+ for(;++$k<$kc;){$add = "</{$q[$k]}>{$add}";}
+ break;
+ }
+ else{$q2[] = $d;}
+ }
+ $q = $q2;
+ if(!isset($cE[$e])){$q[] = $e;}
+ echo $add, '<', $e, $a, '>'; unset($e); continue;
+}
+
+// end
+if($ql = count($q)){
+ $p = array_pop($q);
+ $q[] = $p;
+ if(isset($cS[$p])){$ok = $cS[$p];}
+ elseif(isset($cI[$p])){$ok = $eI; $cI['del'] = 1; $cI['ins'] = 1;}
+ elseif(isset($cF[$p])){$ok = $eF; unset($cI['del'], $cI['ins']);}
+ elseif(isset($cB[$p])){$ok = $eB; unset($cI['del'], $cI['ins']);}
+ if(isset($cO[$p])){$ok = $ok + $cO[$p];}
+ if(isset($cN[$p])){$ok = array_diff_assoc($ok, $cN[$p]);}
+}else{$ok = $inOk; unset($cI['del'], $cI['ins']);}
+if(isset($e) && ($do == 1 or (isset($ok['#pcdata']) && ($do == 3 or $do == 5)))){
+ echo '&lt;', $s, $e, $a, '&gt;';
+}
+if(isset($x[0])){
+ if(strlen(trim($x)) && (($ql && isset($cB[$p])) or (isset($cB[$in]) && !$ql))){
+ echo '<div>', $x, '</div>';
+ }
+ elseif($do < 3 or isset($ok['#pcdata'])){echo $x;}
+ elseif(strpos($x, "\x02\x04")){
+ foreach(preg_split('`(\x01\x02[^\x01\x02]+\x02\x01)`', $x, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY) as $v){
+ echo (substr($v, 0, 2) == "\x01\x02" ? $v : ($do > 4 ? preg_replace('`\S`', '', $v) : ''));
+ }
+ }elseif($do > 4){echo preg_replace('`\S`', '', $x);}
+}
+while(!empty($q) && ($e = array_pop($q))){echo '</', $e, '>';}
+$o = ob_get_contents();
+ob_end_clean();
+return $o;
+// eof
+}
+
+function hl_cmtcd($t){
+// comment/CDATA sec handler
+$t = $t[0];
+global $C;
+if($t[3] == '-'){
+ if(!$C['comment']){return $t;}
+ if($C['comment'] == 1){return '';}
+ if(substr(($t = preg_replace('`--+`', '-', substr($t, 4, -3))), -1) != ' '){$t .= ' ';}
+ $t = $C['comment'] == 2 ? str_replace(array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $t) : $t;
+ $t = "\x01\x02\x04!--$t--\x05\x02\x01";
+}else{ // CDATA
+ if(!$C['cdata']){return $t;}
+ if($C['cdata'] == 1){return '';}
+ $t = substr($t, 1, -1);
+ $t = $C['cdata'] == 2 ? str_replace(array('&', '<', '>'), array('&amp;', '&lt;', '&gt;'), $t) : $t;
+ $t = "\x01\x01\x04$t\x05\x01\x01";
+}
+return str_replace(array('&', '<', '>'), array("\x03", "\x04", "\x05"), $t);
+// eof
+}
+
+function hl_ent($t){
+// entitity handler
+global $C;
+$t = $t[1];
+static $U = array('quot'=>1,'amp'=>1,'lt'=>1,'gt'=>1);
+static $N = array('fnof'=>'402', 'Alpha'=>'913', 'Beta'=>'914', 'Gamma'=>'915', 'Delta'=>'916', 'Epsilon'=>'917', 'Zeta'=>'918', 'Eta'=>'919', 'Theta'=>'920', 'Iota'=>'921', 'Kappa'=>'922', 'Lambda'=>'923', 'Mu'=>'924', 'Nu'=>'925', 'Xi'=>'926', 'Omicron'=>'927', 'Pi'=>'928', 'Rho'=>'929', 'Sigma'=>'931', 'Tau'=>'932', 'Upsilon'=>'933', 'Phi'=>'934', 'Chi'=>'935', 'Psi'=>'936', 'Omega'=>'937', 'alpha'=>'945', 'beta'=>'946', 'gamma'=>'947', 'delta'=>'948', 'epsilon'=>'949', 'zeta'=>'950', 'eta'=>'951', 'theta'=>'952', 'iota'=>'953', 'kappa'=>'954', 'lambda'=>'955', 'mu'=>'956', 'nu'=>'957', 'xi'=>'958', 'omicron'=>'959', 'pi'=>'960', 'rho'=>'961', 'sigmaf'=>'962', 'sigma'=>'963', 'tau'=>'964', 'upsilon'=>'965', 'phi'=>'966', 'chi'=>'967', 'psi'=>'968', 'omega'=>'969', 'thetasym'=>'977', 'upsih'=>'978', 'piv'=>'982', 'bull'=>'8226', 'hellip'=>'8230', 'prime'=>'8242', 'Prime'=>'8243', 'oline'=>'8254', 'frasl'=>'8260', 'weierp'=>'8472', 'image'=>'8465', 'real'=>'8476', 'trade'=>'8482', 'alefsym'=>'8501', 'larr'=>'8592', 'uarr'=>'8593', 'rarr'=>'8594', 'darr'=>'8595', 'harr'=>'8596', 'crarr'=>'8629', 'lArr'=>'8656', 'uArr'=>'8657', 'rArr'=>'8658', 'dArr'=>'8659', 'hArr'=>'8660', 'forall'=>'8704', 'part'=>'8706', 'exist'=>'8707', 'empty'=>'8709', 'nabla'=>'8711', 'isin'=>'8712', 'notin'=>'8713', 'ni'=>'8715', 'prod'=>'8719', 'sum'=>'8721', 'minus'=>'8722', 'lowast'=>'8727', 'radic'=>'8730', 'prop'=>'8733', 'infin'=>'8734', 'ang'=>'8736', 'and'=>'8743', 'or'=>'8744', 'cap'=>'8745', 'cup'=>'8746', 'int'=>'8747', 'there4'=>'8756', 'sim'=>'8764', 'cong'=>'8773', 'asymp'=>'8776', 'ne'=>'8800', 'equiv'=>'8801', 'le'=>'8804', 'ge'=>'8805', 'sub'=>'8834', 'sup'=>'8835', 'nsub'=>'8836', 'sube'=>'8838', 'supe'=>'8839', 'oplus'=>'8853', 'otimes'=>'8855', 'perp'=>'8869', 'sdot'=>'8901', 'lceil'=>'8968', 'rceil'=>'8969', 'lfloor'=>'8970', 'rfloor'=>'8971', 'lang'=>'9001', 'rang'=>'9002', 'loz'=>'9674', 'spades'=>'9824', 'clubs'=>'9827', 'hearts'=>'9829', 'diams'=>'9830', 'apos'=>'39', 'OElig'=>'338', 'oelig'=>'339', 'Scaron'=>'352', 'scaron'=>'353', 'Yuml'=>'376', 'circ'=>'710', 'tilde'=>'732', 'ensp'=>'8194', 'emsp'=>'8195', 'thinsp'=>'8201', 'zwnj'=>'8204', 'zwj'=>'8205', 'lrm'=>'8206', 'rlm'=>'8207', 'ndash'=>'8211', 'mdash'=>'8212', 'lsquo'=>'8216', 'rsquo'=>'8217', 'sbquo'=>'8218', 'ldquo'=>'8220', 'rdquo'=>'8221', 'bdquo'=>'8222', 'dagger'=>'8224', 'Dagger'=>'8225', 'permil'=>'8240', 'lsaquo'=>'8249', 'rsaquo'=>'8250', 'euro'=>'8364', 'nbsp'=>'160', 'iexcl'=>'161', 'cent'=>'162', 'pound'=>'163', 'curren'=>'164', 'yen'=>'165', 'brvbar'=>'166', 'sect'=>'167', 'uml'=>'168', 'copy'=>'169', 'ordf'=>'170', 'laquo'=>'171', 'not'=>'172', 'shy'=>'173', 'reg'=>'174', 'macr'=>'175', 'deg'=>'176', 'plusmn'=>'177', 'sup2'=>'178', 'sup3'=>'179', 'acute'=>'180', 'micro'=>'181', 'para'=>'182', 'middot'=>'183', 'cedil'=>'184', 'sup1'=>'185', 'ordm'=>'186', 'raquo'=>'187', 'frac14'=>'188', 'frac12'=>'189', 'frac34'=>'190', 'iquest'=>'191', 'Agrave'=>'192', 'Aacute'=>'193', 'Acirc'=>'194', 'Atilde'=>'195', 'Auml'=>'196', 'Aring'=>'197', 'AElig'=>'198', 'Ccedil'=>'199', 'Egrave'=>'200', 'Eacute'=>'201', 'Ecirc'=>'202', 'Euml'=>'203', 'Igrave'=>'204', 'Iacute'=>'205', 'Icirc'=>'206', 'Iuml'=>'207', 'ETH'=>'208', 'Ntilde'=>'209', 'Ograve'=>'210', 'Oacute'=>'211', 'Ocirc'=>'212', 'Otilde'=>'213', 'Ouml'=>'214', 'times'=>'215', 'Oslash'=>'216', 'Ugrave'=>'217', 'Uacute'=>'218', 'Ucirc'=>'219', 'Uuml'=>'220', 'Yacute'=>'221', 'THORN'=>'222', 'szlig'=>'223', 'agrave'=>'224', 'aacute'=>'225', 'acirc'=>'226', 'atilde'=>'227', 'auml'=>'228', 'aring'=>'229', 'aelig'=>'230', 'ccedil'=>'231', 'egrave'=>'232', 'eacute'=>'233', 'ecirc'=>'234', 'euml'=>'235', 'igrave'=>'236', 'iacute'=>'237', 'icirc'=>'238', 'iuml'=>'239', 'eth'=>'240', 'ntilde'=>'241', 'ograve'=>'242', 'oacute'=>'243', 'ocirc'=>'244', 'otilde'=>'245', 'ouml'=>'246', 'divide'=>'247', 'oslash'=>'248', 'ugrave'=>'249', 'uacute'=>'250', 'ucirc'=>'251', 'uuml'=>'252', 'yacute'=>'253', 'thorn'=>'254', 'yuml'=>'255');
+if($t[0] != '#'){
+ return ($C['and_mark'] ? "\x06" : '&'). (isset($U[$t]) ? $t : (isset($N[$t]) ? (!$C['named_entity'] ? '#'. ($C['hexdec_entity'] > 1 ? 'x'. dechex($N[$t]) : $N[$t]) : $t) : 'amp;'. $t)). ';';
+}
+if(($n = ctype_digit($t = substr($t, 1)) ? intval($t) : hexdec(substr($t, 1))) < 9 or ($n > 13 && $n < 32) or $n == 11 or $n == 12 or ($n > 126 && $n < 160 && $n != 133) or ($n > 55295 && ($n < 57344 or ($n > 64975 && $n < 64992) or $n == 65534 or $n == 65535 or $n > 1114111))){
+ return ($C['and_mark'] ? "\x06" : '&'). "amp;#{$t};";
+}
+return ($C['and_mark'] ? "\x06" : '&'). '#'. (((ctype_digit($t) && $C['hexdec_entity'] < 2) or !$C['hexdec_entity']) ? $n : 'x'. dechex($n)). ';';
+// eof
+}
+
+function hl_prot($p, $c=null){
+// check URL scheme
+global $C;
+$b = $a = '';
+if($c == null){$c = 'style'; $b = $p[1]; $a = $p[3]; $p = trim($p[2]);}
+$c = isset($C['schemes'][$c]) ? $C['schemes'][$c] : $C['schemes']['*'];
+if(isset($c['*']) or !strcspn($p, '#?;')){return "{$b}{$p}{$a}";} // All ok, frag, query, param
+if(preg_match('`^([a-z\d\-+.&#; ]+?)(:|&#(58|x3a);|%3a|\\\\0{0,4}3a).`i', $p, $m) && !isset($c[strtolower($m[1])])){ // Denied prot
+ return "{$b}denied:{$p}{$a}";
+}
+if($C['abs_url']){
+ if($C['abs_url'] == -1 && strpos($p, $C['base_url']) === 0){ // Make url rel
+ $p = substr($p, strlen($C['base_url']));
+ }elseif(empty($m[1])){ // Make URL abs
+ if(substr($p, 0, 2) == '//'){$p = substr($C['base_url'], 0, strpos($C['base_url'], ':')+1). $p;}
+ elseif($p[0] == '/'){$p = preg_replace('`(^.+?://[^/]+)(.*)`', '$1', $C['base_url']). $p;}
+ elseif(strcspn($p, './')){$p = $C['base_url']. $p;}
+ else{
+ preg_match('`^([a-zA-Z\d\-+.]+://[^/]+)(.*)`', $C['base_url'], $m);
+ $p = preg_replace('`(?<=/)\./`', '', $m[2]. $p);
+ while(preg_match('`(?<=/)([^/]{3,}|[^/.]+?|\.[^/.]|[^/.]\.)/\.\./`', $p)){
+ $p = preg_replace('`(?<=/)([^/]{3,}|[^/.]+?|\.[^/.]|[^/.]\.)/\.\./`', '', $p);
+ }
+ $p = $m[1]. $p;
+ }
+ }
+}
+return "{$b}{$p}{$a}";
+// eof
+}
+
+function hl_regex($p){
+// ?regex
+if(empty($p)){return 0;}
+if($t = ini_get('track_errors')){$o = isset($php_errormsg) ? $php_errormsg : null;}
+else{ini_set('track_errors', 1);}
+unset($php_errormsg);
+if(($d = ini_get('display_errors'))){ini_set('display_errors', 0);}
+preg_match($p, '');
+if($d){ini_set('display_errors', 1);}
+$r = isset($php_errormsg) ? 0 : 1;
+if($t){$php_errormsg = isset($o) ? $o : null;}
+else{ini_set('track_errors', 0);}
+return $r;
+// eof
+}
+
+function hl_spec($t){
+// final $spec
+$s = array();
+$t = str_replace(array("\t", "\r", "\n", ' '), '', preg_replace('/"(?>(`.|[^"])*)"/sme', 'substr(str_replace(array(";", "|", "~", " ", ",", "/", "(", ")", \'`"\'), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\""), "$0"), 1, -1)', trim($t)));
+for($i = count(($t = explode(';', $t))); --$i>=0;){
+ $w = $t[$i];
+ if(empty($w) or ($e = strpos($w, '=')) === false or !strlen(($a = substr($w, $e+1)))){continue;}
+ $y = $n = array();
+ foreach(explode(',', $a) as $v){
+ if(!preg_match('`^([a-z:\-\*]+)(?:\((.*?)\))?`i', $v, $m)){continue;}
+ if(($x = strtolower($m[1])) == '-*'){$n['*'] = 1; continue;}
+ if($x[0] == '-'){$n[substr($x, 1)] = 1; continue;}
+ if(!isset($m[2])){$y[$x] = 1; continue;}
+ foreach(explode('/', $m[2]) as $m){
+ if(empty($m) or ($p = strpos($m, '=')) == 0 or $p < 5){$y[$x] = 1; continue;}
+ $y[$x][strtolower(substr($m, 0, $p))] = str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08"), array(";", "|", "~", " ", ",", "/", "(", ")"), substr($m, $p+1));
+ }
+ if(isset($y[$x]['match']) && !hl_regex($y[$x]['match'])){unset($y[$x]['match']);}
+ if(isset($y[$x]['nomatch']) && !hl_regex($y[$x]['nomatch'])){unset($y[$x]['nomatch']);}
+ }
+ if(!count($y) && !count($n)){continue;}
+ foreach(explode(',', substr($w, 0, $e)) as $v){
+ if(!strlen(($v = strtolower($v)))){continue;}
+ if(count($y)){$s[$v] = $y;}
+ if(count($n)){$s[$v]['n'] = $n;}
+ }
+}
+return $s;
+// eof
+}
+
+function hl_tag($t){
+// tag/attribute handler
+global $C;
+$t = $t[0];
+// invalid < >
+if($t == '< '){return '&lt; ';}
+if($t == '>'){return '&gt;';}
+if(!preg_match('`^<(/?)([a-zA-Z][a-zA-Z1-6]*)([^>]*?)\s?>$`m', $t, $m)){
+ return str_replace(array('<', '>'), array('&lt;', '&gt;'), $t);
+}elseif(!isset($C['elements'][($e = strtolower($m[2]))])){
+ return (($C['keep_bad']%2) ? str_replace(array('<', '>'), array('&lt;', '&gt;'), $t) : '');
+}
+// attr string
+$a = str_replace(array("\xad", "\n", "\r", "\t"), ' ', trim($m[3]));
+if(strpos($a, '&') !== false){
+ str_replace(array('&#xad;', '&#173;', '&shy;'), ' ', $a);
+}
+// tag transform
+static $eD = array('applet'=>1, 'center'=>1, 'dir'=>1, 'embed'=>1, 'font'=>1, 'isindex'=>1, 'menu'=>1, 's'=>1, 'strike'=>1, 'u'=>1); // Deprecated
+if($C['make_tag_strict'] && isset($eD[$e])){
+ $trt = hl_tag2($e, $a, $C['make_tag_strict']);
+ if(!$e){return (($C['keep_bad']%2) ? str_replace(array('<', '>'), array('&lt;', '&gt;'), $t) : '');}
+}
+// close tag
+static $eE = array('area'=>1, 'br'=>1, 'col'=>1, 'embed'=>1, 'hr'=>1, 'img'=>1, 'input'=>1, 'isindex'=>1, 'param'=>1); // Empty ele
+if(!empty($m[1])){
+ return (!isset($eE[$e]) ? "</$e>" : (($C['keep_bad'])%2 ? str_replace(array('<', '>'), array('&lt;', '&gt;'), $t) : ''));
+}
+
+// open tag & attr
+static $aN = array('abbr'=>array('td'=>1, 'th'=>1), 'accept-charset'=>array('form'=>1), 'accept'=>array('form'=>1, 'input'=>1), 'accesskey'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'label'=>1, 'legend'=>1, 'textarea'=>1), 'action'=>array('form'=>1), 'align'=>array('caption'=>1, 'embed'=>1, 'applet'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'object'=>1, 'legend'=>1, 'table'=>1, 'hr'=>1, 'div'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'p'=>1, 'col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'alt'=>array('applet'=>1, 'area'=>1, 'img'=>1, 'input'=>1), 'archive'=>array('applet'=>1, 'object'=>1), 'axis'=>array('td'=>1, 'th'=>1), 'bgcolor'=>array('embed'=>1, 'table'=>1, 'tr'=>1, 'td'=>1, 'th'=>1), 'border'=>array('table'=>1, 'img'=>1, 'object'=>1), 'bordercolor'=>array('table'=>1, 'td'=>1, 'tr'=>1), 'cellpadding'=>array('table'=>1), 'cellspacing'=>array('table'=>1), 'char'=>array('col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'charoff'=>array('col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'charset'=>array('a'=>1, 'script'=>1), 'checked'=>array('input'=>1), 'cite'=>array('blockquote'=>1, 'q'=>1, 'del'=>1, 'ins'=>1), 'classid'=>array('object'=>1), 'clear'=>array('br'=>1), 'code'=>array('applet'=>1), 'codebase'=>array('object'=>1, 'applet'=>1), 'codetype'=>array('object'=>1), 'color'=>array('font'=>1), 'cols'=>array('textarea'=>1), 'colspan'=>array('td'=>1, 'th'=>1), 'compact'=>array('dir'=>1, 'dl'=>1, 'menu'=>1, 'ol'=>1, 'ul'=>1), 'coords'=>array('area'=>1, 'a'=>1), 'data'=>array('object'=>1), 'datetime'=>array('del'=>1, 'ins'=>1), 'declare'=>array('object'=>1), 'defer'=>array('script'=>1), 'dir'=>array('bdo'=>1), 'disabled'=>array('button'=>1, 'input'=>1, 'optgroup'=>1, 'option'=>1, 'select'=>1, 'textarea'=>1), 'enctype'=>array('form'=>1), 'face'=>array('font'=>1), 'for'=>array('label'=>1), 'frame'=>array('table'=>1), 'frameborder'=>array('iframe'=>1), 'headers'=>array('td'=>1, 'th'=>1), 'height'=>array('embed'=>1, 'iframe'=>1, 'td'=>1, 'th'=>1, 'img'=>1, 'object'=>1, 'applet'=>1), 'href'=>array('a'=>1, 'area'=>1), 'hreflang'=>array('a'=>1), 'hspace'=>array('applet'=>1, 'img'=>1, 'object'=>1), 'ismap'=>array('img'=>1, 'input'=>1), 'label'=>array('option'=>1, 'optgroup'=>1), 'language'=>array('script'=>1), 'longdesc'=>array('img'=>1, 'iframe'=>1), 'marginheight'=>array('iframe'=>1), 'marginwidth'=>array('iframe'=>1), 'maxlength'=>array('input'=>1), 'method'=>array('form'=>1), 'model'=>array('embed'=>1), 'multiple'=>array('select'=>1), 'name'=>array('button'=>1, 'embed'=>1, 'textarea'=>1, 'applet'=>1, 'select'=>1, 'form'=>1, 'iframe'=>1, 'img'=>1, 'a'=>1, 'input'=>1, 'object'=>1, 'map'=>1, 'param'=>1), 'nohref'=>array('area'=>1), 'noshade'=>array('hr'=>1), 'nowrap'=>array('td'=>1, 'th'=>1), 'object'=>array('applet'=>1), 'onblur'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'label'=>1, 'select'=>1, 'textarea'=>1), 'onchange'=>array('input'=>1, 'select'=>1, 'textarea'=>1), 'onfocus'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'label'=>1, 'select'=>1, 'textarea'=>1), 'onreset'=>array('form'=>1), 'onselect'=>array('input'=>1, 'textarea'=>1), 'onsubmit'=>array('form'=>1), 'pluginspage'=>array('embed'=>1), 'pluginurl'=>array('embed'=>1), 'prompt'=>array('isindex'=>1), 'readonly'=>array('textarea'=>1, 'input'=>1), 'rel'=>array('a'=>1), 'rev'=>array('a'=>1), 'rows'=>array('textarea'=>1), 'rowspan'=>array('td'=>1, 'th'=>1), 'rules'=>array('table'=>1), 'scope'=>array('td'=>1, 'th'=>1), 'scrolling'=>array('iframe'=>1), 'selected'=>array('option'=>1), 'shape'=>array('area'=>1, 'a'=>1), 'size'=>array('hr'=>1, 'font'=>1, 'input'=>1, 'select'=>1), 'span'=>array('col'=>1, 'colgroup'=>1), 'src'=>array('embed'=>1, 'script'=>1, 'input'=>1, 'iframe'=>1, 'img'=>1), 'standby'=>array('object'=>1), 'start'=>array('ol'=>1), 'summary'=>array('table'=>1), 'tabindex'=>array('a'=>1, 'area'=>1, 'button'=>1, 'input'=>1, 'object'=>1, 'select'=>1, 'textarea'=>1), 'target'=>array('a'=>1, 'area'=>1, 'form'=>1), 'type'=>array('a'=>1, 'embed'=>1, 'object'=>1, 'param'=>1, 'script'=>1, 'input'=>1, 'li'=>1, 'ol'=>1, 'ul'=>1, 'button'=>1), 'usemap'=>array('img'=>1, 'input'=>1, 'object'=>1), 'valign'=>array('col'=>1, 'colgroup'=>1, 'tbody'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1), 'value'=>array('input'=>1, 'option'=>1, 'param'=>1, 'button'=>1, 'li'=>1), 'valuetype'=>array('param'=>1), 'vspace'=>array('applet'=>1, 'img'=>1, 'object'=>1), 'width'=>array('embed'=>1, 'hr'=>1, 'iframe'=>1, 'img'=>1, 'object'=>1, 'table'=>1, 'td'=>1, 'th'=>1, 'applet'=>1, 'col'=>1, 'colgroup'=>1, 'pre'=>1), 'wmode'=>array('embed'=>1), 'xml:space'=>array('pre'=>1, 'script'=>1, 'style'=>1)); // Ele-specific
+static $aNE = array('checked'=>1, 'compact'=>1, 'declare'=>1, 'defer'=>1, 'disabled'=>1, 'ismap'=>1, 'multiple'=>1, 'nohref'=>1, 'noresize'=>1, 'noshade'=>1, 'nowrap'=>1, 'readonly'=>1, 'selected'=>1); // Empty
+static $aNP = array('action'=>1, 'cite'=>1, 'classid'=>1, 'codebase'=>1, 'data'=>1, 'href'=>1, 'longdesc'=>1, 'model'=>1, 'pluginspage'=>1, 'pluginurl'=>1, 'usemap'=>1); // Need scheme check; excludes style, on* & src
+static $aNU = array('class'=>array('param'=>1, 'script'=>1), 'dir'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'iframe'=>1, 'param'=>1, 'script'=>1), 'id'=>array('script'=>1), 'lang'=>array('applet'=>1, 'br'=>1, 'iframe'=>1, 'param'=>1, 'script'=>1), 'xml:lang'=>array('applet'=>1, 'br'=>1, 'iframe'=>1, 'param'=>1, 'script'=>1), 'onclick'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'ondblclick'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onkeydown'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onkeypress'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onkeyup'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmousedown'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmousemove'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmouseout'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmouseover'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'onmouseup'=>array('applet'=>1, 'bdo'=>1, 'br'=>1, 'font'=>1, 'iframe'=>1, 'isindex'=>1, 'param'=>1, 'script'=>1), 'style'=>array('param'=>1, 'script'=>1), 'title'=>array('param'=>1, 'script'=>1)); // Univ & exceptions
+
+if($C['lc_std_val']){
+ // predef attr vals for $eAL & $aNE ele
+ static $aNL = array('all'=>1, 'baseline'=>1, 'bottom'=>1, 'button'=>1, 'center'=>1, 'char'=>1, 'checkbox'=>1, 'circle'=>1, 'col'=>1, 'colgroup'=>1, 'cols'=>1, 'data'=>1, 'default'=>1, 'file'=>1, 'get'=>1, 'groups'=>1, 'hidden'=>1, 'image'=>1, 'justify'=>1, 'left'=>1, 'ltr'=>1, 'middle'=>1, 'none'=>1, 'object'=>1, 'password'=>1, 'poly'=>1, 'post'=>1, 'preserve'=>1, 'radio'=>1, 'rect'=>1, 'ref'=>1, 'reset'=>1, 'right'=>1, 'row'=>1, 'rowgroup'=>1, 'rows'=>1, 'rtl'=>1, 'submit'=>1, 'text'=>1, 'top'=>1);
+ static $eAL = array('a'=>1, 'area'=>1, 'bdo'=>1, 'button'=>1, 'col'=>1, 'form'=>1, 'img'=>1, 'input'=>1, 'object'=>1, 'optgroup'=>1, 'option'=>1, 'param'=>1, 'script'=>1, 'select'=>1, 'table'=>1, 'td'=>1, 'tfoot'=>1, 'th'=>1, 'thead'=>1, 'tr'=>1, 'xml:space'=>1);
+ $lcase = isset($eAL[$e]) ? 1 : 0;
+}
+
+$depTr = 0;
+if($C['no_deprecated_attr']){
+ // dep attr:applicable ele
+ static $aND = array('align'=>array('caption'=>1, 'div'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'img'=>1, 'input'=>1, 'legend'=>1, 'object'=>1, 'p'=>1, 'table'=>1), 'bgcolor'=>array('table'=>1, 'td'=>1, 'th'=>1, 'tr'=>1), 'border'=>array('img'=>1, 'object'=>1), 'bordercolor'=>array('table'=>1, 'td'=>1, 'tr'=>1), 'clear'=>array('br'=>1), 'compact'=>array('dl'=>1, 'ol'=>1, 'ul'=>1), 'height'=>array('td'=>1, 'th'=>1), 'hspace'=>array('img'=>1, 'object'=>1), 'language'=>array('script'=>1), 'name'=>array('a'=>1, 'form'=>1, 'iframe'=>1, 'img'=>1, 'map'=>1), 'noshade'=>array('hr'=>1), 'nowrap'=>array('td'=>1, 'th'=>1), 'size'=>array('hr'=>1), 'start'=>array('ol'=>1), 'type'=>array('li'=>1, 'ol'=>1, 'ul'=>1), 'value'=>array('li'=>1), 'vspace'=>array('img'=>1, 'object'=>1), 'width'=>array('hr'=>1, 'pre'=>1, 'td'=>1, 'th'=>1));
+ static $eAD = array('a'=>1, 'br'=>1, 'caption'=>1, 'div'=>1, 'dl'=>1, 'form'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'hr'=>1, 'iframe'=>1, 'img'=>1, 'input'=>1, 'legend'=>1, 'li'=>1, 'map'=>1, 'object'=>1, 'ol'=>1, 'p'=>1, 'pre'=>1, 'script'=>1, 'table'=>1, 'td'=>1, 'th'=>1, 'tr'=>1, 'ul'=>1);
+ $depTr = isset($eAD[$e]) ? 1 : 0;
+}
+
+// attr name-vals
+if(strpos($a, "\x01") !== false){$a = preg_replace('`\x01[^\x01]*\x01`', '', $a);} // No comment/CDATA sec
+$mode = 0; $a = trim($a, ' /'); $aA = array();
+while(strlen($a)){
+ $w = 0;
+ switch($mode){
+ case 0: // Name
+ if(preg_match('`^[a-zA-Z][\-a-zA-Z:]+`', $a, $m)){
+ $nm = strtolower($m[0]);
+ $w = $mode = 1; $a = ltrim(substr_replace($a, '', 0, strlen($m[0])));
+ }
+ break; case 1:
+ if($a[0] == '='){ // =
+ $w = 1; $mode = 2; $a = ltrim($a, '= ');
+ }else{ // No val
+ $w = 1; $mode = 0; $a = ltrim($a);
+ $aA[$nm] = '';
+ }
+ break; case 2: // Val
+ if(preg_match('`^"[^"]*"`', $a, $m) or preg_match("`^'[^']*'`", $a, $m) or preg_match("`^\s*[^\s\"']+`", $a, $m)){
+ $m = $m[0]; $w = 1; $mode = 0; $a = ltrim(substr_replace($a, '', 0, strlen($m)));
+ $aA[$nm] = trim(($m[0] == '"' or $m[0] == '\'') ? substr($m, 1, -1) : $m);
+ }
+ break;
+ }
+ if($w == 0){ // Parse errs, deal with space, " & '
+ $a = preg_replace('`^(?:"[^"]*("|$)|\'[^\']*(\'|$)|\S)*\s*`', '', $a);
+ $mode = 0;
+ }
+}
+if($mode == 1){$aA[$nm] = '';}
+
+// clean attrs
+global $S;
+$rl = isset($S[$e]) ? $S[$e] : array();
+$a = array(); $nfr = 0;
+foreach($aA as $k=>$v){
+ if(((isset($C['deny_attribute']['*']) ? isset($C['deny_attribute'][$k]) : !isset($C['deny_attribute'][$k])) or isset($rl[$k])) && ((!isset($rl['n'][$k]) && !isset($rl['n']['*'])) or isset($rl[$k])) && (isset($aN[$k][$e]) or (isset($aNU[$k]) && !isset($aNU[$k][$e])))){
+ if(isset($aNE[$k])){$v = $k;}
+ elseif(!empty($lcase) && (($e != 'button' or $e != 'input') or $k == 'type')){ // Rather loose but ?not cause issues
+ $v = (isset($aNL[($v2 = strtolower($v))])) ? $v2 : $v;
+ }
+ if($k == 'style' && !$C['style_pass']){
+ if(false !== strpos($v, '&#')){
+ static $sC = array('&#x20;'=>' ', '&#32;'=>' ', '&#x45;'=>'e', '&#69;'=>'e', '&#x65;'=>'e', '&#101;'=>'e', '&#x58;'=>'x', '&#88;'=>'x', '&#x78;'=>'x', '&#120;'=>'x', '&#x50;'=>'p', '&#80;'=>'p', '&#x70;'=>'p', '&#112;'=>'p', '&#x53;'=>'s', '&#83;'=>'s', '&#x73;'=>'s', '&#115;'=>'s', '&#x49;'=>'i', '&#73;'=>'i', '&#x69;'=>'i', '&#105;'=>'i', '&#x4f;'=>'o', '&#79;'=>'o', '&#x6f;'=>'o', '&#111;'=>'o', '&#x4e;'=>'n', '&#78;'=>'n', '&#x6e;'=>'n', '&#110;'=>'n', '&#x55;'=>'u', '&#85;'=>'u', '&#x75;'=>'u', '&#117;'=>'u', '&#x52;'=>'r', '&#82;'=>'r', '&#x72;'=>'r', '&#114;'=>'r', '&#x4c;'=>'l', '&#76;'=>'l', '&#x6c;'=>'l', '&#108;'=>'l', '&#x28;'=>'(', '&#40;'=>'(', '&#x29;'=>')', '&#41;'=>')', '&#x20;'=>':', '&#32;'=>':', '&#x22;'=>'"', '&#34;'=>'"', '&#x27;'=>"'", '&#39;'=>"'", '&#x2f;'=>'/', '&#47;'=>'/', '&#x2a;'=>'*', '&#42;'=>'*', '&#x5c;'=>'\\', '&#92;'=>'\\');
+ $v = strtr($v, $sC);
+ }
+ $v = preg_replace_callback('`(url(?:\()(?: )*(?:\'|"|&(?:quot|apos);)?)(.+)((?:\'|"|&(?:quot|apos);)?(?: )*(?:\)))`iS', 'hl_prot', $v);
+ $v = !$C['css_expression'] ? preg_replace('`expression`i', ' ', preg_replace('`\\\\\S|(/|(%2f))(\*|(%2a))`i', ' ', $v)) : $v;
+ }elseif(isset($aNP[$k]) or strpos($k, 'src') !== false or $k[0] == 'o'){
+ $v = hl_prot($v, $k);
+ if($k == 'href'){ // X-spam
+ if($C['anti_mail_spam'] && strpos($v, 'mailto:') === 0){
+ $v = str_replace('@', htmlspecialchars($C['anti_mail_spam']), $v);
+ }elseif($C['anti_link_spam']){
+ $r1 = $C['anti_link_spam'][1];
+ if(!empty($r1) && preg_match($r1, $v)){continue;}
+ $r0 = $C['anti_link_spam'][0];
+ if(!empty($r0) && preg_match($r0, $v)){
+ if(isset($a['rel'])){
+ if(!preg_match('`\bnofollow\b`i', $a['rel'])){$a['rel'] .= ' nofollow';}
+ }elseif(isset($aA['rel'])){
+ if(!preg_match('`\bnofollow\b`i', $aA['rel'])){$nfr = 1;}
+ }else{$a['rel'] = 'nofollow';}
+ }
+ }
+ }
+ }
+ if(isset($rl[$k]) && is_array($rl[$k]) && ($v = hl_attrval($v, $rl[$k])) === 0){continue;}
+ $a[$k] = str_replace('"', '&quot;', $v);
+ }
+}
+if($nfr){$a['rel'] = isset($a['rel']) ? $a['rel']. ' nofollow' : 'nofollow';}
+
+// rqd attr
+static $eAR = array('area'=>array('alt'=>'area'), 'bdo'=>array('dir'=>'ltr'), 'form'=>array('action'=>''), 'img'=>array('src'=>'', 'alt'=>'image'), 'map'=>array('name'=>''), 'optgroup'=>array('label'=>''), 'param'=>array('name'=>''), 'script'=>array('type'=>'text/javascript'), 'textarea'=>array('rows'=>'10', 'cols'=>'50'));
+if(isset($eAR[$e])){
+ foreach($eAR[$e] as $k=>$v){
+ if(!isset($a[$k])){$a[$k] = isset($v[0]) ? $v : $k;}
+ }
+}
+
+// depr attrs
+if($depTr){
+ $c = array();
+ foreach($a as $k=>$v){
+ if($k == 'style' or !isset($aND[$k][$e])){continue;}
+ if($k == 'align'){
+ unset($a['align']);
+ if($e == 'img' && ($v == 'left' or $v == 'right')){$c[] = 'float: '. $v;}
+ elseif(($e == 'div' or $e == 'table') && $v == 'center'){$c[] = 'margin: auto';}
+ else{$c[] = 'text-align: '. $v;}
+ }elseif($k == 'bgcolor'){
+ unset($a['bgcolor']);
+ $c[] = 'background-color: '. $v;
+ }elseif($k == 'border'){
+ unset($a['border']); $c[] = "border: {$v}px";
+ }elseif($k == 'bordercolor'){
+ unset($a['bordercolor']); $c[] = 'border-color: '. $v;
+ }elseif($k == 'clear'){
+ unset($a['clear']); $c[] = 'clear: '. ($v != 'all' ? $v : 'both');
+ }elseif($k == 'compact'){
+ unset($a['compact']); $c[] = 'font-size: 85%';
+ }elseif($k == 'height' or $k == 'width'){
+ unset($a[$k]); $c[] = $k. ': '. ($v[0] != '*' ? $v. (ctype_digit($v) ? 'px' : '') : 'auto');
+ }elseif($k == 'hspace'){
+ unset($a['hspace']); $c[] = "margin-left: {$v}px; margin-right: {$v}px";
+ }elseif($k == 'language' && !isset($a['type'])){
+ unset($a['language']);
+ $a['type'] = 'text/'. strtolower($v);
+ }elseif($k == 'name'){
+ if($C['no_deprecated_attr'] == 2 or ($e != 'a' && $e != 'map')){unset($a['name']);}
+ if(!isset($a['id']) && preg_match('`[a-zA-Z][a-zA-Z\d.:_\-]*`', $v)){$a['id'] = $v;}
+ }elseif($k == 'noshade'){
+ unset($a['noshade']); $c[] = 'border-style: none; border: 0; background-color: gray; color: gray';
+ }elseif($k == 'nowrap'){
+ unset($a['nowrap']); $c[] = 'white-space: nowrap';
+ }elseif($k == 'size'){
+ unset($a['size']); $c[] = 'size: '. $v. 'px';
+ }elseif($k == 'start' or $k == 'value'){
+ unset($a[$k]);
+ }elseif($k == 'type'){
+ unset($a['type']);
+ static $ol_type = array('i'=>'lower-roman', 'I'=>'upper-roman', 'a'=>'lower-latin', 'A'=>'upper-latin', '1'=>'decimal');
+ $c[] = 'list-style-type: '. (isset($ol_type[$v]) ? $ol_type[$v] : 'decimal');
+ }elseif($k == 'vspace'){
+ unset($a['vspace']); $c[] = "margin-top: {$v}px; margin-bottom: {$v}px";
+ }
+ }
+ if(count($c)){
+ $c = implode('; ', $c);
+ $a['style'] = isset($a['style']) ? rtrim($a['style'], ' ;'). '; '. $c. ';': $c. ';';
+ }
+}
+// unique ID
+if($C['unique_ids'] && isset($a['id'])){
+ if(!preg_match('`^[A-Za-z][A-Za-z0-9_\-.:]*$`', ($id = $a['id'])) or (isset($GLOBALS['hl_Ids'][$id]) && $C['unique_ids'] == 1)){unset($a['id']);
+ }else{
+ while(isset($GLOBALS['hl_Ids'][$id])){$id = $C['unique_ids']. $id;}
+ $GLOBALS['hl_Ids'][($a['id'] = $id)] = 1;
+ }
+}
+// xml:lang
+if($C['xml:lang'] && isset($a['lang'])){
+ $a['xml:lang'] = isset($a['xml:lang']) ? $a['xml:lang'] : $a['lang'];
+ if($C['xml:lang'] == 2){unset($a['lang']);}
+}
+// for transformed tag
+if(!empty($trt)){
+ $a['style'] = isset($a['style']) ? rtrim($a['style'], ' ;'). '; '. $trt : $trt;
+}
+// return with empty ele /
+if(empty($C['hook_tag'])){
+ $aA = '';
+ foreach($a as $k=>$v){$aA .= " {$k}=\"{$v}\"";}
+ return "<{$e}{$aA}". (isset($eE[$e]) ? ' /' : ''). '>';
+}
+else{return $C['hook_tag']($e, $a);}
+// eof
+}
+
+function hl_tag2(&$e, &$a, $t=1){
+// transform tag
+if($e == 'center'){$e = 'div'; return 'text-align: center;';}
+if($e == 'dir' or $e == 'menu'){$e = 'ul'; return '';}
+if($e == 's' or $e == 'strike'){$e = 'span'; return 'text-decoration: line-through;';}
+if($e == 'u'){$e = 'span'; return 'text-decoration: underline;';}
+static $fs = array('0'=>'xx-small', '1'=>'xx-small', '2'=>'small', '3'=>'medium', '4'=>'large', '5'=>'x-large', '6'=>'xx-large', '7'=>'300%', '-1'=>'smaller', '-2'=>'60%', '+1'=>'larger', '+2'=>'150%', '+3'=>'200%', '+4'=>'300%');
+if($e == 'font'){
+ $a2 = '';
+ if(preg_match('`face\s*=\s*(\'|")([^=]+?)\\1`i', $a, $m) or preg_match('`face\s*=\s*([^"])(\S+)`i', $a, $m)){
+ $a2 .= ' font-family: '. str_replace('"', '\'', trim($m[2])). ';';
+ }
+ if(preg_match('`color\s*=\s*(\'|")?(.+?)(\\1|\s|$)`i', $a, $m)){
+ $a2 .= ' color: '. trim($m[2]). ';';
+ }
+ if(preg_match('`size\s*=\s*(\'|")?(.+?)(\\1|\s|$)`i', $a, $m) && isset($fs[($m = trim($m[2]))])){
+ $a2 .= ' font-size: '. $fs[$m]. ';';
+ }
+ $e = 'span'; return ltrim($a2);
+}
+if($t == 2){$e = 0; return 0;}
+return '';
+// eof
+}
+
+function hl_tidy($t, $w, $p){
+// Tidy/compact HTM
+if(strpos(' pre,script,textarea', "$p,")){return $t;}
+$t = str_replace(' </', '</', preg_replace(array('`(<\w[^>]*(?<!/)>)\s+`', '`\s+`', '`(<\w[^>]*(?<!/)>) `'), array(' $1', ' ', '$1'), preg_replace_callback(array('`(<(!\[CDATA\[))(.+?)(\]\]>)`sm', '`(<(!--))(.+?)(-->)`sm', '`(<(pre|script|textarea).*?>)(.+?)(</\2>)`sm'), create_function('$m', 'return $m[1]. str_replace(array("<", ">", "\n", "\r", "\t", " "), array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), $m[3]). $m[4];'), $t)));
+if(($w = strtolower($w)) == -1){
+ return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array('<', '>', "\n", "\r", "\t", ' '), $t);
+}
+$s = strpos(" $w", 't') ? "\t" : ' ';
+$s = preg_match('`\d`', $w, $m) ? str_repeat($s, $m[0]) : str_repeat($s, ($s == "\t" ? 1 : 2));
+$n = preg_match('`[ts]([1-9])`', $w, $m) ? $m[1] : 0;
+$a = array('br'=>1);
+$b = array('button'=>1, 'input'=>1, 'option'=>1);
+$c = array('caption'=>1, 'dd'=>1, 'dt'=>1, 'h1'=>1, 'h2'=>1, 'h3'=>1, 'h4'=>1, 'h5'=>1, 'h6'=>1, 'isindex'=>1, 'label'=>1, 'legend'=>1, 'li'=>1, 'object'=>1, 'p'=>1, 'pre'=>1, 'td'=>1, 'textarea'=>1, 'th'=>1);
+$d = array('address'=>1, 'blockquote'=>1, 'center'=>1, 'colgroup'=>1, 'dir'=>1, 'div'=>1, 'dl'=>1, 'fieldset'=>1, 'form'=>1, 'hr'=>1, 'iframe'=>1, 'map'=>1, 'menu'=>1, 'noscript'=>1, 'ol'=>1, 'optgroup'=>1, 'rbc'=>1, 'rtc'=>1, 'ruby'=>1, 'script'=>1, 'select'=>1, 'table'=>1, 'tfoot'=>1, 'thead'=>1, 'tr'=>1, 'ul'=>1);
+ob_start();
+if(isset($d[$p])){echo str_repeat($s, ++$n);}
+$t = explode('<', $t);
+echo ltrim(array_shift($t));
+for($i=-1, $j=count($t); ++$i<$j;){
+ $r = ''; list($e, $r) = explode('>', $t[$i]);
+ $x = $e[0] == '/' ? 0 : (substr($e, -1) == '/' ? 1 : ($e[0] != '!' ? 2 : -1));
+ $y = !$x ? ltrim($e, '/') : ($x > 0 ? substr($e, 0, strcspn($e, ' ')) : 0);
+ $e = "<$e>";
+ if(isset($d[$y])){
+ if(!$x){echo "\n", str_repeat($s, --$n), "$e\n", str_repeat($s, $n);}
+ else{echo "\n", str_repeat($s, $n), "$e\n", str_repeat($s, ($x != 1 ? ++$n : $n));}
+ echo ltrim($r); continue;
+ }
+ $f = "\n". str_repeat($s, $n);
+ if(isset($c[$y])){
+ if(!$x){echo $e, $f, ltrim($r);}
+ else{echo $f, $e, $r;}
+ }elseif(isset($b[$y])){echo $f, $e, $r;
+ }elseif(isset($a[$y])){echo $e, $f, ltrim($r);
+ }elseif(!$y){echo $f, $e, $f, ltrim($r);
+ }else{echo $e, $r;}
+}
+$t = preg_replace('`[\n]\s*?[\n]+`', "\n", ob_get_contents());
+ob_end_clean();
+if(($l = strpos(" $w", 'r') ? (strpos(" $w", 'n') ? "\r\n" : "\r") : 0)){
+ $t = str_replace("\n", $l, $t);
+}
+return str_replace(array("\x01", "\x02", "\x03", "\x04", "\x05", "\x07"), array('<', '>', "\n", "\r", "\t", ' '), $t);
+// eof
+}
+
+function hl_version(){
+// rel
+return '1.1.8.1';
+// eof
+}
+
+function kses($t, $h, $p=array('http', 'https', 'ftp', 'news', 'nntp', 'telnet', 'gopher', 'mailto')){
+// kses compat
+foreach($h as $k=>$v){
+ $h[$k]['n']['*'] = 1;
+}
+$C['cdata'] = $C['comment'] = $C['make_tag_strict'] = $C['no_deprecated_attr'] = $C['unique_ids'] = 0;
+$C['keep_bad'] = 1;
+$C['elements'] = count($h) ? strtolower(implode(',', array_keys($h))) : '-*';
+$C['hook'] = 'kses_hook';
+$C['schemes'] = '*:'. implode(',', $p);
+return htmLawed($t, $C, $h);
+// eof
+}
+
+function kses_hook($t, &$C, &$S){
+// kses compat
+return $t;
+// eof
+} \ No newline at end of file
diff --git a/extlib/htmLawed/htmLawedTest.php b/extlib/htmLawed/htmLawedTest.php
new file mode 100644
index 000000000..776828699
--- /dev/null
+++ b/extlib/htmLawed/htmLawedTest.php
@@ -0,0 +1,592 @@
+<?php
+
+/*
+htmLawedTest.php, 16 July 2009
+htmLawed 1.1.8.1, 16 July 2009
+Copyright Santosh Patnaik
+GPL v3 license
+A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed
+
+Test htmLawed; user provides text input; input and processed input are shown as highlighted code and rendered HTML; also shown are execution time and peak memory usage
+*/
+
+// config
+$_errs = 0; // display PHP errors
+$_limit = 8000; // input character limit
+
+// more config
+$_hlimit = 1000; // input character limit for showing hexdumps
+$_hilite = 1; // 0 turns off slow Javascript-based code-highlighting, e.g., if $_limit is high
+$_w3c_validate = 1; // 1 to show buttons to send input/output to w3c validator
+$_sid = 'sid'; // session name; alphanum.
+$_slife = 30; // session life in min.
+
+// errors
+error_reporting(E_ALL | (defined('E_STRICT') ? E_STRICT : 1));
+ini_set('display_errors', $_errs);
+
+// session
+session_name($_sid);
+session_cache_limiter('private');
+session_cache_expire($_slife);
+ini_set('session.gc_maxlifetime', $_slife * 60);
+ini_set('session.use_only_cookies', 1);
+ini_set('session.cookie_lifetime', 0);
+session_start();
+if(!isset($_SESSION['token'])){
+ $_SESSION['token'] = md5(uniqid(rand(), 1));
+}
+
+// slashes
+if(get_magic_quotes_gpc()){
+ foreach($_POST as $k => $v){
+ $_POST[$k] = stripslashes($v);
+ }
+ ini_set('magic_quotes_gpc', 0);
+}
+set_magic_quotes_runtime(0);
+
+$_POST['enc'] = (isset($_POST['enc']) and preg_match('`^[-\w]+$`', $_POST['enc'])) ? $_POST['enc'] : 'utf-8';
+
+// token for anti-CSRF
+if(count($_POST)){
+ if((empty($_GET['pre']) and ((!empty($_POST['token']) and !empty($_SESSION['token']) and $_POST['token'] != $_SESSION['token']) or empty($_POST[$_sid]) or $_POST[$_sid] != session_id() or empty($_COOKIE[$_sid]) or $_COOKIE[$_sid] != session_id())) or ($_POST[$_sid] != session_id())){
+ $_POST = array('enc'=>'utf-8');
+ }
+}
+if(empty($_GET['pre'])){
+ $_SESSION['token'] = md5(uniqid(rand(), 1));
+ $token = $_SESSION['token'];
+ session_regenerate_id(1);
+}
+
+// compress
+if(function_exists('gzencode') && isset($_SERVER['HTTP_ACCEPT_ENCODING']) && preg_match('`gzip|deflate`i', $_SERVER['HTTP_ACCEPT_ENCODING']) && !ini_get('zlib.output_compression')){
+ ob_start('ob_gzhandler');
+}
+
+// HTM for unprocessed
+if(isset($_POST['inputH'])){
+ echo '<html><head><title>htmLawed test: HTML view of unprocessed input</title></head><body style="margin:0; padding: 0;"><p style="background-color: black; color: white; padding: 2px;">&nbsp; Rendering of unprocessed input without an HTML doctype or charset declaration &nbsp; &nbsp; <small><a style="color: white; text-decoration: none;" href="1" onclick="javascript:window.close(this); return false;">close window</a> | <a style="color: white; text-decoration: none;" href="htmLawedTest.php" onclick="javascript: window.open(\'htmLawedTest.php\', \'hlmain\'); window.close(this); return false;">htmLawed test page</a></small></p><div>', $_POST['inputH'], '</div></body></html>';
+ exit;
+}
+
+// main
+$_POST['text'] = isset($_POST['text']) ? $_POST['text'] : 'text to process; < '. $_limit. ' characters'. ($_hlimit ? ' (for binary hexdump view, < '. $_hlimit. ')' : '');
+$do = (!empty($_POST[$_sid]) && isset($_POST['text'][0]) && !isset($_POST['text'][$_limit])) ? 1 : 0;
+$limit_exceeded = isset($_POST['text'][$_limit]) ? 1 : 0;
+$pre_mem = memory_get_usage();
+$validation = (!empty($_POST[$_sid]) and isset($_POST['w3c_validate'][0])) ? 1 : 0;
+include './htmLawed.php';
+
+function format($t){
+ $t = "\n". str_replace(array("\t", "\r\n", "\r", '&', '<', '>', "\n"), array(' ', "\n", "\n", '&amp;', '&lt;', '&gt;', "<span class=\"newline\">&#172;</span><br />\n"), $t);
+ return str_replace(array('<br />', "\n ", ' '), array("\n<br />\n", "\n&nbsp;", ' &nbsp;'), $t);
+}
+
+function hexdump($d){
+// Mainly by Aidan Lister <aidan@php.net>, Peter Waller <iridum@php.net>
+ $hexi = '';
+ $ascii = '';
+ ob_start();
+ echo '<pre>';
+ $offset = 0;
+ $len = strlen($d);
+ for($i=$j=0; $i<$len; $i++)
+ {
+ // Convert to hexidecimal
+ $hexi .= sprintf("%02X ", ord($d[$i]));
+ // Replace non-viewable bytes with '.'
+ if(ord($d[$i]) >= 32){
+ $ascii .= htmlspecialchars($d[$i]);
+ }else{
+ $ascii .= '.';
+ }
+ // Add extra column spacing
+ if($j == 7){
+ $hexi .= ' ';
+ $ascii .= ' ';
+ }
+ // Add row
+ if(++$j == 16 || $i == $len-1){
+ // Join the hexi / ascii output
+ echo sprintf("%04X %-49s %s", $offset, $hexi, $ascii);
+ // Reset vars
+ $hexi = $ascii = '';
+ $offset += 16;
+ $j = 0;
+ // Add newline
+ if ($i !== $len-1){
+ echo "\n";
+ }
+ }
+ }
+ echo '</pre>';
+ $o = ob_get_contents();
+ ob_end_clean();
+ return $o;
+}
+?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en" xml:lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=<?php echo htmlspecialchars($_POST['enc']); ?>" />
+<meta name="description" content="htmLawed <?php echo hl_version();?> test page" />
+<style type="text/css"><!--/*--><![CDATA[/*><!--*/
+a, a.resizer{text-decoration:none;}
+a:hover, a.resizer:hover{color:red;}
+a.resizer{color:green; float:right;}
+body{background-color:#efefef;}
+body, button, div, html, input, p{font-size:13px; font-family:'Lucida grande', Verdana, Arial, Helvetica, sans-serif;}
+button, input{font-size: 85%;}
+div.help{border-top: 1px dotted gray; margin-top: 15px; padding-top: 15px; color:#999999;}
+#inputC, #inputD, #inputF, #inputR, #outputD, #outputF, #outputH, #outputR, #settingF{display:block;}
+#inputC, #settingF{background-color:white; border:1px gray solid; padding:3px;}
+#inputC li{margin: 0; padding: 0;}
+#inputC ul{margin: 0; padding: 0; margin-left: 14px;}
+#inputC input{margin: 0; margin-left: 2px; margin-right: 2px; padding: 1px; vertical-align: middle;}
+#inputD{overflow:auto; background-color:#ffff99; border:1px #cc9966 solid; padding:3px;}
+#inputR{overflow:auto; background-color:#ffffcc; border:1px #ffcc99 solid; padding:3px;}
+#inputC, #settingF, #inputD, #inputR, #outputD, #outputR, textarea{font-size:100%; font-family:'Bitstream vera sans mono', 'courier new', 'courier', monospace;}
+#outputD{overflow:auto; background-color: #99ffcc; border:1px #66cc99 solid; padding:3px;}
+#outputH{overflow:auto; background-color:white; padding:3px; border:1px #dcdcdc solid;}
+#outputR{overflow:auto; background-color: #ccffcc; border:1px #99cc99 solid; padding:3px;}
+span.cmtcdata{color: orange;}
+span.ctag{color:red;}
+span.ent{border-bottom:1px dotted #999999;}
+span.etag{color:purple;}
+span.help{color:#999999;}
+span.newline{color:#dcdcdc;}
+span.notice{color:green;}
+span.otag{color:blue;}
+#topmost{margin:auto; width:98%;}
+/*]]>*/--></style>
+<script type="text/javascript"><!--//--><![CDATA[//><!--
+window.name = 'hlmain';
+function hl(i){
+ <?php if(!$_hilite){echo 'return;'; }?>
+ var e = document.getElementById(i);
+ if(!e){return;}
+ run(e, '</[a-z1-6]+>', 'ctag');
+ run(e, '<[a-z]+(?:[^>]*)/>', 'etag');
+ run(e, '<[a-z1-6]+(?:[^>]*)>', 'otag');
+ run(e, '&[#a-z0-9]+;', 'ent');
+ run(e, '<!(?:(?:--(?:.|\n)*?--)|(?:\\[CDATA\\[(?:.|\n)*?\\]\\]))>', 'cmtcdata');
+}
+function sndProc(){
+ var f = document.getElementById('testform');
+ if(!f){return;}
+ var e = document.createElement('input');
+ e.type = 'hidden';
+ e.name = '<?php echo htmlspecialchars($_sid); ?>';
+ e.id = '<?php echo htmlspecialchars($_sid); ?>';
+ e.value = readCookie('<?php echo htmlspecialchars($_sid); ?>');
+ f.appendChild(e);
+ f.submit();
+}
+function readCookie(n){
+ var ne = n + '=';
+ var ca = document.cookie.split(';');
+ for(var i=0;i < ca.length;i++){
+ var c = ca[i];
+ while(c.charAt(0)==' '){
+ c = c.substring(1,c.length);
+ }
+ if(c.indexOf(ne) == 0){
+ return c.substring(ne.length,c.length);
+ }
+ }
+ return null;
+}
+function run(e, q, c){
+ var q = new RegExp(q);
+ if(e.firstChild == null){
+ var m = q.exec(e.data);
+ if(m){
+ var v = m[0];
+ var k2 = e.splitText(m.index);
+ var k3 = k2.splitText(v.length);
+ var s = e.ownerDocument.createElement('span');
+ e.parentNode.replaceChild(s, k2);
+ s.className = c; s.appendChild(k2);
+ }
+ }
+ for(var k = e.firstChild; k != null; k = k.nextSibling){
+ if(k.nodeType == 3){
+ var m = q.exec(k.data);
+ if(m){
+ var v = m[0];
+ var k2 = k.splitText(m.index);
+ var k3 = k2.splitText(v.length);
+ var s = k.ownerDocument.createElement('span');
+ k.parentNode.replaceChild(s, k2);
+ s.className = c; s.appendChild(k2);
+ }
+ }
+ else if(c == 'ent' && k.nodeType == 1){
+ var d = k.firstChild;
+ if(d){
+ var m = q.exec(d.data);
+ if(m){
+ var v = m[0];
+ var d2 = d.splitText(m.index);
+ var d3 = d2.splitText(v.length);
+ var s = d.ownerDocument.createElement('span');
+ d.parentNode.replaceChild(s, d2);
+ s.className = c; s.appendChild(d2);
+ }
+ }
+ }
+ }
+}
+function toggle(i){
+ var e = document.getElementById(i);
+ if(!e){return;}
+ if(e.style){
+ var a = e.style.display;
+ if(a == 'block'){e.style.display = 'none'; return;}
+ if(a == 'none'){e.style.display = 'block';}
+ else{e.style.display = 'none';}
+ return;
+ }
+ var a = e.visibility;
+ if(a == 'hidden'){e.visibility = 'show'; return;}
+ if(a == 'show'){e.visibility = 'hidden';}
+}
+function sndUnproc(){
+ var i = document.getElementById('text');
+ if(!i){return;}
+ i = i.value;
+ i = i.replace(/>/g, '&gt;');
+ i = i.replace(/</g, '&lt;');
+ i = i.replace(/"/g, '&quot;');
+ var w = window.open('htmLawedTest.php?pre=1', 'hlprehtm');
+ var f = document.createElement('form');
+ f.enctype = 'application/x-www-form-urlencoded';
+ f.method = 'post';
+ f.acceptCharset = '<?php echo htmlspecialchars($_POST['enc']); ?>';
+ if(f.style){f.style.display = 'none';}
+ else{f.visibility = 'hidden';}
+ f.innerHTML = '<p style="display:none;"><input style="display:none;" type="hidden" name="token" id="token" value="<?php echo $token; ?>" /><input style="display:none;" type="hidden" name="<?php echo htmlspecialchars($_sid); ?>" id="<?php echo htmlspecialchars($_sid); ?>" value="' + readCookie('<?php echo htmlspecialchars($_sid); ?>') + '" /><input style="display:none;" type="hidden" name="inputH" id="inputH" value="'+ i+ '" /></p>';
+ f.action = 'htmLawedTest.php?pre=1';
+ f.target = 'hlprehtm';
+ f.method = 'post';
+ var b = document.getElementsByTagName('body')[0];
+ b.appendChild(f);
+ f.submit();
+ w.focus;
+}
+function sndValidn(id, type){
+ var i = document.getElementById(id);
+ if(!i){return;}
+ i = i.value;
+ i = i.replace(/>/g, '&gt;');
+ i = i.replace(/</g, '&lt;');
+ i = i.replace(/"/g, '&quot;');
+ var w = window.open('http://validator.w3.org/check', 'validate'+id+type);
+ var f = document.createElement('form');
+ f.enctype = 'application/x-www-form-urlencoded';
+ f.method = 'post';
+ f.acceptCharset = '<?php echo htmlspecialchars($_POST['enc']); ?>';
+ if(f.style){f.style.display = 'none';}
+ else{f.visibility = 'hidden';}
+ f.innerHTML = '<p style="display:none;"><input style="display:none;" type="hidden" name="fragment" id="fragment" value="'+ i+ '" /><input style="display:none;" type="hidden" name="prefill" id="prefill" value="1" /><input style="display:none;" type="hidden" name="prefill_doctype" id="prefill_doctype" value="'+ type+ '" /><input style="display:none;" type="hidden" name="group" id="group" value="1" /><input type="hidden" name="ss" id="ss" value="1" /></p>';
+ f.action = 'http://validator.w3.org/check';
+ f.target = 'validate'+id+type;
+ var b = document.getElementsByTagName('body')[0];
+ b.appendChild(f);
+ f.submit();
+ w.focus;
+}
+tRs = {
+ formEl: null,
+ resizeClass: 'textarea',
+ adEv: function(t,ev,fn){
+ if(typeof document.addEventListener != 'undefined'){
+ t.addEventListener(ev,fn,false);
+ }else{
+ t.attachEvent('on' + ev, fn);
+ }
+ },
+ rmEv: function(t,ev,fn){
+ if(typeof document.removeEventListener != 'undefined'){
+ t.removeEventListener(ev,fn,false);
+ }else
+ {
+ t.detachEvent('on' + ev, fn);
+ }
+ },
+ adBtn: function(){
+ var textareas = document.getElementsByTagName('textarea');
+ for(var i = 0; i < textareas.length; i++){
+ var txtclass=textareas[i].className;
+ if(txtclass.substring(0,tRs.resizeClass.length)==tRs.resizeClass ||
+ txtclass.substring(txtclass.length -tRs.resizeClass.length)==tRs.resizeClass){
+ var a = document.createElement('a');
+ a.appendChild(document.createTextNode("\u2195"));
+ a.style.cursor = 'n-resize';
+ a.className= 'resizer';
+ a.title = 'click-drag to resize'
+ tRs.adEv(a, 'mousedown', tRs.initResize);
+ textareas[i].parentNode.appendChild(a);
+ }
+ }
+ },
+ initResize: function(event){
+ if(typeof event == 'undefined'){
+ event = window.event;
+ }
+ if(event.srcElement){
+ var target = event.srcElement.previousSibling;
+ }else{
+ var target = event.target.previousSibling;
+ }
+ if(target.nodeName.toLowerCase() == 'textarea' || (target.nodeName.toLowerCase() == 'input' && target.type == 'text')){
+ tRs.formEl = target;
+ tRs.formEl.startHeight = tRs.formEl.clientHeight;
+ tRs.formEl.startY = event.clientY;
+ tRs.adEv(document, 'mousemove', tRs.resize);
+ tRs.adEv(document, 'mouseup', tRs.stopResize);
+ tRs.formEl.parentNode.style.cursor = 'n-resize';
+ tRs.formEl.style.cursor = 'n-resize';
+ try{
+ event.preventDefault();
+ }catch(e){
+ }
+ }
+ },
+ resize: function(event){
+ if(typeof event == 'undefined'){
+ event = window.event;
+ }
+ if(tRs.formEl.nodeName.toLowerCase() == 'textarea'){
+ tRs.formEl.style.height = event.clientY - tRs.formEl.startY + tRs.formEl.startHeight + 'px';
+ }
+ },
+ stopResize: function(event){
+ tRs.rmEv(document, 'mousedown', tRs.initResize);
+ tRs.rmEv(document, 'mousemove', tRs.resize);
+ tRs.formEl.style.cursor = 'text';
+ tRs.formEl.parentNode.style.cursor = 'auto';
+ return false;
+ }
+};
+tRs.adEv(window, 'load', tRs.adBtn);
+//--><!]]></script>
+<title>htmLawed (<?php echo hl_version();?>) test</title>
+</head>
+<body>
+<div id="topmost">
+
+<h5 style="float: left; display: inline; margin-top: 0; margin-bottom: 5px;"><a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/index.php" title="htmLawed home">HTM<big><big>L</big></big>AWED</a> <?php echo hl_version();?> <a href="htmLawedTest.php" title="test home">TEST</a></h5>
+<span style="float: right;" class="help"><a href="htmLawed_README.htm"><span class="notice">htm</span></a> / <a href="htmLawed_README.txt"><span class="notice">txt</span></a> documentation</span><br style="clear:both;" />
+
+<a href="htmLawedTest.php" title="[toggle visibility] type or copy-paste" onclick="javascript:toggle('inputF'); return false;"><span class="notice">Input &raquo;</span> <span class="help" title="limit lower with multibyte characters<?php echo (($_hlimit < $_limit && $_hlimit)? '; limit is '. $_hlimit. ' for viewing binaries' : ''); ?>"><small>(max. <?php echo htmlspecialchars($_limit);?> chars)</small></span></a>
+
+<form id="testform" name="testform" action="htmLawedTest.php" method="post" accept-charset="<?php echo htmlspecialchars($_POST['enc']); ?>" style="padding:0; margin: 0; display:inline;">
+
+<div id="inputF" style="display: block;">
+
+<input type="hidden" name="token" id="token" value="<?php echo $token; ?>" />
+<div><textarea id="text" class="textarea" name="text" rows="5" cols="100" style="width: 100%;"><?php echo htmlspecialchars($_POST['text']);?></textarea></div>
+<input type="submit" id="submitF" name="submitF" value="Process" style="float:left;" title="filter using htmLawed" onclick="javascript: sndProc(); return false;" onkeypress="javascript: sndProc(); return false;" />
+
+<?php
+if($do){
+ if($validation){
+ echo '<input type="hidden" value="1" name="w3c_validate" id="w3c_validate" />';
+ }
+?>
+
+<button type="button" title="rendered as web-page without a doctype or charset declaration" style="float: right;" onclick="javascript: sndUnproc(); return false;" onkeypress="javascript: sndUnproc(); return false;">View unprocessed</button>
+<button type="button" onclick="javascript:document.getElementById('text').focus();document.getElementById('text').select()" title="select all to copy" style="float:right;">Select all</button>
+
+<?php
+if($_w3c_validate && $validation){
+?>
+
+<button type="button" title="HTML 4.01 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text', 'html401'); return false;" onkeypress="javascript: sndValidn('text', 'html401'); return false;">Check HTML</button>
+<button type="button" title="XHTML 1.1 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text', 'xhtml110'); return false;" onkeypress="javascript: sndValidn('text', 'xhtml110'); return false;">Check XHTML</button>
+
+<?php
+ }
+}
+else{
+ if($_w3c_validate){
+ echo '<span style="float: right;" class="help" title="for direct submission of input or output code to W3C validator for (X)HTML validation"><span style="font-size: 85%;">&nbsp;Validator tools: </span><input type="checkbox" value="1" name="w3c_validate" id="w3c_validate" style="vertical-align: middle;"', ($validation ? ' checked="checked"' : ''), ' /></span>';
+ }
+}
+?>
+
+<span style="float:right;" class="help"><span style="font-size: 85%;">Encoding: </span><input type="text" size="8" id="enc" name="enc" style="vertical-align: middle;" value="<?php echo htmlspecialchars($_POST['enc']); ?>" title="IANA-recognized name of the input character-set; can be multiple ;- or space-separated values; may not work in some browsers" /></span>
+
+</div>
+<br style="clear:both;" />
+
+<?php
+if($limit_exceeded){
+ echo '<br /><strong>Input text is too long!</strong><br />';
+}
+?>
+
+<br />
+
+<a href="htmLawedTest.php" title="[toggle visibility] htmLawed configuration" onclick="javascript:toggle('inputC'); return false;"><span class="notice">Settings &raquo;</span></a>
+
+<div id="inputC" style="display: none;">
+<table summary="none">
+<tr>
+<td><span class="help" title="$config argument">Config:</span></td>
+<td><ul>
+
+<?php
+$cfg = array(
+'abs_url'=>array('3', '0', 'absolute/relative URL conversion', '-1'),
+'and_mark'=>array('2', '0', 'mark original <em>&amp;</em> chars', '0', 'd'=>1), // 'd' to disable
+'anti_link_spam'=>array('1', '0', 'modify <em>href</em> values as an anti-link spam measure', '0', array(array('30', '1', '', 'regex for extra <em>rel</em>'), array('30', '2', '', 'regex for no <em>href</em>'))),
+'anti_mail_spam'=>array('1', '0', 'replace <em>@</em> in <em>mailto:</em> URLs', '0', '8', 'NO@SPAM', 'replacement'),
+'balance'=>array('2', '1', 'fix nestings and balance tags', '0'),
+'base_url'=>array('', '', 'base URL', '25'),
+'cdata'=>array('4', 'nil', 'allow <em>CDATA</em> sections', 'nil'),
+'clean_ms_char'=>array('3', '0', 'replace bad characters introduced by Microsoft apps. like <em>Word</em>', '0'),
+'comment'=>array('4', 'nil', 'allow HTML comments', 'nil'),
+'css_expression'=>array('2', 'nil', 'allow dynamic expressions in CSS style properties', 'nil'),
+'deny_attribute'=>array('1', '0', 'denied attributes', '0', '50', '', 'these'),
+'elements'=>array('', '', 'allowed elements', '50'),
+'hexdec_entity'=>array('3', '1', 'convert hexadecimal numeric entities to decimal ones, or vice versa', '0'),
+'hook'=>array('', '', 'name of hook function', '25'),
+'hook_tag'=>array('', '', 'name of custom function to further check attribute values', '25'),
+'keep_bad'=>array('7', '6', 'keep, or remove <em>bad</em> tag content', '0'),
+'lc_std_val'=>array('2', '1', 'lower-case std. attribute values like <em>radio</em>', '0'),
+'make_tag_strict'=>array('3', 'nil', 'transform deprecated elements', 'nil'),
+'named_entity'=>array('2', '1', 'allow named entities, or convert numeric ones', '0'),
+'no_deprecated_attr'=>array('3', '1', 'allow deprecated attributes, or transform them', '0'),
+'parent'=>array('', 'div', 'name of parent element', '25'),
+'safe'=>array('2', '0', 'for most <em>safe</em> HTML', '0'),
+'schemes'=>array('', 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https', 'allowed URL protocols', '50'),
+'show_setting'=>array('', 'htmLawed_setting', 'variable name to record <em>finalized</em> htmLawed settings', '25', 'd'=>1),
+'style_pass'=>array('2', 'nil', 'do not look at <em>style</em> attribute values', 'nil'),
+'tidy'=>array('3', '0', 'beautify/compact', '-1', '8', '1t1', 'format'),
+'unique_ids'=>array('2', '1', 'unique <em>id</em> values', '0', '8', 'my_', 'prefix'),
+'valid_xhtml'=>array('2', 'nil', 'auto-set various parameters for most valid XHTML', 'nil'),
+'xml:lang'=>array('3', 'nil', 'auto-add <em>xml:lang</em> attribute', '0'),
+);
+foreach($cfg as $k=>$v){
+ echo '<li>', $k, ': ';
+ if(!empty($v[0])){ // input radio
+ $j = $v[3];
+ for($i = $j-1; ++$i < $v[0]+$v[3];++$j){
+ echo '<input type="radio" name="h', $k, '" value="', $i, '"', (!isset($_POST['h'. $k]) ? ($v[1] == $i ? ' checked="checked"' : '') : ($_POST['h'. $k] == $i ? ' checked="checked"' : '')), (isset($v['d']) ? ' disabled="disabled"' : ''), ' />', $i, ' ';
+ }
+ if($v[1] == 'nil'){
+ echo '<input type="radio" name="h', $k, '" value="nil"', ((!isset($_POST['h'. $k]) or $_POST['h'. $k] == 'nil') ? ' checked="checked"' : ''), (isset($v['d']) ? ' disabled="disabled"' : ''), ' />not set ';
+ }
+ if(!empty($v[4])){ // + input text box
+ echo '<input type="radio" name="h', $k, '" value="', $j, '"', (((isset($_POST['h'. $k]) && $_POST['h'. $k] == $j) or (!isset($_POST['h'. $k]) && $j == $v[1])) ? ' checked="checked"' : ''), (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';
+ if(!is_array($v[4])){
+ echo $v[6], ': <input type="text" size="', $v[4], '" name="h', $k. $j, '" value="', htmlspecialchars(isset($_POST['h'. $k. $j][0]) ? $_POST['h'. $k. $j] : $v[5]), '"', (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';
+ }
+ else{
+ foreach($v[4] as $z){
+ echo ' ', $z[3], ': <input type="text" size="', $z[0], '" name="h', $k. $j. $z[1], '" value="', htmlspecialchars(isset($_POST['h'. $k. $j. $z[1]][0]) ? $_POST['h'. $k. $j. $z[1]] : $z[2]), '"', (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';
+ }
+ }
+ }
+ }
+ elseif(ctype_digit($v[3])){ // input text
+ echo '<input type="text" size="', $v[3], '" name="h', $k, '" value="', htmlspecialchars(isset($_POST['h'. $k][0]) ? $_POST['h'. $k] : $v[1]), '"', (isset($v['d']) ? ' disabled="disabled"' : ''), ' />';
+ }
+ else{} // text-area
+ echo ' <span class="help">', $v[2], '</span></li>';
+}
+echo '</ul></td></tr><tr><td><span style="vertical-align: top;" class="help" title="$spec argument: element-specific attribute rules">Spec:</span></td><td><textarea name="spec" id="spec" cols="70" rows="3" style="width:80%;">', htmlspecialchars((isset($_POST['spec']) ? $_POST['spec'] : '')), '</textarea></td></tr></table>';
+?>
+
+</div>
+</form>
+
+<?php
+if($do){
+ $cfg = array();
+ foreach($_POST as $k=>$v){
+ if($k[0] == 'h' && $v != 'nil'){
+ $cfg[substr($k, 1)] = $v;
+ }
+ }
+
+ if($cfg['anti_link_spam'] && (!empty($cfg['anti_link_spam11']) or !empty($cfg['anti_link_spam12']))){
+ $cfg['anti_link_spam'] = array($cfg['anti_link_spam11'], $cfg['anti_link_spam12']);
+ }
+ unset($cfg['anti_link_spam11'], $cfg['anti_link_spam12']);
+ if($cfg['anti_mail_spam'] == 1){
+ $cfg['anti_mail_spam'] = isset($cfg['anti_mail_spam1'][0]) ? $cfg['anti_mail_spam1'] : 0;
+ }
+ unset($cfg['anti_mail_spam11']);
+ if($cfg['deny_attribute'] == 1){
+ $cfg['deny_attribute'] = isset($cfg['deny_attribute1'][0]) ? $cfg['deny_attribute1'] : 0;
+ }
+ unset($cfg['deny_attribute1']);
+ if($cfg['tidy'] == 2){
+ $cfg['tidy'] = isset($cfg['tidy2'][0]) ? $cfg['tidy2'] : 0;
+ }
+ unset($cfg['tidy2']);
+ if($cfg['unique_ids'] == 2){
+ $cfg['unique_ids'] = isset($cfg['unique_ids2'][0]) ? $cfg['unique_ids2'] : 1;
+ }
+ unset($cfg['unique_ids2']);
+ unset($cfg['and_mark']); // disabling and_mark
+
+ $cfg['show_setting'] = 'hlcfg';
+ $st = microtime();
+ $out = htmLawed($_POST['text'], $cfg, str_replace(array('$', '{'), '', $_POST['spec']));
+ $et = microtime();
+ echo '<br /><a href="htmLawedTest.php" title="[toggle visibility] syntax-highlighted" onclick="javascript:toggle(\'inputR\'); return false;"><span class="notice">Input code &raquo;</span></a> <span class="help" title="tags estimated as half of total &gt; and &lt; chars; values may be inaccurate for non-ASCII text"><small><big>', strlen($_POST['text']), '</big> chars, ~<big>', round((substr_count($_POST['text'], '>') + substr_count($_POST['text'], '<'))/2), '</big> tags</small>&nbsp;</span><div id="inputR" style="display: none;">', format($_POST['text']), '</div><script type="text/javascript">hl(\'inputR\');</script>', (!isset($_POST['text'][$_hlimit]) ? ' <a href="htmLawedTest.php" title="[toggle visibility] hexdump; non-viewable characters like line-returns are shown as dots" onclick="javascript:toggle(\'inputD\'); return false;"><span class="notice">Input binary &raquo;&nbsp;</span></a><div id="inputD" style="display: none;">'. hexdump($_POST['text']). '</div>' : ''), ' <a href="htmLawedTest.php" title="[toggle visibility] finalized internal settings as interpreted by htmLawed; for developers" onclick="javascript:toggle(\'settingF\'); return false;"><span class="notice">Finalized internal settings &raquo;&nbsp;</span></a> <div id="settingF" style="display: none;">', str_replace(array(' ', "\t", ' '), array(' ', '&nbsp; ', '&nbsp; '), nl2br(htmlspecialchars(print_r($GLOBALS['hlcfg']['config'], true)))), '</div><script type="text/javascript">hl(\'settingF\');</script>', '<br /><a href="htmLawedTest.php" title="[toggle visibility] suitable for copy-paste" onclick="javascript:toggle(\'outputF\'); return false;"><span class="notice">Output &raquo;</span></a> <span class="help" title="approx., server-specific value excluding the \'include()\' call"><small>htmLawed processing time <big>', number_format(((substr($et,0,9)) + (substr($et,-10)) - (substr($st,0,9)) - (substr($st,-10))),4), '</big> s</small></span>', (($mem = memory_get_peak_usage()) !== false ? '<span class="help"><small>, peak memory usage <big>'. round(($mem-$pre_mem)/1048576, 2). '</big> <small>MB</small>' : ''), '</small></span><div id="outputF" style="display: block;"><div><textarea id="text2" class="textarea" name="text2" rows="5" cols="100" style="width: 100%;">', htmlspecialchars($out), '</textarea></div><button type="button" onclick="javascript:document.getElementById(\'text2\').focus();document.getElementById(\'text2\').select()" title="select all to copy" style="float:right;">Select all</button>';
+ if($_w3c_validate && $validation)
+ {
+?>
+
+<button type="button" title="HTML 4.01 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text2', 'html401'); return false;" onkeypress="javascript: sndValidn('text2', 'html401'); return false;">Check HTML</button>
+<button type="button" title="XHTML 1.1 W3C online validation" style="float: right;" onclick="javascript: sndValidn('text2', 'xhtml110'); return false;" onkeypress="javascript: sndValidn('text2', 'xhtml110'); return false;">Check XHTML</button>
+
+<?php
+ }
+ echo '</div><br /><a href="htmLawedTest.php" title="[toggle visibility] syntax-highlighted" onclick="javascript:toggle(\'outputR\'); return false;"><span class="notice">Output code &raquo;</span></a><div id="outputR" style="display: block;">', format($out), '</div><script type="text/javascript">hl(\'outputR\');</script>', (!isset($_POST['text'][$_hlimit]) ? '<br /><a href="htmLawedTest.php" title="[toggle visibility] hexdump; non-viewable characters like line-returns are shown as dots" onclick="javascript:toggle(\'outputD\'); return false;"><span class="notice">Output binary &raquo;</span></a><div id="outputD" style="display: none;">'. hexdump($out). '</div>' : ''), '<br /><a href="htmLawedTest.php" title="[toggle visibility] XHTML 1 Transitional doctype" onclick="javascript:toggle(\'outputH\'); return false;"><span class="notice">Output rendered &raquo;</span></a><div id="outputH" style="display: block;">', $out, '</div>';
+}
+else{
+?>
+
+<br />
+
+<div class="help">Use with a Javascript- and cookie-enabled, relatively new version of a common browser. <em>Submitted input will also be HTML-rendered (XHTML 1) after htmLawed-filtering.</em>
+
+<?php echo (file_exists('./htmLawed_TESTCASE.txt') ? '<br /><br />You can use text from <a href="htmLawed_TESTCASE.txt"><span class="notice">this collection of test-cases</span></a> in the input. Set the character encoding of the browser to Unicode/utf-8 before copying.' : ''); ?>
+
+<br /><br />For anti-XSS tests, try the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/htmLawedSafeModeTest.php"><span class="notice">special test-page</span></a> or see <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/rsnake/RSnakeXSSTest.htm"><span class="notice">these results</span></a>.
+
+<br /><br /><small>Change <em>Encoding</em> to reflect the character encoding of the input text. Even then, it may not work or some characters may not display properly because of variable browser support and because of the form interface. Developers can write some PHP code to capture the filtered input to a file if this is important.
+<br /><br />Refer to the htmLawed documentation (<a href="htmLawed_README.htm"><span class="notice">htm</span></a>/<a href="htmLawed_README.txt"><span class="notice">txt</span></a>) for details about <em>Settings</em>, and htmLawed's behavior and limitations. For <em>Settings</em>, incorrectly-specified values like regular expressions are silently ignored. One or more settings form-fields may have been disabled. Some characters are not allowed in the <em>Spec</em> field.
+
+
+<br /><br />Hovering the mouse over some of the text can provide additional information in some browsers.</small>
+
+<?php
+if($_w3c_validate){
+?>
+
+<small><br /><br />Because of character-encoding issues, the W3C validator (anyway not perfect) may reject validation requests or invalidate otherwise-valid code, esp. if text was copy-pasted in the input box. Local applications like the <em>HTML Validator</em> Firefox browser add-on may be useful in such cases.</small>
+
+<?php
+}
+?>
+
+</div>
+
+<?php
+}
+?>
+
+</div>
+</body>
+</html> \ No newline at end of file
diff --git a/extlib/htmLawed/htmLawed_README.htm b/extlib/htmLawed/htmLawed_README.htm
new file mode 100644
index 000000000..e560e2eb2
--- /dev/null
+++ b/extlib/htmLawed/htmLawed_README.htm
@@ -0,0 +1,1979 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta http-equiv="Content-Language" content="en" />
+<meta name="description" content="htmLawed PHP software is a free, open-source, customizable HTML input purifier and filter - htmLawed_README.txt - presented with rTxt2htm, a PHP Labware utility" />
+<meta name="keywords" content="htmLawed, HTM, HTML, HTML Tidy, converter, filter, formatter, purifier, sanitizer, XSS, input, PHP, software, code, script, security, cross-site scripting, hack, sanitize, remove, standards, tags, attributes, elements, htmLawed_README.txt, rTxt2htm, PHP Labware" />
+<style type="text/css" media="all">
+<!--/*--><![CDATA[/*><!--*/
+a {text-decoration:none; color: blue;}
+a:hover {color: red;}
+a:visited {color: blue;}
+body {margin: 0; padding: 0;}
+body, div, html, p {font-family: Georgia, 'Times new roman', Times;}
+code.code {font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}
+div.comment {padding: 5px; color: #999999; font-size: 80%;}
+div.comment a {color: #6699cc;}
+div#body {width: 70%; margin: 5px; padding: 5px;} /* holds non-toc content */
+div#toc {position: fixed; top: 5px; left: 73%; z-index: 2; margin-top: 5px; margin-left: 5px; border: 1px solid gray; padding: 5px; background-color: #ededed; width: 23%; overflow: auto; max-height:94%; font-size: 90%;} /* holds content table (toc) */
+div#top {font-size: 14px; margin: 5px; padding: 5px;} /* holds all content */
+div.monospace {overflow: auto; font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}
+div.sub-section {padding-left: 15px;}
+div.sub-sub-section {padding-left: 30px;}
+h1 {font-size: 22px; margin-top: 5px; margin-bottom: 5px;}
+h2 {font-size: 20px; float: left; margin-top: 15px; margin-bottom: 5px;}
+h3 {font-size: 18px; float: left; margin-top: 15px; margin-bottom: 5px;}
+h4 {font-size: 16px; float: left; margin-top: 15px; margin-bottom: 5px;}
+hr {margin-top: 15px; margin-bottom: 5px;}
+input, textarea {font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}
+p.subtle {color: gray; padding: 0; padding-top: 10px; margin: 0;}
+p.subtle a, p.subtle a:visited {color: #6699cc;}
+span.item-no {color: black;}
+span.subtle {color: gray; margin: 0; padding:0;}
+span.subtle a, span.subtle a:visited {color: #6699cc;}
+span.term {font-family: 'Bitstream vera sans mono', 'Courier New', 'Courier', monospace;}
+span.toc-item {color: black;}
+span.totop {float: right; margin-top: 15px; margin-bottom: 5px;}
+span.totop a, span.totop a:visited {color: #6699cc;}
+@media screen { /* fixes for old IE */
+ * html, * html body {overflow-y: auto!important; height: 100%; margin: 0; padding: 0;}
+ * html div#body {height: 100%; overflow-y: auto; position: relative;}
+ * html div#toc {position: absolute;}
+}
+/*]]>*/-->
+</style>
+<title>htmLawed documentation | htmLawed PHP software is a free, open-source, customizable HTML input purifier and filter</title>
+</head>
+<body>
+<div id="top">
+<h1><a id="peak" name="peak"></a>htmLawed documentation</h1>
+
+<div id="toc"><span class="toc-item"><a href="#s1"><span class="item-no">1</span>&#160; About htmLawed</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.1"><span class="item-no">1.1</span>&#160; Example uses</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.2"><span class="item-no">1.2</span>&#160; Features</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.3"><span class="item-no">1.3</span>&#160; History</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.4"><span class="item-no">1.4</span>&#160; License &amp; copyright</a></span><br />
+&#160; <span class="toc-item"><a href="#s1.5"><span class="item-no">1.5</span>&#160; Terms used here</a></span><br />
+<span class="toc-item"><a href="#s2"><span class="item-no">2</span>&#160; Usage</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.1"><span class="item-no">2.1</span>&#160; Simple</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.2"><span class="item-no">2.2</span>&#160; Configuring htmLawed using the <span class="term">$config</span>&#160;parameter</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.3"><span class="item-no">2.3</span>&#160; Extra HTML specifications using the <span class="term">$spec</span>&#160;parameter</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.4"><span class="item-no">2.4</span>&#160; Performance time &amp; memory usage</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.5"><span class="item-no">2.5</span>&#160; Some security risks to keep in mind</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.6"><span class="item-no">2.6</span>&#160; Use without modifying old <span class="term">kses()</span>&#160;code</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.7"><span class="item-no">2.7</span>&#160; Tolerance for ill-written HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.8"><span class="item-no">2.8</span>&#160; Limitations &amp; work-arounds</a></span><br />
+&#160; <span class="toc-item"><a href="#s2.9"><span class="item-no">2.9</span>&#160; Examples</a></span><br />
+<span class="toc-item"><a href="#s3"><span class="item-no">3</span>&#160; Details</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.1"><span class="item-no">3.1</span>&#160; Invalid/dangerous characters</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.2"><span class="item-no">3.2</span>&#160; Character references/entities</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.3"><span class="item-no">3.3</span>&#160; HTML elements</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.1"><span class="item-no">3.3.1</span>&#160; HTML comments and <span class="term">CDATA</span>&#160;sections</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.2"><span class="item-no">3.3.2</span>&#160; Tag-transformation for better XHTML-Strict</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.3"><span class="item-no">3.3.3</span>&#160; Tag balancing and proper nesting</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.4"><span class="item-no">3.3.4</span>&#160; Elements requiring child elements</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.3.5"><span class="item-no">3.3.5</span>&#160; Beautify or compact HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.4"><span class="item-no">3.4</span>&#160; Attributes</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.1"><span class="item-no">3.4.1</span>&#160; Auto-addition of XHTML-required attributes</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.2"><span class="item-no">3.4.2</span>&#160; Duplicate/invalid <span class="term">id</span>&#160;values</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.3"><span class="item-no">3.4.3</span>&#160; URL schemes (protocols) and scripts in attribute values</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.4"><span class="item-no">3.4.4</span>&#160; Absolute &amp; relative URLs</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.5"><span class="item-no">3.4.5</span>&#160; Lower-cased, standard attribute values</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.6"><span class="item-no">3.4.6</span>&#160; Transformation of deprecated attributes</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.7"><span class="item-no">3.4.7</span>&#160; Anti-spam &amp; <span class="term">href</span></a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.8"><span class="item-no">3.4.8</span>&#160; Inline style properties</a></span><br />
+&#160; &#160; <span class="toc-item"><a href="#s3.4.9"><span class="item-no">3.4.9</span>&#160; Hook function for tag content</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.5"><span class="item-no">3.5</span>&#160; Simple configuration directive for most valid XHTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.6"><span class="item-no">3.6</span>&#160; Simple configuration directive for most <em>safe</em>&#160;HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.7"><span class="item-no">3.7</span>&#160; Using a hook function</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.8"><span class="item-no">3.8</span>&#160; Obtaining <em>finalized</em>&#160;parameter values</a></span><br />
+&#160; <span class="toc-item"><a href="#s3.9"><span class="item-no">3.9</span>&#160; Retaining non-HTML tags in input with mixed markup</a></span><br />
+<span class="toc-item"><a href="#s4"><span class="item-no">4</span>&#160; Other</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.1"><span class="item-no">4.1</span>&#160; Support</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.2"><span class="item-no">4.2</span>&#160; Known issues</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.3"><span class="item-no">4.3</span>&#160; Change-log</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.4"><span class="item-no">4.4</span>&#160; Testing</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.5"><span class="item-no">4.5</span>&#160; Upgrade, &amp; old versions</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.6"><span class="item-no">4.6</span>&#160; Comparison with <span class="term">HTMLPurifier</span></a></span><br />
+&#160; <span class="toc-item"><a href="#s4.7"><span class="item-no">4.7</span>&#160; Use through application plug-ins/modules</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.8"><span class="item-no">4.8</span>&#160; Use in non-PHP applications</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.9"><span class="item-no">4.9</span>&#160; Donate</a></span><br />
+&#160; <span class="toc-item"><a href="#s4.10"><span class="item-no">4.10</span>&#160; Acknowledgements</a></span><br />
+<span class="toc-item"><a href="#s5"><span class="item-no">5</span>&#160; Appendices</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.1"><span class="item-no">5.1</span>&#160; Characters discouraged in HTML</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.2"><span class="item-no">5.2</span>&#160; Valid attribute-element combinations</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.3"><span class="item-no">5.3</span>&#160; CSS 2.1 properties accepting URLs</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.4"><span class="item-no">5.4</span>&#160; Microsoft Windows 1252 character replacements</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.5"><span class="item-no">5.5</span>&#160; URL format</a></span><br />
+&#160; <span class="toc-item"><a href="#s5.6"><span class="item-no">5.6</span>&#160; Brief on htmLawed code</a></span></div><!-- ended div toc -->
+
+<div id="body">
+<br />
+<div class="comment">htmLawed_README.txt, 16 July 2009<br />
+htmLawed 1.1.8.1, 16 July 2009 <br />
+Copyright Santosh Patnaik<br />
+GPL v3 license<br />
+A PHP Labware internal utility &#45; <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed</a>&#160;</div>
+<br />
+
+<div class="section"><h2>
+<a name="s1" id="s1"></a><span class="item-no">1</span>&#160; About htmLawed
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed is a highly customizable single-file PHP script to make text secure, and standard- and admin policy-compliant for use in the body of HTML 4, XHTML 1 or 1.1, or generic XML documents. It is thus a configurable input (X)HTML filter, processor, purifier, sanitizer, beautifier, etc., and an alternative to the <a href="http://tidy.sourceforge.net">HTMLTidy</a>&#160;application.<br />
+<br />
+&#160; The <em>lawing in</em>&#160;of input text is needed to ensure that HTML code in the text is standard-compliant, does not introduce security vulnerabilities, and does not break the aesthetics, design or layout of web-pages. htmLawed tries to do this by, for example, making HTML well-formed with balanced and properly nested tags, neutralizing code that may be used for cross-site scripting (<span class="term">XSS</span>) attacks, and allowing only specified HTML elements/tags and attributes.<br />
+
+<div class="sub-section"><h3>
+<a name="s1.1" id="s1.1"></a><span class="item-no">1.1</span>&#160; Example uses
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; * &#160;Filtering of text submitted as comments on blogs to allow only certain HTML elements<br />
+<br />
+&#160; * &#160;Making RSS/Atom newsfeed item-content standard-compliant: often one uses an excerpt from an HTML document for the content, and with unbalanced tags, non-numerical entities, etc., such excerpts may not be XML-compliant<br />
+<br />
+&#160; * &#160;Text processing for stricter XML standard-compliance: e.g., to have lowercased <span class="term">x</span>&#160;in hexadecimal numeric entities becomes necessary if an XHTML document with MathML content needs to be served as <span class="term">application/xml</span><br />
+<br />
+&#160; * &#160;Scraping text or data from web-pages<br />
+<br />
+&#160; * &#160;Pretty-printing HTML code<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.2" id="s1.2"></a><span class="item-no">1.2</span>&#160; Features
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Key: <span class="term">&#42;</span>&#160;security feature, <span class="term">^</span>&#160;standard compliance, <span class="term">~</span>&#160;requires setting right options, <span class="term">&#96;</span>&#160;different from <span class="term">Kses</span><br />
+<br />
+&#160; * &#160;make input more <strong>secure</strong>&#160;and <strong>standard-compliant</strong><br />
+&#160; * &#160;use for HTML 4, XHTML 1.0 or 1.1, or even generic <strong>XML</strong>&#160;documents &#160;^~`<br />
+<br />
+&#160; * &#160;<strong>beautify</strong>&#160;or <strong>compact</strong>&#160;HTML &#160;^~`<br />
+<br />
+&#160; * &#160;<strong>restrict elements</strong>&#160; ^~`<br />
+&#160; * &#160;proper closure of empty elements like <span class="term">img</span>&#160; ^`<br />
+&#160; * &#160;<strong>transform deprecated elements</strong>&#160;like <span class="term">u</span>&#160; ^~`<br />
+&#160; * &#160;HTML <strong>comments</strong>&#160;and <span class="term">CDATA</span>&#160;sections can be permitted &#160;^~`<br />
+&#160; * &#160;elements like <span class="term">script</span>, <span class="term">object</span>&#160;and <span class="term">form</span>&#160;can be permitted &#160;~<br />
+<br />
+&#160; * &#160;<strong>restrict attributes</strong>, including <strong>element-specifically</strong>&#160; ^~`<br />
+&#160; * &#160;remove <strong>invalid attributes</strong>&#160; ^`<br />
+&#160; * &#160;element and attribute names are <strong>lower-cased</strong>&#160; ^<br />
+&#160; * &#160;provide <strong>required attributes</strong>, like <span class="term">alt</span>&#160;for <span class="term">image</span>&#160; ^`<br />
+&#160; * &#160;<strong>transform deprecated attributes</strong>&#160; ^~`<br />
+&#160; * &#160;attributes <strong>declared only once</strong>&#160; ^`<br />
+<br />
+&#160; * &#160;<strong>restrict attribute values</strong>, including <strong>element-specifically</strong>&#160; ^~`<br />
+&#160; * &#160;a value is declared for <em>empty</em>&#160;(<em>minimized</em>) attributes like <span class="term">checked</span>&#160; ^<br />
+&#160; * &#160;check for potentially dangerous attribute values &#160;*~<br />
+&#160; * &#160;ensure <strong>unique</strong>&#160;<span class="term">id</span>&#160;attribute values &#160;^~`<br />
+&#160; * &#160;<strong>double-quote</strong>&#160;attribute values &#160;^<br />
+&#160; * &#160;lower-case <strong>standard attribute values</strong>&#160;like <span class="term">password</span>&#160; ^`<br />
+<br />
+&#160; * &#160;<strong>attribute-specific URL protocol/scheme restriction</strong>&#160; *~`<br />
+&#160; * &#160;disable <strong>dynamic expressions</strong>&#160;in <span class="term">style</span>&#160;values &#160;*~`<br />
+<br />
+&#160; * &#160;neutralize invalid named character entities &#160;^`<br />
+&#160; * &#160;<strong>convert</strong>&#160;hexadecimal numeric entities to decimal ones, or vice versa &#160;^~`<br />
+&#160; * &#160;convert named entities to numeric ones for generic XML use &#160;^~`<br />
+<br />
+&#160; * &#160;remove <strong>null</strong>&#160;characters &#160;*<br />
+&#160; * &#160;neutralize potentially dangerous proprietary Netscape <strong>Javascript entities</strong>&#160; *<br />
+&#160; * &#160;replace potentially dangerous <strong>soft-hyphen</strong>&#160;character in attribute values with spaces &#160;*<br />
+<br />
+&#160; * &#160;remove common <strong>invalid characters</strong>&#160;not allowed in HTML or XML &#160;^`<br />
+&#160; * &#160;replace <strong>characters from Microsoft applications</strong>&#160;like <span class="term">Word</span>&#160;that are discouraged in HTML or XML &#160;^~`<br />
+&#160; * &#160;neutralize entities for characters invalid or discouraged in HTML or XML &#160;^`<br />
+&#160; * &#160;appropriately neutralize <span class="term">&lt;</span>, <span class="term">&amp;</span>, <span class="term">"</span>, and <span class="term">&gt;</span>&#160;characters &#160;^*`<br />
+<br />
+&#160; * &#160;understands improperly spaced tag content (like, spread over more than a line) and properly spaces them &#160;`<br />
+&#160; * &#160;attempts to <strong>balance tags</strong>&#160;for well-formedness &#160;^~`<br />
+&#160; * &#160;understands when <strong>omitable closing tags</strong>&#160;like <span class="term">&lt;/p&gt;</span>&#160;(allowed in HTML 4, transitional, e.g.) are missing &#160;^~`<br />
+&#160; * &#160;attempts to permit only <strong>validly nested tags</strong>&#160; ^~`<br />
+&#160; * &#160;option to <strong>remove or neutralize bad content</strong>&#160;^~`<br />
+&#160; * &#160;attempts to <strong>rectify common errors of plain-text misplacement</strong>&#160;(e.g., directly inside <span class="term">blockquote</span>) ^~`<br />
+<br />
+&#160; * &#160;fast, <strong>non-OOP</strong>&#160;code of ~45 kb incurring peak basal memory usage of ~0.5 MB<br />
+&#160; * &#160;<strong>compatible</strong>&#160;with pre-existing code using <span class="term">Kses</span>&#160;(the filter used by <span class="term">WordPress</span>)<br />
+<br />
+&#160; * &#160;optional <strong>anti-spam</strong>&#160;measures such as addition of <span class="term">rel="nofollow"</span>&#160;and link-disabling &#160;~`<br />
+&#160; * &#160;optionally makes <strong>relative URLs absolute</strong>, and vice versa &#160;~`<br />
+<br />
+&#160; * &#160;optionally mark <span class="term">&amp;</span>&#160;to identify the entities for <span class="term">&amp;</span>, <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;introduced by htmLawed &#160;~`<br />
+<br />
+&#160; * &#160;allows deployment of powerful <strong>hook functions</strong>&#160;to <strong>inject</strong>&#160;HTML, <strong>consolidate</strong>&#160;<span class="term">style</span>&#160;attributes to <span class="term">class</span>, finely check attribute values, etc. &#160;~`<br />
+<br />
+&#160; * &#160;<strong>independent of character encoding</strong>&#160;of input and does not affect it<br />
+<br />
+&#160; * &#160;<strong>tolerance for ill-written HTML</strong>&#160;to a certain degree<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.3" id="s1.3"></a><span class="item-no">1.3</span>&#160; History
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed was developed for use with <span class="term">LabWiki</span>, a wiki software developed at PHP Labware, as a suitable software could not be found. Existing PHP software like <span class="term">Kses</span>&#160;and <span class="term">HTMLPurifier</span>&#160;were deemed inadequate, slow, resource-intensive, or dependent on external applications like <span class="term">HTML Tidy</span>.<br />
+<br />
+&#160; htmLawed started as a modification of Ulf Harnhammar's <span class="term">Kses</span>&#160;(version 0.2.2) software, and is compatible with code that uses <span class="term">Kses</span>; see <a href="#s2.6">section 2.6</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.4" id="s1.4"></a><span class="item-no">1.4</span>&#160; License &amp; copyright
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed is free and open-source software licensed under GPL license version <a href="http://www.gnu.org/licenses/gpl-3.0.txt">3</a>, and copyrighted by Santosh Patnaik, MD, PhD.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s1.5" id="s1.5"></a><span class="item-no">1.5</span>&#160; Terms used here
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; * &#160;<em>administrator</em>&#160;- or admin; person setting up the code to pass input through htmLawed; also, <em>user</em><br />
+&#160; * &#160;<em>attributes</em>&#160;- name-value pairs like <span class="term">href="http&#58;//x.com"</span>&#160;in opening tags<br />
+&#160; * &#160;<em>author</em>&#160;- <em>writer</em><br />
+&#160; * &#160;<em>character</em>&#160;- atomic unit of text; internally represented by a numeric <em>code-point</em>&#160;as specified by the <em>encoding</em>&#160;or <em>charset</em>&#160;in use<br />
+&#160; * &#160;<em>entity</em>&#160;- markup like <span class="term">&amp;gt;</span>&#160;and <span class="term">&amp;#160;</span>&#160;used to refer to a character<br />
+&#160; * &#160;<em>element</em>&#160;- HTML element like <span class="term">a</span>&#160;and <span class="term">img</span><br />
+&#160; * &#160;<em>element content</em>&#160;- &#160;content between the opening and closing tags of an element, like <span class="term">click</span>&#160;of <span class="term">&lt;a href="x"&gt;click&lt;/a&gt;</span><br />
+&#160; * &#160;<em>HTML</em>&#160;- implies XHTML unless specified otherwise<br />
+&#160; * &#160;<em>input</em>&#160;- text string given to htmLawed to process<br />
+&#160; * &#160;<em>processing</em>&#160;- involves filtering, correction, etc., of input<br />
+&#160; * &#160;<em>safe</em>&#160;- absence or reduction of certain characters and HTML elements and attributes in the input that can otherwise potentially and circumstantially expose web-site users to security vulnerabilities like cross-site scripting attacks (XSS)<br />
+&#160; * &#160;<em>scheme</em>&#160;- URL protocol like <span class="term">http</span>&#160;and <span class="term">ftp</span><br />
+&#160; * &#160;<em>specs</em>&#160;- standard specifications<br />
+&#160; * &#160;<em>style property</em>&#160;- terms like <span class="term">border</span>&#160;and <span class="term">height</span>&#160;for which declarations are made in values for the <span class="term">style</span>&#160;attribute of elements<br />
+&#160; * &#160;<em>tag</em>&#160;- markers like <span class="term">&lt;a href="x"&gt;</span>&#160;and <span class="term">&lt;/a&gt;</span>&#160;delineating element content; the opening tag can contain attributes<br />
+&#160; * &#160;<em>tag content</em>&#160;- consists of tag markers <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>, element names like <span class="term">div</span>, and possibly attributes<br />
+&#160; * &#160;<em>user</em>&#160;- administrator<br />
+&#160; * &#160;<em>writer</em>&#160;- end-user like a blog commenter providing the input that is to be processed; also, <em>author</em><br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s2" id="s2"></a><span class="item-no">2</span>&#160; Usage
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed should work with PHP 4.3 and higher. Either <span class="term">include()</span>&#160;the <span class="term">htmLawed.php</span>&#160;file or copy-paste the entire code.<br />
+<br />
+&#160; To easily <strong>test</strong>&#160;htmLawed using a form-based interface, use the provided <a href="htmLawedTest.php">demo</a>&#160;(<span class="term">htmLawed.php</span>&#160;and <span class="term">htmLawedTest.php</span>&#160;should be in the same directory on the web-server).<br />
+
+<div class="sub-section"><h3>
+<a name="s2.1" id="s2.1"></a><span class="item-no">2.1</span>&#160; Simple
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The input text to be processed, <span class="term">$text</span>, is passed as an argument of type string; <span class="term">htmLawed()</span>&#160;returns the processed string:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text);</code>
+<br />
+<br />
+&#160; <strong>Note</strong>: If input is from a <span class="term">$_GET</span>&#160;or <span class="term">$_POST</span>&#160;value, and <span class="term">magic quotes</span>&#160;are enabled on the PHP setup, run <span class="term">stripslashes()</span>&#160;on the input before passing to htmLawed.<br />
+<br />
+&#160; By default, htmLawed will process the text allowing all valid HTML elements/tags, secure URL scheme/CSS style properties, etc. It will allow <span class="term">CDATA</span>&#160;sections and HTML comments, balance tags, and ensure proper nesting of elements. Such actions can be configured using two other optional arguments -- <span class="term">$config</span>&#160;and <span class="term">$spec</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config, $spec);</code>
+<br />
+<br />
+&#160; These extra parameters are detailed below. Some examples are shown in <a href="#s2.9">section 2.9</a>.<br />
+<br />
+&#160; <strong>Note</strong>: For maximum protection against <span class="term">XSS</span>&#160;and other scripting attacks (e.g., by disallowing Javascript code), consider using the <span class="term">safe</span>&#160;parameter; see <a href="#s3.6">section 3.6</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.2" id="s2.2"></a><span class="item-no">2.2</span>&#160; Configuring htmLawed using the <span class="term">$config</span>&#160;parameter
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; <span class="term">$config</span>&#160;instructs htmLawed on how to tackle certain tasks. When <span class="term">$config</span>&#160;is not specified, or not set as an array (e.g., <span class="term">$config = 1</span>), htmLawed will take default actions. One or many of the task-action or value-specification pairs can be specified in <span class="term">$config</span>&#160;as array key-value pairs. If a parameter is not specified, htmLawed will use the default value/action indicated further below.<br />
+<br />
+
+<code class="code">&#160; &#160; $config = array(&#39;comment&#39;=&gt;0, &#39;cdata&#39;=&gt;1);</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config);</code>
+<br />
+<br />
+&#160; Or,<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, array(&#39;comment&#39;=&gt;0, &#39;cdata&#39;=&gt;1));</code>
+<br />
+<br />
+&#160; Below are the possible value-specification combinations. In PHP code, values that are integers should not be quoted and should be used as numeric types (unless meant as string/text).<br />
+<br />
+&#160; Key: <span class="term">&#42;</span>&#160;default, <span class="term">^</span>&#160;different default when htmLawed is used in the Kses-compatible mode (see <a href="#s2.6">section 2.6</a>), <span class="term">~</span>&#160;different default when <span class="term">valid_xhtml</span>&#160;is set to <span class="term">1</span>&#160;(see <a href="#s3.5">section 3.5</a>), <span class="term">"</span>&#160;different default when <span class="term">safe</span>&#160;is set to <span class="term">1</span>&#160;(see <a href="#s3.6">section 3.6</a>)<br />
+<br />
+&#160; <strong>abs_url</strong><br />
+&#160; Make URLs absolute or relative; <span class="term">$config["base_url"]</span>&#160;needs to be set; see <a href="#s3.4.4">section 3.4.4</a><br />
+<br />
+&#160; <span class="term">-1</span>&#160;- make relative<br />
+&#160; <span class="term">0</span>&#160;- no action &#160;*<br />
+&#160; <span class="term">1</span>&#160;- make absolute<br />
+<br />
+&#160; <strong>and_mark</strong><br />
+&#160; Mark <span class="term">&amp;</span>&#160;characters in the original input; see <a href="#s3.2">section 3.2</a><br />
+<br />
+&#160; <strong>anti_link_spam</strong><br />
+&#160; Anti-link-spam measure; see <a href="#s3.4.7">section 3.4.7</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no measure taken &#160;*<br />
+&#160; <span class="term">array("regex1", "regex2")</span>&#160;- will ensure a <span class="term">rel</span>&#160;attribute with <span class="term">nofollow</span>&#160;in its value in case the <span class="term">href</span>&#160;attribute value matches the regular expression pattern <span class="term">regex1</span>, and/or will remove <span class="term">href</span>&#160;if its value matches the regular expression pattern <span class="term">regex2</span>. E.g., <span class="term">array("/./", "/&#58;//\W&#42;(?!(abc\.com|xyz\.org))/")</span>; see <a href="#s3.4.7">section 3.4.7</a>&#160;for more.<br />
+<br />
+&#160; <strong>anti_mail_spam</strong><br />
+&#160; Anti-mail-spam measure; see <a href="#s3.4.7">section 3.4.7</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no measure taken &#160;*<br />
+&#160; <span class="term">word</span>&#160;- <span class="term">@</span>&#160;in mail address in <span class="term">href</span>&#160;attribute value is replaced with specified <span class="term">word</span><br />
+<br />
+&#160; <strong>balance</strong><br />
+&#160; Balance tags for well-formedness and proper nesting; see <a href="#s3.3.3">section 3.3.3</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- yes &#160;*<br />
+<br />
+&#160; <strong>base_url</strong><br />
+&#160; Base URL value that needs to be set if <span class="term">$config["abs_url"]</span>&#160;is not <span class="term">0</span>; see <a href="#s3.4.4">section 3.4.4</a><br />
+<br />
+&#160; <strong>cdata</strong><br />
+&#160; Handling of <span class="term">CDATA</span>&#160;sections; see <a href="#s3.3.1">section 3.3.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- don't consider <span class="term">CDATA</span>&#160;sections as markup and proceed as if plain text &#160;^"<br />
+&#160; <span class="term">1</span>&#160;- remove<br />
+&#160; <span class="term">2</span>&#160;- allow, but neutralize any <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;inside by converting them to named entities<br />
+&#160; <span class="term">3</span>&#160;- allow &#160;*<br />
+<br />
+&#160; <strong>clean_ms_char</strong><br />
+&#160; Replace discouraged characters introduced by Microsoft Word, etc.; see <a href="#s3.1">section 3.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- yes<br />
+&#160; <span class="term">2</span>&#160;- yes, but replace special single &amp; double quotes with ordinary ones<br />
+<br />
+&#160; <strong>comment</strong><br />
+&#160; Handling of HTML comments; see <a href="#s3.3.1">section 3.3.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- don't consider comments as markup and proceed as if plain text &#160;^"<br />
+&#160; <span class="term">1</span>&#160;- remove<br />
+&#160; <span class="term">2</span>&#160;- allow, but neutralize any <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;inside by converting to named entities<br />
+&#160; <span class="term">3</span>&#160;- allow &#160;*<br />
+<br />
+&#160; <strong>css_expression</strong><br />
+&#160; Allow dynamic CSS expression by not removing the expression from CSS property values in <span class="term">style</span>&#160;attributes; see <a href="#s3.4.8">section 3.4.8</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- remove &#160;*<br />
+&#160; <span class="term">1</span>&#160;- allow<br />
+<br />
+&#160; <strong>deny_attribute</strong><br />
+&#160; Denied HTML attributes; see <a href="#s3.4">section 3.4</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- none &#160;*<br />
+&#160; <span class="term">string</span>&#160;- dictated by values in <span class="term">string</span><br />
+&#160; <span class="term">on&#42;</span>&#160;(like <span class="term">onfocus</span>) attributes not allowed - "<br />
+<br />
+&#160; <strong>elements</strong><br />
+&#160; Allowed HTML elements; see <a href="#s3.3">section 3.3</a><br />
+<br />
+&#160; <span class="term">&#42; -center -dir -font -isindex -menu -s -strike -u</span>&#160;- &#160;~<br />
+&#160; <span class="term">applet, embed, iframe, object, script</span>&#160;not allowed - "<br />
+<br />
+&#160; <strong>hexdec_entity</strong><br />
+&#160; Allow hexadecimal numeric entities and do not convert to the more widely accepted decimal ones, or convert decimal to hexadecimal ones; see <a href="#s3.2">section 3.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- yes &#160;*<br />
+&#160; <span class="term">2</span>&#160;- convert decimal to hexadecimal ones<br />
+<br />
+&#160; <strong>hook</strong><br />
+&#160; Name of an optional hook function to alter the input string, <span class="term">$config</span>&#160;or <span class="term">$spec</span>&#160;before htmLawed starts its main work; see <a href="#s3.7">section 3.7</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no hook function &#160;*<br />
+&#160; <span class="term">name</span>&#160;- <span class="term">name</span>&#160;is name of the hook function (<span class="term">kses_hook</span>&#160; ^)<br />
+<br />
+&#160; <strong>hook_tag</strong><br />
+&#160; Name of an optional hook function to alter tag content finalized by htmLawed; see <a href="#s3.4.9">section 3.4.9</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no hook function &#160;*<br />
+&#160; <span class="term">name</span>&#160;- <span class="term">name</span>&#160;is name of the hook function<br />
+<br />
+&#160; <strong>keep_bad</strong><br />
+&#160; Neutralize bad tags by converting <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;to entities, or remove them; see <a href="#s3.3.3">section 3.3.3</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- remove &#160;^<br />
+&#160; <span class="term">1</span>&#160;- neutralize both tags and element content<br />
+&#160; <span class="term">2</span>&#160;- remove tags but neutralize element content<br />
+&#160; <span class="term">3</span>&#160;and <span class="term">4</span>&#160;- like <span class="term">1</span>&#160;and <span class="term">2</span>&#160;but remove if text (<span class="term">pcdata</span>) is invalid in parent element<br />
+&#160; <span class="term">5</span>&#160;and <span class="term">6</span>&#160;* - &#160;like <span class="term">3</span>&#160;and <span class="term">4</span>&#160;but line-breaks, tabs and spaces are left<br />
+<br />
+&#160; <strong>lc_std_val</strong><br />
+&#160; For XHTML compliance, predefined, standard attribute values, like <span class="term">get</span>&#160;for the <span class="term">method</span>&#160;attribute of <span class="term">form</span>, must be lowercased; see <a href="#s3.4.5">section 3.4.5</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no<br />
+&#160; <span class="term">1</span>&#160;- yes &#160;*<br />
+<br />
+&#160; <strong>make_tag_strict</strong><br />
+&#160; Transform/remove these non-strict XHTML elements, even if they are allowed by the admin: <span class="term">applet</span>&#160;<span class="term">center</span>&#160;<span class="term">dir</span>&#160;<span class="term">embed</span>&#160;<span class="term">font</span>&#160;<span class="term">isindex</span>&#160;<span class="term">menu</span>&#160;<span class="term">s</span>&#160;<span class="term">strike</span>&#160;<span class="term">u</span>; see <a href="#s3.3.2">section 3.3.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;^<br />
+&#160; <span class="term">1</span>&#160;- yes, but leave <span class="term">applet</span>, <span class="term">embed</span>&#160;and <span class="term">isindex</span>&#160;elements that currently can't be transformed &#160;*<br />
+&#160; <span class="term">2</span>&#160;- yes, removing <span class="term">applet</span>, <span class="term">embed</span>&#160;and <span class="term">isindex</span>&#160;elements and their contents (nested elements remain) &#160;~<br />
+<br />
+&#160; <strong>named_entity</strong><br />
+&#160; Allow non-universal named HTML entities, or convert to numeric ones; see <a href="#s3.2">section 3.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- convert<br />
+&#160; <span class="term">1</span>&#160;- allow &#160;*<br />
+<br />
+&#160; <strong>no_deprecated_attr</strong><br />
+&#160; Allow deprecated attributes or transform them; see <a href="#s3.4.6">section 3.4.6</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- allow &#160;^<br />
+&#160; <span class="term">1</span>&#160;- transform, but <span class="term">name</span>&#160;attributes for <span class="term">a</span>&#160;and <span class="term">map</span>&#160;are retained &#160;*<br />
+&#160; <span class="term">2</span>&#160;- transform<br />
+<br />
+&#160; <strong>parent</strong><br />
+&#160; Name of the parent element, possibly imagined, that will hold the input; see <a href="#s3.3">section 3.3</a><br />
+<br />
+&#160; <strong>safe</strong><br />
+&#160; Magic parameter to make input the most secure against XSS without needing to specify other relevant <span class="term">$config</span>&#160;parameters; see <a href="#s3.6">section 3.6</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- will auto-adjust other relevant <span class="term">$config</span>&#160;parameters (indicated by <span class="term">"</span>&#160;in this list)<br />
+<br />
+&#160; <strong>schemes</strong><br />
+&#160; Array of attribute-specific, comma-separated, lower-cased list of schemes (protocols) allowed in attributes accepting URLs; <span class="term">&#42;</span>&#160;covers all unspecified attributes; see <a href="#s3.4.3">section 3.4.3</a><br />
+<br />
+&#160; <span class="term">href&#58; aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; &#42;&#58;file, http, https</span>&#160; *<br />
+&#160; <span class="term">&#42;&#58; ftp, gopher, http, https, mailto, news, nntp, telnet</span>&#160; ^<br />
+&#160; <span class="term">href&#58; aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; style&#58; nil; &#42;&#58;file, http, https</span>&#160; "<br />
+<br />
+&#160; <strong>show_setting</strong><br />
+&#160; Name of a PHP variable to assign the <em>finalized</em>&#160;<span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;values; see <a href="#s3.8">section 3.8</a><br />
+<br />
+&#160; <strong>style_pass</strong><br />
+&#160; Do not look at <span class="term">style</span>&#160;attribute values, letting them through without any alteration<br />
+<br />
+&#160; <span class="term">0</span>&#160;- no *<br />
+&#160; <span class="term">1</span>&#160;- htmLawed will let through any <span class="term">style</span>&#160;value; see <a href="#s3.4.8">section 3.4.8</a><br />
+<br />
+&#160; <strong>tidy</strong><br />
+&#160; Beautify or compact HTML code; see <a href="#s3.3.5">section 3.3.5</a><br />
+<br />
+&#160; <span class="term">-1</span>&#160;- compact<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;or <span class="term">string</span>&#160;- beautify (custom format specified by <span class="term">string</span>)<br />
+<br />
+&#160; <strong>unique_ids</strong><br />
+&#160; <span class="term">id</span>&#160;attribute value checks; see <a href="#s3.4.2">section 3.4.2</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;^<br />
+&#160; <span class="term">1</span>&#160;- remove duplicate and/or invalid ones &#160;*<br />
+&#160; <span class="term">word</span>&#160;- remove invalid ones and replace duplicate ones with new and unique ones based on the <span class="term">word</span>; the admin-specified <span class="term">word</span>, like <span class="term">my_</span>, should begin with a letter (a-z) and can contain letters, digits, <span class="term">.</span>, <span class="term">_</span>, <span class="term">-</span>, and <span class="term">&#58;</span>.<br />
+<br />
+&#160; <strong>valid_xhtml</strong><br />
+&#160; Magic parameter to make input the most valid XHTML without needing to specify other relevant <span class="term">$config</span>&#160;parameters; see <a href="#s3.5">section 3.5</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- will auto-adjust other relevant <span class="term">$config</span>&#160;parameters (indicated by <span class="term">~</span>&#160;in this list)<br />
+<br />
+&#160; <strong>xml:lang</strong><br />
+&#160; Auto-adding <span class="term">xml&#58;lang</span>&#160;attribute; see <a href="#s3.4.1">section 3.4.1</a><br />
+<br />
+&#160; <span class="term">0</span>&#160;- no &#160;*<br />
+&#160; <span class="term">1</span>&#160;- add if <span class="term">lang</span>&#160;attribute is present<br />
+&#160; <span class="term">2</span>&#160;- add if <span class="term">lang</span>&#160;attribute is present, and remove <span class="term">lang</span>&#160; ~<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.3" id="s2.3"></a><span class="item-no">2.3</span>&#160; Extra HTML specifications using the $spec parameter
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The <span class="term">$spec</span>&#160;argument can be used to disallow an otherwise legal attribute for an element, or to restrict the attribute's values. This can also be helpful as a security measure (e.g., in certain versions of browsers, certain values can cause buffer overflows and denial of service attacks), or in enforcing admin policy compliance. <span class="term">$spec</span>&#160;is specified as a string of text containing one or more <em>rules</em>, with multiple rules separated from each other by a semi-colon (<span class="term">;</span>). E.g.,<br />
+<br />
+
+<code class="code">&#160; &#160; $spec = &#39;i=-&#42;; td, tr=style, id, -&#42;; a=id(match="/[a-z][a-z\d.&#58;\-&#96;"]&#42;/i"/minval=2), href(maxlen=100/minlen=34); img=-width,-alt&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config, $spec);</code>
+<br />
+<br />
+&#160; Or,<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, $config, &#39;i=-&#42;; td, tr=style, id, -&#42;; a=id(match="/[a-z][a-z\d.&#58;\-&#96;"]&#42;/i"/minval=2), href(maxlen=100/minlen=34); img=-width,-alt&#39;);</code>
+<br />
+<br />
+&#160; A rule begins with an HTML <strong>element</strong>&#160;name(s) (<em>rule-element</em>), for which the rule applies, followed by an equal (<span class="term">=</span>) sign. A rule-element may represent multiple elements if comma (,)-separated element names are used. E.g., <span class="term">th,td,tr=</span>.<br />
+<br />
+&#160; Rest of the rule consists of comma-separated HTML <strong>attribute names</strong>. A minus (<span class="term">-</span>) character before an attribute means that the attribute is not permitted inside the rule-element. E.g., <span class="term">-width</span>. To deny all attributes, <span class="term">-&#42;</span>&#160;can be used.<br />
+<br />
+&#160; Following shows examples of rule excerpts with rule-element <span class="term">a</span>&#160;and the attributes that are being permitted:<br />
+<br />
+&#160; * &#160;<span class="term">a=</span>&#160;- all<br />
+&#160; * &#160;<span class="term">a=id</span>&#160;- all<br />
+&#160; * &#160;<span class="term">a=href, title, -id, -onclick</span>&#160;- all except <span class="term">id</span>&#160;and <span class="term">onclick</span><br />
+&#160; * &#160;<span class="term">a=&#42;, id, -id</span>&#160;- all except <span class="term">id</span><br />
+&#160; * &#160;<span class="term">a=-&#42;</span>&#160;- none<br />
+&#160; * &#160;<span class="term">a=-&#42;, href, title</span>&#160;- none except <span class="term">href</span>&#160;and <span class="term">title</span><br />
+&#160; * &#160;<span class="term">a=-&#42;, -id, href, title</span>&#160;- none except <span class="term">href</span>&#160;and <span class="term">title</span><br />
+<br />
+&#160; Rules regarding <strong>attribute values</strong>&#160;are optionally specified inside round brackets after attribute names in slash ('/')-separated <em>parameter = value</em>&#160;pairs. E.g., <span class="term">title(maxlen=30/minlen=5)</span>. None, or one or more of the following parameters may be specified:<br />
+<br />
+&#160; * &#160;<span class="term">oneof</span>&#160;- one or more choices separated by <span class="term">|</span>&#160;that the value should match; if only one choice is provided, then the value must match that choice<br />
+<br />
+&#160; * &#160;<span class="term">noneof</span>&#160;- one or more choices separated by <span class="term">|</span>&#160;that the value should not match<br />
+<br />
+&#160; * &#160;<span class="term">maxlen</span>&#160;and <span class="term">minlen</span>&#160;- upper and lower limits for the number of characters in the attribute value; specified in numbers<br />
+<br />
+&#160; * &#160;<span class="term">maxval</span>&#160;and <span class="term">minval</span>&#160;- upper and lower limits for the numerical value specified in the attribute value; specified in numbers<br />
+<br />
+&#160; * &#160;<span class="term">match</span>&#160;and <span class="term">nomatch</span>&#160;- pattern that the attribute value should or should not match; specified as PHP/PCRE-compatible regular expressions with delimiters and possibly modifiers<br />
+<br />
+&#160; * &#160;<span class="term">default</span>&#160;- a value to force on the attribute if the value provided by the writer does not fit any of the specified parameters<br />
+<br />
+&#160; If <span class="term">default</span>&#160;is not set and the attribute value does not satisfy any of the specified parameters, then the attribute is removed. The <span class="term">default</span>&#160;value can also be used to force all attribute declarations to take the same value (by getting the values declared illegal by setting, e.g., <span class="term">maxlen</span>&#160;to <span class="term">-1</span>).<br />
+<br />
+&#160; Examples with <em>input</em>&#160;<span class="term">&lt;input title="WIDTH" value="10em" /&gt;&lt;input title="length" value="5" /&gt;</span>&#160;are shown below.<br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=title(maxlen=60/minlen=6), value</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input value="10em" /&gt;&lt;input title="length" value="5" /&gt;</span><br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=title(), value(maxval=8/default=6)</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input title="WIDTH" value="6" /&gt;&lt;input title="length" value="5" /&gt;</span><br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=title(nomatch=$w.d$i), value(match=$em$/default=6em)</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input value="10em" /&gt;&lt;input title="length" value="6em" /&gt;</span><br />
+<br />
+&#160; <em>Rule</em>: <span class="term">input=title(oneof=height|depth/default=depth), value(noneof=5|6)</span><br />
+&#160; <em>Output</em>: <span class="term">&lt;input title="depth" value="10em" /&gt;&lt;input title="depth" /&gt;</span><br />
+<br />
+&#160; <strong>Special characters</strong>: The characters <span class="term">;</span>, <span class="term">,</span>, <span class="term">/</span>, <span class="term">(</span>, <span class="term">)</span>, <span class="term">|</span>, <span class="term">~</span>&#160;and space have special meanings in the rules. Words in the rules that use such characters, or the characters themselves, should be <em>escaped</em>&#160;by enclosing in pairs of double-quotes (<span class="term">"</span>). A back-tick (<span class="term">&#96;</span>) can be used to escape a literal <span class="term">"</span>. An example rule illustrating this is <span class="term">input=value(maxlen=30/match="/^\w/"/default="your &#96;"ID&#96;"")</span>.<br />
+<br />
+&#160; <strong>Note</strong>: To deny an attribute for all elements for which it is legal, <span class="term">$config["deny_attribute"]</span>&#160;(see <a href="#s3.4">section 3.4</a>) can be used instead of <span class="term">$spec</span>. Also, attributes can be allowed element-specifically through <span class="term">$spec</span>&#160;while being denied globally through <span class="term">$config["deny_attribute"]</span>. The <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) can also be used to implement the <span class="term">$spec</span>&#160;functionality.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.4" id="s2.4"></a><span class="item-no">2.4</span>&#160; Performance time &amp; memory usage
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The time and memory used by htmLawed depends on its configuration and the size of the input, and the amount, nestedness and well-formedness of the HTML markup within it. In particular, tag balancing and beautification each can increase the processing time by about a quarter.<br />
+<br />
+&#160; The htmLawed <a href="htmLawedTest.php">demo</a>&#160;can be used to evaluate the performance and effects of different types of input and <span class="term">$config</span>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.5" id="s2.5"></a><span class="item-no">2.5</span>&#160; Some security risks to keep in mind
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; When setting the parameters/arguments (like those to allow certain HTML elements) for use with htmLawed, one should bear in mind that the setting may let through potentially <em>dangerous</em>&#160;HTML code. (This may not be a problem if the authors are trusted.)<br />
+<br />
+&#160; For example, following increase security risks:<br />
+<br />
+&#160; * &#160;Allowing <span class="term">script</span>, <span class="term">applet</span>, <span class="term">embed</span>, <span class="term">iframe</span>&#160;or <span class="term">object</span>&#160;elements, or certain of their attributes like <span class="term">allowscriptaccess</span><br />
+<br />
+&#160; * &#160;Allowing HTML comments (some Internet Explorer versions are vulnerable with, e.g., <span class="term">&lt;!--[if gte IE 4]&gt;&lt;script&gt;alert("xss");&lt;/script&gt;&lt;![endif]--&gt;</span><br />
+<br />
+&#160; * &#160;Allowing dynamic CSS expressions (a feature of the IE browser)<br />
+<br />
+&#160; <em>Unsafe</em>&#160;HTML can be removed by setting <span class="term">$config</span>&#160;appropriately. E.g., <span class="term">$config["elements"] = "&#42; -script"</span>&#160;(<a href="#s3.3">section 3.3</a>), <span class="term">$config["safe"] = 1</span>&#160;(<a href="#s3.6">section 3.6</a>), etc.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.6" id="s2.6"></a><span class="item-no">2.6</span>&#160; Use without modifying old <span class="term">kses()</span>&#160;code
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The <span class="term">Kses</span>&#160;PHP script is used by many applications (like <span class="term">WordPress</span>). It is possible to have such applications use htmLawed instead, since it is compatible with code that calls the <span class="term">kses()</span>&#160;function declared in the <span class="term">Kses</span>&#160;file (usually named <span class="term">kses.php</span>). E.g., application code like this will continue to work after replacing <span class="term">Kses</span>&#160;with htmLawed:<br />
+<br />
+
+<code class="code">&#160; &#160; $comment_filtered = kses($comment_input, array(&#39;a&#39;=&gt;array(), &#39;b&#39;=&gt;array(), &#39;i&#39;=&gt;array()));</code>
+<br />
+<br />
+&#160; For some of the <span class="term">$config</span>&#160;parameters, htmLawed will use values other than the default ones. These are indicated by <span class="term">^</span>&#160;in <a href="#s2.2">section 2.2</a>. To force htmLawed to use other values, function <span class="term">kses()</span>&#160;in the htmLawed code should be edited -- a few configurable parameters/variables need to be changed.<br />
+<br />
+&#160; If the application uses a <span class="term">Kses</span>&#160;file that has the <span class="term">kses()</span>&#160;function declared, then, to have the application use htmLawed instead of <span class="term">Kses</span>, simply rename <span class="term">htmLawed.php</span>&#160;(to <span class="term">kses.php</span>, e.g.) and replace the <span class="term">Kses</span>&#160;file (or just replace the code in the <span class="term">Kses</span>&#160;file with the htmLawed code). If the <span class="term">kses()</span>&#160;function in the <span class="term">Kses</span>&#160;file had been renamed by the application developer (e.g., in <span class="term">WordPress</span>, it is named <span class="term">wp_kses()</span>), then appropriately rename the <span class="term">kses()</span>&#160;function in the htmLawed code.<br />
+<br />
+&#160; If the <span class="term">Kses</span>&#160;file used by the application has been highly altered by the application developers, then one may need a different approach. E.g., with <span class="term">WordPress</span>, it is best to copy the htmLawed code to <span class="term">wp_includes/kses.php</span>, rename the newly added function <span class="term">kses()</span>&#160;to <span class="term">wp_kses()</span>, and delete the code for the original <span class="term">wp_kses()</span>&#160;function.<br />
+<br />
+&#160; If the <span class="term">Kses</span>&#160;code has a non-empty hook function (e.g., <span class="term">wp_kses_hook()</span>&#160;in case of <span class="term">WordPress</span>), then the code for htmLawed's <span class="term">kses_hook()</span>&#160;function should be appropriately edited. However, the requirement of the hook function should be re-evaluated considering that htmLawed has extra capabilities. With <span class="term">WordPress</span>, the hook function is an essential one. The following code is suggested for the htmLawed <span class="term">kses_hook()</span>&#160;in case of <span class="term">WordPress</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; function kses_hook($string, &amp;$cf, &amp;$spec){</code>
+<br />
+
+<code class="code">&#160; &#160; // kses compatibility</code>
+<br />
+
+<code class="code">&#160; &#160; $allowed_html = $spec;</code>
+<br />
+
+<code class="code">&#160; &#160; $allowed_protocols = array();</code>
+<br />
+
+<code class="code">&#160; &#160; foreach($cf[&#39;schemes&#39;] as $v){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;foreach($v as $k2=&gt;$v2){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; if(!in_array($k2, $allowed_protocols)){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;$allowed_protocols[] = $k2;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;}</code>
+<br />
+
+<code class="code">&#160; &#160; }</code>
+<br />
+
+<code class="code">&#160; &#160; return wp_kses_hook($string, $allowed_html, $allowed_protocols);</code>
+<br />
+
+<code class="code">&#160; &#160; // eof</code>
+<br />
+
+<code class="code">&#160; &#160; }</code>
+<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.7" id="s2.7"></a><span class="item-no">2.7</span>&#160; Tolerance for ill-written HTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can work with ill-written HTML code in the input. However, HTML that is too ill-written may not be <em>read</em>&#160;as HTML, and be considered mere plain text instead. Following statements indicate the degree of <em>looseness</em>&#160;that htmLawed can work with, and can be provided in instructions to writers:<br />
+<br />
+&#160; * &#160;Tags must be flanked by <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;with no <span class="term">&gt;</span>&#160;inside -- any needed <span class="term">&gt;</span>&#160;should be put in as <span class="term">&amp;gt;</span>. It is possible for tag content (element name and attributes) to be spread over many lines instead of being on one. A space may be present between the tag content and <span class="term">&gt;</span>, like <span class="term">&lt;div &gt;</span>&#160;and <span class="term">&lt;img / &gt;</span>, but not after the <span class="term">&lt;</span>.<br />
+<br />
+&#160; * &#160;Element and attribute names need not be lower-cased.<br />
+<br />
+&#160; * &#160;Attribute string of elements may be liberally spaced with tabs, line-breaks, etc.<br />
+<br />
+&#160; * &#160;Attribute values may not be double-quoted, or may be single-quoted.<br />
+<br />
+&#160; * &#160;Left-padding of numeric entities (like, <span class="term">&amp;#0160;</span>, <span class="term">&amp;x07ff;</span>) with <span class="term">0</span>&#160;is okay as long as the number of characters between between the <span class="term">&amp;</span>&#160;and the <span class="term">;</span>&#160;does not exceed 8. All entities must end with <span class="term">;</span>&#160;though.<br />
+<br />
+&#160; * &#160;Named character entities must be properly cased. E.g., <span class="term">&amp;Lt;</span>&#160;or <span class="term">&amp;TILDE;</span>&#160;will not be let through without modification.<br />
+<br />
+&#160; * &#160;HTML comments should not be inside element tags (okay between tags), and should begin with <span class="term">&lt;!--</span>&#160;and end with <span class="term">--&gt;</span>. Characters like <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;may be allowed inside depending on <span class="term">$config</span>, but any <span class="term">--&gt;</span>&#160;inside should be put in as <span class="term">--&amp;gt;</span>. Any <span class="term">--</span>&#160;inside will be automatically converted to <span class="term">-</span>, and a space will be added before the comment delimiter <span class="term">--&gt;</span>.<br />
+<br />
+&#160; * &#160;<span class="term">CDATA</span>&#160;sections should not be inside element tags, and can be in element content only if plain text is allowed for that element. They should begin with <span class="term">&lt;[CDATA[</span>&#160;and end with <span class="term">]]&gt;</span>. Characters like <span class="term">&lt;</span>, <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;may be allowed inside depending on <span class="term">$config</span>, but any <span class="term">]]&gt;</span>&#160;inside should be put in as <span class="term">]]&amp;gt;</span>.<br />
+<br />
+&#160; * &#160;For attribute values, character entities <span class="term">&amp;lt;</span>, <span class="term">&amp;gt;</span>&#160;and <span class="term">&amp;amp;</span>&#160;should be used instead of characters <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>, and <span class="term">&amp;</span>&#160;(when <span class="term">&amp;</span>&#160;is not part of a character entity). This applies even for Javascript code in values of attributes like <span class="term">onclick</span>.<br />
+<br />
+&#160; * &#160;Characters <span class="term">&lt;</span>, <span class="term">&gt;</span>, <span class="term">&amp;</span>&#160;and <span class="term">"</span>&#160;that are part of actual Javascript, etc., code in <span class="term">script</span>&#160;elements should be used as such and not be put in as entities like <span class="term">&amp;gt;</span>. Otherwise, though the HTML will be valid, the code may fail to work. Further, if such characters have to be used, then they should be put inside <span class="term">CDATA</span>&#160;sections.<br />
+<br />
+&#160; * &#160;Simple instructions like "an opening tag cannot be present between two closing tags" and "nested elements should be closed in the reverse order of how they were opened" can help authors write balanced HTML. If tags are imbalanced, htmLawed will try to balance them, but in the process, depending on <span class="term">$config["keep_bad"]</span>, some code/text may be lost.<br />
+<br />
+&#160; * &#160;Input authors should be notified of admin-specified allowed elements, attributes, configuration values (like conversion of named entities to numeric ones), etc.<br />
+<br />
+&#160; * &#160;With <span class="term">$config["unique_ids"]</span>&#160;not <span class="term">0</span>&#160;and the <span class="term">id</span>&#160;attribute being permitted, writers should carefully avoid using duplicate or invalid <span class="term">id</span>&#160;values as even though htmLawed will correct/remove the values, the final output may not be the one desired. E.g., when <span class="term">&lt;a id="home"&gt;&lt;/a&gt;&lt;input id="home" /&gt;&lt;label for="home"&gt;&lt;/label&gt;</span>&#160;is processed into<br />
+<span class="term">&lt;a id="home"&gt;&lt;/a&gt;&lt;input id="prefix_home" /&gt;&lt;label for="home"&gt;&lt;/label&gt;</span>.<br />
+<br />
+&#160; * &#160;Note that even if intended HTML is lost in a highly ill-written input, the processed output will be more secure and standard-compliant.<br />
+<br />
+&#160; * &#160;For URLs, unless <span class="term">$config["scheme"]</span>&#160;is appropriately set, writers should avoid using escape characters or entities in schemes. E.g., <span class="term">htt&amp;#112;</span>&#160;(which many browsers will read as the harmless <span class="term">http</span>) may be considered bad by htmLawed.<br />
+<br />
+&#160; * &#160;htmLawed will attempt to put plain text present directly inside <span class="term">blockquote</span>, <span class="term">form</span>, <span class="term">map</span>&#160;and <span class="term">noscript</span>&#160;elements (illegal as per the specs) inside auto-generated <span class="term">div</span>&#160;elements.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.8" id="s2.8"></a><span class="item-no">2.8</span>&#160; Limitations &amp; work-arounds
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed's main objective is to make the input text <em>more</em>&#160;standard-compliant, secure for web-page readers, and free of HTML elements and attributes considered undesirable by the administrator. Some of its current limitations, regardless of this objective, are noted below along with work-arounds.<br />
+<br />
+&#160; It should be borne in mind that no browser application is 100% standard-compliant, and that some of the standard specs (like asking for normalization of white-spacing within <span class="term">textarea</span>&#160;elements) are clearly wrong. Regarding security, note that <em>unsafe</em>&#160;HTML code is not necessarily legally invalid.<br />
+<br />
+&#160; * &#160;htmLawed is meant for input that goes into the <span class="term">body</span>&#160;of HTML documents. HTML's head-level elements are not supported, nor are the frameset elements <span class="term">frameset</span>, <span class="term">frame</span>&#160;and <span class="term">noframes</span>.<br />
+<br />
+&#160; * &#160;It cannot transform the non-standard <span class="term">embed</span>&#160;elements to the standard-compliant <span class="term">object</span>&#160;elements. Yet, it can allow <span class="term">embed</span>&#160;elements if permitted (<span class="term">embed</span>&#160;is widely used and supported). Admins can certainly use the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) to deploy a custom embed-to-object converter function.<br />
+<br />
+&#160; * &#160;The only non-standard element that may be permitted is <span class="term">embed</span>; others like <span class="term">noembed</span>&#160;and <span class="term">nobr</span>&#160;cannot be permitted without modifying the htmLawed code.<br />
+<br />
+&#160; * &#160;It cannot handle input that has non-HTML code like <span class="term">SVG</span>&#160;and <span class="term">MathML</span>. One way around is to break the input into pieces and passing only those without non-HTML code to htmLawed. Another is described in <a href="#s3.9">section 3.9</a>. A third way may be to some how take advantage of the <span class="term">$config["and_mark"]</span>&#160;parameter (see <a href="#s3.2">section 3.2</a>).<br />
+<br />
+&#160; * &#160;By default, htmLawed won't check many attribute values for standard compliance. E.g., <span class="term">width="20m"</span>&#160;with the dimension in non-standard <span class="term">m</span>&#160;is let through. Implementing universal and strict attribute value checks can make htmLawed slow and resource-intensive. Admins should look at the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) or <span class="term">$spec</span>&#160;to enforce finer checks.<br />
+<br />
+&#160; * &#160;The attributes, deprecated (which can be transformed too) or not, that it supports are largely those that are in the specs. Only a few of the proprietary attributes are supported.<br />
+<br />
+&#160; * &#160;Except for contained URLs and dynamic expressions (also optional), htmLawed does not check CSS style property values. Admins should look at using the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) or <span class="term">$spec</span>&#160;for finer checks. Perhaps the best option is to disallow <span class="term">style</span>&#160;but allow <span class="term">class</span>&#160;attributes with the right <span class="term">oneof</span>&#160;or <span class="term">match</span>&#160;values for <span class="term">class</span>, and have the various class style properties in <span class="term">.css</span>&#160;CSS stylesheet files.<br />
+<br />
+&#160; * &#160;htmLawed does not parse emoticons, decode <em>BBcode</em>, or <em>wikify</em>, auto-converting text to proper HTML. Similarly, it won't convert line-breaks to <span class="term">br</span>&#160;elements. Such functions are beyond its purview. Admins should use other code to pre- or post-process the input for such purposes.<br />
+<br />
+&#160; * &#160;htmLawed cannot be used to have links force-opened in new windows (by auto-adding appropriate <span class="term">target</span>&#160;and <span class="term">onclick</span>&#160;attributes to <span class="term">a</span>). Admins should look at Javascript-based DOM-modifying solutions for this. Admins may also be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;Nesting-based checks are not possible. E.g., one cannot disallow <span class="term">p</span>&#160;elements specifically inside <span class="term">td</span>&#160;while permitting it elsewhere. Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;Except for optionally converting absolute or relative URLs to the other type, htmLawed will not alter URLs (e.g., to change the value of query strings or to convert <span class="term">http</span>&#160;to <span class="term">https</span>. Having absolute URLs may be a standard-requirement, e.g., when HTML is embedded in email messages, whereas altering URLs for other purposes is beyond htmLawed's goals. Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;Pairs of opening and closing tags that do not enclose any content (like <span class="term">&lt;em&gt;&lt;/em&gt;</span>) are not removed. This may be against the standard specs for certain elements (e.g., <span class="term">table</span>). However, presence of such standard-incompliant code will not break the display or layout of content. Admins can also use simple regex-based code to filter out such code.<br />
+<br />
+&#160; * &#160;htmLawed does not check for certain element orderings described in the standard specs (e.g., in a <span class="term">table</span>, <span class="term">tbody</span>&#160;is allowed before <span class="term">tfoot</span>). Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;htmLawed does not check the number of nested elements. E.g., it will allow two <span class="term">caption</span>&#160;elements in a <span class="term">table</span>&#160;element, illegal as per the specs. Admins may be able to use a custom hook function to enforce such checks (<span class="term">hook_tag</span>&#160;parameter; see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; * &#160;htmLawed might convert certain entities to actual characters and remove backslashes and CSS comment-markers (<span class="term">/&#42;</span>) in <span class="term">style</span>&#160;attribute values in order to detect malicious HTML like crafted IE-specific dynamic expressions like <span class="term">&amp;#101;xpression...</span>. If this is too harsh, admins can allow CSS expressions through htmLawed core but then use a custom function through the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>) to more specifically identify CSS expressions in the <span class="term">style</span>&#160;attribute values. Also, using <span class="term">$config["style_pass"]</span>, it is possible to have htmLawed pass <span class="term">style</span>&#160;attribute values without even looking at them (<a href="#s3.4.8">section 3.4.8</a>).<br />
+<br />
+&#160; * &#160;htmLawed does not correct certain possible attribute-based security vulnerabilities (e.g., <span class="term">&lt;a href="http&#58;//x%22+style=%22background-image&#58;xss"&gt;x&lt;/a&gt;</span>). These arise when browsers mis-identify markup in <em>escaped</em>&#160;text, defeating the very purpose of escaping text (a bad browser will read the given example as <span class="term">&lt;a href="http&#58;//x" style="background-image&#58;xss"&gt;x&lt;/a&gt;</span>).<br />
+<br />
+&#160; * &#160;Because of poor Unicode support in PHP, htmLawed does not remove the <em>high value</em>&#160;HTML-invalid characters with multi-byte code-points. Such characters however are extremely unlikely to be in the input. (see <a href="#s3.1">section 3.1</a>).<br />
+<br />
+&#160; * &#160;Like any script using PHP's PCRE regex functions, PHP setup-specific low PCRE limit values can cause htmLawed to at least partially fail with very long input texts.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s2.9" id="s2.9"></a><span class="item-no">2.9</span>&#160; Examples
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; <strong>1.</strong>&#160;A blog administrator wants to allow only <span class="term">a</span>, <span class="term">em</span>, <span class="term">strike</span>, <span class="term">strong</span>&#160;and <span class="term">u</span>&#160;in comments, but needs <span class="term">strike</span>&#160;and <span class="term">u</span>&#160;transformed to <span class="term">span</span>&#160;for better XHTML 1-strict compliance, and, he wants the <span class="term">a</span>&#160;links to be to <span class="term">http</span>&#160;or <span class="term">https</span>&#160;resources:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($in, array(&#39;elements&#39;=&gt;&#39;a, em, strike, strong, u&#39;, &#39;make_tag_strict&#39;=&gt;1, &#39;safe&#39;=&gt;1, &#39;schemes&#39;=&gt;&#39;&#42;&#58;http, https&#39;), &#39;a=href&#39;);</code>
+<br />
+<br />
+&#160; <strong>2.</strong>&#160;An author uses a custom-made web application to load content on his web-site. He is the only one using that application and the content he generates has all types of HTML, including scripts. The web application uses htmLawed primarily as a tool to correct errors that creep in while writing HTML and to take care of the occasional <em>bad</em>&#160;characters in copy-paste text introduced by Microsoft Office. The web application provides a preview before submitted input is added to the content. For the previewing process, htmLawed is set up as follows:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($in, array(&#39;css_expression&#39;=&gt;1, &#39;keep_bad&#39;=&gt;1, &#39;make_tag_strict&#39;=&gt;1, &#39;schemes&#39;=&gt;&#39;&#42;&#58;&#42;&#39;, &#39;valid_xhtml&#39;=&gt;1));</code>
+<br />
+<br />
+&#160; For the final submission process, <span class="term">keep_bad</span>&#160;is set to <span class="term">6</span>. A value of <span class="term">1</span>&#160;for the preview process allows the author to note and correct any HTML mistake without losing any of the typed text.<br />
+<br />
+&#160; <strong>3.</strong>&#160;A data-miner is scraping information in a specific table of similar web-pages and is collating the data rows, and uses htmLawed to reduce unnecessary markup and white-spaces:<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($in, array(&#39;elements&#39;=&gt;&#39;tr, td&#39;, &#39;tidy&#39;=&gt;-1), &#39;tr, td =&#39;);</code>
+<br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s3" id="s3"></a><span class="item-no">3</span>&#160; Details
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<div class="sub-section"><h3>
+<a name="s3.1" id="s3.1"></a><span class="item-no">3.1</span>&#160; Invalid/dangerous characters
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Valid characters (more correctly, their code-points) in HTML or XML are, hexadecimally, <span class="term">9</span>, <span class="term">a</span>, <span class="term">d</span>, <span class="term">20</span>&#160;to <span class="term">d7ff</span>, and <span class="term">e000</span>&#160;to <span class="term">10ffff</span>, except <span class="term">fffe</span>&#160;and <span class="term">ffff</span>&#160;(decimally, <span class="term">9</span>, <span class="term">10</span>, <span class="term">13</span>, <span class="term">32</span>&#160;to <span class="term">55295</span>, and <span class="term">57344</span>&#160;to <span class="term">1114111</span>, except <span class="term">65534</span>&#160;and <span class="term">65535</span>). htmLawed removes the invalid characters <span class="term">0</span>&#160;to <span class="term">8</span>, <span class="term">b</span>, <span class="term">c</span>, and <span class="term">e</span>&#160;to <span class="term">1f</span>.<br />
+<br />
+&#160; Because of PHP's poor native support for multi-byte characters, htmLawed cannot check for the remaining invalid code-points. However, for various reasons, it is very unlikely for any of those characters to be in the input.<br />
+<br />
+&#160; Characters that are discouraged (see <a href="#s5.1">section 5.1</a>) but not invalid are not removed by htmLawed.<br />
+<br />
+&#160; It (function <span class="term">hl_tag()</span>) also replaces the potentially dangerous (in some Mozilla [Firefox] and Opera browsers) soft-hyphen character (code-point, hexadecimally, <span class="term">ad</span>, or decimally, <span class="term">173</span>) in attribute values with spaces. Where required, the characters <span class="term">&lt;</span>, <span class="term">&gt;</span>, <span class="term">&amp;</span>, and <span class="term">"</span>&#160;are converted to entities.<br />
+<br />
+&#160; With <span class="term">$config["clean_ms_char"]</span>&#160;set as <span class="term">1</span>&#160;or <span class="term">2</span>, many of the discouraged characters (decimal code-points <span class="term">127</span>&#160;to <span class="term">159</span>&#160;except <span class="term">133</span>) that many Microsoft applications incorrectly use (as per the <span class="term">Windows 1252</span>&#160;[<span class="term">Cp-1252</span>] or a similar encoding system), and the character for decimal code-point <span class="term">133</span>, are converted to appropriate decimal numerical entities (or removed for a few cases)-- see appendix in <a href="#s5.4">section 5.4</a>. This can help avoid some display issues arising from copying-pasting of content.<br />
+<br />
+&#160; With <span class="term">$config["clean_ms_char"]</span>&#160;set as <span class="term">2</span>, characters for the hexadecimal code-points <span class="term">82</span>, <span class="term">91</span>, and <span class="term">92</span>&#160;(for special single-quotes), and <span class="term">84</span>, <span class="term">93</span>, and <span class="term">94</span>&#160;(for special double-quotes) are converted to ordinary single and double quotes respectively and not to entities.<br />
+<br />
+&#160; The character values are replaced with entities/characters and not character values referred to by the entities/characters to keep this task independent of the character-encoding of input text.<br />
+<br />
+&#160; The <span class="term">$config["clean_ms_char"]</span>&#160;parameter need not be used if authors do not copy-paste Microsoft-created text or if the input text is not believed to use the <span class="term">Windows 1252</span>&#160;or a similar encoding. Further, the input form and the web-pages displaying it or its content should have the character encoding appropriately marked-up.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.2" id="s3.2"></a><span class="item-no">3.2</span>&#160; Character references/entities
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Valid character entities take the form <span class="term">&amp;&#42;;</span>&#160;where <span class="term">&#42;</span>&#160;is <span class="term">#x</span>&#160;followed by a hexadecimal number (hexadecimal numeric entity; like <span class="term">&amp;#xA0;</span>&#160;for non-breaking space), or alphanumeric like <span class="term">gt</span>&#160;(external or named entity; like <span class="term">&amp;nbsp;</span>&#160;for non-breaking space), or <span class="term">#</span>&#160;followed by a number (decimal numeric entity; like <span class="term">&amp;#160;</span>&#160;for non-breaking space). Character entities referring to the soft-hyphen character (the <span class="term">&amp;shy;</span>&#160;or <span class="term">\xad</span>&#160;character; hexadecimal code-point <span class="term">ad</span>&#160;[decimal <span class="term">173</span>]) in attribute values are always replaced with spaces; soft-hyphens in attribute values introduce vulnerabilities in some older versions of the Opera and Mozilla [Firefox] browsers.<br />
+<br />
+&#160; htmLawed (function <span class="term">hl_ent()</span>):<br />
+<br />
+&#160; * &#160;Neutralizes entities with multiple leading zeroes or missing semi-colons (potentially dangerous)<br />
+<br />
+&#160; * &#160;Lowercases the <span class="term">X</span>&#160;(for XML-compliance) and <span class="term">A-F</span>&#160;of hexadecimal numeric entities<br />
+<br />
+&#160; * &#160;Neutralizes entities referring to characters that are HTML-invalid (see <a href="#s3.1">section 3.1</a>)<br />
+<br />
+&#160; * &#160;Neutralizes entities referring to characters that are HTML-discouraged (code-points, hexadecimally, <span class="term">7f</span>&#160;to <span class="term">84</span>, <span class="term">86</span>&#160;to <span class="term">9f</span>, and <span class="term">fdd0</span>&#160;to <span class="term">fddf</span>, or decimally, <span class="term">127</span>&#160;to <span class="term">132</span>, <span class="term">134</span>&#160;to <span class="term">159</span>, and <span class="term">64991</span>&#160;to <span class="term">64976</span>). Entities referring to the remaining discouraged characters (see <a href="#s5.1">section 5.1</a>&#160;for a full list) are let through.<br />
+<br />
+&#160; * &#160;Neutralizes named entities that are not in the specs.<br />
+<br />
+&#160; * &#160;Optionally converts valid HTML-specific named entities except <span class="term">&amp;gt;</span>, <span class="term">&amp;lt;</span>, <span class="term">&amp;quot;</span>, and <span class="term">&amp;amp;</span>&#160;to decimal numeric ones (hexadecimal if $config["hexdec_entity"] is <span class="term">2</span>) for generic XML-compliance. For this, <span class="term">$config["named_entity"]</span>&#160;should be <span class="term">1</span>.<br />
+<br />
+&#160; * &#160;Optionally converts hexadecimal numeric entities to the more widely supported decimal ones. For this, <span class="term">$config["hexdec_entity"]</span>&#160;should be <span class="term">0</span>.<br />
+<br />
+&#160; * &#160;Optionally converts decimal numeric entities to the hexadecimal ones. For this, <span class="term">$config["hexdec_entity"]</span>&#160;should be <span class="term">2</span>.<br />
+<br />
+&#160; <em>Neutralization</em>&#160;refers to the <em>entitification</em>&#160;of <span class="term">&amp;</span>&#160;to <span class="term">&amp;amp;</span>.<br />
+<br />
+&#160; <strong>Note</strong>: htmLawed does not convert entities to the actual characters represented by them; one can pass the htmLawed output through PHP's <span class="term">html_entity_decode</span>&#160;<a href="http://www.php.net/html_entity_decode">function</a>&#160;for that.<br />
+<br />
+&#160; <strong>Note</strong>: If <span class="term">$config["and_mark"]</span>&#160;is set, and set to a value other than <span class="term">0</span>, then the <span class="term">&amp;</span>&#160;characters in the original input are replaced with the control character for the hexadecimal code-point <span class="term">6</span>&#160;(<span class="term">\x06</span>; <span class="term">&amp;</span>&#160;characters introduced by htmLawed, e.g., after converting <span class="term">&lt;</span>&#160;to <span class="term">&amp;lt;</span>, are not affected). This allows one to distinguish, say, an <span class="term">&amp;gt;</span>&#160;introduced by htmLawed and an <span class="term">&amp;gt;</span>&#160;put in by the input writer, and can be helpful in further processing of the htmLawed-processed text (e.g., to identify the character sequence <span class="term">o(&gt;&lt;)o</span>&#160;to generate an emoticon image). When this feature is active, admins should ensure that the htmLawed output is not directly used in web pages or XML documents as the presence of the <span class="term">\x06</span>&#160;can break documents. Before use in such documents, and preferably before any storage, any remaining <span class="term">\x06</span>&#160;should be changed back to <span class="term">&amp;</span>, e.g., with:<br />
+<br />
+
+<code class="code">&#160; &#160; $final = str_replace("\x06", &#39;&amp;&#39;, $prelim);</code>
+<br />
+<br />
+&#160; Also, see <a href="#s3.9">section 3.9</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.3" id="s3.3"></a><span class="item-no">3.3</span>&#160; HTML elements
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can be configured to allow only certain HTML elements (tags) in the input. Disallowed elements (just tag-content, and not element-content), based on <span class="term">$config["keep_bad"]</span>, are either <em>neutralized</em>&#160;(converted to plain text by entitification of <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>) or removed.<br />
+<br />
+&#160; E.g., with only <span class="term">em</span>&#160;permitted:<br />
+<br />
+&#160; Input:<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;em&gt;My&lt;/em&gt; website is &lt;a href="http&#58;//a.com&gt;a.com&lt;/a&gt;.</code>
+<br />
+<br />
+&#160; Output, with <span class="term">$config["keep_bad"] = 0</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;em&gt;My&lt;/em&gt; website is a.com.</code>
+<br />
+<br />
+&#160; Output, with <span class="term">$config["keep_bad"]</span>&#160;not <span class="term">0</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;em&gt;My&lt;/em&gt; website is &amp;lt;a href=""&amp;gt;a.com&amp;lt;/a&amp;gt;.</code>
+<br />
+<br />
+&#160; See <a href="#s3.3.3">section 3.3.3</a>&#160;for differences between the various non-zero <span class="term">$config["keep_bad"]</span>&#160;values.<br />
+<br />
+&#160; htmLawed by default permits these 86 elements:<br />
+<br />
+
+<code class="code">&#160; &#160; a, abbr, acronym, address, applet, area, b, bdo, big, blockquote, br, button, caption, center, cite, code, col, colgroup, dd, del, dfn, dir, div, dl, dt, em, embed, fieldset, font, form, h1, h2, h3, h4, h5, h6, hr, i, iframe, img, input, ins, isindex, kbd, label, legend, li, map, menu, noscript, object, ol, optgroup, option, p, param, pre, q, rb, rbc, rp, rt, rtc, ruby, s, samp, script, select, small, span, strike, strong, sub, sup, table, tbody, td, textarea, tfoot, th, thead, tr, tt, u, ul, var</code>
+<br />
+<br />
+&#160; Except for <span class="term">embed</span>&#160;(included because of its wide-spread use) and the Ruby elements (<span class="term">rb</span>, <span class="term">rbc</span>, <span class="term">rp</span>, <span class="term">rt</span>, <span class="term">rtc</span>, <span class="term">ruby</span>; part of XHTML 1.1), these are all the elements in the HTML 4/XHTML 1 specs. Strict-specific specs. exclude <span class="term">center</span>, <span class="term">dir</span>, <span class="term">font</span>, <span class="term">isindex</span>, <span class="term">menu</span>, <span class="term">s</span>, <span class="term">strike</span>, and <span class="term">u</span>.<br />
+<br />
+&#160; With <span class="term">$config["safe"] = 1</span>, the default set will exclude <span class="term">applet</span>, <span class="term">embed</span>, <span class="term">iframe</span>, <span class="term">object</span>&#160;and <span class="term">script</span>; see <a href="#s3.6">section 3.6</a>.<br />
+<br />
+&#160; When <span class="term">$config["elements"]</span>, which specifies allowed elements, is <em>properly</em>&#160;defined, and neither empty nor set to <span class="term">0</span>&#160;or <span class="term">&#42;</span>, the default set is not used. To have elements added to or removed from the default set, a <span class="term">+/-</span>&#160;notation is used. E.g., <span class="term">&#42;-script-object</span>&#160;implies that only <span class="term">script</span>&#160;and <span class="term">object</span>&#160;are disallowed, whereas <span class="term">&#42;+embed</span>&#160;means that <span class="term">noembed</span>&#160;is also allowed. Elements can also be specified as comma separated names. E.g., <span class="term">a, b, i</span>&#160;means only <span class="term">a</span>, <span class="term">b</span>&#160;and <span class="term">i</span>&#160;are permitted. In this notation, <span class="term">&#42;</span>, <span class="term">+</span>&#160;and <span class="term">-</span>&#160;have no significance and can actually cause a mis-reading.<br />
+<br />
+&#160; Some more examples of <span class="term">$config["elements"]</span>&#160;values indicating permitted elements (note that empty spaces are liberally allowed for clarity):<br />
+<br />
+&#160; * &#160;<span class="term">a, blockquote, code, em, strong</span>&#160;-- only <span class="term">a</span>, <span class="term">blockquote</span>, <span class="term">code</span>, <span class="term">em</span>, and <span class="term">strong</span><br />
+&#160; * &#160;<span class="term">&#42;-script</span>&#160;-- all excluding <span class="term">script</span><br />
+&#160; * &#160;<span class="term">&#42; -center -dir -font -isindex -menu -s -strike -u</span>&#160;-- only XHTML-Strict elements<br />
+&#160; * &#160;<span class="term">&#42;+noembed-script</span>&#160;-- all including <span class="term">noembed</span>&#160;excluding <span class="term">script</span><br />
+<br />
+&#160; Some mis-usages (and the resulting permitted elements) that can be avoided:<br />
+<br />
+&#160; * &#160;<span class="term">-&#42;</span>&#160;-- none; instead of htmLawed, one might just use, e.g., the <span class="term">htmlspecialchars()</span>&#160;PHP function<br />
+&#160; * &#160;<span class="term">&#42;, -script</span>&#160;-- all except <span class="term">script</span>; admin probably meant <span class="term">&#42;-script</span><br />
+&#160; * &#160;<span class="term">-&#42;, a, em, strong</span>&#160;-- all; admin probably meant <span class="term">a, em, strong</span><br />
+&#160; * &#160;<span class="term">&#42;</span>&#160;-- all; admin need not have set <span class="term">elements</span><br />
+&#160; * &#160;<span class="term">&#42;-form+form</span>&#160;-- all; a <span class="term">+</span>&#160;will always over-ride any <span class="term">-</span><br />
+&#160; * &#160;<span class="term">&#42;, noembed</span>&#160;-- only <span class="term">noembed</span>; admin probably meant <span class="term">&#42;+noembed</span><br />
+&#160; * &#160;<span class="term">a, +b, i</span>&#160;-- only <span class="term">a</span>&#160;and <span class="term">i</span>; admin probably meant <span class="term">a, b, i</span><br />
+<br />
+&#160; Basically, when using the <span class="term">+/-</span>&#160;notation, commas (<span class="term">,</span>) should not be used, and vice versa, and <span class="term">&#42;</span>&#160;should be used with the former but not the latter.<br />
+<br />
+&#160; <strong>Note</strong>: Even if an element that is not in the default set is allowed through <span class="term">$config["elements"]</span>, like <span class="term">noembed</span>&#160;in the last example, it will eventually be removed during tag balancing unless such balancing is turned off (<span class="term">$config["balance"]</span>&#160;set to <span class="term">0</span>). Currently, the only way around this, which actually is simple, is to edit the various arrays in the function <span class="term">hl_bal()</span>&#160;to accommodate the element and its nesting properties.<br />
+<br />
+&#160; <strong>A possibly second way to specify allowed elements</strong>&#160;is to set <span class="term">$config["parent"]</span>&#160;to an element name that supposedly will hold the input, and to set <span class="term">$config["balance"]</span>&#160;to <span class="term">1</span>. During tag balancing (see <a href="#s3.3.3">section 3.3.3</a>), all elements that cannot legally nest inside the parent element will be removed. The parent element is auto-reset to <span class="term">div</span>&#160;if <span class="term">$config["parent"]</span>&#160;is empty, <span class="term">body</span>, or an element not in htmLawed's default set of 86 elements.<br />
+<br />
+&#160; <em>Tag transformation</em>&#160;is possible for improving XHTML-Strict compliance -- most of the deprecated elements are removed or converted to valid XHTML-Strict ones; see <a href="#s3.3.2">section 3.3.2</a>.<br />
+
+<div class="sub-sub-section"><h4>
+<a name="s3.3.1" id="s3.3.1"></a><span class="item-no">3.3.1</span>&#160; Handling of comments and CDATA sections
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; <span class="term">CDATA</span>&#160;sections have the format <span class="term">&lt;![CDATA[...anything but not "]]&gt;"...]]&gt;</span>, and HTML comments, <span class="term">&lt;!--...anything but not "--&gt;"... --&gt;</span>. Neither HTML comments nor <span class="term">CDATA</span>&#160;sections can reside inside tags. HTML comments can exist anywhere else, but <span class="term">CDATA</span>&#160;sections can exist only where plain text is allowed (e.g., immediately inside <span class="term">td</span>&#160;element content but not immediately inside <span class="term">tr</span>&#160;element content).<br />
+<br />
+&#160; htmLawed (function <span class="term">hl_cmtcd()</span>) handles HTML comments or <span class="term">CDATA</span>&#160;sections depending on the values of <span class="term">$config["comment"]</span>&#160;or <span class="term">$config["cdata"]</span>. If <span class="term">0</span>, such markup is not looked for and the text is processed like plain text. If <span class="term">1</span>, it is removed completely. If <span class="term">2</span>, it is preserved but any <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;inside are changed to entities. If <span class="term">3</span>, they are left as such.<br />
+<br />
+&#160; Note that for the last two cases, HTML comments and <span class="term">CDATA</span>&#160;sections will always be removed from tag content (function <span class="term">hl_tag()</span>).<br />
+<br />
+&#160; Examples:<br />
+<br />
+&#160; Input:<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link --&gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 0, $config["cdata"] = 2</span>):<br />
+
+<code class="code">&#160; &#160; &amp;lt;-- home link --&amp;gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 1, $config["cdata"] = 2</span>):<br />
+
+<code class="code">&#160; &#160; &lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 2, $config["cdata"] = 2</span>):<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link --&gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 2, $config["cdata"] = 1</span>):<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link --&gt;&lt;a href="home.htm"&gt;Home&lt;/a&gt;</code>
+<br />
+&#160; Output (<span class="term">$config["comment"] = 3, $config["cdata"] = 3</span>):<br />
+
+<code class="code">&#160; &#160; &lt;!-- home link --&gt;&lt;a href="home.htm"&gt;&lt;![CDATA[x=&amp;y]]&gt;Home&lt;/a&gt;</code>
+<br />
+<br />
+&#160; For standard-compliance, comments are given the form <span class="term">&lt;!--comment --&gt;</span>, and any <span class="term">--</span>&#160;in the content is made <span class="term">-</span>.<br />
+<br />
+&#160; When <span class="term">$config["safe"] = 1</span>, CDATA sections and comments are considered plain text unless <span class="term">$config["comment"]</span>&#160;or <span class="term">$config["cdata"]</span>&#160;is explicitly specified; see <a href="#s3.6">section 3.6</a>.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.3.2" id="s3.3.2"></a><span class="item-no">3.3.2</span>&#160; Tag-transformation for better XHTML-Strict
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["make_tag_strict"]</span>&#160;is set and not <span class="term">0</span>, following non-XHTML-Strict elements (and attributes), even if admin-permitted, are mutated as indicated (element content remains intact; function <span class="term">hl_tag2()</span>):<br />
+<br />
+&#160; * &#160;applet - (based on <span class="term">$config["make_tag_strict"]</span>, unchanged (<span class="term">1</span>) or removed (<span class="term">2</span>))<br />
+&#160; * &#160;center - <span class="term">div style="text-align&#58; center;"</span><br />
+&#160; * &#160;dir - <span class="term">ul</span><br />
+&#160; * &#160;embed - (based on <span class="term">$config["make_tag_strict"]</span>, unchanged (<span class="term">1</span>) or removed (<span class="term">2</span>))<br />
+&#160; * &#160;font (face, size, color) - &#160; &#160;<span class="term">span style="font-family&#58; ; font-size&#58; ; color&#58; ;"</span>&#160;(size transformation <a href="http://style.cleverchimp.com/font_size_intervals/altintervals.html">reference</a>)<br />
+&#160; * &#160;isindex - (based on <span class="term">$config["make_tag_strict"]</span>, unchanged (<span class="term">1</span>) or removed (<span class="term">2</span>))<br />
+&#160; * &#160;menu - <span class="term">ul</span><br />
+&#160; * &#160;s - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
+&#160; * &#160;strike - <span class="term">span style="text-decoration&#58; line-through;"</span><br />
+&#160; * &#160;u - <span class="term">span style="text-decoration&#58; underline;"</span><br />
+<br />
+&#160; For an element with a pre-existing <span class="term">style</span>&#160;attribute value, the extra style properties are appended.<br />
+<br />
+&#160; Example input:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;center&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;The PHP &lt;s&gt;software&lt;/s&gt; script used for this &lt;strike&gt;web-page&lt;/strike&gt; web-page is &lt;font style="font-weight&#58; bold " face=arial size=&#39;+3&#39; color &#160; = &#160;"red &#160;"&gt;htmLawedTest.php&lt;/font&gt;, from &lt;u style= &#39;color&#58;green&#39;&gt;PHP Labware&lt;/u&gt;.</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/center&gt;</code>
+<br />
+<br />
+&#160; The output:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;div style="text-align&#58; center;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;The PHP &lt;span style="text-decoration&#58; line-through;"&gt;software&lt;/span&gt; script used for this &lt;span style="text-decoration&#58; line-through;"&gt;web-page&lt;/span&gt; web-page is &lt;span style="font-weight&#58; bold; font-family&#58; arial; color&#58; red; font-size&#58; 200%;"&gt;htmLawedTest.php&lt;/span&gt;, from &lt;span style="color&#58;green; text-decoration&#58; underline;"&gt;PHP Labware&lt;/span&gt;.</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/div&gt;</code>
+<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.3.3" id="s3.3.3"></a><span class="item-no">3.3.3</span>&#160; Tag balancing and proper nesting
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["balance"]</span>&#160;is set to <span class="term">1</span>, htmLawed (function <span class="term">hl_bal()</span>) checks and corrects the input to have properly balanced tags and legal element content (i.e., any element nesting should be valid, and plain text may be present only in the content of elements that allow them).<br />
+<br />
+&#160; Depending on the value of <span class="term">$config["keep_bad"]</span>&#160;(see <a href="#s2.2">section 2.2</a>&#160;and <a href="#s3.3">section 3.3</a>), illegal content may be removed or neutralized to plain text by converting &lt; and &gt; to entities:<br />
+<br />
+&#160; <span class="term">0</span>&#160;- remove; this option is available only to maintain Kses-compatibility and should not be used otherwise (see <a href="#s2.6">section 2.6</a>)<br />
+&#160; <span class="term">1</span>&#160;- neutralize tags and keep element content<br />
+&#160; <span class="term">2</span>&#160;- remove tags but keep element content<br />
+&#160; <span class="term">3</span>&#160;and <span class="term">4</span>&#160;- like <span class="term">1</span>&#160;and <span class="term">2</span>, but keep element content only if text (<span class="term">pcdata</span>) is valid in parent element as per specs<br />
+&#160; <span class="term">5</span>&#160;and <span class="term">6</span>&#160;- &#160;like <span class="term">3</span>&#160;and <span class="term">4</span>, but line-breaks, tabs and spaces are left<br />
+<br />
+&#160; Example input (disallowing the <span class="term">p</span>&#160;element):<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;&#42;&gt; Pseudo-tags &lt;&#42;&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;xml&gt;Non-HTML tag xml&lt;/xml&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;Bad&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; The output with <span class="term">$config["keep_bad"] = 1</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;&#42;&amp;gt; Pseudo-tags &amp;lt;&#42;&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;xml&amp;gt;Non-HTML tag xml&amp;lt;/xml&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;/p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;Bad&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; The output with <span class="term">$config["keep_bad"] = 3</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;&#42;&amp;gt; Pseudo-tags &amp;lt;&#42;&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;xml&amp;gt;Non-HTML tag xml&amp;lt;/xml&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;/p&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; The output with <span class="term">$config["keep_bad"] = 6</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &amp;lt;&#42;&amp;gt; Pseudo-tags &amp;lt;&#42;&amp;gt;</code>
+<br />
+
+<code class="code">&#160; &#160; Non-HTML tag xml</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; Disallowed tag p</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;ul&gt;&lt;li&gt;OK&lt;/li&gt;&lt;/ul&gt;</code>
+<br />
+<br />
+&#160; An option like <span class="term">1</span>&#160;is useful, e.g., when a writer previews his submission, whereas one like <span class="term">3</span>&#160;is useful before content is finalized and made available to all.<br />
+<br />
+&#160; <strong>Note:</strong>&#160;In the example above, unlike <span class="term">&lt;&#42;&gt;</span>, <span class="term">&lt;xml&gt;</span>&#160;gets considered as a tag (even though there is no HTML element named <span class="term">xml</span>). In general, text matching the regular expression pattern <span class="term">&lt;(/?)([a-zA-Z][a-zA-Z1-6]&#42;)([^&gt;]&#42;?)\s?&gt;</span>&#160;is considered a tag (phrase enclosed by the angled brackets <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>, and starting [with an optional slash preceding] with an alphanumeric word that starts with an alphabet...).<br />
+<br />
+&#160; Nesting/content rules for each of the 86 elements in htmLawed's default set (see <a href="#s3.3">section 3.3</a>) are defined in function <span class="term">hl_bal()</span>. This means that if a non-standard element besides <span class="term">embed</span>&#160;is being permitted through <span class="term">$config["elements"]</span>, the element's tag content will end up getting removed if <span class="term">$config["balance"]</span>&#160;is set to <span class="term">1</span>.<br />
+<br />
+&#160; Plain text and/or certain elements nested inside <span class="term">blockquote</span>, <span class="term">form</span>, <span class="term">map</span>&#160;and <span class="term">noscript</span>&#160;need to be in block-level elements. This point is often missed during manual writing of HTML code. htmLawed attempts to address this during balancing. E.g., if the parent container is set as <span class="term">form</span>, the input <span class="term">B&#58;&lt;input type="text" value="b" /&gt;C&#58;&lt;input type="text" value="c" /&gt;</span>&#160;is converted to <span class="term">&lt;div&gt;B&#58;&lt;input type="text" value="b" /&gt;C&#58;&lt;input type="text" value="c" /&gt;&lt;/div&gt;</span>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.3.4" id="s3.3.4"></a><span class="item-no">3.3.4</span>&#160; Elements requiring child elements
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; As per specs, the following elements require legal child elements nested inside them:<br />
+<br />
+
+<code class="code">&#160; &#160; blockquote, dir, dl, form, map, menu, noscript, ol, optgroup, rbc, rtc, ruby, select, table, tbody, tfoot, thead, tr, ul</code>
+<br />
+<br />
+&#160; In some cases, the specs stipulate the number and/or the ordering of the child elements. A <span class="term">table</span>&#160;can have 0 or 1 <span class="term">caption</span>, <span class="term">tbody</span>, <span class="term">tfoot</span>, and <span class="term">thead</span>, but they must be in this order: <span class="term">caption</span>, <span class="term">thead</span>, <span class="term">tfoot</span>, <span class="term">tbody</span>.<br />
+<br />
+&#160; htmLawed currently does not check for conformance to these rules. Note that any non-compliance in this regard will not introduce security vulnerabilities, crash browser applications, or affect the rendering of web-pages.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.3.5" id="s3.3.5"></a><span class="item-no">3.3.5</span>&#160; Beautify or compact HTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; By default, htmLawed will neither <em>beautify</em>&#160;HTML code by formatting it with indentations, etc., nor will it make it compact by removing un-needed white-space.(It does always properly white-space tag content.)<br />
+<br />
+&#160; As per the HTML standards, spaces, tabs and line-breaks in web-pages (except those inside <span class="term">pre</span>&#160;elements) are all considered equivalent, and referred to as <em>white-spaces</em>. Browser applications are supposed to consider contiguous white-spaces as just a single space, and to disregard white-spaces trailing opening tags or preceding closing tags. This white-space <em>normalization</em>&#160;allows the use of text/code beautifully formatted with indentations and line-spacings for readability. Such <em>pretty</em>&#160;HTML can, however, increase the size of web-pages, or make the extraction or scraping of plain text cumbersome.<br />
+<br />
+&#160; With the <span class="term">$config</span>&#160;parameter <span class="term">tidy</span>, htmLawed can be used to beautify or compact the input text. Input with just plain text and no HTML markup is also subject to this. Besides <span class="term">pre</span>, the <span class="term">script</span>&#160;and <span class="term">textarea</span>&#160;elements, CDATA sections, and HTML comments are not subjected to the tidying process.<br />
+<br />
+&#160; To <em>compact</em>, use <span class="term">$config["tidy"] = -1</span>; single instances or runs of white-spaces are replaced with a single space, and white-spaces trailing and leading open and closing tags, respectively, are removed.<br />
+<br />
+&#160; To <em>beautify</em>, <span class="term">$config["tidy"]</span>&#160;is set as <span class="term">1</span>, or for customized tidying, as a string like <span class="term">2s2n</span>. The <span class="term">s</span>&#160;or <span class="term">t</span>&#160;character specifies the use of spaces or tabs for indentation. The first and third characters, any of the digits 0-9, specify the number of spaces or tabs per indentation, and any parental lead spacing (extra indenting of the whole block of input text). The <span class="term">r</span>&#160;and <span class="term">n</span>&#160;characters are used to specify line-break characters: <span class="term">n</span>&#160;for <span class="term">\n</span>&#160;(Unix/Mac OS X line-breaks), <span class="term">rn</span>&#160;or <span class="term">nr</span>&#160;for <span class="term">\r\n</span>&#160;(Windows/DOS line-breaks), or <span class="term">r</span>&#160;for <span class="term">\r</span>.<br />
+<br />
+&#160; The <span class="term">$config["tidy"]</span>&#160;value of <span class="term">1</span>&#160;is equivalent to <span class="term">2s0n</span>. Other <span class="term">$config["tidy"]</span>&#160;values are read loosely: a value of <span class="term">4</span>&#160;is equivalent to <span class="term">4s0n</span>; <span class="term">t2</span>, to <span class="term">1t2n</span>; <span class="term">s</span>, to <span class="term">2s0n</span>; <span class="term">2TR</span>, to <span class="term">2t0r</span>; <span class="term">T1</span>, to <span class="term">1t1n</span>; <span class="term">nr3</span>, to <span class="term">3s0nr</span>, and so on. Except in the indentations and line-spacings, runs of white-spaces are replaced with a single space during beautification.<br />
+<br />
+&#160; Input formatting using <span class="term">$config["tidy"]</span>&#160;is not recommended when input text has mixed markup (like HTML + PHP).<br />
+
+</div>
+</div>
+<div class="sub-section"><h3>
+<a name="s3.4" id="s3.4"></a><span class="item-no">3.4</span>&#160; Attributes
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed will only permit attributes described in the HTML specs (including deprecated ones). It also permits some attributes for use with the <span class="term">embed</span>&#160;element (the non-standard <span class="term">embed</span>&#160;element is supported in htmLawed because of its widespread use), and the the <span class="term">xml&#58;space</span>&#160;attribute (valid only in XHTML 1.1). A list of such 111 attributes and the elements they are allowed in is in <a href="#s5.2">section 5.2</a>.<br />
+<br />
+&#160; When <span class="term">$config["deny_attribute"]</span>&#160;is not set, or set to <span class="term">0</span>, or empty (<span class="term">""</span>), all the 111 attributes are permitted. Otherwise, <span class="term">$config["deny_attribute"]</span>&#160;can be set as a list of comma-separated names of the denied attributes. <span class="term">on&#42;</span>&#160;can be used to refer to the group of potentially dangerous, script-accepting attributes: <span class="term">onblur</span>, <span class="term">onchange</span>, <span class="term">onclick</span>, <span class="term">ondblclick</span>, <span class="term">onfocus</span>, <span class="term">onkeydown</span>, <span class="term">onkeypress</span>, <span class="term">onkeyup</span>, <span class="term">onmousedown</span>, <span class="term">onmousemove</span>, <span class="term">onmouseout</span>, <span class="term">onmouseover</span>, <span class="term">onmouseup</span>, <span class="term">onreset</span>, <span class="term">onselect</span>&#160;and <span class="term">onsubmit</span>.<br />
+<br />
+&#160; Note that attributes specified in <span class="term">$config["deny_attribute"]</span>&#160;are denied globally, for all elements. To deny attributes for only specific elements, <span class="term">$spec</span>&#160;(see <a href="#s2.3">section 2.3</a>) can be used. <span class="term">$spec</span>&#160;can also be used to element-specifically permit an attribute otherwise denied through <span class="term">$config["deny_attribute"]</span>.<br />
+<br />
+&#160; With <span class="term">$config["safe"] = 1</span>&#160;(<a href="#s3.6">section 3.6</a>), the <span class="term">on&#42;</span>&#160;attributes are automatically disallowed.<br />
+<br />
+&#160; <strong>Note</strong>: To deny all but a few attributes globally, a simpler way to specify <span class="term">$config["deny_attribute"]</span>&#160;would be to use the notation <span class="term">&#42; -attribute1 -attribute2 ...</span>. Thus, a value of <span class="term">&#42; -title -href</span>&#160;implies that except <span class="term">href</span>&#160;and <span class="term">title</span>&#160;(where allowed as per standards) all other attributes are to be removed. With this notation, the value for the parameter <span class="term">safe</span>&#160;(<a href="#s3.6">section 3.6</a>) will have no effect on <span class="term">deny_attribute</span>.<br />
+<br />
+&#160; htmLawed (function <span class="term">hl_tag()</span>) also:<br />
+<br />
+&#160; * &#160;Lower-cases attribute names<br />
+&#160; * &#160;Removes duplicate attributes (last one stays)<br />
+&#160; * &#160;Gives attributes the form <span class="term">name="value"</span>&#160;and single-spaces them, removing unnecessary white-spacing<br />
+&#160; * &#160;Provides <em>required</em>&#160;attributes (see <a href="#s3.4.1">section 3.4.1</a>)<br />
+&#160; * &#160;Double-quotes values and escapes any <span class="term">"</span>&#160;inside them<br />
+&#160; * &#160;Replaces the possibly dangerous soft-hyphen characters (hexadecimal code-point <span class="term">ad</span>) in the values with spaces<br />
+&#160; * &#160;Allows custom function to additionally filter/modify attribute values (see <a href="#s3.4.9">section 3.4.9</a>)<br />
+
+<div class="sub-sub-section"><h4>
+<a name="s3.4.1" id="s3.4.1"></a><span class="item-no">3.4.1</span>&#160; Auto-addition of XHTML-required attributes
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If indicated attributes for the following elements are found missing, htmLawed (function <span class="term">hl_tag()</span>) will add them (with values same as attribute names unless indicated otherwise below):<br />
+<br />
+&#160; * &#160;area - alt (<span class="term">area</span>)<br />
+&#160; * &#160;area, img - src, alt (<span class="term">image</span>)<br />
+&#160; * &#160;bdo - dir (<span class="term">ltr</span>)<br />
+&#160; * &#160;form - action<br />
+&#160; * &#160;map - name<br />
+&#160; * &#160;optgroup - label<br />
+&#160; * &#160;param - name<br />
+&#160; * &#160;script - type (<span class="term">text/javascript</span>)<br />
+&#160; * &#160;textarea - rows (<span class="term">10</span>), cols (<span class="term">50</span>)<br />
+<br />
+&#160; Additionally, with <span class="term">$config["xml&#58;lang"]</span>&#160;set to <span class="term">1</span>&#160;or <span class="term">2</span>, if the <span class="term">lang</span>&#160;but not the <span class="term">xml&#58;lang</span>&#160;attribute is declared, then the latter is added too, with a value copied from that of <span class="term">lang</span>. This is for better standard-compliance. With <span class="term">$config["xml&#58;lang"]</span>&#160;set to <span class="term">2</span>, the <span class="term">lang</span>&#160;attribute is removed (XHTML 1.1 specs).<br />
+<br />
+&#160; Note that the <span class="term">name</span>&#160;attribute for <span class="term">map</span>, invalid in XHTML 1.1, is also transformed if required -- see <a href="#s3.4.6">section 3.4.6</a>.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.2" id="s3.4.2"></a><span class="item-no">3.4.2</span>&#160; Duplicate/invalid <span class="term">id</span>&#160;values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["unique_ids"]</span>&#160;is <span class="term">1</span>, htmLawed (function <span class="term">hl_tag()</span>) removes <span class="term">id</span>&#160;attributes with values that are not XHTML-compliant (must begin with a letter and can contain letters, digits, <span class="term">&#58;</span>, <span class="term">.</span>, <span class="term">-</span>&#160;and <span class="term">_</span>) or duplicate. If <span class="term">$config["unique_ids"]</span>&#160;is a word, any duplicate but otherwise valid value will be appropriately prefixed with the word to ensure its uniqueness. The word should begin with a letter and should contain only letters, numbers, <span class="term">&#58;</span>, <span class="term">.</span>, <span class="term">_</span>&#160;and <span class="term">-</span>.<br />
+<br />
+&#160; Even if multiple inputs need to be filtered (through multiple calls to htmLawed), htmLawed ensures uniqueness of <span class="term">id</span>&#160;values as it uses a global variable (<span class="term">$GLOBALS["hl_Ids"]</span>&#160;array). Further, an admin can restrict the use of certain <span class="term">id</span>&#160;values by presetting this variable before htmLawed is called into use. E.g.:<br />
+<br />
+
+<code class="code">&#160; &#160; $GLOBALS[&#39;hl_Ids&#39;] = array(&#39;top&#39;=&gt;1, &#39;bottom&#39;=&gt;1, &#39;myform&#39;=&gt;1); // id values not allowed in input</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text); // filter input</code>
+<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.3" id="s3.4.3"></a><span class="item-no">3.4.3</span>&#160; URL schemes (protocols) and scripts in attribute values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed edits attributes that take URLs as values if they are found to contain un-permitted schemes. E.g., if the <span class="term">afp</span>&#160;scheme is not permitted, then <span class="term">&lt;a href="afp&#58;//domain.org"&gt;</span>&#160;becomes <span class="term">&lt;a href="denied&#58;afp&#58;//domain.org"&gt;</span>, and if Javascript is not permitted <span class="term">&lt;a onclick="javascript&#58;xss();"&gt;</span>&#160;becomes <span class="term">&lt;a onclick="denied&#58;javascript&#58;xss();"&gt;</span>.<br />
+<br />
+&#160; By default htmLawed permits these schemes in URLs for the <span class="term">href</span>&#160;attribute:<br />
+<br />
+
+<code class="code">&#160; &#160; aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet</code>
+<br />
+<br />
+&#160; Also, only <span class="term">file</span>, <span class="term">http</span>&#160;and <span class="term">https</span>&#160;are permitted in attributes whose names start with <span class="term">o</span>&#160;(like <span class="term">onmouseover</span>), and in these attributes that accept URLs:<br />
+<br />
+
+<code class="code">&#160; &#160; action, cite, classid, codebase, data, href, longdesc, model, pluginspage, pluginurl, src, style, usemap</code>
+<br />
+<br />
+&#160; These default sets are used when <span class="term">$config["schemes"]</span>&#160;is not set (see <a href="#s2.2">section 2.2</a>). To over-ride the defaults, <span class="term">$config["schemes"]</span>&#160;is defined as a string of semi-colon-separated sub-strings of type <span class="term">attribute&#58; comma-separated schemes</span>. E.g., <span class="term">href&#58; mailto, http, https; onclick&#58; javascript; src&#58; http, https</span>. For unspecified attributes, <span class="term">file</span>, <span class="term">http</span>&#160;and <span class="term">https</span>&#160;are permitted. This can be changed by passing schemes for <span class="term">&#42;</span>&#160;in <span class="term">$config["schemes"]</span>. E.g., <span class="term">href&#58; mailto, http, https; &#42;&#58; https, https</span>.<br />
+<br />
+&#160; <span class="term">&#42;</span>&#160;can be put in the list of schemes to permit all protocols. E.g., <span class="term">style&#58; &#42;; img&#58; http, https</span>&#160;results in protocols not being checked in <span class="term">style</span>&#160;attribute values. However, in such cases, any relative-to-absolute URL conversion, or vice versa, (<a href="#s3.4.4">section 3.4.4</a>) is not done.<br />
+<br />
+&#160; Thus, <em>to allow Javascript</em>, one can set <span class="term">$config["schemes"]</span>&#160;as <span class="term">href&#58; mailto, http, https; &#42;&#58; http, https, javascript</span>, or <span class="term">href&#58; mailto, http, https, javascript; &#42;&#58; http, https, javascript</span>, or <span class="term">&#42;&#58; &#42;</span>, and so on.<br />
+<br />
+&#160; As a side-note, one may find <span class="term">style&#58; &#42;</span>&#160;useful as URLs in <span class="term">style</span>&#160;attributes can be specified in a variety of ways, and the patterns that htmLawed uses to identify URLs may mistakenly identify non-URL text.<br />
+<br />
+&#160; <strong>Note</strong>: If URL-accepting attributes other than those listed above are being allowed, then the scheme will not be checked unless the attribute name contains the string <span class="term">src</span>&#160;(e.g., <span class="term">dynsrc</span>) or starts with <span class="term">o</span>&#160;(e.g., <span class="term">onbeforecopy</span>).<br />
+<br />
+&#160; With <span class="term">$config["safe"] = 1</span>, all URLs are disallowed in the <span class="term">style</span>&#160;attribute values.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.4" id="s3.4.4"></a><span class="item-no">3.4.4</span>&#160; Absolute &amp; relative URLs in attribute values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can make absolute URLs in attributes like <span class="term">href</span>&#160;relative (<span class="term">$config["abs_url"]</span>&#160;is <span class="term">-1</span>), and vice versa (<span class="term">$config["abs_url"]</span>&#160;is <span class="term">1</span>). URLs in scripts are not considered for this, and so are URLs like <span class="term">#section_6</span>&#160;(fragment), <span class="term">?name=Tim#show</span>&#160;(starting with query string), and <span class="term">;var=1?name=Tim#show</span>&#160;(starting with parameters). Further, this requires that <span class="term">$config["base_url"]</span>&#160;be set properly, with the <span class="term">&#58;//</span>&#160;and a trailing slash (<span class="term">/</span>), with no query string, etc. E.g., <span class="term">file&#58;///D&#58;/page/</span>, <span class="term">https&#58;//abc.com/x/y/</span>, or <span class="term">http&#58;//localhost/demo/</span>&#160;are okay, but <span class="term">file&#58;///D&#58;/page/?help=1</span>, <span class="term">abc.com/x/y/</span>&#160;and <span class="term">http&#58;//localhost/demo/index.htm</span>&#160;are not.<br />
+<br />
+&#160; For making absolute URLs relative, only those URLs that have the <span class="term">$config["base_url"]</span>&#160;string at the beginning are converted. E.g., with <span class="term">$config["base_url"] = "https&#58;//abc.com/x/y/"</span>, <span class="term">https&#58;//abc.com/x/y/a.gif</span>&#160;and <span class="term">https&#58;//abc.com/x/y/z/b.gif</span>&#160;become <span class="term">a.gif</span>&#160;and <span class="term">z/b.gif</span>&#160;respectively, while <span class="term">https&#58;//abc.com/x/c.gif</span>&#160;is not changed.<br />
+<br />
+&#160; When making relative URLs absolute, only values for scheme, network location (host-name) and path values in the base URL are inherited. See <a href="#s5.5">section 5.5</a>&#160;for more about the URL specification as per RFC <a href="http://www.ietf.org/rfc/rfc1808.txt">1808</a>.<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.5" id="s3.4.5"></a><span class="item-no">3.4.5</span>&#160; Lower-cased, standard attribute values
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Optionally, for standard-compliance, htmLawed (function <span class="term">hl_tag()</span>) lower-cases standard attribute values to give, e.g., <span class="term">input type="password"</span>&#160;instead of <span class="term">input type="Password"</span>, if <span class="term">$config["lc_std_val"]</span>&#160;is <span class="term">1</span>. Attribute values matching those listed below for any of the elements (plus those for the <span class="term">type</span>&#160;attribute of <span class="term">button</span>&#160;or <span class="term">input</span>) are lower-cased:<br />
+<br />
+
+<code class="code">&#160; &#160; all, baseline, bottom, button, center, char, checkbox, circle, col, colgroup, cols, data, default, file, get, groups, hidden, image, justify, left, ltr, middle, none, object, password, poly, post, preserve, radio, rect, ref, reset, right, row, rowgroup, rows, rtl, submit, text, top</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; a, area, bdo, button, col, form, img, input, object, option, optgroup, param, script, select, table, td, tfoot, th, thead, tr, xml&#58;space</code>
+<br />
+<br />
+&#160; The following <em>empty</em>&#160;(<em>minimized</em>) attributes are always assigned lower-cased values (same as the names):<br />
+<br />
+
+<code class="code">&#160; &#160; checked, compact, declare, defer, disabled, ismap, multiple, nohref, noresize, noshade, nowrap, readonly, selected</code>
+<br />
+
+</div>
+<div class="sub-sub-section"><h4>
+<a name="s3.4.6" id="s3.4.6"></a><span class="item-no">3.4.6</span>&#160; Transformation of deprecated attributes
+</h4><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["no_deprecated_attr"]</span>&#160;is <span class="term">0</span>, then deprecated attributes (see appendix in <a href="#s5.2">section 5.2</a>) are removed and, in most cases, their values are transformed to CSS style properties and added to the <span class="term">style</span>&#160;attributes (function <span class="term">hl_tag()</span>). Except for <span class="term">bordercolor</span>&#160;for <span class="term">table</span>, <span class="term">tr</span>&#160;and <span class="term">td</span>, the scores of proprietary attributes that were never part of any cross-browser standard are not supported.<br />
+<br />
+&#160; <strong>Note</strong>: The attribute <span class="term">target</span>&#160;for <span class="term">a</span>&#160;is allowed even though it is not in XHTML 1.0 specs. This is because of the attribute's wide-spread use and browser-support, and because the attribute is valid in XHTML 1.1 onwards.<br />
+<br />
+&#160; * &#160;align - for <span class="term">img</span>&#160;with value of <span class="term">left</span>&#160;or <span class="term">right</span>, becomes, e.g., <span class="term">float&#58; left</span>; for <span class="term">div</span>&#160;and <span class="term">table</span>&#160;with value <span class="term">center</span>, becomes <span class="term">margin&#58; auto</span>; all others become, e.g., <span class="term">text-align&#58; right</span><br />
+<br />
+&#160; * &#160;bgcolor - E.g., <span class="term">bgcolor="#ffffff"</span>&#160;becomes <span class="term">background-color&#58; #ffffff</span><br />
+&#160; * &#160;border - E.g., <span class="term">height= "10"</span>&#160;becomes <span class="term">height&#58; 10px</span><br />
+&#160; * &#160;bordercolor - E.g., <span class="term">bordercolor=#999999</span>&#160;becomes <span class="term">border-color&#58; #999999;</span><br />
+&#160; * &#160;compact - <span class="term">font-size&#58; 85%</span><br />
+&#160; * &#160;clear - E.g., 'clear="all" becomes <span class="term">clear&#58; both</span><br />
+<br />
+&#160; * &#160;height - E.g., <span class="term">height= "10"</span>&#160;becomes <span class="term">height&#58; 10px</span>&#160;and <span class="term">height="&#42;"</span>&#160;becomes <span class="term">height&#58; auto</span><br />
+<br />
+&#160; * &#160;hspace - E.g., <span class="term">hspace="10"</span>&#160;becomes <span class="term">margin-left&#58; 10px; margin-right&#58; 10px</span><br />
+&#160; * &#160;language - <span class="term">language="VBScript"</span>&#160;becomes <span class="term">type="text/vbscript"</span><br />
+&#160; * &#160;name - E.g., <span class="term">name="xx"</span>&#160;becomes <span class="term">id="xx"</span><br />
+&#160; * &#160;noshade - <span class="term">border-style&#58; none; border&#58; 0; background-color&#58; gray; color&#58; gray</span><br />
+&#160; * &#160;nowrap - <span class="term">white-space&#58; nowrap</span><br />
+&#160; * &#160;size - E.g., <span class="term">size="10"</span>&#160;becomes <span class="term">height&#58; 10px</span><br />
+&#160; * &#160;start - removed<br />
+&#160; * &#160;type - E.g., <span class="term">type="i"</span>&#160;becomes <span class="term">list-style-type&#58; lower-roman</span><br />
+&#160; * &#160;value - removed<br />
+&#160; * &#160;vspace - E.g., <span class="term">vspace="10"</span>&#160;becomes <span class="term">margin-top&#58; 10px; margin-bottom&#58; 10px</span><br />
+&#160; * &#160;width - like <span class="term">height</span><br />
+<br />
+&#160; Example input:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;img src="j.gif" alt="image" name="dad&#39;s" /&gt;&lt;img src="k.gif" alt="image" id="dad_off" name="dad" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br clear="left" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;hr noshade size="1" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;img name="img" src="i.gif" align="left" alt="image" hspace="10" vspace="10" width="10em" height="20" border="1" style="padding&#58;5px;" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;table width="50em" align="center" bgcolor="red"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td width="20%"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;div align="center"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;h3 align="right"&gt;Section&lt;/h3&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;p align="right"&gt;Para&lt;/p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;ol type="a" start="e"&gt;&lt;li value="x"&gt;First item&lt;/li&gt;&lt;/ol&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;/div&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td width="&#42;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;ol type="1"&gt;&lt;li&gt;First item&lt;/li&gt;&lt;/ol&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;/tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/table&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br clear="all" /&gt;</code>
+<br />
+<br />
+&#160; And the output with <span class="term">$config["no_deprecated_attr"] = 1</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; &lt;img src="j.gif" alt="image" /&gt;&lt;img src="k.gif" alt="image" id="dad_off" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br style="clear&#58; left;" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;hr style="border-style&#58; none; border&#58; 0; background-color&#58; gray; color&#58; gray; size&#58; 1px;" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;img src="i.gif" alt="image" width="10em" height="20" style="padding&#58;5px; float&#58; left; margin-left&#58; 10px; margin-right&#58; 10px; margin-top&#58; 10px; margin-bottom&#58; 10px; border&#58; 1px;" id="img" /&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;table width="50em" style="margin&#58; auto; background-color&#58; red;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td style="width&#58; 20%;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;div style="margin&#58; auto;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;h3 style="text-align&#58; right;"&gt;Section&lt;/h3&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;p style="text-align&#58; right;"&gt;Para&lt;/p&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; &lt;ol style="list-style-type&#58; lower-latin;"&gt;&lt;li&gt;First item&lt;/li&gt;&lt;/ol&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;/div&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;td style="width&#58; auto;"&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160;&lt;ol style="list-style-type&#58; decimal;"&gt;&lt;li&gt;First item&lt;/li&gt;&lt;/ol&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &lt;/td&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160;&lt;/tr&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;/table&gt;</code>
+<br />
+
+<code class="code">&#160; &#160; &lt;br style="clear&#58; both;" /&gt;</code>
+<br />
+<br />
+&#160; For <span class="term">lang</span>, deprecated in XHTML 1.1, transformation is taken care of through <span class="term">$config["xml&#58;lang"]</span>; see <a href="#s3.4.1">section 3.4.1</a>.<br />
+<br />
+&#160; The attribute <span class="term">name</span>&#160;is deprecated in <span class="term">form</span>, <span class="term">iframe</span>, and <span class="term">img</span>, and is replaced with <span class="term">id</span>&#160;if an <span class="term">id</span>&#160;attribute doesn't exist and if the <span class="term">name</span>&#160;value is appropriate for <span class="term">id</span>. For such replacements for <span class="term">a</span>&#160;and <span class="term">map</span>, for which the <span class="term">name</span>&#160;attribute is deprecated in XHTML 1.1, <span class="term">$config["no_deprecated_attr"]</span>&#160;should be set to <span class="term">2</span>&#160;(when set to <span class="term">1</span>, for these two elements, the <span class="term">name</span>&#160;attribute is retained).<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.4.7" id="s3.4.7"></a><span class="item-no">3.4.7</span>&#160; Anti-spam &amp; <span class="term">href</span>
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed (function <span class="term">hl_tag()</span>) can check the <span class="term">href</span>&#160;attribute values (link addresses) as an anti-spam (email or link spam) measure.<br />
+<br />
+&#160; If <span class="term">$config["anti_mail_spam"]</span>&#160;is not <span class="term">0</span>, the <span class="term">@</span>&#160;of email addresses in <span class="term">href</span>&#160;values like <span class="term">mailto&#58;a@b.com</span>&#160;is replaced with text specified by <span class="term">$config["anti_mail_spam"]</span>. The text should be of a form that makes it clear to others that the address needs to be edited before a mail is sent; e.g., <span class="term">&lt;remove_this_antispam&gt;@</span>&#160;(makes the example address <span class="term">a&lt;remove_this_antispam&gt;@b.com</span>).<br />
+<br />
+&#160; For regular links, one can choose to have a <span class="term">rel</span>&#160;attribute with <span class="term">nofollow</span>&#160;in its value (which tells some search engines to not follow a link). This can discourage link spammers. Additionally, or as an alternative, one can choose to empty the <span class="term">href</span>&#160;value altogether (disable the link).<br />
+<br />
+&#160; For use of these options, <span class="term">$config["anti_link_spam"]</span>&#160;should be set as an array with values <span class="term">regex1</span>&#160;and <span class="term">regex2</span>, both or one of which can be empty (like <span class="term">array("", "regex2")</span>) to indicate that that option is not to be used. Otherwise, <span class="term">regex1</span>&#160;or <span class="term">regex2</span>&#160;should be PHP- and PCRE-compatible regular expression patterns: <span class="term">href</span>&#160;values will be matched against them and those matching the pattern will accordingly be treated.<br />
+<br />
+&#160; Note that the regular expressions should have <em>delimiters</em>, and be well-formed and preferably fast. Absolute efficiency/accuracy is often not needed.<br />
+<br />
+&#160; An example, to have a <span class="term">rel</span>&#160;attribute with <span class="term">nofollow</span>&#160;for all links, and to disable links that do not point to domains <span class="term">abc.com</span>&#160;and <span class="term">xyz.org</span>:<br />
+<br />
+
+<code class="code">&#160; &#160; $config["anti_link_spam"] = array(&#39;&#96;.&#96;&#39;, &#39;&#96;&#58;//\W&#42;(?!(abc\.com|xyz\.org))&#96;&#39;);</code>
+<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.4.8" id="s3.4.8"></a><span class="item-no">3.4.8</span>&#160; Inline style properties
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can check URL schemes and dynamic expressions (to guard against Javascript, etc., script-based insecurities) in inline CSS style property values in the <span class="term">style</span>&#160;attributes. (CSS properties like <span class="term">background-image</span>&#160;that accept URLs in their values are noted in <a href="#s5.3">section 5.3</a>.) Dynamic CSS expressions that allow scripting in the IE browser, and can be a vulnerability, can be removed from property values by setting <span class="term">$config["css_expression"]</span>&#160;to <span class="term">1</span>&#160;(default setting).<br />
+<br />
+&#160; <strong>Note</strong>: Because of the various ways of representing characters in attribute values (URL-escapement, entitification, etc.), htmLawed might alter the values of the <span class="term">style</span>&#160;attribute values, and may even falsely identify dynamic CSS expressions and URL schemes in them. If this is an important issue, checking of URLs and dynamic expressions can be turned off (<span class="term">$config["schemes"] = "...style&#58;&#42;..."</span>, see <a href="#s3.4.3">section 3.4.3</a>, and <span class="term">$config["css_expression"] = 0</span>). Alternately, admins can use their own custom function for finer handling of <span class="term">style</span>&#160;values through the <span class="term">hook_tag</span>&#160;parameter (see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; It is also possible to have htmLawed let through any <span class="term">style</span>&#160;value by setting <span class="term">$config["style_pass"]</span>&#160;to <span class="term">1</span>.<br />
+<br />
+&#160; As such, it is better to set up a CSS file with class declarations, disallow the <span class="term">style</span>&#160;attribute, set a <span class="term">$spec</span>&#160;rule (see <a href="#s2.3">section 2.3</a>) for <span class="term">class</span>&#160;for the <span class="term">oneof</span>&#160;or <span class="term">match</span>&#160;parameter, and ask writers to make use of the <span class="term">class</span>&#160;attribute.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.4.9" id="s3.4.9"></a><span class="item-no">3.4.9</span>&#160; Hook function for tag content
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; It is possible to utilize a custom hook function to alter the tag content htmLawed has finalized (i.e., after it has checked/corrected for required attributes, transformed attributes, lower-cased attribute names, etc.).<br />
+<br />
+&#160; When <span class="term">$config</span>&#160;parameter <span class="term">hook_tag</span>&#160;is set to the name of a function, htmLawed (function <span class="term">hl_tag()</span>) will pass on the element name, and the <em>finalized</em>&#160;attribute name-value pairs as array elements to the function. The function is expected to return the full opening tag string like <span class="term">&lt;element_name attribute_1_name="attribute_1_value"...&gt;</span>&#160;(for empty elements like <span class="term">img</span>&#160;and <span class="term">input</span>, the element-closing slash <span class="term">/</span>&#160;should also be included).<br />
+<br />
+&#160; This is a <strong>powerful functionality</strong>&#160;that can be exploited for various objectives: consolidate-and-convert inline <span class="term">style</span>&#160;attributes to <span class="term">class</span>, convert <span class="term">embed</span>&#160;elements to <span class="term">object</span>, permit only one <span class="term">caption</span>&#160;element in a <span class="term">table</span>&#160;element, disallow embedding of certain types of media, <strong>inject HTML</strong>, use <a href="http://csstidy.sourceforge.net">CSSTidy</a>&#160;to sanitize <span class="term">style</span>&#160;attribute values, etc.<br />
+<br />
+&#160; As an example, the custom hook code below can be used to force a series of specifically ordered <span class="term">id</span>&#160;attributes on all elements, and a specific <span class="term">param</span>&#160;element inside all <span class="term">object</span>&#160;elements:<br />
+<br />
+
+<code class="code">&#160; &#160; function my_tag_function($element, $attribute_array){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; static $id = 0;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; // Remove any duplicate element</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; if($element == &#39;param&#39; &amp;&amp; isset($attribute_array[&#39;allowscriptaccess&#39;])){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; return &#39;&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; $new_element = &#39;&#39;;</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; // Force a serialized ID number</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; $attribute_array[&#39;id&#39;] = &#39;my_&#39;. $id;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; ++$id;</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; // Inject param for allowscriptaccess</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; if($element == &#39;object&#39;){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; $new_element = &#39;&lt;param id=&#39;my_&#39;. $id; allowscriptaccess="never" /&gt;&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; ++$id;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+<br />
+
+<code class="code">&#160; &#160; &#160; $string = &#39;&#39;;</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; foreach($attribute_array as $k=&gt;$v){</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; &#160; $string .= " {$k}=\"{$v}\"";</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; }</code>
+<br />
+
+<code class="code">&#160; &#160; &#160; return "&lt;{$element}{$string}". (isset($in_array($element, $empty_elements) ? &#39; /&#39; &#58; &#39;&#39;). &#39;&gt;&#39;. $new_element;</code>
+<br />
+
+<code class="code">&#160; &#160; }</code>
+<br />
+<br />
+&#160; The <span class="term">hook_tag</span>&#160;parameter is different from the <span class="term">hook</span>&#160;parameter (<a href="#s3.7">section 3.7</a>).<br />
+<br />
+&#160; Snippets of hook function code developed by others may be available on the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">htmLawed</a>&#160;website.<br />
+
+</div>
+</div>
+<div class="sub-section"><h3>
+<a name="s3.5" id="s3.5"></a><span class="item-no">3.5</span>&#160; Simple configuration directive for most valid XHTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["valid_xhtml"]</span>&#160;is set to <span class="term">1</span>, some relevant <span class="term">$config</span>&#160;parameters (indicated by <span class="term">~</span>&#160;in <a href="#s2.2">section 2.2</a>) are auto-adjusted. This allows one to pass the <span class="term">$config</span>&#160;argument with a simpler value. If a value for a parameter auto-set through <span class="term">valid_xhtml</span>&#160;is still manually provided, then that value will over-ride the auto-set value.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.6" id="s3.6"></a><span class="item-no">3.6</span>&#160; Simple configuration directive for most <em>safe</em>&#160;HTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; <em>Safe</em>&#160;HTML refers to HTML that is restricted to reduce the vulnerability for scripting attacks (such as XSS) based on HTML code which otherwise may still be legal and compliant with the HTML standard specs. When elements such as <span class="term">script</span>&#160;and <span class="term">object</span>, and attributes such as <span class="term">onmouseover</span>&#160;and <span class="term">style</span>&#160;are allowed in the input text, an input writer can introduce malevolent HTML code. Note that what is considered <span class="term">safe</span>&#160;depends on the nature of the web application and the trust-level accorded to its users.<br />
+<br />
+&#160; htmLawed allows an admin to use <span class="term">$config["safe"]</span>&#160;to auto-adjust multiple <span class="term">$config</span>&#160;parameters (such as <span class="term">elements</span>&#160;which declares the allowed element-set), which otherwise would have to be manually set. The relevant parameters are indicated by <span class="term">"</span>&#160;in <a href="#s2.2">section 2.2</a>). Thus, one can pass the <span class="term">$config</span>&#160;argument with a simpler value.<br />
+<br />
+&#160; With the value of <span class="term">1</span>, htmLawed considers <span class="term">CDATA</span>&#160;sections and HTML comments as plain text, and prohibits the <span class="term">applet</span>, <span class="term">embed</span>, <span class="term">iframe</span>, <span class="term">object</span>&#160;and <span class="term">script</span>&#160;elements, and the <span class="term">on&#42;</span>&#160;attributes like <span class="term">onclick</span>. ( There are <span class="term">$config</span>&#160;parameters like <span class="term">css_expression</span>&#160;that are not affected by the value set for <span class="term">safe</span>&#160;but whose default values still contribute towards a more <em>safe</em>&#160;output.) Further, URLs with schemes (see <a href="#s3.4.3">section 3.4.3</a>) are neutralized so that, e.g., <span class="term">style="moz-binding&#58;url(http&#58;//danger)"</span>&#160;becomes <span class="term">style="moz-binding&#58;url(denied&#58;http&#58;//danger)"</span>&#160;while <span class="term">style="moz-binding&#58;url(ok)"</span>&#160;remains intact.<br />
+<br />
+&#160; Admins, however, may still want to completely deny the <span class="term">style</span>&#160;attribute, e.g., with code like<br />
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text, array(&#39;safe&#39;=&gt;1, &#39;deny_attribute&#39;=&gt;&#39;style&#39;));</code>
+<br />
+<br />
+&#160; If a value for a parameter auto-set through <span class="term">safe</span>&#160;is still manually provided, then that value can over-ride the auto-set value. E.g., with <span class="term">$config["safe"] = 1</span>&#160;and <span class="term">$config["elements"] = "&#42;+script"</span>, <span class="term">script</span>, but not <span class="term">applet</span>, is allowed.<br />
+<br />
+&#160; A page illustrating the efficacy of htmLawed's anti-XSS abilities with <span class="term">safe</span>&#160;set to <span class="term">1</span>&#160;against XSS vectors listed by <a href="http://ha.ckers.org/xss.html">RSnake</a>&#160;may be available <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/rsnake/RSnakeXSSTest.htm">here</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.7" id="s3.7"></a><span class="item-no">3.7</span>&#160; Using a hook function
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; If <span class="term">$config["hook"]</span>&#160;is not set to <span class="term">0</span>, then htmLawed will allow preliminarily processed input to be altered by a hook function named by <span class="term">$config["hook"]</span>&#160;before starting the main work (but after handling of characters, entities, HTML comments and <span class="term">CDATA</span>&#160;sections -- see code for function <span class="term">htmLawed()</span>).<br />
+<br />
+&#160; The hook function also allows one to alter the <em>finalized</em>&#160;values of <span class="term">$config</span>&#160;and <span class="term">$spec</span>.<br />
+<br />
+&#160; Note that the <span class="term">hook</span>&#160;parameter is different from the <span class="term">hook_tag</span>&#160;parameter (<a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; Snippets of hook function code developed by others may be available on the <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">htmLawed</a>&#160;website.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.8" id="s3.8"></a><span class="item-no">3.8</span>&#160; Obtaining <em>finalized</em>&#160;parameter values
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed can assign the <em>finalized</em>&#160;<span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;values to a variable named by <span class="term">$config["show_setting"]</span>. The variable, made global by htmLawed, is set as an array with three keys: <span class="term">config</span>, with the <span class="term">$config</span>&#160;value, <span class="term">spec</span>, with the <span class="term">$spec</span>&#160;value, and <span class="term">time</span>, with a value that is the Unix time (the output of PHP's <span class="term">microtime()</span>&#160;function) when the value was assigned. Admins should use a PHP-compliant variable name (e.g., one that does not begin with a numerical digit) that does not conflict with variable names in their non-htmLawed code.<br />
+<br />
+&#160; The values, which are also post-hook function (if any), can be used to auto-generate information (on, e.g., the elements that are permitted) for input writers.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s3.9" id="s3.9"></a><span class="item-no">3.9</span>&#160; Retaining non-HTML tags in input with mixed markup
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; htmLawed does not remove certain characters that though invalid are nevertheless discouraged in HTML documents as per the specs (see <a href="#s5.1">section 5.1</a>). This can be utilized to deal with input that contains mixed markup. Input that may have HTML markup as well as some other markup that is based on the <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters is considered to have mixed markup. The non-HTML markup can be rather proprietary (like markup for emoticons/smileys), or standard (like MathML or SVG). Or it can be programming code meant for execution/evaluation (such as embedded PHP code).<br />
+<br />
+&#160; To deal with such mixed markup, the input text can be pre-processed to hide the non-HTML markup by specifically replacing the <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters with some of the HTML-discouraged characters (see <a href="#s3.1.2">section 3.1.2</a>). Post-htmLawed processing, the replacements are reverted.<br />
+<br />
+&#160; An example (mixed HTML and PHP code in input text):<br />
+<br />
+
+<code class="code">&#160; &#160; $text = preg_replace(&#39;&#96;&lt;\?php(.+?)\?&gt;&#96;sm&#39;, "\x83?php\\1?\x84", $text);</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = htmLawed($text);</code>
+<br />
+
+<code class="code">&#160; &#160; $processed = preg_replace(&#39;&#96;\x83\?php(.+?)\?\x84&#96;sm&#39;, &#39;&lt;?php$1?&gt;&#39;, $processed);</code>
+<br />
+<br />
+&#160; This code will not work if <span class="term">$config["clean_ms_char"]</span>&#160;is set to <span class="term">1</span>&#160;(<a href="#s3.1">section 3.1</a>), in which case one should instead deploy a hook function (<a href="#s3.7">section 3.7</a>). (htmLawed internally uses certain control characters, code-points <span class="term">1</span>&#160;to <span class="term">7</span>, and use of these characters as markers in the logic of hook functions may cause issues.)<br />
+<br />
+&#160; Admins may also be able to use <span class="term">$config["and_mark"]</span>&#160;to deal with such mixed markup; see <a href="#s3.2">section 3.2</a>.<br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s4" id="s4"></a><span class="item-no">4</span>&#160; Other
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<div class="sub-section"><h3>
+<a name="s4.1" id="s4.1"></a><span class="item-no">4.1</span>&#160; Support
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; A careful re-reading of this documentation will very likely answer your questions.<br />
+<br />
+&#160; Software updates and forum-based community-support may be found at <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed</a>. For general PHP issues (not htmLawed-specific), support may be found through internet searches and at <a href="http://php.net">http://php.net</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.2" id="s4.2"></a><span class="item-no">4.2</span>&#160; Known issues
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; See <a href="#s2.8">section 2.8</a>.<br />
+<br />
+&#160; Readers are advised to cross-check information given in this document.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.3" id="s4.3"></a><span class="item-no">4.3</span>&#160; Change-log
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; (The release date for the downloadable package of files containing documentation, demo script, test-cases, etc., besides the <span class="term">htmLawed.php</span>&#160;file may be updated independently if the secondary files are revised.)<br />
+<br />
+&#160; <em>Version number - Release date. Notes</em><br />
+<br />
+&#160; 1.1.8.1 - 16 July 2009. Minor code-change to fix a PHP error notice<br />
+<br />
+&#160; 1.1.8 - 23 April 2009. Parameter <span class="term">deny_attribute</span>&#160;now accepts the wild-card <span class="term">&#42;</span>, making it simpler to specify its value when all but a few attributes are being denied; fixed a bug in interpreting <span class="term">$spec</span><br />
+<br />
+&#160; 1.1.7 - 11-12 March 2009. Attributes globally denied through <span class="term">deny_attribute</span>&#160;can be allowed element-specifically through <span class="term">$spec</span>; <span class="term">$config["style_pass"]</span>&#160;allowing letting through any <span class="term">style</span>&#160;value introduced; altered logic to catch certain types of dynamic crafted CSS expressions<br />
+<br />
+&#160; 1.1.3-6 - 28-31 January - 4 February 2009. Altered logic to catch certain types of dynamic crafted CSS expressions<br />
+<br />
+&#160; 1.1.2 - 22 January 2009. Fixed bug in parsing of <span class="term">font</span>&#160;attributes during tag transformation<br />
+<br />
+&#160; 1.1.1 - 27 September 2008. Better nesting correction when omitable closing tags are absent<br />
+<br />
+&#160; 1.1 - 29 June 2008. <span class="term">$config["hook_tag"]</span>&#160;and <span class="term">$config["format"]</span>&#160;introduced for custom tag/attribute check/modification/injection and output compaction/beautification; fixed a regex-in-$spec parsing bug<br />
+<br />
+&#160; 1.0.9 - 11 June 2008. Fixed bug in invalid HTML code-point entity check<br />
+<br />
+&#160; 1.0.8 - 15 May 2008. <span class="term">bordercolor</span>&#160;attribute for <span class="term">table</span>, <span class="term">td</span>&#160;and <span class="term">tr</span><br />
+<br />
+&#160; 1.0.7 - 1 May 2008. Support for <span class="term">wmode</span>&#160;attribute for <span class="term">embed</span>; <span class="term">$config["show_setting"]</span>&#160;introduced; improved <span class="term">$config["elements"]</span>&#160;evaluation<br />
+<br />
+&#160; 1.0.6 - 20 April 2008. <span class="term">$config["and_mark"]</span>&#160;introduced<br />
+<br />
+&#160; 1.0.5 - 12 March 2008. <span class="term">style</span>&#160;URL schemes essentially disallowed when $config <span class="term">safe</span>&#160;is on; improved regex for CSS expression search<br />
+<br />
+&#160; 1.0.4 - 10 March 2008. Improved corrections for <span class="term">blockquote</span>, <span class="term">form</span>, <span class="term">map</span>&#160;and <span class="term">noscript</span><br />
+<br />
+&#160; 1.0.3 - 3 March 2008. Character entities for soft-hyphens are now replaced with spaces (instead of being removed); a bug allowing <span class="term">td</span>&#160;directly inside <span class="term">table</span>&#160;fixed; <span class="term">safe</span>&#160;<span class="term">$config</span>&#160;parameter added<br />
+<br />
+&#160; 1.0.2 - 13 February 2008. Improved implementation of <span class="term">$config["keep_bad"]</span><br />
+<br />
+&#160; 1.0.1 - 7 November 2007. Improved regex for identifying URLs, protocols and dynamic expressions (<span class="term">hl_tag()</span>&#160;and <span class="term">hl_prot()</span>); no error display with <span class="term">hl_regex()</span><br />
+<br />
+&#160; 1.0 - 2 November 2007. First release<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.4" id="s4.4"></a><span class="item-no">4.4</span>&#160; Testing
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; To test htmLawed using a form interface, a <a href="htmLawedTest.php">demo</a>&#160;web-page is provided with the htmLawed distribution (<span class="term">htmLawed.php</span>&#160;and <span class="term">htmLawedTest.php</span>&#160;should be in the same directory on the web-server). A file with <a href="htmLawed_TESTCASE.txt">test-cases</a>&#160;is also provided.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.5" id="s4.5"></a><span class="item-no">4.5</span>&#160; Upgrade, &amp; old versions
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Upgrading is as simple as replacing the previous version of <span class="term">htmLawed.php</span>&#160;(assuming it was not modified for customized features). As htmLawed output is almost always used in static documents, upgrading should not affect old, finalized content.<br />
+<br />
+&#160; Old versions of htmLawed may be available online. E.g., for version 1.0, check <a href="http://www.bioinformatics.org/phplabware/downloads/htmLawed1.zip">http://www.bioinformatics.org/phplabware/downloads/htmLawed1.zip</a>, for 1.1.1, htmLawed111.zip, and for 1.1.10, htmLawed1110.zip.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.6" id="s4.6"></a><span class="item-no">4.6</span>&#160; Comparison with <span class="term">HTMLPurifier</span>
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; The HTMLPurifier PHP library by Edward Yang is a very good HTML filtering script that uses object oriented PHP code. Compared to htmLawed, it:<br />
+<br />
+&#160; * &#160;does not support PHP versions older than 5.0 (HTMLPurifier dropped PHP 4 support after version 2)<br />
+<br />
+&#160; * &#160;is 15-20 times bigger (scores of files totalling more than 750 kb)<br />
+<br />
+&#160; * &#160;consumes 10-15 times more RAM memory (just including the HTMLPurifier files without calling the filter requires a few MBs of memory)<br />
+<br />
+&#160; * &#160;is expectedly slower<br />
+<br />
+&#160; * &#160;does not allow admins to fully allow all valid HTML (because of incomplete HTML support, it always considers elements like <span class="term">script</span>&#160;illegal)<br />
+<br />
+&#160; * &#160;lacks many of the extra features of htmLawed (like entity conversions and code compaction/beautification)<br />
+<br />
+&#160; * &#160;has poor documentation<br />
+<br />
+&#160; However, HTMLPurifier has finer checks for character encodings and attribute values, and can log warnings and errors. Visit the HTMLPurifier <a href="http://htmlpurifier.org">website</a>&#160;for updated information.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.7" id="s4.7"></a><span class="item-no">4.7</span>&#160; Use through application plug-ins/modules
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Plug-ins/modules to implement htmLawed in applications such as Drupal and DokuWiki may have been developed. Please check the application websites and the forum on the htmLawed <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">site</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.8" id="s4.8"></a><span class="item-no">4.8</span>&#160; Use in non-PHP applications
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Non-PHP applications written in Python, Ruby, etc., may be able to use htmLawed through system calls to the PHP engine. Such code may have been documented on the internet. Also check the forum on the htmLawed <a href="http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed">site</a>.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.9" id="s4.9"></a><span class="item-no">4.9</span>&#160; Donate
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; A donation in any currency and amount to appreciate or support this software can be sent by <a href="http://paypal.com">PayPal</a>&#160;to this email address: drpatnaik at yahoo dot com.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s4.10" id="s4.10"></a><span class="item-no">4.10</span>&#160; Acknowledgements
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Bryan Blakey, Ulf Harnhammer, Gareth Heyes, Lukasz Pilorz, Shelley Powers, Edward Yang, and many anonymous users.<br />
+<br />
+&#160; Thank you!<br />
+
+</div>
+</div>
+<div class="section"><h2>
+<a name="s5" id="s5"></a><span class="item-no">5</span>&#160; Appendices
+</h2><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<div class="sub-section"><h3>
+<a name="s5.1" id="s5.1"></a><span class="item-no">5.1</span>&#160; Characters discouraged in XHTML
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Characters represented by the following hexadecimal code-points are <em>not</em>&#160;invalid, even though some validators may issue messages stating otherwise.<br />
+<br />
+&#160; <span class="term">7f</span>&#160;to <span class="term">84</span>, <span class="term">86</span>&#160;to <span class="term">9f</span>, <span class="term">fdd0</span>&#160;to <span class="term">fddf</span>, <span class="term">1fffe</span>, <span class="term">1ffff</span>, <span class="term">2fffe</span>, <span class="term">2ffff</span>, <span class="term">3fffe</span>, <span class="term">3ffff</span>, <span class="term">4fffe</span>, <span class="term">4ffff</span>, <span class="term">5fffe</span>, <span class="term">5ffff</span>, <span class="term">6fffe</span>, <span class="term">6ffff</span>, <span class="term">7fffe</span>, <span class="term">7ffff</span>, <span class="term">8fffe</span>, <span class="term">8ffff</span>, <span class="term">9fffe</span>, <span class="term">9ffff</span>, <span class="term">afffe</span>, <span class="term">affff</span>, <span class="term">bfffe</span>, <span class="term">bffff</span>, <span class="term">cfffe</span>, <span class="term">cffff</span>, <span class="term">dfffe</span>, <span class="term">dffff</span>, <span class="term">efffe</span>, <span class="term">effff</span>, <span class="term">ffffe</span>, <span class="term">fffff</span>, <span class="term">10fffe</span>&#160;and <span class="term">10ffff</span><br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.2" id="s5.2"></a><span class="item-no">5.2</span>&#160; Valid attribute-element combinations
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Valid attribute-element combinations as per W3C specs.<br />
+<br />
+&#160; * &#160;includes deprecated attributes (marked <span class="term">^</span>), attributes for the non-standard <span class="term">embed</span>&#160;element (marked <span class="term">&#42;</span>), and the proprietary <span class="term">bordercolor</span>&#160;(marked <span class="term">~</span>)<br />
+&#160; * &#160;only non-frameset, HTML body elements<br />
+&#160; * &#160;<span class="term">name</span>&#160;for <span class="term">a</span>&#160;and <span class="term">map</span>, and <span class="term">lang</span>&#160;are invalid in XHTML 1.1<br />
+&#160; * &#160;<span class="term">target</span>&#160;is valid for <span class="term">a</span>&#160;in XHTML 1.1 and higher<br />
+&#160; * &#160;<span class="term">xml&#58;space</span>&#160;is only for XHTML 1.1<br />
+<br />
+&#160; abbr - td, th<br />
+&#160; accept - form, input<br />
+&#160; accept-charset - form<br />
+&#160; accesskey - a, area, button, input, label, legend, textarea<br />
+&#160; action - form<br />
+&#160; align - caption^, embed, applet, iframe, img^, input^, object^, legend^, table^, hr^, div^, h1^, h2^, h3^, h4^, h5^, h6^, p^, col, colgroup, tbody, td, tfoot, th, thead, tr<br />
+&#160; alt - applet, area, img, input<br />
+&#160; archive - applet, object<br />
+&#160; axis - td, th<br />
+&#160; bgcolor - embed, table^, tr^, td^, th^<br />
+&#160; border - table, img^, object^<br />
+&#160; bordercolor~ - table, td, tr<br />
+&#160; cellpadding - table<br />
+&#160; cellspacing - table<br />
+&#160; char - col, colgroup, tbody, td, tfoot, th, thead, tr<br />
+&#160; charoff - col, colgroup, tbody, td, tfoot, th, thead, tr<br />
+&#160; charset - a, script<br />
+&#160; checked - input<br />
+&#160; cite - blockquote, q, del, ins<br />
+&#160; classid - object<br />
+&#160; clear - br^<br />
+&#160; code - applet<br />
+&#160; codebase - object, applet<br />
+&#160; codetype - object<br />
+&#160; color - font<br />
+&#160; cols - textarea<br />
+&#160; colspan - td, th<br />
+&#160; compact - dir, dl^, menu, ol^, ul^<br />
+&#160; coords - area, a<br />
+&#160; data - object<br />
+&#160; datetime - del, ins<br />
+&#160; declare - object<br />
+&#160; defer - script<br />
+&#160; dir - bdo<br />
+&#160; disabled - button, input, optgroup, option, select, textarea<br />
+&#160; enctype - form<br />
+&#160; face - font<br />
+&#160; for - label<br />
+&#160; frame - table<br />
+&#160; frameborder - iframe<br />
+&#160; headers - td, th<br />
+&#160; height - embed, iframe, td^, th^, img, object, applet<br />
+&#160; href - a, area<br />
+&#160; hreflang - a<br />
+&#160; hspace - applet, img^, object^<br />
+&#160; ismap - img, input<br />
+&#160; label - option, optgroup<br />
+&#160; language - script^<br />
+&#160; longdesc - img, iframe<br />
+&#160; marginheight - iframe<br />
+&#160; marginwidth - iframe<br />
+&#160; maxlength - input<br />
+&#160; method - form<br />
+&#160; model* - embed<br />
+&#160; multiple - select<br />
+&#160; name - button, embed, textarea, applet^, select, form^, iframe^, img^, a^, input, object, map^, param<br />
+&#160; nohref - area<br />
+&#160; noshade - hr^<br />
+&#160; nowrap - td^, th^<br />
+&#160; object - applet<br />
+&#160; onblur - a, area, button, input, label, select, textarea<br />
+&#160; onchange - input, select, textarea<br />
+&#160; onfocus - a, area, button, input, label, select, textarea<br />
+&#160; onreset - form<br />
+&#160; onselect - input, textarea<br />
+&#160; onsubmit - form<br />
+&#160; pluginspage* - embed<br />
+&#160; pluginurl* - embed<br />
+&#160; prompt - isindex<br />
+&#160; readonly - textarea, input<br />
+&#160; rel - a<br />
+&#160; rev - a<br />
+&#160; rows - textarea<br />
+&#160; rowspan - td, th<br />
+&#160; rules - table<br />
+&#160; scope - td, th<br />
+&#160; scrolling - iframe<br />
+&#160; selected - option<br />
+&#160; shape - area, a<br />
+&#160; size - hr^, font, input, select<br />
+&#160; span - col, colgroup<br />
+&#160; src - embed, script, input, iframe, img<br />
+&#160; standby - object<br />
+&#160; start - ol^<br />
+&#160; summary - table<br />
+&#160; tabindex - a, area, button, input, object, select, textarea<br />
+&#160; target - a^, area, form<br />
+&#160; type - a, embed, object, param, script, input, li^, ol^, ul^, button<br />
+&#160; usemap - img, input, object<br />
+&#160; valign - col, colgroup, tbody, td, tfoot, th, thead, tr<br />
+&#160; value - input, option, param, button, li^<br />
+&#160; valuetype - param<br />
+&#160; vspace - applet, img^, object^<br />
+&#160; width - embed, hr^, iframe, img, object, table, td^, th^, applet, col, colgroup, pre^<br />
+&#160; wmode - embed<br />
+&#160; xml:space - pre, script, style<br />
+<br />
+&#160; These are allowed in all but the shown elements:<br />
+<br />
+&#160; class - param, script<br />
+&#160; dir - applet, bdo, br, iframe, param, script<br />
+&#160; id - script<br />
+&#160; lang - applet, br, iframe, param, script<br />
+&#160; onclick - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; ondblclick - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onkeydown - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onkeypress - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onkeyup - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onmousedown - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onmousemove - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onmouseout - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onmouseover - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; onmouseup - applet, bdo, br, font, iframe, isindex, param, script<br />
+&#160; style - param, script<br />
+&#160; title - param, script<br />
+&#160; xml:lang - applet, br, iframe, param, script<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.3" id="s5.3"></a><span class="item-no">5.3</span>&#160; CSS 2.1 properties accepting URLs
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; background<br />
+&#160; background-image<br />
+&#160; content<br />
+&#160; cue-after<br />
+&#160; cue-before<br />
+&#160; cursor<br />
+&#160; list-style<br />
+&#160; list-style-image<br />
+&#160; play-during<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.4" id="s5.4"></a><span class="item-no">5.4</span>&#160; Microsoft Windows 1252 character replacements
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Key: <span class="term">d</span>&#160;double, <span class="term">l</span>&#160;left, <span class="term">q</span>&#160;quote, <span class="term">r</span>&#160;right, <span class="term">s.</span>&#160;single<br />
+<br />
+&#160; Code-point (decimal) - hexadecimal value - replacement entity - represented character<br />
+<br />
+&#160; 127 - 7f - (removed) - (not used)<br />
+&#160; 128 - 80 - &amp;#8364; - euro<br />
+&#160; 129 - 81 - (removed) - (not used)<br />
+&#160; 130 - 82 - &amp;#8218; - baseline s. q<br />
+&#160; 131 - 83 - &amp;#402; - florin<br />
+&#160; 132 - 84 - &amp;#8222; - baseline d q<br />
+&#160; 133 - 85 - &amp;#8230; - ellipsis<br />
+&#160; 134 - 86 - &amp;#8224; - dagger<br />
+&#160; 135 - 87 - &amp;#8225; - d dagger<br />
+&#160; 136 - 88 - &amp;#710; - circumflex accent<br />
+&#160; 137 - 89 - &amp;#8240; - permile<br />
+&#160; 138 - 8a - &amp;#352; - S Hacek<br />
+&#160; 139 - 8b - &amp;#8249; - l s. guillemet<br />
+&#160; 140 - 8c - &amp;#338; - OE ligature<br />
+&#160; 141 - 8d - (removed) - (not used)<br />
+&#160; 142 - 8e - &amp;#381; - Z dieresis<br />
+&#160; 143 - 8f - (removed) - (not used)<br />
+&#160; 144 - 90 - (removed) - (not used)<br />
+&#160; 145 - 91 - &amp;#8216; - l s. q<br />
+&#160; 146 - 92 - &amp;#8217; - r s. q<br />
+&#160; 147 - 93 - &amp;#8220; - l d q<br />
+&#160; 148 - 94 - &amp;#8221; - r d q<br />
+&#160; 149 - 95 - &amp;#8226; - bullet<br />
+&#160; 150 - 96 - &amp;#8211; - en dash<br />
+&#160; 151 - 97 - &amp;#8212; - em dash<br />
+&#160; 152 - 98 - &amp;#732; - tilde accent<br />
+&#160; 153 - 99 - &amp;#8482; - trademark<br />
+&#160; 154 - 9a - &amp;#353; - s Hacek<br />
+&#160; 155 - 9b - &amp;#8250; - r s. guillemet<br />
+&#160; 156 - 9c - &amp;#339; - oe ligature<br />
+&#160; 157 - 9d - (removed) - (not used)<br />
+&#160; 158 - 9e - &amp;#382; - z dieresis<br />
+&#160; 159 - 9f - &amp;#376; - Y dieresis<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.5" id="s5.5"></a><span class="item-no">5.5</span>&#160; URL format
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; An <em>absolute</em>&#160;URL has a <span class="term">protocol</span>&#160;or <span class="term">scheme</span>, a <span class="term">network location</span>&#160;or <span class="term">hostname</span>, and, optional <span class="term">path</span>, <span class="term">parameters</span>, <span class="term">query</span>&#160;and <span class="term">fragment</span>&#160;segments. Thus, an absolute URL has this generic structure:<br />
+<br />
+
+<code class="code">&#160; &#160; (scheme) &#58; (//network location) /(path) ;(parameters) ?(query) #(fragment)</code>
+<br />
+<br />
+&#160; The schemes can only contain letters, digits, <span class="term">+</span>, <span class="term">.</span>&#160;and <span class="term">-</span>. Hostname is the portion after the <span class="term">//</span>&#160;and up to the first <span class="term">/</span>&#160;(if any; else, up to the end) when <span class="term">&#58;</span>&#160;is followed by a <span class="term">//</span>&#160;(e.g., <span class="term">abc.com</span>&#160;in <span class="term">ftp&#58;//abc.com/def</span>); otherwise, it consists of everything after the <span class="term">&#58;</span>&#160;(e.g., <span class="term">def@abc.com</span>&#160;in mailto:def@abc.com').<br />
+<br />
+&#160; <em>Relative</em>&#160;URLs do not have explicit schemes and network locations; such values are inherited from a <em>base</em>&#160;URL.<br />
+
+</div>
+<div class="sub-section"><h3>
+<a name="s5.6" id="s5.6"></a><span class="item-no">5.6</span>&#160; Brief on htmLawed code
+</h3><span class="totop"><a href="#peak">(to top)</a></span><br style="clear: both;" />
+<br />
+&#160; Much of the code's logic and reasoning can be understood from the documentation above.<br />
+<br />
+&#160; The <strong>output</strong>&#160;of htmLawed is a text string containing the processed input. There is no custom error tracking.<br />
+<br />
+&#160; <strong>Function arguments</strong>&#160;for htmLawed are:<br />
+<br />
+&#160; * &#160;<span class="term">$in</span>&#160;- 1st argument; a text string; the <strong>input text</strong>&#160;to be processed. Any extraneous slashes added by PHP when <em>magic quotes</em>&#160;are enabled should be removed beforehand using PHP's <span class="term">stripslashes()</span>&#160;function.<br />
+<br />
+&#160; * &#160;<span class="term">$config</span>&#160;- 2nd argument; an associative array; optional (named <span class="term">$C</span>&#160;in htmLawed code). The array has keys with names like <span class="term">balance</span>&#160;and <span class="term">keep_bad</span>, and the values, which can be boolean, string, or array, depending on the key, are read to accordingly set the <strong>configurable parameters</strong>&#160;(indicated by the keys). All configurable parameters receive some default value if the value to be used is not specified by the user through <span class="term">$config</span>. <em>Finalized</em>&#160;<span class="term">$config</span>&#160;is thus a filtered and possibly larger array.<br />
+<br />
+&#160; * &#160;<span class="term">$spec</span>&#160;- 3rd argument; a text string; optional. The string has rules, written in an htmLawed-designated format, <strong>specifying</strong>&#160;element-specific attribute and attribute value restrictions. Function <span class="term">hl_spec()</span>&#160;is used to convert the string to an associative-array for internal use. <em>Finalized</em>&#160;<span class="term">$spec</span>&#160;is thus an array.<br />
+<br />
+&#160; <em>Finalized</em>&#160;<span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;are made <strong>global variables</strong>&#160;while htmLawed is at work. Values of any pre-existing global variables with same names are noted, and their values are restored after htmLawed finishes processing the input (to capture the <em>finalized</em>&#160;values, the <span class="term">show_settings</span>&#160;parameter of <span class="term">$config</span>&#160;should be used). Depending on <span class="term">$config</span>, another global variable <span class="term">hl_Ids</span>, to track <span class="term">id</span>&#160;attribute values for uniqueness, may be set. Unlike the other two variables, this one is not reset (or unset) post-processing.<br />
+<br />
+&#160; Except for the main function <span class="term">htmLawed()</span>&#160;and the functions <span class="term">kses()</span>&#160;and <span class="term">kses_hook()</span>, htmLawed's functions are <strong>name-spaced</strong>&#160;using the <span class="term">hl_</span>&#160;prefix. The <strong>functions</strong>&#160;and their roles are:<br />
+<br />
+&#160; * &#160;<span class="term">hl_attrval</span>&#160;- checking attribute values against $spec<br />
+&#160; * &#160;<span class="term">hl_bal</span>&#160;- tag balancing<br />
+&#160; * &#160;<span class="term">hl_cmtcd</span>&#160;- handling CDATA sections and HTML comments<br />
+&#160; * &#160;<span class="term">hl_ent</span>&#160;- entity handling<br />
+&#160; * &#160;<span class="term">hl_prot</span>&#160;- checking a URL scheme/protocol<br />
+&#160; * &#160;<span class="term">hl_regex</span>&#160;- checking syntax of a regular expression<br />
+&#160; * &#160;<span class="term">hl_spec</span>&#160;- converting user-supplied $spec value to one used by htmLawed internally<br />
+&#160; * &#160;<span class="term">hl_tag</span>&#160;- handling tags<br />
+&#160; * &#160;<span class="term">hl_tag2</span>&#160;- transforming tags<br />
+&#160; * &#160;<span class="term">hl_tidy</span>&#160;- compact/beautify HTML<br />
+&#160; * &#160;<span class="term">hl_version</span>&#160;- reporting htmLawed version<br />
+&#160; * &#160;<span class="term">htmLawed</span>&#160;- main function<br />
+&#160; * &#160;<span class="term">kses</span>&#160;- main function of <span class="term">kses</span><br />
+&#160; * &#160;<span class="term">kses_hook</span>&#160;- hook function of <span class="term">kses</span><br />
+<br />
+&#160; The last two are for compatibility with pre-existing code using the <span class="term">kses</span>&#160;script. htmLawed's <span class="term">kses()</span>&#160;basically passes on the filtering task to <span class="term">htmLawed()</span>&#160;function after deciphering <span class="term">$config</span>&#160;and <span class="term">$spec</span>&#160;from the argument values supplied to it. <span class="term">kses_hook()</span>&#160;is an empty function and is meant for being filled with custom code if the <span class="term">kses</span>&#160;script users were using one.<br />
+<br />
+&#160; <span class="term">htmLawed()</span>&#160;finalizes <span class="term">$spec</span>&#160;(with the help of <span class="term">hl_spec()</span>) and <span class="term">$config</span>, and globalizes them. Finalization of <span class="term">$config</span>&#160;involves setting default values if an inappropriate or invalid one is supplied. This includes calling <span class="term">hl_regex()</span>&#160;to check well-formedness of regular expression patterns if such expressions are user-supplied through <span class="term">$config</span>. <span class="term">htmLawed()</span>&#160;then removes invalid characters like nulls and <span class="term">x01</span>&#160;and appropriately handles entities using <span class="term">hl_ent()</span>. HTML comments and CDATA sections are identified and treated as per <span class="term">$config</span>&#160;with the help of <span class="term">hl_cmtcd()</span>. When retained, the <span class="term">&lt;</span>&#160;and <span class="term">&gt;</span>&#160;characters identifying them, and the <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters inside them, are replaced with control characters (code-points <span class="term">1</span>&#160;to <span class="term">5</span>) till any tag balancing is completed.<br />
+<br />
+&#160; After this <em>initial processing</em>&#160;<span class="term">htmLawed()</span>&#160;identifies tags using regex and processes them with the help of <span class="term">hl_tag()</span>&#160;-- &#160;a large function that analyzes tag content, filtering it as per HTML standards, <span class="term">$config</span>&#160;and <span class="term">$spec</span>. Among other things, <span class="term">hl_tag()</span>&#160;transforms deprecated elements using <span class="term">hl_tag2()</span>, removes attributes from closing tags, checks attribute values as per <span class="term">$spec</span>&#160;rules using <span class="term">hl_attrval()</span>, and checks URL protocols using <span class="term">hl_prot()</span>. <span class="term">htmLawed()</span>&#160;performs tag balancing and nesting checks with a call to <span class="term">hl_bal()</span>, and optionally compacts/beautifies the output with proper white-spacing with a call to <span class="term">hl_tidy()</span>. The latter temporarily replaces white-space, and <span class="term">&lt;</span>, <span class="term">&gt;</span>&#160;and <span class="term">&amp;</span>&#160;characters inside <span class="term">pre</span>, <span class="term">script</span>&#160;and <span class="term">textarea</span>&#160;elements, and HTML comments and CDATA sections with control characters (code-points <span class="term">1</span>&#160;to <span class="term">5</span>, and <span class="term">7</span>).<br />
+<br />
+&#160; htmLawed permits the use of custom code or <strong>hook functions</strong>&#160;at two stages. The first, called inside <span class="term">htmLawed()</span>, allows the input text as well as the finalized $config and $spec values to be altered right after the initial processing (see <a href="#s3.7">section 3.7</a>). The second is called by <span class="term">hl_tag()</span>&#160;once the tag content is finalized (see <a href="#s3.4.9">section 3.4.9</a>).<br />
+<br />
+&#160; Being dictated by the external and stable HTML standard, htmLawed's objective is very clear-cut and less concerned with tweakability. The code is only minimally annotated with comments -- it is not meant to instruct; PHP developers familiar with the HTML specs will see the logic, and others can always refer to the htmLawed documentation. The compact structuring of the statements is meant to aid in quickly grasping the logic, at least when viewed with code syntax highlighted.
+</div>
+</div>
+<br />
+<hr /><br /><br /><span class="subtle"><small>HTM version of <em><a href="htmLawed_README.txt">htmLawed_README.txt</a></em> generated on 23 Apr, 2009 using <a href="http://www.bioinformatics.org/phplabware/internal_utilities">rTxt2htm</a> from PHP Labware</small></span>
+</div><!-- ended div body -->
+</div><!-- ended div top -->
+</body>
+</html> \ No newline at end of file
diff --git a/extlib/htmLawed/htmLawed_README.txt b/extlib/htmLawed/htmLawed_README.txt
new file mode 100644
index 000000000..3ce4b9ac1
--- /dev/null
+++ b/extlib/htmLawed/htmLawed_README.txt
@@ -0,0 +1,1600 @@
+/*
+htmLawed_README.txt, 16 July 2009
+htmLawed 1.1.8.1, 16 July 2009
+Copyright Santosh Patnaik
+GPL v3 license
+A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed
+*/
+
+
+== Content ==========================================================
+
+
+1 About htmLawed
+ 1.1 Example uses
+ 1.2 Features
+ 1.3 History
+ 1.4 License & copyright
+ 1.5 Terms used here
+2 Usage
+ 2.1 Simple
+ 2.2 Configuring htmLawed using the '$config' parameter
+ 2.3 Extra HTML specifications using the '$spec' parameter
+ 2.4 Performance time & memory usage
+ 2.5 Some security risks to keep in mind
+ 2.6 Use without modifying old 'kses()' code
+ 2.7 Tolerance for ill-written HTML
+ 2.8 Limitations & work-arounds
+ 2.9 Examples
+3 Details
+ 3.1 Invalid/dangerous characters
+ 3.2 Character references/entities
+ 3.3 HTML elements
+ 3.3.1 HTML comments and 'CDATA' sections
+ 3.3.2 Tag-transformation for better XHTML-Strict
+ 3.3.3 Tag balancing and proper nesting
+ 3.3.4 Elements requiring child elements
+ 3.3.5 Beautify or compact HTML
+ 3.4 Attributes
+ 3.4.1 Auto-addition of XHTML-required attributes
+ 3.4.2 Duplicate/invalid 'id' values
+ 3.4.3 URL schemes (protocols) and scripts in attribute values
+ 3.4.4 Absolute & relative URLs
+ 3.4.5 Lower-cased, standard attribute values
+ 3.4.6 Transformation of deprecated attributes
+ 3.4.7 Anti-spam & 'href'
+ 3.4.8 Inline style properties
+ 3.4.9 Hook function for tag content
+ 3.5 Simple configuration directive for most valid XHTML
+ 3.6 Simple configuration directive for most `safe` HTML
+ 3.7 Using a hook function
+ 3.8 Obtaining `finalized` parameter values
+ 3.9 Retaining non-HTML tags in input with mixed markup
+4 Other
+ 4.1 Support
+ 4.2 Known issues
+ 4.3 Change-log
+ 4.4 Testing
+ 4.5 Upgrade, & old versions
+ 4.6 Comparison with 'HTMLPurifier'
+ 4.7 Use through application plug-ins/modules
+ 4.8 Use in non-PHP applications
+ 4.9 Donate
+ 4.10 Acknowledgements
+5 Appendices
+ 5.1 Characters discouraged in HTML
+ 5.2 Valid attribute-element combinations
+ 5.3 CSS 2.1 properties accepting URLs
+ 5.4 Microsoft Windows 1252 character replacements
+ 5.5 URL format
+ 5.6 Brief on htmLawed code
+
+
+== 1 About htmLawed ================================================
+
+
+ htmLawed is a highly customizable single-file PHP script to make text secure, and standard- and admin policy-compliant for use in the body of HTML 4, XHTML 1 or 1.1, or generic XML documents. It is thus a configurable input (X)HTML filter, processor, purifier, sanitizer, beautifier, etc., and an alternative to the HTMLTidy:- http://tidy.sourceforge.net application.
+
+ The `lawing in` of input text is needed to ensure that HTML code in the text is standard-compliant, does not introduce security vulnerabilities, and does not break the aesthetics, design or layout of web-pages. htmLawed tries to do this by, for example, making HTML well-formed with balanced and properly nested tags, neutralizing code that may be used for cross-site scripting ('XSS') attacks, and allowing only specified HTML elements/tags and attributes.
+
+
+-- 1.1 Example uses ------------------------------------------------
+
+
+ * Filtering of text submitted as comments on blogs to allow only certain HTML elements
+
+ * Making RSS/Atom newsfeed item-content standard-compliant: often one uses an excerpt from an HTML document for the content, and with unbalanced tags, non-numerical entities, etc., such excerpts may not be XML-compliant
+
+ * Text processing for stricter XML standard-compliance: e.g., to have lowercased 'x' in hexadecimal numeric entities becomes necessary if an XHTML document with MathML content needs to be served as 'application/xml'
+
+ * Scraping text or data from web-pages
+
+ * Pretty-printing HTML code
+
+
+-- 1.2 Features ---------------------------------------------------o
+
+
+ Key: '*' security feature, '^' standard compliance, '~' requires setting right options, '`' different from 'Kses'
+
+ * make input more *secure* and *standard-compliant*
+ * use for HTML 4, XHTML 1.0 or 1.1, or even generic *XML* documents ^~`
+
+ * *beautify* or *compact* HTML ^~`
+
+ * *restrict elements* ^~`
+ * proper closure of empty elements like 'img' ^`
+ * *transform deprecated elements* like 'u' ^~`
+ * HTML *comments* and 'CDATA' sections can be permitted ^~`
+ * elements like 'script', 'object' and 'form' can be permitted ~
+
+ * *restrict attributes*, including *element-specifically* ^~`
+ * remove *invalid attributes* ^`
+ * element and attribute names are *lower-cased* ^
+ * provide *required attributes*, like 'alt' for 'image' ^`
+ * *transform deprecated attributes* ^~`
+ * attributes *declared only once* ^`
+
+ * *restrict attribute values*, including *element-specifically* ^~`
+ * a value is declared for `empty` (`minimized`) attributes like 'checked' ^
+ * check for potentially dangerous attribute values *~
+ * ensure *unique* 'id' attribute values ^~`
+ * *double-quote* attribute values ^
+ * lower-case *standard attribute values* like 'password' ^`
+
+ * *attribute-specific URL protocol/scheme restriction* *~`
+ * disable *dynamic expressions* in 'style' values *~`
+
+ * neutralize invalid named character entities ^`
+ * *convert* hexadecimal numeric entities to decimal ones, or vice versa ^~`
+ * convert named entities to numeric ones for generic XML use ^~`
+
+ * remove *null* characters *
+ * neutralize potentially dangerous proprietary Netscape *Javascript entities* *
+ * replace potentially dangerous *soft-hyphen* character in attribute values with spaces *
+
+ * remove common *invalid characters* not allowed in HTML or XML ^`
+ * replace *characters from Microsoft applications* like 'Word' that are discouraged in HTML or XML ^~`
+ * neutralize entities for characters invalid or discouraged in HTML or XML ^`
+ * appropriately neutralize '<', '&', '"', and '>' characters ^*`
+
+ * understands improperly spaced tag content (like, spread over more than a line) and properly spaces them `
+ * attempts to *balance tags* for well-formedness ^~`
+ * understands when *omitable closing tags* like '</p>' (allowed in HTML 4, transitional, e.g.) are missing ^~`
+ * attempts to permit only *validly nested tags* ^~`
+ * option to *remove or neutralize bad content* ^~`
+ * attempts to *rectify common errors of plain-text misplacement* (e.g., directly inside 'blockquote') ^~`
+
+ * fast, *non-OOP* code of ~45 kb incurring peak basal memory usage of ~0.5 MB
+ * *compatible* with pre-existing code using 'Kses' (the filter used by 'WordPress')
+
+ * optional *anti-spam* measures such as addition of 'rel="nofollow"' and link-disabling ~`
+ * optionally makes *relative URLs absolute*, and vice versa ~`
+
+ * optionally mark '&' to identify the entities for '&', '<' and '>' introduced by htmLawed ~`
+
+ * allows deployment of powerful *hook functions* to *inject* HTML, *consolidate* 'style' attributes to 'class', finely check attribute values, etc. ~`
+
+ * *independent of character encoding* of input and does not affect it
+
+ * *tolerance for ill-written HTML* to a certain degree
+
+
+-- 1.3 History ----------------------------------------------------o
+
+
+ htmLawed was developed for use with 'LabWiki', a wiki software developed at PHP Labware, as a suitable software could not be found. Existing PHP software like 'Kses' and 'HTMLPurifier' were deemed inadequate, slow, resource-intensive, or dependent on external applications like 'HTML Tidy'.
+
+ htmLawed started as a modification of Ulf Harnhammar's 'Kses' (version 0.2.2) software, and is compatible with code that uses 'Kses'; see section:- #2.6.
+
+
+-- 1.4 License & copyright ----------------------------------------o
+
+
+ htmLawed is free and open-source software licensed under GPL license version 3:- http://www.gnu.org/licenses/gpl-3.0.txt, and copyrighted by Santosh Patnaik, MD, PhD.
+
+
+-- 1.5 Terms used here --------------------------------------------o
+
+
+ * `administrator` - or admin; person setting up the code to pass input through htmLawed; also, `user`
+ * `attributes` - name-value pairs like 'href="http://x.com"' in opening tags
+ * `author` - `writer`
+ * `character` - atomic unit of text; internally represented by a numeric `code-point` as specified by the `encoding` or `charset` in use
+ * `entity` - markup like '&gt;' and '&#160;' used to refer to a character
+ * `element` - HTML element like 'a' and 'img'
+ * `element content` - content between the opening and closing tags of an element, like 'click' of '<a href="x">click</a>'
+ * `HTML` - implies XHTML unless specified otherwise
+ * `input` - text string given to htmLawed to process
+ * `processing` - involves filtering, correction, etc., of input
+ * `safe` - absence or reduction of certain characters and HTML elements and attributes in the input that can otherwise potentially and circumstantially expose web-site users to security vulnerabilities like cross-site scripting attacks (XSS)
+ * `scheme` - URL protocol like 'http' and 'ftp'
+ * `specs` - standard specifications
+ * `style property` - terms like 'border' and 'height' for which declarations are made in values for the 'style' attribute of elements
+ * `tag` - markers like '<a href="x">' and '</a>' delineating element content; the opening tag can contain attributes
+ * `tag content` - consists of tag markers '<' and '>', element names like 'div', and possibly attributes
+ * `user` - administrator
+ * `writer` - end-user like a blog commenter providing the input that is to be processed; also, `author`
+
+
+== 2 Usage ========================================================oo
+
+
+ htmLawed should work with PHP 4.3 and higher. Either 'include()' the 'htmLawed.php' file or copy-paste the entire code.
+
+ To easily *test* htmLawed using a form-based interface, use the provided demo:- htmLawedTest.php ('htmLawed.php' and 'htmLawedTest.php' should be in the same directory on the web-server).
+
+
+-- 2.1 Simple ------------------------------------------------------
+
+
+ The input text to be processed, '$text', is passed as an argument of type string; 'htmLawed()' returns the processed string:
+
+ $processed = htmLawed($text);
+
+ *Note*: If input is from a '$_GET' or '$_POST' value, and 'magic quotes' are enabled on the PHP setup, run 'stripslashes()' on the input before passing to htmLawed.
+
+ By default, htmLawed will process the text allowing all valid HTML elements/tags, secure URL scheme/CSS style properties, etc. It will allow 'CDATA' sections and HTML comments, balance tags, and ensure proper nesting of elements. Such actions can be configured using two other optional arguments -- '$config' and '$spec':
+
+ $processed = htmLawed($text, $config, $spec);
+
+ These extra parameters are detailed below. Some examples are shown in section:- #2.9.
+
+ *Note*: For maximum protection against 'XSS' and other scripting attacks (e.g., by disallowing Javascript code), consider using the 'safe' parameter; see section:- #3.6.
+
+
+-- 2.2 Configuring htmLawed using the '$config' parameter ---------o
+
+
+ '$config' instructs htmLawed on how to tackle certain tasks. When '$config' is not specified, or not set as an array (e.g., '$config = 1'), htmLawed will take default actions. One or many of the task-action or value-specification pairs can be specified in '$config' as array key-value pairs. If a parameter is not specified, htmLawed will use the default value/action indicated further below.
+
+ $config = array('comment'=>0, 'cdata'=>1);
+ $processed = htmLawed($text, $config);
+
+ Or,
+
+ $processed = htmLawed($text, array('comment'=>0, 'cdata'=>1));
+
+ Below are the possible value-specification combinations. In PHP code, values that are integers should not be quoted and should be used as numeric types (unless meant as string/text).
+
+ Key: '*' default, '^' different default when htmLawed is used in the Kses-compatible mode (see section:- #2.6), '~' different default when 'valid_xhtml' is set to '1' (see section:- #3.5), '"' different default when 'safe' is set to '1' (see section:- #3.6)
+
+ *abs_url*
+ Make URLs absolute or relative; '$config["base_url"]' needs to be set; see section:- #3.4.4
+
+ '-1' - make relative
+ '0' - no action *
+ '1' - make absolute
+
+ *and_mark*
+ Mark '&' characters in the original input; see section:- #3.2
+
+ *anti_link_spam*
+ Anti-link-spam measure; see section:- #3.4.7
+
+ '0' - no measure taken *
+ 'array("regex1", "regex2")' - will ensure a 'rel' attribute with 'nofollow' in its value in case the 'href' attribute value matches the regular expression pattern 'regex1', and/or will remove 'href' if its value matches the regular expression pattern 'regex2'. E.g., 'array("/./", "/://\W*(?!(abc\.com|xyz\.org))/")'; see section:- #3.4.7 for more.
+
+ *anti_mail_spam*
+ Anti-mail-spam measure; see section:- #3.4.7
+
+ '0' - no measure taken *
+ 'word' - '@' in mail address in 'href' attribute value is replaced with specified 'word'
+
+ *balance*
+ Balance tags for well-formedness and proper nesting; see section:- #3.3.3
+
+ '0' - no
+ '1' - yes *
+
+ *base_url*
+ Base URL value that needs to be set if '$config["abs_url"]' is not '0'; see section:- #3.4.4
+
+ *cdata*
+ Handling of 'CDATA' sections; see section:- #3.3.1
+
+ '0' - don't consider 'CDATA' sections as markup and proceed as if plain text ^"
+ '1' - remove
+ '2' - allow, but neutralize any '<', '>', and '&' inside by converting them to named entities
+ '3' - allow *
+
+ *clean_ms_char*
+ Replace discouraged characters introduced by Microsoft Word, etc.; see section:- #3.1
+
+ '0' - no *
+ '1' - yes
+ '2' - yes, but replace special single & double quotes with ordinary ones
+
+ *comment*
+ Handling of HTML comments; see section:- #3.3.1
+
+ '0' - don't consider comments as markup and proceed as if plain text ^"
+ '1' - remove
+ '2' - allow, but neutralize any '<', '>', and '&' inside by converting to named entities
+ '3' - allow *
+
+ *css_expression*
+ Allow dynamic CSS expression by not removing the expression from CSS property values in 'style' attributes; see section:- #3.4.8
+
+ '0' - remove *
+ '1' - allow
+
+ *deny_attribute*
+ Denied HTML attributes; see section:- #3.4
+
+ '0' - none *
+ 'string' - dictated by values in 'string'
+ 'on*' (like 'onfocus') attributes not allowed - "
+
+ *elements*
+ Allowed HTML elements; see section:- #3.3
+
+ '* -center -dir -font -isindex -menu -s -strike -u' - ~
+ 'applet, embed, iframe, object, script' not allowed - "
+
+ *hexdec_entity*
+ Allow hexadecimal numeric entities and do not convert to the more widely accepted decimal ones, or convert decimal to hexadecimal ones; see section:- #3.2
+
+ '0' - no
+ '1' - yes *
+ '2' - convert decimal to hexadecimal ones
+
+ *hook*
+ Name of an optional hook function to alter the input string, '$config' or '$spec' before htmLawed starts its main work; see section:- #3.7
+
+ '0' - no hook function *
+ 'name' - 'name' is name of the hook function ('kses_hook' ^)
+
+ *hook_tag*
+ Name of an optional hook function to alter tag content finalized by htmLawed; see section:- #3.4.9
+
+ '0' - no hook function *
+ 'name' - 'name' is name of the hook function
+
+ *keep_bad*
+ Neutralize bad tags by converting '<' and '>' to entities, or remove them; see section:- #3.3.3
+
+ '0' - remove ^
+ '1' - neutralize both tags and element content
+ '2' - remove tags but neutralize element content
+ '3' and '4' - like '1' and '2' but remove if text ('pcdata') is invalid in parent element
+ '5' and '6' * - like '3' and '4' but line-breaks, tabs and spaces are left
+
+ *lc_std_val*
+ For XHTML compliance, predefined, standard attribute values, like 'get' for the 'method' attribute of 'form', must be lowercased; see section:- #3.4.5
+
+ '0' - no
+ '1' - yes *
+
+ *make_tag_strict*
+ Transform/remove these non-strict XHTML elements, even if they are allowed by the admin: 'applet' 'center' 'dir' 'embed' 'font' 'isindex' 'menu' 's' 'strike' 'u'; see section:- #3.3.2
+
+ '0' - no ^
+ '1' - yes, but leave 'applet', 'embed' and 'isindex' elements that currently can't be transformed *
+ '2' - yes, removing 'applet', 'embed' and 'isindex' elements and their contents (nested elements remain) ~
+
+ *named_entity*
+ Allow non-universal named HTML entities, or convert to numeric ones; see section:- #3.2
+
+ '0' - convert
+ '1' - allow *
+
+ *no_deprecated_attr*
+ Allow deprecated attributes or transform them; see section:- #3.4.6
+
+ '0' - allow ^
+ '1' - transform, but 'name' attributes for 'a' and 'map' are retained *
+ '2' - transform
+
+ *parent*
+ Name of the parent element, possibly imagined, that will hold the input; see section:- #3.3
+
+ *safe*
+ Magic parameter to make input the most secure against XSS without needing to specify other relevant '$config' parameters; see section:- #3.6
+
+ '0' - no *
+ '1' - will auto-adjust other relevant '$config' parameters (indicated by '"' in this list)
+
+ *schemes*
+ Array of attribute-specific, comma-separated, lower-cased list of schemes (protocols) allowed in attributes accepting URLs; '*' covers all unspecified attributes; see section:- #3.4.3
+
+ 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; *:file, http, https' *
+ '*: ftp, gopher, http, https, mailto, news, nntp, telnet' ^
+ 'href: aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet; style: nil; *:file, http, https' "
+
+ *show_setting*
+ Name of a PHP variable to assign the `finalized` '$config' and '$spec' values; see section:- #3.8
+
+ *style_pass*
+ Do not look at 'style' attribute values, letting them through without any alteration
+
+ '0' - no *
+ '1' - htmLawed will let through any 'style' value; see section:- #3.4.8
+
+ *tidy*
+ Beautify or compact HTML code; see section:- #3.3.5
+
+ '-1' - compact
+ '0' - no *
+ '1' or 'string' - beautify (custom format specified by 'string')
+
+ *unique_ids*
+ 'id' attribute value checks; see section:- #3.4.2
+
+ '0' - no ^
+ '1' - remove duplicate and/or invalid ones *
+ 'word' - remove invalid ones and replace duplicate ones with new and unique ones based on the 'word'; the admin-specified 'word', like 'my_', should begin with a letter (a-z) and can contain letters, digits, '.', '_', '-', and ':'.
+
+ *valid_xhtml*
+ Magic parameter to make input the most valid XHTML without needing to specify other relevant '$config' parameters; see section:- #3.5
+
+ '0' - no *
+ '1' - will auto-adjust other relevant '$config' parameters (indicated by '~' in this list)
+
+ *xml:lang*
+ Auto-adding 'xml:lang' attribute; see section:- #3.4.1
+
+ '0' - no *
+ '1' - add if 'lang' attribute is present
+ '2' - add if 'lang' attribute is present, and remove 'lang' ~
+
+
+-- 2.3 Extra HTML specifications using the $spec parameter --------o
+
+
+ The '$spec' argument can be used to disallow an otherwise legal attribute for an element, or to restrict the attribute's values. This can also be helpful as a security measure (e.g., in certain versions of browsers, certain values can cause buffer overflows and denial of service attacks), or in enforcing admin policy compliance. '$spec' is specified as a string of text containing one or more `rules`, with multiple rules separated from each other by a semi-colon (';'). E.g.,
+
+ $spec = 'i=-*; td, tr=style, id, -*; a=id(match="/[a-z][a-z\d.:\-`"]*/i"/minval=2), href(maxlen=100/minlen=34); img=-width,-alt';
+ $processed = htmLawed($text, $config, $spec);
+
+ Or,
+
+ $processed = htmLawed($text, $config, 'i=-*; td, tr=style, id, -*; a=id(match="/[a-z][a-z\d.:\-`"]*/i"/minval=2), href(maxlen=100/minlen=34); img=-width,-alt');
+
+ A rule begins with an HTML *element* name(s) (`rule-element`), for which the rule applies, followed by an equal ('=') sign. A rule-element may represent multiple elements if comma (,)-separated element names are used. E.g., 'th,td,tr='.
+
+ Rest of the rule consists of comma-separated HTML *attribute names*. A minus ('-') character before an attribute means that the attribute is not permitted inside the rule-element. E.g., '-width'. To deny all attributes, '-*' can be used.
+
+ Following shows examples of rule excerpts with rule-element 'a' and the attributes that are being permitted:
+
+ * 'a=' - all
+ * 'a=id' - all
+ * 'a=href, title, -id, -onclick' - all except 'id' and 'onclick'
+ * 'a=*, id, -id' - all except 'id'
+ * 'a=-*' - none
+ * 'a=-*, href, title' - none except 'href' and 'title'
+ * 'a=-*, -id, href, title' - none except 'href' and 'title'
+
+ Rules regarding *attribute values* are optionally specified inside round brackets after attribute names in slash ('/')-separated `parameter = value` pairs. E.g., 'title(maxlen=30/minlen=5)'. None, or one or more of the following parameters may be specified:
+
+ * 'oneof' - one or more choices separated by '|' that the value should match; if only one choice is provided, then the value must match that choice
+
+ * 'noneof' - one or more choices separated by '|' that the value should not match
+
+ * 'maxlen' and 'minlen' - upper and lower limits for the number of characters in the attribute value; specified in numbers
+
+ * 'maxval' and 'minval' - upper and lower limits for the numerical value specified in the attribute value; specified in numbers
+
+ * 'match' and 'nomatch' - pattern that the attribute value should or should not match; specified as PHP/PCRE-compatible regular expressions with delimiters and possibly modifiers
+
+ * 'default' - a value to force on the attribute if the value provided by the writer does not fit any of the specified parameters
+
+ If 'default' is not set and the attribute value does not satisfy any of the specified parameters, then the attribute is removed. The 'default' value can also be used to force all attribute declarations to take the same value (by getting the values declared illegal by setting, e.g., 'maxlen' to '-1').
+
+ Examples with `input` '<input title="WIDTH" value="10em" /><input title="length" value="5" />' are shown below.
+
+ `Rule`: 'input=title(maxlen=60/minlen=6), value'
+ `Output`: '<input value="10em" /><input title="length" value="5" />'
+
+ `Rule`: 'input=title(), value(maxval=8/default=6)'
+ `Output`: '<input title="WIDTH" value="6" /><input title="length" value="5" />'
+
+ `Rule`: 'input=title(nomatch=$w.d$i), value(match=$em$/default=6em)'
+ `Output`: '<input value="10em" /><input title="length" value="6em" />'
+
+ `Rule`: 'input=title(oneof=height|depth/default=depth), value(noneof=5|6)'
+ `Output`: '<input title="depth" value="10em" /><input title="depth" />'
+
+ *Special characters*: The characters ';', ',', '/', '(', ')', '|', '~' and space have special meanings in the rules. Words in the rules that use such characters, or the characters themselves, should be `escaped` by enclosing in pairs of double-quotes ('"'). A back-tick ('`') can be used to escape a literal '"'. An example rule illustrating this is 'input=value(maxlen=30/match="/^\w/"/default="your `"ID`"")'.
+
+ *Note*: To deny an attribute for all elements for which it is legal, '$config["deny_attribute"]' (see section:- #3.4) can be used instead of '$spec'. Also, attributes can be allowed element-specifically through '$spec' while being denied globally through '$config["deny_attribute"]'. The 'hook_tag' parameter (section:- #3.4.9) can also be used to implement the '$spec' functionality.
+
+
+-- 2.4 Performance time & memory usage ----------------------------o
+
+
+ The time and memory used by htmLawed depends on its configuration and the size of the input, and the amount, nestedness and well-formedness of the HTML markup within it. In particular, tag balancing and beautification each can increase the processing time by about a quarter.
+
+ The htmLawed demo:- htmLawedTest.php can be used to evaluate the performance and effects of different types of input and '$config'.
+
+
+-- 2.5 Some security risks to keep in mind ------------------------o
+
+
+ When setting the parameters/arguments (like those to allow certain HTML elements) for use with htmLawed, one should bear in mind that the setting may let through potentially `dangerous` HTML code. (This may not be a problem if the authors are trusted.)
+
+ For example, following increase security risks:
+
+ * Allowing 'script', 'applet', 'embed', 'iframe' or 'object' elements, or certain of their attributes like 'allowscriptaccess'
+
+ * Allowing HTML comments (some Internet Explorer versions are vulnerable with, e.g., '<!--[if gte IE 4]><script>alert("xss");</script><![endif]-->'
+
+ * Allowing dynamic CSS expressions (a feature of the IE browser)
+
+ `Unsafe` HTML can be removed by setting '$config' appropriately. E.g., '$config["elements"] = "* -script"' (section:- #3.3), '$config["safe"] = 1' (section:- #3.6), etc.
+
+
+-- 2.6 Use without modifying old 'kses()' code --------------------o
+
+
+ The 'Kses' PHP script is used by many applications (like 'WordPress'). It is possible to have such applications use htmLawed instead, since it is compatible with code that calls the 'kses()' function declared in the 'Kses' file (usually named 'kses.php'). E.g., application code like this will continue to work after replacing 'Kses' with htmLawed:
+
+ $comment_filtered = kses($comment_input, array('a'=>array(), 'b'=>array(), 'i'=>array()));
+
+ For some of the '$config' parameters, htmLawed will use values other than the default ones. These are indicated by '^' in section:- #2.2. To force htmLawed to use other values, function 'kses()' in the htmLawed code should be edited -- a few configurable parameters/variables need to be changed.
+
+ If the application uses a 'Kses' file that has the 'kses()' function declared, then, to have the application use htmLawed instead of 'Kses', simply rename 'htmLawed.php' (to 'kses.php', e.g.) and replace the 'Kses' file (or just replace the code in the 'Kses' file with the htmLawed code). If the 'kses()' function in the 'Kses' file had been renamed by the application developer (e.g., in 'WordPress', it is named 'wp_kses()'), then appropriately rename the 'kses()' function in the htmLawed code.
+
+ If the 'Kses' file used by the application has been highly altered by the application developers, then one may need a different approach. E.g., with 'WordPress', it is best to copy the htmLawed code to 'wp_includes/kses.php', rename the newly added function 'kses()' to 'wp_kses()', and delete the code for the original 'wp_kses()' function.
+
+ If the 'Kses' code has a non-empty hook function (e.g., 'wp_kses_hook()' in case of 'WordPress'), then the code for htmLawed's 'kses_hook()' function should be appropriately edited. However, the requirement of the hook function should be re-evaluated considering that htmLawed has extra capabilities. With 'WordPress', the hook function is an essential one. The following code is suggested for the htmLawed 'kses_hook()' in case of 'WordPress':
+
+ function kses_hook($string, &$cf, &$spec){
+ // kses compatibility
+ $allowed_html = $spec;
+ $allowed_protocols = array();
+ foreach($cf['schemes'] as $v){
+ foreach($v as $k2=>$v2){
+ if(!in_array($k2, $allowed_protocols)){
+ $allowed_protocols[] = $k2;
+ }
+ }
+ }
+ return wp_kses_hook($string, $allowed_html, $allowed_protocols);
+ // eof
+ }
+
+
+-- 2.7 Tolerance for ill-written HTML -----------------------------o
+
+
+ htmLawed can work with ill-written HTML code in the input. However, HTML that is too ill-written may not be `read` as HTML, and be considered mere plain text instead. Following statements indicate the degree of `looseness` that htmLawed can work with, and can be provided in instructions to writers:
+
+ * Tags must be flanked by '<' and '>' with no '>' inside -- any needed '>' should be put in as '&gt;'. It is possible for tag content (element name and attributes) to be spread over many lines instead of being on one. A space may be present between the tag content and '>', like '<div >' and '<img / >', but not after the '<'.
+
+ * Element and attribute names need not be lower-cased.
+
+ * Attribute string of elements may be liberally spaced with tabs, line-breaks, etc.
+
+ * Attribute values may not be double-quoted, or may be single-quoted.
+
+ * Left-padding of numeric entities (like, '&#0160;', '&x07ff;') with '0' is okay as long as the number of characters between between the '&' and the ';' does not exceed 8. All entities must end with ';' though.
+
+ * Named character entities must be properly cased. E.g., '&Lt;' or '&TILDE;' will not be let through without modification.
+
+ * HTML comments should not be inside element tags (okay between tags), and should begin with '<!--' and end with '-->'. Characters like '<', '>', and '&' may be allowed inside depending on '$config', but any '-->' inside should be put in as '--&gt;'. Any '--' inside will be automatically converted to '-', and a space will be added before the comment delimiter '-->'.
+
+ * 'CDATA' sections should not be inside element tags, and can be in element content only if plain text is allowed for that element. They should begin with '<[CDATA[' and end with ']]>'. Characters like '<', '>', and '&' may be allowed inside depending on '$config', but any ']]>' inside should be put in as ']]&gt;'.
+
+ * For attribute values, character entities '&lt;', '&gt;' and '&amp;' should be used instead of characters '<' and '>', and '&' (when '&' is not part of a character entity). This applies even for Javascript code in values of attributes like 'onclick'.
+
+ * Characters '<', '>', '&' and '"' that are part of actual Javascript, etc., code in 'script' elements should be used as such and not be put in as entities like '&gt;'. Otherwise, though the HTML will be valid, the code may fail to work. Further, if such characters have to be used, then they should be put inside 'CDATA' sections.
+
+ * Simple instructions like "an opening tag cannot be present between two closing tags" and "nested elements should be closed in the reverse order of how they were opened" can help authors write balanced HTML. If tags are imbalanced, htmLawed will try to balance them, but in the process, depending on '$config["keep_bad"]', some code/text may be lost.
+
+ * Input authors should be notified of admin-specified allowed elements, attributes, configuration values (like conversion of named entities to numeric ones), etc.
+
+ * With '$config["unique_ids"]' not '0' and the 'id' attribute being permitted, writers should carefully avoid using duplicate or invalid 'id' values as even though htmLawed will correct/remove the values, the final output may not be the one desired. E.g., when '<a id="home"></a><input id="home" /><label for="home"></label>' is processed into
+'<a id="home"></a><input id="prefix_home" /><label for="home"></label>'.
+
+ * Note that even if intended HTML is lost in a highly ill-written input, the processed output will be more secure and standard-compliant.
+
+ * For URLs, unless '$config["scheme"]' is appropriately set, writers should avoid using escape characters or entities in schemes. E.g., 'htt&#112;' (which many browsers will read as the harmless 'http') may be considered bad by htmLawed.
+
+ * htmLawed will attempt to put plain text present directly inside 'blockquote', 'form', 'map' and 'noscript' elements (illegal as per the specs) inside auto-generated 'div' elements.
+
+
+-- 2.8 Limitations & work-arounds ---------------------------------o
+
+
+ htmLawed's main objective is to make the input text `more` standard-compliant, secure for web-page readers, and free of HTML elements and attributes considered undesirable by the administrator. Some of its current limitations, regardless of this objective, are noted below along with work-arounds.
+
+ It should be borne in mind that no browser application is 100% standard-compliant, and that some of the standard specs (like asking for normalization of white-spacing within 'textarea' elements) are clearly wrong. Regarding security, note that `unsafe` HTML code is not necessarily legally invalid.
+
+ * htmLawed is meant for input that goes into the 'body' of HTML documents. HTML's head-level elements are not supported, nor are the frameset elements 'frameset', 'frame' and 'noframes'.
+
+ * It cannot transform the non-standard 'embed' elements to the standard-compliant 'object' elements. Yet, it can allow 'embed' elements if permitted ('embed' is widely used and supported). Admins can certainly use the 'hook_tag' parameter (section:- #3.4.9) to deploy a custom embed-to-object converter function.
+
+ * The only non-standard element that may be permitted is 'embed'; others like 'noembed' and 'nobr' cannot be permitted without modifying the htmLawed code.
+
+ * It cannot handle input that has non-HTML code like 'SVG' and 'MathML'. One way around is to break the input into pieces and passing only those without non-HTML code to htmLawed. Another is described in section:- #3.9. A third way may be to some how take advantage of the '$config["and_mark"]' parameter (see section:- #3.2).
+
+ * By default, htmLawed won't check many attribute values for standard compliance. E.g., 'width="20m"' with the dimension in non-standard 'm' is let through. Implementing universal and strict attribute value checks can make htmLawed slow and resource-intensive. Admins should look at the 'hook_tag' parameter (section:- #3.4.9) or '$spec' to enforce finer checks.
+
+ * The attributes, deprecated (which can be transformed too) or not, that it supports are largely those that are in the specs. Only a few of the proprietary attributes are supported.
+
+ * Except for contained URLs and dynamic expressions (also optional), htmLawed does not check CSS style property values. Admins should look at using the 'hook_tag' parameter (section:- #3.4.9) or '$spec' for finer checks. Perhaps the best option is to disallow 'style' but allow 'class' attributes with the right 'oneof' or 'match' values for 'class', and have the various class style properties in '.css' CSS stylesheet files.
+
+ * htmLawed does not parse emoticons, decode `BBcode`, or `wikify`, auto-converting text to proper HTML. Similarly, it won't convert line-breaks to 'br' elements. Such functions are beyond its purview. Admins should use other code to pre- or post-process the input for such purposes.
+
+ * htmLawed cannot be used to have links force-opened in new windows (by auto-adding appropriate 'target' and 'onclick' attributes to 'a'). Admins should look at Javascript-based DOM-modifying solutions for this. Admins may also be able to use a custom hook function to enforce such checks ('hook_tag' parameter; see section:- #3.4.9).
+
+ * Nesting-based checks are not possible. E.g., one cannot disallow 'p' elements specifically inside 'td' while permitting it elsewhere. Admins may be able to use a custom hook function to enforce such checks ('hook_tag' parameter; see section:- #3.4.9).
+
+ * Except for optionally converting absolute or relative URLs to the other type, htmLawed will not alter URLs (e.g., to change the value of query strings or to convert 'http' to 'https'. Having absolute URLs may be a standard-requirement, e.g., when HTML is embedded in email messages, whereas altering URLs for other purposes is beyond htmLawed's goals. Admins may be able to use a custom hook function to enforce such checks ('hook_tag' parameter; see section:- #3.4.9).
+
+ * Pairs of opening and closing tags that do not enclose any content (like '<em></em>') are not removed. This may be against the standard specs for certain elements (e.g., 'table'). However, presence of such standard-incompliant code will not break the display or layout of content. Admins can also use simple regex-based code to filter out such code.
+
+ * htmLawed does not check for certain element orderings described in the standard specs (e.g., in a 'table', 'tbody' is allowed before 'tfoot'). Admins may be able to use a custom hook function to enforce such checks ('hook_tag' parameter; see section:- #3.4.9).
+
+ * htmLawed does not check the number of nested elements. E.g., it will allow two 'caption' elements in a 'table' element, illegal as per the specs. Admins may be able to use a custom hook function to enforce such checks ('hook_tag' parameter; see section:- #3.4.9).
+
+ * htmLawed might convert certain entities to actual characters and remove backslashes and CSS comment-markers ('/*') in 'style' attribute values in order to detect malicious HTML like crafted IE-specific dynamic expressions like '&#101;xpression...'. If this is too harsh, admins can allow CSS expressions through htmLawed core but then use a custom function through the 'hook_tag' parameter (section:- #3.4.9) to more specifically identify CSS expressions in the 'style' attribute values. Also, using '$config["style_pass"]', it is possible to have htmLawed pass 'style' attribute values without even looking at them (section:- #3.4.8).
+
+ * htmLawed does not correct certain possible attribute-based security vulnerabilities (e.g., '<a href="http://x%22+style=%22background-image:xss">x</a>'). These arise when browsers mis-identify markup in `escaped` text, defeating the very purpose of escaping text (a bad browser will read the given example as '<a href="http://x" style="background-image:xss">x</a>').
+
+ * Because of poor Unicode support in PHP, htmLawed does not remove the `high value` HTML-invalid characters with multi-byte code-points. Such characters however are extremely unlikely to be in the input. (see section:- #3.1).
+
+ * Like any script using PHP's PCRE regex functions, PHP setup-specific low PCRE limit values can cause htmLawed to at least partially fail with very long input texts.
+
+
+-- 2.9 Examples ---------------------------------------------------o
+
+
+ *1.* A blog administrator wants to allow only 'a', 'em', 'strike', 'strong' and 'u' in comments, but needs 'strike' and 'u' transformed to 'span' for better XHTML 1-strict compliance, and, he wants the 'a' links to be to 'http' or 'https' resources:
+
+ $processed = htmLawed($in, array('elements'=>'a, em, strike, strong, u', 'make_tag_strict'=>1, 'safe'=>1, 'schemes'=>'*:http, https'), 'a=href');
+
+ *2.* An author uses a custom-made web application to load content on his web-site. He is the only one using that application and the content he generates has all types of HTML, including scripts. The web application uses htmLawed primarily as a tool to correct errors that creep in while writing HTML and to take care of the occasional `bad` characters in copy-paste text introduced by Microsoft Office. The web application provides a preview before submitted input is added to the content. For the previewing process, htmLawed is set up as follows:
+
+ $processed = htmLawed($in, array('css_expression'=>1, 'keep_bad'=>1, 'make_tag_strict'=>1, 'schemes'=>'*:*', 'valid_xhtml'=>1));
+
+ For the final submission process, 'keep_bad' is set to '6'. A value of '1' for the preview process allows the author to note and correct any HTML mistake without losing any of the typed text.
+
+ *3.* A data-miner is scraping information in a specific table of similar web-pages and is collating the data rows, and uses htmLawed to reduce unnecessary markup and white-spaces:
+
+ $processed = htmLawed($in, array('elements'=>'tr, td', 'tidy'=>-1), 'tr, td =');
+
+
+== 3 Details =====================================================oo
+
+
+-- 3.1 Invalid/dangerous characters --------------------------------
+
+
+ Valid characters (more correctly, their code-points) in HTML or XML are, hexadecimally, '9', 'a', 'd', '20' to 'd7ff', and 'e000' to '10ffff', except 'fffe' and 'ffff' (decimally, '9', '10', '13', '32' to '55295', and '57344' to '1114111', except '65534' and '65535'). htmLawed removes the invalid characters '0' to '8', 'b', 'c', and 'e' to '1f'.
+
+ Because of PHP's poor native support for multi-byte characters, htmLawed cannot check for the remaining invalid code-points. However, for various reasons, it is very unlikely for any of those characters to be in the input.
+
+ Characters that are discouraged (see section:- #5.1) but not invalid are not removed by htmLawed.
+
+ It (function 'hl_tag()') also replaces the potentially dangerous (in some Mozilla [Firefox] and Opera browsers) soft-hyphen character (code-point, hexadecimally, 'ad', or decimally, '173') in attribute values with spaces. Where required, the characters '<', '>', '&', and '"' are converted to entities.
+
+ With '$config["clean_ms_char"]' set as '1' or '2', many of the discouraged characters (decimal code-points '127' to '159' except '133') that many Microsoft applications incorrectly use (as per the 'Windows 1252' ['Cp-1252'] or a similar encoding system), and the character for decimal code-point '133', are converted to appropriate decimal numerical entities (or removed for a few cases)-- see appendix in section:- #5.4. This can help avoid some display issues arising from copying-pasting of content.
+
+ With '$config["clean_ms_char"]' set as '2', characters for the hexadecimal code-points '82', '91', and '92' (for special single-quotes), and '84', '93', and '94' (for special double-quotes) are converted to ordinary single and double quotes respectively and not to entities.
+
+ The character values are replaced with entities/characters and not character values referred to by the entities/characters to keep this task independent of the character-encoding of input text.
+
+ The '$config["clean_ms_char"]' parameter need not be used if authors do not copy-paste Microsoft-created text or if the input text is not believed to use the 'Windows 1252' or a similar encoding. Further, the input form and the web-pages displaying it or its content should have the character encoding appropriately marked-up.
+
+
+-- 3.2 Character references/entities ------------------------------o
+
+
+ Valid character entities take the form '&*;' where '*' is '#x' followed by a hexadecimal number (hexadecimal numeric entity; like '&#xA0;' for non-breaking space), or alphanumeric like 'gt' (external or named entity; like '&nbsp;' for non-breaking space), or '#' followed by a number (decimal numeric entity; like '&#160;' for non-breaking space). Character entities referring to the soft-hyphen character (the '&shy;' or '\xad' character; hexadecimal code-point 'ad' [decimal '173']) in attribute values are always replaced with spaces; soft-hyphens in attribute values introduce vulnerabilities in some older versions of the Opera and Mozilla [Firefox] browsers.
+
+ htmLawed (function 'hl_ent()'):
+
+ * Neutralizes entities with multiple leading zeroes or missing semi-colons (potentially dangerous)
+
+ * Lowercases the 'X' (for XML-compliance) and 'A-F' of hexadecimal numeric entities
+
+ * Neutralizes entities referring to characters that are HTML-invalid (see section:- #3.1)
+
+ * Neutralizes entities referring to characters that are HTML-discouraged (code-points, hexadecimally, '7f' to '84', '86' to '9f', and 'fdd0' to 'fddf', or decimally, '127' to '132', '134' to '159', and '64991' to '64976'). Entities referring to the remaining discouraged characters (see section:- #5.1 for a full list) are let through.
+
+ * Neutralizes named entities that are not in the specs.
+
+ * Optionally converts valid HTML-specific named entities except '&gt;', '&lt;', '&quot;', and '&amp;' to decimal numeric ones (hexadecimal if $config["hexdec_entity"] is '2') for generic XML-compliance. For this, '$config["named_entity"]' should be '1'.
+
+ * Optionally converts hexadecimal numeric entities to the more widely supported decimal ones. For this, '$config["hexdec_entity"]' should be '0'.
+
+ * Optionally converts decimal numeric entities to the hexadecimal ones. For this, '$config["hexdec_entity"]' should be '2'.
+
+ `Neutralization` refers to the `entitification` of '&' to '&amp;'.
+
+ *Note*: htmLawed does not convert entities to the actual characters represented by them; one can pass the htmLawed output through PHP's 'html_entity_decode' function:- http://www.php.net/html_entity_decode for that.
+
+ *Note*: If '$config["and_mark"]' is set, and set to a value other than '0', then the '&' characters in the original input are replaced with the control character for the hexadecimal code-point '6' ('\x06'; '&' characters introduced by htmLawed, e.g., after converting '<' to '&lt;', are not affected). This allows one to distinguish, say, an '&gt;' introduced by htmLawed and an '&gt;' put in by the input writer, and can be helpful in further processing of the htmLawed-processed text (e.g., to identify the character sequence 'o(><)o' to generate an emoticon image). When this feature is active, admins should ensure that the htmLawed output is not directly used in web pages or XML documents as the presence of the '\x06' can break documents. Before use in such documents, and preferably before any storage, any remaining '\x06' should be changed back to '&', e.g., with:
+
+ $final = str_replace("\x06", '&', $prelim);
+
+ Also, see section:- #3.9.
+
+
+-- 3.3 HTML elements ----------------------------------------------o
+
+
+ htmLawed can be configured to allow only certain HTML elements (tags) in the input. Disallowed elements (just tag-content, and not element-content), based on '$config["keep_bad"]', are either `neutralized` (converted to plain text by entitification of '<' and '>') or removed.
+
+ E.g., with only 'em' permitted:
+
+ Input:
+
+ <em>My</em> website is <a href="http://a.com>a.com</a>.
+
+ Output, with '$config["keep_bad"] = 0':
+
+ <em>My</em> website is a.com.
+
+ Output, with '$config["keep_bad"]' not '0':
+
+ <em>My</em> website is &lt;a href=""&gt;a.com&lt;/a&gt;.
+
+ See section:- #3.3.3 for differences between the various non-zero '$config["keep_bad"]' values.
+
+ htmLawed by default permits these 86 elements:
+
+ a, abbr, acronym, address, applet, area, b, bdo, big, blockquote, br, button, caption, center, cite, code, col, colgroup, dd, del, dfn, dir, div, dl, dt, em, embed, fieldset, font, form, h1, h2, h3, h4, h5, h6, hr, i, iframe, img, input, ins, isindex, kbd, label, legend, li, map, menu, noscript, object, ol, optgroup, option, p, param, pre, q, rb, rbc, rp, rt, rtc, ruby, s, samp, script, select, small, span, strike, strong, sub, sup, table, tbody, td, textarea, tfoot, th, thead, tr, tt, u, ul, var
+
+ Except for 'embed' (included because of its wide-spread use) and the Ruby elements ('rb', 'rbc', 'rp', 'rt', 'rtc', 'ruby'; part of XHTML 1.1), these are all the elements in the HTML 4/XHTML 1 specs. Strict-specific specs. exclude 'center', 'dir', 'font', 'isindex', 'menu', 's', 'strike', and 'u'.
+
+ With '$config["safe"] = 1', the default set will exclude 'applet', 'embed', 'iframe', 'object' and 'script'; see section:- #3.6.
+
+ When '$config["elements"]', which specifies allowed elements, is `properly` defined, and neither empty nor set to '0' or '*', the default set is not used. To have elements added to or removed from the default set, a '+/-' notation is used. E.g., '*-script-object' implies that only 'script' and 'object' are disallowed, whereas '*+embed' means that 'noembed' is also allowed. Elements can also be specified as comma separated names. E.g., 'a, b, i' means only 'a', 'b' and 'i' are permitted. In this notation, '*', '+' and '-' have no significance and can actually cause a mis-reading.
+
+ Some more examples of '$config["elements"]' values indicating permitted elements (note that empty spaces are liberally allowed for clarity):
+
+ * 'a, blockquote, code, em, strong' -- only 'a', 'blockquote', 'code', 'em', and 'strong'
+ * '*-script' -- all excluding 'script'
+ * '* -center -dir -font -isindex -menu -s -strike -u' -- only XHTML-Strict elements
+ * '*+noembed-script' -- all including 'noembed' excluding 'script'
+
+ Some mis-usages (and the resulting permitted elements) that can be avoided:
+
+ * '-*' -- none; instead of htmLawed, one might just use, e.g., the 'htmlspecialchars()' PHP function
+ * '*, -script' -- all except 'script'; admin probably meant '*-script'
+ * '-*, a, em, strong' -- all; admin probably meant 'a, em, strong'
+ * '*' -- all; admin need not have set 'elements'
+ * '*-form+form' -- all; a '+' will always over-ride any '-'
+ * '*, noembed' -- only 'noembed'; admin probably meant '*+noembed'
+ * 'a, +b, i' -- only 'a' and 'i'; admin probably meant 'a, b, i'
+
+ Basically, when using the '+/-' notation, commas (',') should not be used, and vice versa, and '*' should be used with the former but not the latter.
+
+ *Note*: Even if an element that is not in the default set is allowed through '$config["elements"]', like 'noembed' in the last example, it will eventually be removed during tag balancing unless such balancing is turned off ('$config["balance"]' set to '0'). Currently, the only way around this, which actually is simple, is to edit the various arrays in the function 'hl_bal()' to accommodate the element and its nesting properties.
+
+ *A possibly second way to specify allowed elements* is to set '$config["parent"]' to an element name that supposedly will hold the input, and to set '$config["balance"]' to '1'. During tag balancing (see section:- #3.3.3), all elements that cannot legally nest inside the parent element will be removed. The parent element is auto-reset to 'div' if '$config["parent"]' is empty, 'body', or an element not in htmLawed's default set of 86 elements.
+
+ `Tag transformation` is possible for improving XHTML-Strict compliance -- most of the deprecated elements are removed or converted to valid XHTML-Strict ones; see section:- #3.3.2.
+
+
+.. 3.3.1 Handling of comments and CDATA sections ...................
+
+
+ 'CDATA' sections have the format '<![CDATA[...anything but not "]]>"...]]>', and HTML comments, '<!--...anything but not "-->"... -->'. Neither HTML comments nor 'CDATA' sections can reside inside tags. HTML comments can exist anywhere else, but 'CDATA' sections can exist only where plain text is allowed (e.g., immediately inside 'td' element content but not immediately inside 'tr' element content).
+
+ htmLawed (function 'hl_cmtcd()') handles HTML comments or 'CDATA' sections depending on the values of '$config["comment"]' or '$config["cdata"]'. If '0', such markup is not looked for and the text is processed like plain text. If '1', it is removed completely. If '2', it is preserved but any '<', '>' and '&' inside are changed to entities. If '3', they are left as such.
+
+ Note that for the last two cases, HTML comments and 'CDATA' sections will always be removed from tag content (function 'hl_tag()').
+
+ Examples:
+
+ Input:
+ <!-- home link --><a href="home.htm"><![CDATA[x=&y]]>Home</a>
+ Output ('$config["comment"] = 0, $config["cdata"] = 2'):
+ &lt;-- home link --&gt;<a href="home.htm"><![CDATA[x=&amp;y]]>Home</a>
+ Output ('$config["comment"] = 1, $config["cdata"] = 2'):
+ <a href="home.htm"><![CDATA[x=&amp;y]]>Home</a>
+ Output ('$config["comment"] = 2, $config["cdata"] = 2'):
+ <!-- home link --><a href="home.htm"><![CDATA[x=&amp;y]]>Home</a>
+ Output ('$config["comment"] = 2, $config["cdata"] = 1'):
+ <!-- home link --><a href="home.htm">Home</a>
+ Output ('$config["comment"] = 3, $config["cdata"] = 3'):
+ <!-- home link --><a href="home.htm"><![CDATA[x=&y]]>Home</a>
+
+ For standard-compliance, comments are given the form '<!--comment -->', and any '--' in the content is made '-'.
+
+ When '$config["safe"] = 1', CDATA sections and comments are considered plain text unless '$config["comment"]' or '$config["cdata"]' is explicitly specified; see section:- #3.6.
+
+
+.. 3.3.2 Tag-transformation for better XHTML-Strict ................o
+
+
+ If '$config["make_tag_strict"]' is set and not '0', following non-XHTML-Strict elements (and attributes), even if admin-permitted, are mutated as indicated (element content remains intact; function 'hl_tag2()'):
+
+ * applet - (based on '$config["make_tag_strict"]', unchanged ('1') or removed ('2'))
+ * center - 'div style="text-align: center;"'
+ * dir - 'ul'
+ * embed - (based on '$config["make_tag_strict"]', unchanged ('1') or removed ('2'))
+ * font (face, size, color) - 'span style="font-family: ; font-size: ; color: ;"' (size transformation reference:- http://style.cleverchimp.com/font_size_intervals/altintervals.html)
+ * isindex - (based on '$config["make_tag_strict"]', unchanged ('1') or removed ('2'))
+ * menu - 'ul'
+ * s - 'span style="text-decoration: line-through;"'
+ * strike - 'span style="text-decoration: line-through;"'
+ * u - 'span style="text-decoration: underline;"'
+
+ For an element with a pre-existing 'style' attribute value, the extra style properties are appended.
+
+ Example input:
+
+ <center>
+ The PHP <s>software</s> script used for this <strike>web-page</strike> web-page is <font style="font-weight: bold " face=arial size='+3' color = "red ">htmLawedTest.php</font>, from <u style= 'color:green'>PHP Labware</u>.
+ </center>
+
+ The output:
+
+ <div style="text-align: center;">
+ The PHP <span style="text-decoration: line-through;">software</span> script used for this <span style="text-decoration: line-through;">web-page</span> web-page is <span style="font-weight: bold; font-family: arial; color: red; font-size: 200%;">htmLawedTest.php</span>, from <span style="color:green; text-decoration: underline;">PHP Labware</span>.
+ </div>
+
+
+-- 3.3.3 Tag balancing and proper nesting -------------------------o
+
+
+ If '$config["balance"]' is set to '1', htmLawed (function 'hl_bal()') checks and corrects the input to have properly balanced tags and legal element content (i.e., any element nesting should be valid, and plain text may be present only in the content of elements that allow them).
+
+ Depending on the value of '$config["keep_bad"]' (see section:- #2.2 and section:- #3.3), illegal content may be removed or neutralized to plain text by converting < and > to entities:
+
+ '0' - remove; this option is available only to maintain Kses-compatibility and should not be used otherwise (see section:- #2.6)
+ '1' - neutralize tags and keep element content
+ '2' - remove tags but keep element content
+ '3' and '4' - like '1' and '2', but keep element content only if text ('pcdata') is valid in parent element as per specs
+ '5' and '6' - like '3' and '4', but line-breaks, tabs and spaces are left
+
+ Example input (disallowing the 'p' element):
+
+ <*> Pseudo-tags <*>
+ <xml>Non-HTML tag xml</xml>
+ <p>
+ Disallowed tag p
+ </p>
+ <ul>Bad<li>OK</li></ul>
+
+ The output with '$config["keep_bad"] = 1':
+
+ &lt;*&gt; Pseudo-tags &lt;*&gt;
+ &lt;xml&gt;Non-HTML tag xml&lt;/xml&gt;
+ &lt;p&gt;
+ Disallowed tag p
+ &lt;/p&gt;
+ <ul>Bad<li>OK</li></ul>
+
+ The output with '$config["keep_bad"] = 3':
+
+ &lt;*&gt; Pseudo-tags &lt;*&gt;
+ &lt;xml&gt;Non-HTML tag xml&lt;/xml&gt;
+ &lt;p&gt;
+ Disallowed tag p
+ &lt;/p&gt;
+ <ul><li>OK</li></ul>
+
+ The output with '$config["keep_bad"] = 6':
+
+ &lt;*&gt; Pseudo-tags &lt;*&gt;
+ Non-HTML tag xml
+
+ Disallowed tag p
+
+ <ul><li>OK</li></ul>
+
+ An option like '1' is useful, e.g., when a writer previews his submission, whereas one like '3' is useful before content is finalized and made available to all.
+
+ *Note:* In the example above, unlike '<*>', '<xml>' gets considered as a tag (even though there is no HTML element named 'xml'). In general, text matching the regular expression pattern '<(/?)([a-zA-Z][a-zA-Z1-6]*)([^>]*?)\s?>' is considered a tag (phrase enclosed by the angled brackets '<' and '>', and starting [with an optional slash preceding] with an alphanumeric word that starts with an alphabet...).
+
+ Nesting/content rules for each of the 86 elements in htmLawed's default set (see section:- #3.3) are defined in function 'hl_bal()'. This means that if a non-standard element besides 'embed' is being permitted through '$config["elements"]', the element's tag content will end up getting removed if '$config["balance"]' is set to '1'.
+
+ Plain text and/or certain elements nested inside 'blockquote', 'form', 'map' and 'noscript' need to be in block-level elements. This point is often missed during manual writing of HTML code. htmLawed attempts to address this during balancing. E.g., if the parent container is set as 'form', the input 'B:<input type="text" value="b" />C:<input type="text" value="c" />' is converted to '<div>B:<input type="text" value="b" />C:<input type="text" value="c" /></div>'.
+
+
+-- 3.3.4 Elements requiring child elements ------------------------o
+
+
+ As per specs, the following elements require legal child elements nested inside them:
+
+ blockquote, dir, dl, form, map, menu, noscript, ol, optgroup, rbc, rtc, ruby, select, table, tbody, tfoot, thead, tr, ul
+
+ In some cases, the specs stipulate the number and/or the ordering of the child elements. A 'table' can have 0 or 1 'caption', 'tbody', 'tfoot', and 'thead', but they must be in this order: 'caption', 'thead', 'tfoot', 'tbody'.
+
+ htmLawed currently does not check for conformance to these rules. Note that any non-compliance in this regard will not introduce security vulnerabilities, crash browser applications, or affect the rendering of web-pages.
+
+
+-- 3.3.5 Beautify or compact HTML ---------------------------------o
+
+
+ By default, htmLawed will neither `beautify` HTML code by formatting it with indentations, etc., nor will it make it compact by removing un-needed white-space.(It does always properly white-space tag content.)
+
+ As per the HTML standards, spaces, tabs and line-breaks in web-pages (except those inside 'pre' elements) are all considered equivalent, and referred to as `white-spaces`. Browser applications are supposed to consider contiguous white-spaces as just a single space, and to disregard white-spaces trailing opening tags or preceding closing tags. This white-space `normalization` allows the use of text/code beautifully formatted with indentations and line-spacings for readability. Such `pretty` HTML can, however, increase the size of web-pages, or make the extraction or scraping of plain text cumbersome.
+
+ With the '$config' parameter 'tidy', htmLawed can be used to beautify or compact the input text. Input with just plain text and no HTML markup is also subject to this. Besides 'pre', the 'script' and 'textarea' elements, CDATA sections, and HTML comments are not subjected to the tidying process.
+
+ To `compact`, use '$config["tidy"] = -1'; single instances or runs of white-spaces are replaced with a single space, and white-spaces trailing and leading open and closing tags, respectively, are removed.
+
+ To `beautify`, '$config["tidy"]' is set as '1', or for customized tidying, as a string like '2s2n'. The 's' or 't' character specifies the use of spaces or tabs for indentation. The first and third characters, any of the digits 0-9, specify the number of spaces or tabs per indentation, and any parental lead spacing (extra indenting of the whole block of input text). The 'r' and 'n' characters are used to specify line-break characters: 'n' for '\n' (Unix/Mac OS X line-breaks), 'rn' or 'nr' for '\r\n' (Windows/DOS line-breaks), or 'r' for '\r'.
+
+ The '$config["tidy"]' value of '1' is equivalent to '2s0n'. Other '$config["tidy"]' values are read loosely: a value of '4' is equivalent to '4s0n'; 't2', to '1t2n'; 's', to '2s0n'; '2TR', to '2t0r'; 'T1', to '1t1n'; 'nr3', to '3s0nr', and so on. Except in the indentations and line-spacings, runs of white-spaces are replaced with a single space during beautification.
+
+ Input formatting using '$config["tidy"]' is not recommended when input text has mixed markup (like HTML + PHP).
+
+
+-- 3.4 Attributes ------------------------------------------------oo
+
+
+ htmLawed will only permit attributes described in the HTML specs (including deprecated ones). It also permits some attributes for use with the 'embed' element (the non-standard 'embed' element is supported in htmLawed because of its widespread use), and the the 'xml:space' attribute (valid only in XHTML 1.1). A list of such 111 attributes and the elements they are allowed in is in section:- #5.2.
+
+ When '$config["deny_attribute"]' is not set, or set to '0', or empty ('""'), all the 111 attributes are permitted. Otherwise, '$config["deny_attribute"]' can be set as a list of comma-separated names of the denied attributes. 'on*' can be used to refer to the group of potentially dangerous, script-accepting attributes: 'onblur', 'onchange', 'onclick', 'ondblclick', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onmousedown', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onreset', 'onselect' and 'onsubmit'.
+
+ Note that attributes specified in '$config["deny_attribute"]' are denied globally, for all elements. To deny attributes for only specific elements, '$spec' (see section:- #2.3) can be used. '$spec' can also be used to element-specifically permit an attribute otherwise denied through '$config["deny_attribute"]'.
+
+ With '$config["safe"] = 1' (section:- #3.6), the 'on*' attributes are automatically disallowed.
+
+ *Note*: To deny all but a few attributes globally, a simpler way to specify '$config["deny_attribute"]' would be to use the notation '* -attribute1 -attribute2 ...'. Thus, a value of '* -title -href' implies that except 'href' and 'title' (where allowed as per standards) all other attributes are to be removed. With this notation, the value for the parameter 'safe' (section:- #3.6) will have no effect on 'deny_attribute'.
+
+ htmLawed (function 'hl_tag()') also:
+
+ * Lower-cases attribute names
+ * Removes duplicate attributes (last one stays)
+ * Gives attributes the form 'name="value"' and single-spaces them, removing unnecessary white-spacing
+ * Provides `required` attributes (see section:- #3.4.1)
+ * Double-quotes values and escapes any '"' inside them
+ * Replaces the possibly dangerous soft-hyphen characters (hexadecimal code-point 'ad') in the values with spaces
+ * Allows custom function to additionally filter/modify attribute values (see section:- #3.4.9)
+
+
+.. 3.4.1 Auto-addition of XHTML-required attributes ................
+
+
+ If indicated attributes for the following elements are found missing, htmLawed (function 'hl_tag()') will add them (with values same as attribute names unless indicated otherwise below):
+
+ * area - alt ('area')
+ * area, img - src, alt ('image')
+ * bdo - dir ('ltr')
+ * form - action
+ * map - name
+ * optgroup - label
+ * param - name
+ * script - type ('text/javascript')
+ * textarea - rows ('10'), cols ('50')
+
+ Additionally, with '$config["xml:lang"]' set to '1' or '2', if the 'lang' but not the 'xml:lang' attribute is declared, then the latter is added too, with a value copied from that of 'lang'. This is for better standard-compliance. With '$config["xml:lang"]' set to '2', the 'lang' attribute is removed (XHTML 1.1 specs).
+
+ Note that the 'name' attribute for 'map', invalid in XHTML 1.1, is also transformed if required -- see section:- #3.4.6.
+
+
+.. 3.4.2 Duplicate/invalid 'id' values ............................o
+
+
+ If '$config["unique_ids"]' is '1', htmLawed (function 'hl_tag()') removes 'id' attributes with values that are not XHTML-compliant (must begin with a letter and can contain letters, digits, ':', '.', '-' and '_') or duplicate. If '$config["unique_ids"]' is a word, any duplicate but otherwise valid value will be appropriately prefixed with the word to ensure its uniqueness. The word should begin with a letter and should contain only letters, numbers, ':', '.', '_' and '-'.
+
+ Even if multiple inputs need to be filtered (through multiple calls to htmLawed), htmLawed ensures uniqueness of 'id' values as it uses a global variable ('$GLOBALS["hl_Ids"]' array). Further, an admin can restrict the use of certain 'id' values by presetting this variable before htmLawed is called into use. E.g.:
+
+ $GLOBALS['hl_Ids'] = array('top'=>1, 'bottom'=>1, 'myform'=>1); // id values not allowed in input
+ $processed = htmLawed($text); // filter input
+
+
+.. 3.4.3 URL schemes (protocols) and scripts in attribute values ............o
+
+
+ htmLawed edits attributes that take URLs as values if they are found to contain un-permitted schemes. E.g., if the 'afp' scheme is not permitted, then '<a href="afp://domain.org">' becomes '<a href="denied:afp://domain.org">', and if Javascript is not permitted '<a onclick="javascript:xss();">' becomes '<a onclick="denied:javascript:xss();">'.
+
+ By default htmLawed permits these schemes in URLs for the 'href' attribute:
+
+ aim, feed, file, ftp, gopher, http, https, irc, mailto, news, nntp, sftp, ssh, telnet
+
+ Also, only 'file', 'http' and 'https' are permitted in attributes whose names start with 'o' (like 'onmouseover'), and in these attributes that accept URLs:
+
+ action, cite, classid, codebase, data, href, longdesc, model, pluginspage, pluginurl, src, style, usemap
+
+ These default sets are used when '$config["schemes"]' is not set (see section:- #2.2). To over-ride the defaults, '$config["schemes"]' is defined as a string of semi-colon-separated sub-strings of type 'attribute: comma-separated schemes'. E.g., 'href: mailto, http, https; onclick: javascript; src: http, https'. For unspecified attributes, 'file', 'http' and 'https' are permitted. This can be changed by passing schemes for '*' in '$config["schemes"]'. E.g., 'href: mailto, http, https; *: https, https'.
+
+ '*' can be put in the list of schemes to permit all protocols. E.g., 'style: *; img: http, https' results in protocols not being checked in 'style' attribute values. However, in such cases, any relative-to-absolute URL conversion, or vice versa, (section:- #3.4.4) is not done.
+
+ Thus, `to allow Javascript`, one can set '$config["schemes"]' as 'href: mailto, http, https; *: http, https, javascript', or 'href: mailto, http, https, javascript; *: http, https, javascript', or '*: *', and so on.
+
+ As a side-note, one may find 'style: *' useful as URLs in 'style' attributes can be specified in a variety of ways, and the patterns that htmLawed uses to identify URLs may mistakenly identify non-URL text.
+
+ *Note*: If URL-accepting attributes other than those listed above are being allowed, then the scheme will not be checked unless the attribute name contains the string 'src' (e.g., 'dynsrc') or starts with 'o' (e.g., 'onbeforecopy').
+
+ With '$config["safe"] = 1', all URLs are disallowed in the 'style' attribute values.
+
+
+.. 3.4.4 Absolute & relative URLs in attribute values .............o
+
+
+ htmLawed can make absolute URLs in attributes like 'href' relative ('$config["abs_url"]' is '-1'), and vice versa ('$config["abs_url"]' is '1'). URLs in scripts are not considered for this, and so are URLs like '#section_6' (fragment), '?name=Tim#show' (starting with query string), and ';var=1?name=Tim#show' (starting with parameters). Further, this requires that '$config["base_url"]' be set properly, with the '://' and a trailing slash ('/'), with no query string, etc. E.g., 'file:///D:/page/', 'https://abc.com/x/y/', or 'http://localhost/demo/' are okay, but 'file:///D:/page/?help=1', 'abc.com/x/y/' and 'http://localhost/demo/index.htm' are not.
+
+ For making absolute URLs relative, only those URLs that have the '$config["base_url"]' string at the beginning are converted. E.g., with '$config["base_url"] = "https://abc.com/x/y/"', 'https://abc.com/x/y/a.gif' and 'https://abc.com/x/y/z/b.gif' become 'a.gif' and 'z/b.gif' respectively, while 'https://abc.com/x/c.gif' is not changed.
+
+ When making relative URLs absolute, only values for scheme, network location (host-name) and path values in the base URL are inherited. See section:- #5.5 for more about the URL specification as per RFC 1808:- http://www.ietf.org/rfc/rfc1808.txt.
+
+
+.. 3.4.5 Lower-cased, standard attribute values ....................o
+
+
+ Optionally, for standard-compliance, htmLawed (function 'hl_tag()') lower-cases standard attribute values to give, e.g., 'input type="password"' instead of 'input type="Password"', if '$config["lc_std_val"]' is '1'. Attribute values matching those listed below for any of the elements (plus those for the 'type' attribute of 'button' or 'input') are lower-cased:
+
+ all, baseline, bottom, button, center, char, checkbox, circle, col, colgroup, cols, data, default, file, get, groups, hidden, image, justify, left, ltr, middle, none, object, password, poly, post, preserve, radio, rect, ref, reset, right, row, rowgroup, rows, rtl, submit, text, top
+
+ a, area, bdo, button, col, form, img, input, object, option, optgroup, param, script, select, table, td, tfoot, th, thead, tr, xml:space
+
+ The following `empty` (`minimized`) attributes are always assigned lower-cased values (same as the names):
+
+ checked, compact, declare, defer, disabled, ismap, multiple, nohref, noresize, noshade, nowrap, readonly, selected
+
+
+.. 3.4.6 Transformation of deprecated attributes ..................o
+
+
+ If '$config["no_deprecated_attr"]' is '0', then deprecated attributes (see appendix in section:- #5.2) are removed and, in most cases, their values are transformed to CSS style properties and added to the 'style' attributes (function 'hl_tag()'). Except for 'bordercolor' for 'table', 'tr' and 'td', the scores of proprietary attributes that were never part of any cross-browser standard are not supported.
+
+ *Note*: The attribute 'target' for 'a' is allowed even though it is not in XHTML 1.0 specs. This is because of the attribute's wide-spread use and browser-support, and because the attribute is valid in XHTML 1.1 onwards.
+
+ * align - for 'img' with value of 'left' or 'right', becomes, e.g., 'float: left'; for 'div' and 'table' with value 'center', becomes 'margin: auto'; all others become, e.g., 'text-align: right'
+
+ * bgcolor - E.g., 'bgcolor="#ffffff"' becomes 'background-color: #ffffff'
+ * border - E.g., 'height= "10"' becomes 'height: 10px'
+ * bordercolor - E.g., 'bordercolor=#999999' becomes 'border-color: #999999;'
+ * compact - 'font-size: 85%'
+ * clear - E.g., 'clear="all" becomes 'clear: both'
+
+ * height - E.g., 'height= "10"' becomes 'height: 10px' and 'height="*"' becomes 'height: auto'
+
+ * hspace - E.g., 'hspace="10"' becomes 'margin-left: 10px; margin-right: 10px'
+ * language - 'language="VBScript"' becomes 'type="text/vbscript"'
+ * name - E.g., 'name="xx"' becomes 'id="xx"'
+ * noshade - 'border-style: none; border: 0; background-color: gray; color: gray'
+ * nowrap - 'white-space: nowrap'
+ * size - E.g., 'size="10"' becomes 'height: 10px'
+ * start - removed
+ * type - E.g., 'type="i"' becomes 'list-style-type: lower-roman'
+ * value - removed
+ * vspace - E.g., 'vspace="10"' becomes 'margin-top: 10px; margin-bottom: 10px'
+ * width - like 'height'
+
+ Example input:
+
+ <img src="j.gif" alt="image" name="dad's" /><img src="k.gif" alt="image" id="dad_off" name="dad" />
+ <br clear="left" />
+ <hr noshade size="1" />
+ <img name="img" src="i.gif" align="left" alt="image" hspace="10" vspace="10" width="10em" height="20" border="1" style="padding:5px;" />
+ <table width="50em" align="center" bgcolor="red">
+ <tr>
+ <td width="20%">
+ <div align="center">
+ <h3 align="right">Section</h3>
+ <p align="right">Para</p>
+ <ol type="a" start="e"><li value="x">First item</li></ol>
+ </div>
+ </td>
+ <td width="*">
+ <ol type="1"><li>First item</li></ol>
+ </td>
+ </tr>
+ </table>
+ <br clear="all" />
+
+ And the output with '$config["no_deprecated_attr"] = 1':
+
+ <img src="j.gif" alt="image" /><img src="k.gif" alt="image" id="dad_off" />
+ <br style="clear: left;" />
+ <hr style="border-style: none; border: 0; background-color: gray; color: gray; size: 1px;" />
+ <img src="i.gif" alt="image" width="10em" height="20" style="padding:5px; float: left; margin-left: 10px; margin-right: 10px; margin-top: 10px; margin-bottom: 10px; border: 1px;" id="img" />
+ <table width="50em" style="margin: auto; background-color: red;">
+ <tr>
+ <td style="width: 20%;">
+ <div style="margin: auto;">
+ <h3 style="text-align: right;">Section</h3>
+ <p style="text-align: right;">Para</p>
+ <ol style="list-style-type: lower-latin;"><li>First item</li></ol>
+ </div>
+ </td>
+ <td style="width: auto;">
+ <ol style="list-style-type: decimal;"><li>First item</li></ol>
+ </td>
+ </tr>
+ </table>
+ <br style="clear: both;" />
+
+ For 'lang', deprecated in XHTML 1.1, transformation is taken care of through '$config["xml:lang"]'; see section:- #3.4.1.
+
+ The attribute 'name' is deprecated in 'form', 'iframe', and 'img', and is replaced with 'id' if an 'id' attribute doesn't exist and if the 'name' value is appropriate for 'id'. For such replacements for 'a' and 'map', for which the 'name' attribute is deprecated in XHTML 1.1, '$config["no_deprecated_attr"]' should be set to '2' (when set to '1', for these two elements, the 'name' attribute is retained).
+
+
+-- 3.4.7 Anti-spam & 'href' ---------------------------------------o
+
+
+ htmLawed (function 'hl_tag()') can check the 'href' attribute values (link addresses) as an anti-spam (email or link spam) measure.
+
+ If '$config["anti_mail_spam"]' is not '0', the '@' of email addresses in 'href' values like 'mailto:a@b.com' is replaced with text specified by '$config["anti_mail_spam"]'. The text should be of a form that makes it clear to others that the address needs to be edited before a mail is sent; e.g., '<remove_this_antispam>@' (makes the example address 'a<remove_this_antispam>@b.com').
+
+ For regular links, one can choose to have a 'rel' attribute with 'nofollow' in its value (which tells some search engines to not follow a link). This can discourage link spammers. Additionally, or as an alternative, one can choose to empty the 'href' value altogether (disable the link).
+
+ For use of these options, '$config["anti_link_spam"]' should be set as an array with values 'regex1' and 'regex2', both or one of which can be empty (like 'array("", "regex2")') to indicate that that option is not to be used. Otherwise, 'regex1' or 'regex2' should be PHP- and PCRE-compatible regular expression patterns: 'href' values will be matched against them and those matching the pattern will accordingly be treated.
+
+ Note that the regular expressions should have `delimiters`, and be well-formed and preferably fast. Absolute efficiency/accuracy is often not needed.
+
+ An example, to have a 'rel' attribute with 'nofollow' for all links, and to disable links that do not point to domains 'abc.com' and 'xyz.org':
+
+ $config["anti_link_spam"] = array('`.`', '`://\W*(?!(abc\.com|xyz\.org))`');
+
+
+-- 3.4.8 Inline style properties ----------------------------------o
+
+
+ htmLawed can check URL schemes and dynamic expressions (to guard against Javascript, etc., script-based insecurities) in inline CSS style property values in the 'style' attributes. (CSS properties like 'background-image' that accept URLs in their values are noted in section:- #5.3.) Dynamic CSS expressions that allow scripting in the IE browser, and can be a vulnerability, can be removed from property values by setting '$config["css_expression"]' to '1' (default setting).
+
+ *Note*: Because of the various ways of representing characters in attribute values (URL-escapement, entitification, etc.), htmLawed might alter the values of the 'style' attribute values, and may even falsely identify dynamic CSS expressions and URL schemes in them. If this is an important issue, checking of URLs and dynamic expressions can be turned off ('$config["schemes"] = "...style:*..."', see section:- #3.4.3, and '$config["css_expression"] = 0'). Alternately, admins can use their own custom function for finer handling of 'style' values through the 'hook_tag' parameter (see section:- #3.4.9).
+
+ It is also possible to have htmLawed let through any 'style' value by setting '$config["style_pass"]' to '1'.
+
+ As such, it is better to set up a CSS file with class declarations, disallow the 'style' attribute, set a '$spec' rule (see section:- #2.3) for 'class' for the 'oneof' or 'match' parameter, and ask writers to make use of the 'class' attribute.
+
+
+-- 3.4.9 Hook function for tag content ----------------------------o
+
+
+ It is possible to utilize a custom hook function to alter the tag content htmLawed has finalized (i.e., after it has checked/corrected for required attributes, transformed attributes, lower-cased attribute names, etc.).
+
+ When '$config' parameter 'hook_tag' is set to the name of a function, htmLawed (function 'hl_tag()') will pass on the element name, and the `finalized` attribute name-value pairs as array elements to the function. The function is expected to return the full opening tag string like '<element_name attribute_1_name="attribute_1_value"...>' (for empty elements like 'img' and 'input', the element-closing slash '/' should also be included).
+
+ This is a *powerful functionality* that can be exploited for various objectives: consolidate-and-convert inline 'style' attributes to 'class', convert 'embed' elements to 'object', permit only one 'caption' element in a 'table' element, disallow embedding of certain types of media, *inject HTML*, use CSSTidy:- http://csstidy.sourceforge.net to sanitize 'style' attribute values, etc.
+
+ As an example, the custom hook code below can be used to force a series of specifically ordered 'id' attributes on all elements, and a specific 'param' element inside all 'object' elements:
+
+ function my_tag_function($element, $attribute_array){
+ static $id = 0;
+ // Remove any duplicate element
+ if($element == 'param' && isset($attribute_array['allowscriptaccess'])){
+ return '';
+ }
+
+ $new_element = '';
+
+ // Force a serialized ID number
+ $attribute_array['id'] = 'my_'. $id;
+ ++$id;
+
+ // Inject param for allowscriptaccess
+ if($element == 'object'){
+ $new_element = '<param id='my_'. $id; allowscriptaccess="never" />';
+ ++$id;
+ }
+
+ $string = '';
+ foreach($attribute_array as $k=>$v){
+ $string .= " {$k}=\"{$v}\"";
+ }
+ return "<{$element}{$string}". (isset($in_array($element, $empty_elements) ? ' /' : ''). '>'. $new_element;
+ }
+
+ The 'hook_tag' parameter is different from the 'hook' parameter (section:- #3.7).
+
+ Snippets of hook function code developed by others may be available on the htmLawed:- http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed website.
+
+
+-- 3.5 Simple configuration directive for most valid XHTML -------oo
+
+
+ If '$config["valid_xhtml"]' is set to '1', some relevant '$config' parameters (indicated by '~' in section:- #2.2) are auto-adjusted. This allows one to pass the '$config' argument with a simpler value. If a value for a parameter auto-set through 'valid_xhtml' is still manually provided, then that value will over-ride the auto-set value.
+
+
+-- 3.6 Simple configuration directive for most `safe` HTML --------o
+
+
+ `Safe` HTML refers to HTML that is restricted to reduce the vulnerability for scripting attacks (such as XSS) based on HTML code which otherwise may still be legal and compliant with the HTML standard specs. When elements such as 'script' and 'object', and attributes such as 'onmouseover' and 'style' are allowed in the input text, an input writer can introduce malevolent HTML code. Note that what is considered 'safe' depends on the nature of the web application and the trust-level accorded to its users.
+
+ htmLawed allows an admin to use '$config["safe"]' to auto-adjust multiple '$config' parameters (such as 'elements' which declares the allowed element-set), which otherwise would have to be manually set. The relevant parameters are indicated by '"' in section:- #2.2). Thus, one can pass the '$config' argument with a simpler value.
+
+ With the value of '1', htmLawed considers 'CDATA' sections and HTML comments as plain text, and prohibits the 'applet', 'embed', 'iframe', 'object' and 'script' elements, and the 'on*' attributes like 'onclick'. ( There are '$config' parameters like 'css_expression' that are not affected by the value set for 'safe' but whose default values still contribute towards a more `safe` output.) Further, URLs with schemes (see section:- #3.4.3) are neutralized so that, e.g., 'style="moz-binding:url(http://danger)"' becomes 'style="moz-binding:url(denied:http://danger)"' while 'style="moz-binding:url(ok)"' remains intact.
+
+ Admins, however, may still want to completely deny the 'style' attribute, e.g., with code like
+
+ $processed = htmLawed($text, array('safe'=>1, 'deny_attribute'=>'style'));
+
+ If a value for a parameter auto-set through 'safe' is still manually provided, then that value can over-ride the auto-set value. E.g., with '$config["safe"] = 1' and '$config["elements"] = "*+script"', 'script', but not 'applet', is allowed.
+
+ A page illustrating the efficacy of htmLawed's anti-XSS abilities with 'safe' set to '1' against XSS vectors listed by RSnake:- http://ha.ckers.org/xss.html may be available here:- http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed/rsnake/RSnakeXSSTest.htm.
+
+
+-- 3.7 Using a hook function --------------------------------------o
+
+
+ If '$config["hook"]' is not set to '0', then htmLawed will allow preliminarily processed input to be altered by a hook function named by '$config["hook"]' before starting the main work (but after handling of characters, entities, HTML comments and 'CDATA' sections -- see code for function 'htmLawed()').
+
+ The hook function also allows one to alter the `finalized` values of '$config' and '$spec'.
+
+ Note that the 'hook' parameter is different from the 'hook_tag' parameter (section:- #3.4.9).
+
+ Snippets of hook function code developed by others may be available on the htmLawed:- http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed website.
+
+
+-- 3.8 Obtaining `finalized` parameter values ---------------------o
+
+
+ htmLawed can assign the `finalized` '$config' and '$spec' values to a variable named by '$config["show_setting"]'. The variable, made global by htmLawed, is set as an array with three keys: 'config', with the '$config' value, 'spec', with the '$spec' value, and 'time', with a value that is the Unix time (the output of PHP's 'microtime()' function) when the value was assigned. Admins should use a PHP-compliant variable name (e.g., one that does not begin with a numerical digit) that does not conflict with variable names in their non-htmLawed code.
+
+ The values, which are also post-hook function (if any), can be used to auto-generate information (on, e.g., the elements that are permitted) for input writers.
+
+
+-- 3.9 Retaining non-HTML tags in input with mixed markup ---------o
+
+
+ htmLawed does not remove certain characters that though invalid are nevertheless discouraged in HTML documents as per the specs (see section:- #5.1). This can be utilized to deal with input that contains mixed markup. Input that may have HTML markup as well as some other markup that is based on the '<', '>' and '&' characters is considered to have mixed markup. The non-HTML markup can be rather proprietary (like markup for emoticons/smileys), or standard (like MathML or SVG). Or it can be programming code meant for execution/evaluation (such as embedded PHP code).
+
+ To deal with such mixed markup, the input text can be pre-processed to hide the non-HTML markup by specifically replacing the '<', '>' and '&' characters with some of the HTML-discouraged characters (see section:- #3.1.2). Post-htmLawed processing, the replacements are reverted.
+
+ An example (mixed HTML and PHP code in input text):
+
+ $text = preg_replace('`<\?php(.+?)\?>`sm', "\x83?php\\1?\x84", $text);
+ $processed = htmLawed($text);
+ $processed = preg_replace('`\x83\?php(.+?)\?\x84`sm', '<?php$1?>', $processed);
+
+ This code will not work if '$config["clean_ms_char"]' is set to '1' (section:- #3.1), in which case one should instead deploy a hook function (section:- #3.7). (htmLawed internally uses certain control characters, code-points '1' to '7', and use of these characters as markers in the logic of hook functions may cause issues.)
+
+ Admins may also be able to use '$config["and_mark"]' to deal with such mixed markup; see section:- #3.2.
+
+
+== 4 Other =======================================================oo
+
+
+-- 4.1 Support -----------------------------------------------------
+
+
+ A careful re-reading of this documentation will very likely answer your questions.
+
+ Software updates and forum-based community-support may be found at http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed. For general PHP issues (not htmLawed-specific), support may be found through internet searches and at http://php.net.
+
+
+-- 4.2 Known issues -----------------------------------------------o
+
+
+ See section:- #2.8.
+
+ Readers are advised to cross-check information given in this document.
+
+
+-- 4.3 Change-log -------------------------------------------------o
+
+
+ (The release date for the downloadable package of files containing documentation, demo script, test-cases, etc., besides the 'htmLawed.php' file may be updated independently if the secondary files are revised.)
+
+ `Version number - Release date. Notes`
+
+ 1.1.8.1 - 16 July 2009. Minor code-change to fix a PHP error notice
+
+ 1.1.8 - 23 April 2009. Parameter 'deny_attribute' now accepts the wild-card '*', making it simpler to specify its value when all but a few attributes are being denied; fixed a bug in interpreting '$spec'
+
+ 1.1.7 - 11-12 March 2009. Attributes globally denied through 'deny_attribute' can be allowed element-specifically through '$spec'; '$config["style_pass"]' allowing letting through any 'style' value introduced; altered logic to catch certain types of dynamic crafted CSS expressions
+
+ 1.1.3-6 - 28-31 January - 4 February 2009. Altered logic to catch certain types of dynamic crafted CSS expressions
+
+ 1.1.2 - 22 January 2009. Fixed bug in parsing of 'font' attributes during tag transformation
+
+ 1.1.1 - 27 September 2008. Better nesting correction when omitable closing tags are absent
+
+ 1.1 - 29 June 2008. '$config["hook_tag"]' and '$config["format"]' introduced for custom tag/attribute check/modification/injection and output compaction/beautification; fixed a regex-in-$spec parsing bug
+
+ 1.0.9 - 11 June 2008. Fixed bug in invalid HTML code-point entity check
+
+ 1.0.8 - 15 May 2008. 'bordercolor' attribute for 'table', 'td' and 'tr'
+
+ 1.0.7 - 1 May 2008. Support for 'wmode' attribute for 'embed'; '$config["show_setting"]' introduced; improved '$config["elements"]' evaluation
+
+ 1.0.6 - 20 April 2008. '$config["and_mark"]' introduced
+
+ 1.0.5 - 12 March 2008. 'style' URL schemes essentially disallowed when $config 'safe' is on; improved regex for CSS expression search
+
+ 1.0.4 - 10 March 2008. Improved corrections for 'blockquote', 'form', 'map' and 'noscript'
+
+ 1.0.3 - 3 March 2008. Character entities for soft-hyphens are now replaced with spaces (instead of being removed); a bug allowing 'td' directly inside 'table' fixed; 'safe' '$config' parameter added
+
+ 1.0.2 - 13 February 2008. Improved implementation of '$config["keep_bad"]'
+
+ 1.0.1 - 7 November 2007. Improved regex for identifying URLs, protocols and dynamic expressions ('hl_tag()' and 'hl_prot()'); no error display with 'hl_regex()'
+
+ 1.0 - 2 November 2007. First release
+
+
+-- 4.4 Testing ----------------------------------------------------o
+
+
+ To test htmLawed using a form interface, a demo:- htmLawedTest.php web-page is provided with the htmLawed distribution ('htmLawed.php' and 'htmLawedTest.php' should be in the same directory on the web-server). A file with test-cases:- htmLawed_TESTCASE.txt is also provided.
+
+
+-- 4.5 Upgrade, & old versions ------------------------------------o
+
+
+ Upgrading is as simple as replacing the previous version of 'htmLawed.php' (assuming it was not modified for customized features). As htmLawed output is almost always used in static documents, upgrading should not affect old, finalized content.
+
+ Old versions of htmLawed may be available online. E.g., for version 1.0, check http://www.bioinformatics.org/phplabware/downloads/htmLawed1.zip, for 1.1.1, htmLawed111.zip, and for 1.1.10, htmLawed1110.zip.
+
+
+-- 4.6 Comparison with 'HTMLPurifier' -----------------------------o
+
+
+ The HTMLPurifier PHP library by Edward Yang is a very good HTML filtering script that uses object oriented PHP code. Compared to htmLawed, it:
+
+ * does not support PHP versions older than 5.0 (HTMLPurifier dropped PHP 4 support after version 2)
+
+ * is 15-20 times bigger (scores of files totalling more than 750 kb)
+
+ * consumes 10-15 times more RAM memory (just including the HTMLPurifier files without calling the filter requires a few MBs of memory)
+
+ * is expectedly slower
+
+ * does not allow admins to fully allow all valid HTML (because of incomplete HTML support, it always considers elements like 'script' illegal)
+
+ * lacks many of the extra features of htmLawed (like entity conversions and code compaction/beautification)
+
+ * has poor documentation
+
+ However, HTMLPurifier has finer checks for character encodings and attribute values, and can log warnings and errors. Visit the HTMLPurifier website:- http://htmlpurifier.org for updated information.
+
+
+-- 4.7 Use through application plug-ins/modules -------------------o
+
+
+ Plug-ins/modules to implement htmLawed in applications such as Drupal and DokuWiki may have been developed. Please check the application websites and the forum on the htmLawed site:- http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed.
+
+
+-- 4.8 Use in non-PHP applications --------------------------------o
+
+
+ Non-PHP applications written in Python, Ruby, etc., may be able to use htmLawed through system calls to the PHP engine. Such code may have been documented on the internet. Also check the forum on the htmLawed site:- http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed.
+
+
+-- 4.9 Donate -----------------------------------------------------o
+
+
+ A donation in any currency and amount to appreciate or support this software can be sent by PayPal:- http://paypal.com to this email address: drpatnaik at yahoo dot com.
+
+
+-- 4.10 Acknowledgements ------------------------------------------o
+
+
+ Bryan Blakey, Ulf Harnhammer, Gareth Heyes, Lukasz Pilorz, Shelley Powers, Edward Yang, and many anonymous users.
+
+ Thank you!
+
+
+== 5 Appendices ==================================================oo
+
+
+-- 5.1 Characters discouraged in XHTML -----------------------------
+
+
+ Characters represented by the following hexadecimal code-points are `not` invalid, even though some validators may issue messages stating otherwise.
+
+ '7f' to '84', '86' to '9f', 'fdd0' to 'fddf', '1fffe', '1ffff', '2fffe', '2ffff', '3fffe', '3ffff', '4fffe', '4ffff', '5fffe', '5ffff', '6fffe', '6ffff', '7fffe', '7ffff', '8fffe', '8ffff', '9fffe', '9ffff', 'afffe', 'affff', 'bfffe', 'bffff', 'cfffe', 'cffff', 'dfffe', 'dffff', 'efffe', 'effff', 'ffffe', 'fffff', '10fffe' and '10ffff'
+
+
+-- 5.2 Valid attribute-element combinations -----------------------o
+
+
+ Valid attribute-element combinations as per W3C specs.
+
+ * includes deprecated attributes (marked '^'), attributes for the non-standard 'embed' element (marked '*'), and the proprietary 'bordercolor' (marked '~')
+ * only non-frameset, HTML body elements
+ * 'name' for 'a' and 'map', and 'lang' are invalid in XHTML 1.1
+ * 'target' is valid for 'a' in XHTML 1.1 and higher
+ * 'xml:space' is only for XHTML 1.1
+
+ abbr - td, th
+ accept - form, input
+ accept-charset - form
+ accesskey - a, area, button, input, label, legend, textarea
+ action - form
+ align - caption^, embed, applet, iframe, img^, input^, object^, legend^, table^, hr^, div^, h1^, h2^, h3^, h4^, h5^, h6^, p^, col, colgroup, tbody, td, tfoot, th, thead, tr
+ alt - applet, area, img, input
+ archive - applet, object
+ axis - td, th
+ bgcolor - embed, table^, tr^, td^, th^
+ border - table, img^, object^
+ bordercolor~ - table, td, tr
+ cellpadding - table
+ cellspacing - table
+ char - col, colgroup, tbody, td, tfoot, th, thead, tr
+ charoff - col, colgroup, tbody, td, tfoot, th, thead, tr
+ charset - a, script
+ checked - input
+ cite - blockquote, q, del, ins
+ classid - object
+ clear - br^
+ code - applet
+ codebase - object, applet
+ codetype - object
+ color - font
+ cols - textarea
+ colspan - td, th
+ compact - dir, dl^, menu, ol^, ul^
+ coords - area, a
+ data - object
+ datetime - del, ins
+ declare - object
+ defer - script
+ dir - bdo
+ disabled - button, input, optgroup, option, select, textarea
+ enctype - form
+ face - font
+ for - label
+ frame - table
+ frameborder - iframe
+ headers - td, th
+ height - embed, iframe, td^, th^, img, object, applet
+ href - a, area
+ hreflang - a
+ hspace - applet, img^, object^
+ ismap - img, input
+ label - option, optgroup
+ language - script^
+ longdesc - img, iframe
+ marginheight - iframe
+ marginwidth - iframe
+ maxlength - input
+ method - form
+ model* - embed
+ multiple - select
+ name - button, embed, textarea, applet^, select, form^, iframe^, img^, a^, input, object, map^, param
+ nohref - area
+ noshade - hr^
+ nowrap - td^, th^
+ object - applet
+ onblur - a, area, button, input, label, select, textarea
+ onchange - input, select, textarea
+ onfocus - a, area, button, input, label, select, textarea
+ onreset - form
+ onselect - input, textarea
+ onsubmit - form
+ pluginspage* - embed
+ pluginurl* - embed
+ prompt - isindex
+ readonly - textarea, input
+ rel - a
+ rev - a
+ rows - textarea
+ rowspan - td, th
+ rules - table
+ scope - td, th
+ scrolling - iframe
+ selected - option
+ shape - area, a
+ size - hr^, font, input, select
+ span - col, colgroup
+ src - embed, script, input, iframe, img
+ standby - object
+ start - ol^
+ summary - table
+ tabindex - a, area, button, input, object, select, textarea
+ target - a^, area, form
+ type - a, embed, object, param, script, input, li^, ol^, ul^, button
+ usemap - img, input, object
+ valign - col, colgroup, tbody, td, tfoot, th, thead, tr
+ value - input, option, param, button, li^
+ valuetype - param
+ vspace - applet, img^, object^
+ width - embed, hr^, iframe, img, object, table, td^, th^, applet, col, colgroup, pre^
+ wmode - embed
+ xml:space - pre, script, style
+
+ These are allowed in all but the shown elements:
+
+ class - param, script
+ dir - applet, bdo, br, iframe, param, script
+ id - script
+ lang - applet, br, iframe, param, script
+ onclick - applet, bdo, br, font, iframe, isindex, param, script
+ ondblclick - applet, bdo, br, font, iframe, isindex, param, script
+ onkeydown - applet, bdo, br, font, iframe, isindex, param, script
+ onkeypress - applet, bdo, br, font, iframe, isindex, param, script
+ onkeyup - applet, bdo, br, font, iframe, isindex, param, script
+ onmousedown - applet, bdo, br, font, iframe, isindex, param, script
+ onmousemove - applet, bdo, br, font, iframe, isindex, param, script
+ onmouseout - applet, bdo, br, font, iframe, isindex, param, script
+ onmouseover - applet, bdo, br, font, iframe, isindex, param, script
+ onmouseup - applet, bdo, br, font, iframe, isindex, param, script
+ style - param, script
+ title - param, script
+ xml:lang - applet, br, iframe, param, script
+
+
+-- 5.3 CSS 2.1 properties accepting URLs ------------------------o
+
+
+ background
+ background-image
+ content
+ cue-after
+ cue-before
+ cursor
+ list-style
+ list-style-image
+ play-during
+
+
+-- 5.4 Microsoft Windows 1252 character replacements --------------o
+
+
+ Key: 'd' double, 'l' left, 'q' quote, 'r' right, 's.' single
+
+ Code-point (decimal) - hexadecimal value - replacement entity - represented character
+
+ 127 - 7f - (removed) - (not used)
+ 128 - 80 - &#8364; - euro
+ 129 - 81 - (removed) - (not used)
+ 130 - 82 - &#8218; - baseline s. q
+ 131 - 83 - &#402; - florin
+ 132 - 84 - &#8222; - baseline d q
+ 133 - 85 - &#8230; - ellipsis
+ 134 - 86 - &#8224; - dagger
+ 135 - 87 - &#8225; - d dagger
+ 136 - 88 - &#710; - circumflex accent
+ 137 - 89 - &#8240; - permile
+ 138 - 8a - &#352; - S Hacek
+ 139 - 8b - &#8249; - l s. guillemet
+ 140 - 8c - &#338; - OE ligature
+ 141 - 8d - (removed) - (not used)
+ 142 - 8e - &#381; - Z dieresis
+ 143 - 8f - (removed) - (not used)
+ 144 - 90 - (removed) - (not used)
+ 145 - 91 - &#8216; - l s. q
+ 146 - 92 - &#8217; - r s. q
+ 147 - 93 - &#8220; - l d q
+ 148 - 94 - &#8221; - r d q
+ 149 - 95 - &#8226; - bullet
+ 150 - 96 - &#8211; - en dash
+ 151 - 97 - &#8212; - em dash
+ 152 - 98 - &#732; - tilde accent
+ 153 - 99 - &#8482; - trademark
+ 154 - 9a - &#353; - s Hacek
+ 155 - 9b - &#8250; - r s. guillemet
+ 156 - 9c - &#339; - oe ligature
+ 157 - 9d - (removed) - (not used)
+ 158 - 9e - &#382; - z dieresis
+ 159 - 9f - &#376; - Y dieresis
+
+
+-- 5.5 URL format -------------------------------------------------o
+
+
+ An `absolute` URL has a 'protocol' or 'scheme', a 'network location' or 'hostname', and, optional 'path', 'parameters', 'query' and 'fragment' segments. Thus, an absolute URL has this generic structure:
+
+ (scheme) : (//network location) /(path) ;(parameters) ?(query) #(fragment)
+
+ The schemes can only contain letters, digits, '+', '.' and '-'. Hostname is the portion after the '//' and up to the first '/' (if any; else, up to the end) when ':' is followed by a '//' (e.g., 'abc.com' in 'ftp://abc.com/def'); otherwise, it consists of everything after the ':' (e.g., 'def@abc.com' in mailto:def@abc.com').
+
+ `Relative` URLs do not have explicit schemes and network locations; such values are inherited from a `base` URL.
+
+
+-- 5.6 Brief on htmLawed code -------------------------------------o
+
+
+ Much of the code's logic and reasoning can be understood from the documentation above.
+
+ The *output* of htmLawed is a text string containing the processed input. There is no custom error tracking.
+
+ *Function arguments* for htmLawed are:
+
+ * '$in' - 1st argument; a text string; the *input text* to be processed. Any extraneous slashes added by PHP when `magic quotes` are enabled should be removed beforehand using PHP's 'stripslashes()' function.
+
+ * '$config' - 2nd argument; an associative array; optional (named '$C' in htmLawed code). The array has keys with names like 'balance' and 'keep_bad', and the values, which can be boolean, string, or array, depending on the key, are read to accordingly set the *configurable parameters* (indicated by the keys). All configurable parameters receive some default value if the value to be used is not specified by the user through '$config'. `Finalized` '$config' is thus a filtered and possibly larger array.
+
+ * '$spec' - 3rd argument; a text string; optional. The string has rules, written in an htmLawed-designated format, *specifying* element-specific attribute and attribute value restrictions. Function 'hl_spec()' is used to convert the string to an associative-array for internal use. `Finalized` '$spec' is thus an array.
+
+ `Finalized` '$config' and '$spec' are made *global variables* while htmLawed is at work. Values of any pre-existing global variables with same names are noted, and their values are restored after htmLawed finishes processing the input (to capture the `finalized` values, the 'show_settings' parameter of '$config' should be used). Depending on '$config', another global variable 'hl_Ids', to track 'id' attribute values for uniqueness, may be set. Unlike the other two variables, this one is not reset (or unset) post-processing.
+
+ Except for the main function 'htmLawed()' and the functions 'kses()' and 'kses_hook()', htmLawed's functions are *name-spaced* using the 'hl_' prefix. The *functions* and their roles are:
+
+ * 'hl_attrval' - checking attribute values against $spec
+ * 'hl_bal' - tag balancing
+ * 'hl_cmtcd' - handling CDATA sections and HTML comments
+ * 'hl_ent' - entity handling
+ * 'hl_prot' - checking a URL scheme/protocol
+ * 'hl_regex' - checking syntax of a regular expression
+ * 'hl_spec' - converting user-supplied $spec value to one used by htmLawed internally
+ * 'hl_tag' - handling tags
+ * 'hl_tag2' - transforming tags
+ * 'hl_tidy' - compact/beautify HTML
+ * 'hl_version' - reporting htmLawed version
+ * 'htmLawed' - main function
+ * 'kses' - main function of 'kses'
+ * 'kses_hook' - hook function of 'kses'
+
+ The last two are for compatibility with pre-existing code using the 'kses' script. htmLawed's 'kses()' basically passes on the filtering task to 'htmLawed()' function after deciphering '$config' and '$spec' from the argument values supplied to it. 'kses_hook()' is an empty function and is meant for being filled with custom code if the 'kses' script users were using one.
+
+ 'htmLawed()' finalizes '$spec' (with the help of 'hl_spec()') and '$config', and globalizes them. Finalization of '$config' involves setting default values if an inappropriate or invalid one is supplied. This includes calling 'hl_regex()' to check well-formedness of regular expression patterns if such expressions are user-supplied through '$config'. 'htmLawed()' then removes invalid characters like nulls and 'x01' and appropriately handles entities using 'hl_ent()'. HTML comments and CDATA sections are identified and treated as per '$config' with the help of 'hl_cmtcd()'. When retained, the '<' and '>' characters identifying them, and the '<', '>' and '&' characters inside them, are replaced with control characters (code-points '1' to '5') till any tag balancing is completed.
+
+ After this `initial processing` 'htmLawed()' identifies tags using regex and processes them with the help of 'hl_tag()' -- a large function that analyzes tag content, filtering it as per HTML standards, '$config' and '$spec'. Among other things, 'hl_tag()' transforms deprecated elements using 'hl_tag2()', removes attributes from closing tags, checks attribute values as per '$spec' rules using 'hl_attrval()', and checks URL protocols using 'hl_prot()'. 'htmLawed()' performs tag balancing and nesting checks with a call to 'hl_bal()', and optionally compacts/beautifies the output with proper white-spacing with a call to 'hl_tidy()'. The latter temporarily replaces white-space, and '<', '>' and '&' characters inside 'pre', 'script' and 'textarea' elements, and HTML comments and CDATA sections with control characters (code-points '1' to '5', and '7').
+
+ htmLawed permits the use of custom code or *hook functions* at two stages. The first, called inside 'htmLawed()', allows the input text as well as the finalized $config and $spec values to be altered right after the initial processing (see section:- #3.7). The second is called by 'hl_tag()' once the tag content is finalized (see section:- #3.4.9).
+
+ Being dictated by the external and stable HTML standard, htmLawed's objective is very clear-cut and less concerned with tweakability. The code is only minimally annotated with comments -- it is not meant to instruct; PHP developers familiar with the HTML specs will see the logic, and others can always refer to the htmLawed documentation. The compact structuring of the statements is meant to aid in quickly grasping the logic, at least when viewed with code syntax highlighted.
+
+___________________________________________________________________oo
+
+
+@@description: htmLawed PHP software is a free, open-source, customizable HTML input purifier and filter
+@@encoding: utf-8
+@@keywords: htmLawed, HTM, HTML, HTML Tidy, converter, filter, formatter, purifier, sanitizer, XSS, input, PHP, software, code, script, security, cross-site scripting, hack, sanitize, remove, standards, tags, attributes, elements
+@@language: en
+@@title: htmLawed documentation \ No newline at end of file
diff --git a/extlib/htmLawed/htmLawed_TESTCASE.txt b/extlib/htmLawed/htmLawed_TESTCASE.txt
new file mode 100644
index 000000000..366465ce3
--- /dev/null
+++ b/extlib/htmLawed/htmLawed_TESTCASE.txt
@@ -0,0 +1,370 @@
+/*
+htmLawed_TESTCASE.txt, 23 April 2009
+htmLawed 1.1.8.1, 16 July 2009
+Copyright Santosh Patnaik
+GPL v3 license
+A PHP Labware internal utility - http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed
+*/
+
+This file has UTF-8-encoded text with both correct and incorrect/malformed HTML/XHTML code snippets to test htmLawed (test cases/samples). The entire text may also be used as a unit.
+
+************************************************
+when viewing this file in a web browser, set the
+character encoding to Unicode/UTF-8
+************************************************
+
+--------------------- start --------------------
+
+<em>Try different $config and $spec values. Some text even when filtered in will not be displayed in a rendered web-page</em><br />
+
+<h6>Attributes</h6>
+
+<strong>Xml:lang:</strong><a lang="en" xml:lang="en"></a>, <a lang="en"></a>, <a xml:lang="en"></a><br />
+<strong>Standard, predefined value, or empty attribute:</strong> <input type="text" disabled />, <input type="text" disabled="DISABLED" />, <input type="text" disabled="1" /><br />
+<strong>Required:</strong> <img />, <img alt="image" /><br />
+<strong>Quote & space variation:</strong> <a id=id1 name=xy>a</a>, <a id='id2' name="xy">a</a>, <a id=' id3 ' name = "n" >a</a><br />
+<strong>Invalid:</strong> <a id="id4" src="s">a</a><br />
+<strong>Duplicated:</strong> <a id="id5" id="id6">a</a><br />
+<strong>Deprecated:</strong> <a id="id7" target="self" name="n">a</a>, <hr noshade="noshade" /><br />
+<strong>Casing:</strong> <a HREF=""></a><br />
+<strong>Admin-restricted?:</strong> <a href="x" onclick="alert();"></a>
+
+<h6>Attribute values</h6>
+
+<strong>Duplicate ID value:</strong><a id="id8"></a>, <a id="my_id8"></a>, <a id="id8"></a><br />
+(try 'my_' for prefix)<br />
+<strong>Double-quotes in value:</strong><a title=ab"c"></a>, <a title="ab"c"></a>, <a title='ab"c'></a><br />
+(try filter for CSS expression)<br />
+<strong>CSS expression</strong>: <div style="prop:expression();"></div><div style="prop:expression()"></div><div style="prop: expression();"></div><div style="prop : expression()"></div><div style="prop:expression(js);"></div><div style="prop:expression(js;)"></div><div style="prop: expression('js');"></div><div style="prop : expr ession('js':)"></div><div style="prop&#x3a;expression( 'js&#x40; );"></div><br />
+<strong>Other:</strong> <input size="50" class="my" value="an input an input an input" />, <input size="5" class="your" value="an input" /><br />
+(try 'maxlen', 'maxval', etc., for 'input' in '$spec')
+
+<h6>Blockquotes</h6>
+
+<blockquote>abc</blockquote><br />
+<blockquote>abc<div>def</div></blockquote><br />
+<blockquote><div>abc</div>def</blockquote><br />
+<blockquote>abc<div>def</div>ghi</blockquote><br />
+abc<div>def</div>ghi<br />
+(try with blockquote parent)
+
+<h6>CDATA sections</h6>
+
+<strong>Special characters inside:</strong> <![CDATA[ ]]> ]]>, <![CDATA[ 3 < 4 > 3.5, & 4 &gt; 4 ]]><br />
+<strong>Normal:</strong> <![CDATA[ check ]]>, <em>CDATA follows:<![CDATA[ check ]]></em><br />
+<strong>Malformed:</strong> <![cdata check ]]>, < ![CDATA check ]]>, <![CDATA check ]]>, < ![CDATA check ] ]><br />
+<strong>Invalid:</strong> <em <![CDATA[ check ]]>>CDATA in tag content</em>, <table><![CDATA[ check ]]><tr><td>text not allowed</td></tr></table>
+
+<h6>Complex-1: deprecated elements</h6>
+
+<center>
+The PHP <s>software</s> script used for this <strike>web-page</strike> webpage is <font style="font-weight: bold " face=arial size='+3' color = "red ">htmLawedTest.php</font>, from <u style= 'color:green'>PHP Labware</u>.
+</center>
+
+<h6>Complex-2: deprecated attributes</h6>
+
+<img src="s" alt="a" name="n" /><img src="s" alt="a" id="id9" name="n" />
+<br clear="left" />
+<hr noshade size="1" />
+<img name="id10" src="s" align="left" alt="image" hspace="10" vspace="10" width="10em" height="20" border="1" style="padding:5px;" />
+<table width="50em" align="center" bgcolor="red">
+ <tr>
+ <td width="20%">
+ <div align="center">
+ <h3 align="right">Section</h3>
+ <p align="right">Para</p>
+ <ol type="a" start="e"><li value="x"><a name="x">First</a> <a name="x" id="id11">item</a></li></ol>
+ </div>
+ </td>
+ <td width="*">
+ <ol type="1"><li>First item</li></ol>
+ </td>
+ </tr>
+ </table>
+<br clear="all" />
+
+<h6>Complex-3: embed, object, area</h6>
+
+<object width="425" height="350"><param name="movie" value="http://www.youtube.com/v/ls7gi1VwdIQ"></param><embed src="http://www.youtube.com/v/ls7gi1VwdIQ" type="application/x-shockwave-flash" width="425" height="350"></embed></object><br />
+
+<embed src="http://www.youtube.com/v/ls7gi1VwdIQ" type="application/x-shockwave-flash" width="425" height="350"></embed><br />
+
+<object data="1.gif" type="image/gif" usemap="#map1"><map name="map1">
+<p>navigate the site: <a href="1" shape="REct" coOrds="0,0,118,28">1</a> | <a href="3" shape="circle" coords="184,200,60">3</a> | <a href="4" shape="poly" coords="276,0,276,28,100,200,50,50,276,0">4</a></p>
+<area href="5" shape="Rect" coords="0,0,118,28">
+</map></object>
+
+<h6>Complex-4: nested and other tables</h6>
+
+<table border="1" bgcolor="red"> <tr> <td> Cell </td> <td colspan="2" rowspan="2"> <table border="1" bgcolor="green"> <tr> <td> Cell </td> <td colspan="2" rowspan="2"> </td> </tr> <tr> <td> Cell </td> </tr> <tr> <td> Cell </td> <td> Cell </td> <td> Cell </td> </tr> </table> </td> </tr> <tr> <td> Cell </td> </tr> <tr> <td> Cell </td> <td> Cell </td> <td> Cell </td> </tr> </table><br />
+<strong>PCDATA wrong:</strong> <table>Well<caption>Hello</caption></table><br />
+<strong>Missing tr:</strong> <table><td>Well</td></table><br />
+
+<h6>Complex-5: pseudo, disallowed or non-HTML tags</h6>
+
+(Try different 'keep_bad' values)
+<*> Pseudotags <*>
+<xml>Non-HTML tag xml</xml>
+<p>
+Disallowed tag p
+</p>
+<ul>Bad<li>OK</li></ul>
+
+<h6>Elements</h6>
+
+<strong>Unbalanced:</strong> <a href="h"><em>check</a></em><br />
+<strong>Non-XHTML:</strong> <div><center><dir></dir></center></div><br />
+<strong>Malformed:</strong> < a href=""></a>, <a href="" ></a>, <a href="" ></a>, <a href=""
+></a>, <a href="">< /a>, < a href=""></a >, <img src="s" alt="a" />, <img src="s" alt="a"/ >, <imgsrc="s" alt="a" /><br />
+<strong>Invalid:</strong> <image src="s" alt="a" /><br />
+<strong>Empty:</strong> <img src="s" alt="a" />, <img src="s" alt="a"></img>, <img src="s" alt="a">text</img><br />
+<strong>Content invalid:</strong> <a href="h">1<a>2</a></a><br />
+<strong>Content invalid?:</strong> <form></form><br /> (try setting 'form' as parent)
+<strong>Casing:</strong> <A href=""></a>
+
+<h6>Entities</h6>
+
+<strong>Special:</strong> &amp; 3 < 2 & 5>4 and j >i >a & i<j>a<br />
+<strong>Padding:</strong> &#00066; &#066; &#x00066; &#x066; &#x003; &#0003;<br />
+<strong>Malformed:</strong> & #x27;, &x27;, &#x27; &TILDE;, &tilde<br />
+<strong>Invalid:</strong> &#x3;, &#55296;, &#03;, &#1114112;, &#xffff, &bad;<br />
+<strong>Discouraged characters:</strong> &#x7f;, &#132;, &#64992;, &#1114110;<br />
+<strong>Context:</strong> '&gt;', &lt;?<br />
+<strong>Casing:</strong> &#X27;, &#x27;, &TILDE;, &tilde;
+<br />
+(also check named-to-numeric and hexdec-to-decimal, and vice versa, conversions)
+
+<h6>Format</h6>
+
+<strong>Valid but ill-formatted:</strong> text <!-- comment -->
+text <!--
+A c o m m e n t -->
+<script>
+ <![CDATA[
+ code
+ ]]>
+</script><!-- comment --><![CDATA[ cdata ]]> <a>text</b> text<pre id="none">p r e</pre>
+<textarea>text</textarea> <textarea>
+ text text
+</textarea> text text <br /><hr />
+text <img src="none" alt="none" /> t<em class="none">e<strong>x</strong>t</em>
+text <img src="none" alt="none" /> <b>t<em> e <strong> x </strong> t</em></b>
+ <a href="a"> text <img src="none" alt="none" /> <b>t <em> e <strong> x </strong> t</em></b>
+ </a>
+<span style="background-color: yellow;">text <img src="none" alt="none" /> <b> <em> t e <strong> x </strong> t</em></b></span>
+<script>script</script>
+<div>
+ <pre id="none">p <a>r</a> e <!-- comment --> </pre>
+ <pre>
+ pre
+ </pre>
+</div>
+<div><div><table border="1" style="background-color: red;"><tr><td>Cell</td><td colspan="2" rowspan="2"><table border="1" style="background-color: green;"><tr><td>Cell</td><td colspan="2" rowspan="2"></td></tr><tr><td>Cell</td></tr><tr><td>Cell</td><td>Cell</td><td>Cell</td></tr></table></td></tr><tr><td>Cell</td></tr><tr><td>Cell</td><td>Cell</td><td>Cell</td></tr></table></div></div>
+(try to compact or beautify)
+
+<h6>Forms</h6>
+
+(note nesting of 'form', missing required attributes, etc.)<br />
+<form>
+<script type="text/javascript">s</script>
+<fieldset><legend>p</legend>l <input name="personal_lastname" type="text" tabindex="1"></fieldset>
+<input name="h" type="checkbox" value="h" tabindex="20"> h
+<textarea name="t">t</textarea>
+<form action="a" method="get"></form></form><br />
+<form action="b" method="get"><p><input type="text" value="i" /></form><br />
+<form>B:<input type="text" value="b" />C:<input type="text" value="c" /></form><br />
+(try each of these lines separately)<br />
+<form action="a">what<br />
+<form action="a">what
+(try with container as div and as form)<br />
+<form>c <a>a</a> <b>b</b><input /><script>s</script>
+
+<h6>HTML comments (also CDATA)</h6>
+
+Special characters inside: <!-- <![CDATA check ]]> -->, <!-- 3 < 4 > 3.5, & 4 &gt; 4 -->, <!-- che--ck -->, <!--[if !IE]> <--><a>c</a><!--> <![endif]--><br />
+Normal: <!-- check -->, <!--check -->, <em>comment:<!-- check --></em><!-- check -->, <table><!-- check --><tr><td>text not allowed</td></tr></table><br />
+Malformed: <![cdata check ]]>, < ![CDATA check ]]>, < ![CDATA check ] ]><br />
+Invalid: <em <!-- check -->>comment in tag content</em>, <!--check-->
+
+<h6>Ins-Del</h6>
+
+(depending on context, these elements can be of either block or inline type)<br />
+<p><ins datetime="d" cite="c"><div>block</div></ins></p><br />
+<p><del>d</del></p><br />
+<p><ins><del>d</del></ins></p><div><ins><p><del><div>d</div></del></p></ins></div><ins><div>d</div></ins>
+
+<h6>Lists</h6>
+
+<strong>Invalid character data</strong>: <ul><li>(item</li>)</ul><br />
+<strong>Definition list</strong>: <dl><dt>a</dt>bad<dd>first <em>one</em></dd><dt>b</dt><dd>second</dd></dl><br />
+<strong>Definition list, close-tags omitted</strong>: <dl><dt>a</dt>bad<dd>first <em>one</em></dd><dt>b<dd>second</dl><br />
+<strong>Definition lists, nested</strong>: <dl>
+ <dt>T1</dt>
+ <dd>D1</dd>
+ <dt>T2</dt>
+ <dd>D2<dl><dt>t1</dt><dd>d1</dd><dt>t2</dt><dd>d2</dd></dl></dd>
+ <dt>T3</dt>
+ <dd>D3</dd>
+ <dt>T4</dt>
+ <dd>D4<dl><dt>t1</dt><dd>d1</dd></dl></dd>
+</dl><br />
+<strong>Definition lists, nested, close-tags omitted</strong>: <dl>
+ <dt>T1
+ <dd>D1</dd>
+ <dt>T2</dt>
+ <dd>D2<dl><dt>t1<dd>d1<dt>t2</dt><dd>d2</dd></dl></dd>
+ <dt>T3
+ <dd>D3
+ <dt>T4
+ <dd>D4<dl><dt>t1<dd>d1</dl></dd>
+</dl><br />
+<strong>Nested</strong>: <ul>
+ <li>l1</li>
+ <li>l2<ol><li>lo1</li><li>lo2</li></ol></li>
+ <li>l3</li>
+ <li>l4<ol><li>lo3</li><li>lo4<ol><li>lo5</li></ol></li></ol></li>
+</ul><br />
+<strong>Nested, close-tags omitted</strong>: <ul>
+ <li>l1</li>
+ <li>l2<ol><li>lo1<li>lo2</ol>
+ <li>l3
+ <li>l4<ol><li>lo3<li>lo4<ol><li>lo5</ol></ol>
+</ul><br />
+<strong>Complex</strong>:
+<ol><script></script><li><table><tr><td>
+<ul><li id="search" class="widget widget_search"> <form id="searchform" method="get" action="http://kohei.us">
+ <div>
+
+ <input type="text" name="s" id="s" size="15" /><br />
+ <input type="submit" value="Search" />
+ </div>
+ </form>
+ </li></ul>
+</td></tr></table></li></ol>
+
+<h6>Non-English text-1</h6>
+
+Inscrieţi-vă acum la a Zecea Conferinţă Internaţională<br />
+გთხáƒáƒ•áƒ— áƒáƒ®áƒšáƒáƒ•áƒ” გáƒáƒ˜áƒáƒ áƒáƒ— რეგისტრáƒáƒªáƒ˜áƒ<br />
+veÄjeziÄno raÄunalniÅ¡tvo<br />
+<a title="הירשמו
+כעת לכנס ">ЗарегиÑтрируйтеÑÑŒ ÑейчаÑ
+на ДеÑÑтую Международную Конференцию по</a><br />
+(this file should have utf-8 encoding; some characters may not be displayed because of missing fonts, etc.)
+
+<h6>Non-English text-2: entities</h6>
+
+&#29992;&#32479;&#19968;&#30721;<br />
+&#4306;&#4311;&#4334;&#4317;&#4309;&#4311;<br />
+Inscreva-se agora para a D&#233;cima Confer&#234;ncia Internacional Sobre O Unicode, realizada entre os dias 10 e 12 de mar&#231;o de 1997 em Mainz
+na Alemanha.
+
+<h6>Ruby</h6>
+
+(need compatible browser)<br />
+<ruby xml:lang="ja">
+ <rbc>
+ <rb>æ–Ž</rb>
+ <rb>è—¤</rb>
+ <rb>ä¿¡</rb>
+ <rb>ç”·</rb>
+ </rbc>
+ <rtc class="reading">
+ <rt>ã•ã„</rt>
+ <rt>ã¨ã†</rt>
+ <rt>ã®ã¶</rt>
+ <rt>ãŠ</rt>
+ </rtc>
+ <rtc class="annotation">
+ <rt rbspan="4" xml:lang="en">W3C Associate Chairman</rt>
+ </rtc>
+</ruby><br />
+<ruby>
+ <rb>WWW</rb>
+ <rp>(</rp><rt>World Wide Web</rt><rp>)</rp>
+</ruby><br />
+<ruby>
+ A
+ <rp>(</rp><rt>aaa</rt><rp>)</rp>
+</ruby>
+
+<h6>Tables</h6>
+
+<strong>Omitted closing tags:</strong> <table>
+<colgroup><col style="x" /><col style="y" />
+<thead>
+<tr><th>h1c1<th>h1c2
+<tbody>
+<tr><td>r1c1<td>r1c2
+<tr><td>r2c1<td>r2c2
+</table><br />
+<strong>Nested, omitted closing tags:</strong> <table>
+<colgroup><col style="x" /><col style="y" />
+<thead>
+<tr><th>h1c1<th>h1c2
+<tbody>
+<tr><td>r1c1<td>r1c2<table>
+<colgroup><col style="x" /><col style="y" />
+<thead>
+<tr><th>h1c1<th>h1c2
+<tbody>
+<tr><td>r1c1<td>r1c2
+<tr><td>r2c1<td>r2c2
+</table>
+<tr><td>r2c1<td>r2c2
+</table><br />
+
+<h6>URLs</h6>
+
+<strong>Relative and absolute:</strong> <a href="mailto:x"></a>, <a href="http://a.com/b/c/d.f"></a>, <a href="./../d.f"></a>, <a href="./d.f"></a>, <a href="d.f"></a>, <a href="#s"></a>, <a href="./../../d.f#s"></a><br />
+(try base URL value of 'http://a.com/b/')<br />
+<strong>CSS URLs:</strong> <div style="background-image: url('a.gif');"></div>, <div style="background-image: URL(&quot;a.gif&quot;);"></div>, <div style="background-image: url('http://a.com/a.gif');"></div>, <div style="background-image: url('./../a.gif');"></div>, <div style="background-image: &#117;r&#x6C;('js&#58;xss'&#x29;"></div><br />
+<strong>Anti-spam:</strong> (try regex for 'http://a.com', etc.) <a href="mailto:x@y.com"></a>, <a href="http://a.com/b@d.f"></a>, <a href="a.com/d.f" rel="nofollow"></a>, <a href="a.com/d.f" rel="1, 2"></a>, <a href="a.com/d.f"></a>, <a href="b.com/d.f"></a>, <a href="c.com/d.f"></a><br />
+
+<h6>XSS</h6>
+
+'';!--"<xss>=&{()}<br />
+<img src="javascript%3Aalert('xss');" /><br />
+<img src="javascript:alert('xss');" /><br />
+<img src="java script:alert('xss');" /><br />
+<img
+src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41; /><br />
+<div style="javascript:alert('xss');"></div><br />
+<div style="background-image:url(javascript:alert('xss'));"></div><br />
+<div style="background-image:url(&quot;javascript:alert('xss')&quot; );"></div><br />
+<!--[if gte IE 4]><script>alert('xss');</script><![endif]--><br />
+<script a=">" src="http://ha.ckers.org/xss.js"></script><br />
+<div style="background-image: &#117;r&#x6C;('js&#58;xss'&#x29;"></div><br />
+<a style=";-moz-binding:url(http://lukasz.pilorz.net/xss/xss.xml#xss)" href="http://example.com">test</a><br />
+<strong>Bad IE7:</strong> <a href="http://x&x=%22+style%3d%22background-image%3a+expression%28alert
+%28%27xss%3f%29%29">x</a><br />
+<strong>Bad IE7:</strong> <a style=color:expr/*comment*/ession(alert(document.domain))>xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp&#x72;ession(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: &#101;xpression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: %45xpression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/**/expression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/**/&#69;xpression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/**/Exp&#x72;ession(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: expr%45ssion(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp/* */ression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp /* */ression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background: exp/ * * /ression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/* x */expression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="xxx" style="background:/* */ */expression(alert('xss'));">xxx</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="width: /****/**;;;;;;*/expression/**/(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="padding:10px; background:/**/expression(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="background: huh /* */ */expression(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> <a href="x" style="background:/**/expression(alert('xss'));background:/**/expression(alert('xss'));">x</a><br />
+<strong>Bad IE7:</strong> exp/*<a style='no\xss:noxss("*//*");xss:&#101;x&#x2F;*XSS*//*/*/pression(alert("XSS"))'>x</a><br />
+<strong>Bad IE7:</strong> <a style="background:&#69;xpre\ssion(alert('xss'));">hi</a><br />
+<strong>Bad IE7:</strong> <a style="background:expre&#x5c;ssion(alert('xss'));">hi</a><br />
+<strong>Bad IE7:</strong> <a style="color: \0065 \0078 \0070 \0072 \0065 \0073 \0073 \0069 \006f \006e \0028 \0061 \006c \0065 \0072 \0074 \0028 \0031 \0029 \0029">test</a><br />
+<strong>Bad IE7:</strong> <a style="xss:e&#92;&#48;&#48;&#55;&#56;pression(window.x?0:(alert(/XSS/),window.x=1));">hi</a><br />
+<strong>Bad IE7:</strong> <a style="background:url('java
+script:eval(document.all.mycode.expr)')">hi</a><br />
+
+<h6>Other</h6>
+
+3 < 4 <br />
+3 > 4 <br />
+ > 3 <br /> \ No newline at end of file
diff --git a/extlib/php-gettext/AUTHORS b/extlib/php-gettext/AUTHORS
new file mode 100644
index 000000000..da6ade7b6
--- /dev/null
+++ b/extlib/php-gettext/AUTHORS
@@ -0,0 +1,3 @@
+Danilo Segan <danilo@kvota.net>
+Nico Kaiser <nico@siriux.net> (contributed most changes between 1.0.2 and 1.0.3, bugfix for 1.0.5)
+Steven Armstrong <sa@c-area.ch> (gettext.inc, leading to 1.0.6)
diff --git a/extlib/php-gettext/COPYING b/extlib/php-gettext/COPYING
new file mode 100644
index 000000000..5b6e7c66c
--- /dev/null
+++ b/extlib/php-gettext/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/extlib/php-gettext/ChangeLog b/extlib/php-gettext/ChangeLog
new file mode 100644
index 000000000..5e0949dfd
--- /dev/null
+++ b/extlib/php-gettext/ChangeLog
@@ -0,0 +1,144 @@
+2006-02-07 Danilo Å egan <danilo@gnome.org>
+
+ * examples/pigs_dropin.php: comment-out bind_textdomain_codeset
+
+ * gettext.inc (T_bind_textdomain_codeset): bind_textdomain_codeset
+ is available only in PHP 4.2.0+ (thanks to Jens A. Tkotz).
+
+ * Makefile: Include gettext.inc in DIST_FILES, VERSION up to
+ 1.0.7.
+
+2006-02-03 Danilo Å egan <danilo@gnome.org>
+
+ Added setlocale() emulation as well.
+
+ * examples/pigs_dropin.php: Use T_setlocale() and locale_emulation().
+ * examples/pigs_fallback.php: Use T_setlocale() and locale_emulation().
+
+ * gettext.inc: Added globals $EMULATEGETTEXT and $CURRENTLOCALE.
+ (locale_emulation): Whether emulation is active.
+ (_check_locale): Rewrite.
+ (_setlocale): Added emulated setlocale function.
+ (T_setlocale): Wrapper around _setlocale.
+ (_get_reader): Use variables and _setlocale.
+
+2006-02-02 Danilo Å egan <danilo@gnome.org>
+
+ Fix bug #12192.
+
+ * examples/locale/sr_CS/LC_MESSAGES/messages.po: Correct grammar.
+ * examples/locale/sr_CS/LC_MESSAGES/messages.mo: Rebuild.
+
+2006-02-02 Danilo Å egan <danilo@gnome.org>
+
+ Fix bug #15419.
+
+ * streams.php: Support for PHP 5.1.1 fread() which reads most 8kb.
+ (Fix by Piotr Szotkowski <shot@hot.pl>)
+
+2006-02-02 Danilo Å egan <danilo@gnome.org>
+
+ Merge Steven Armstrong's changes, supporting standard gettext
+ interfaces:
+
+ * examples/*: Restructured examples.
+ * gettext.inc: Added.
+ * AUTHORS: Added Steven.
+ * Makefile (VERSION): Up to 1.0.6.
+
+2006-01-28 Nico Kaiser <nico@siriux.net>
+
+ * gettext.php (select_string): Fix "true" <-> 1 difference of PHP
+
+2005-07-29 Danilo Å egan <danilo@gnome.org>
+
+ * Makefile (VERSION): Up to 1.0.5.
+
+2005-07-29 Danilo Å egan <danilo@gnome.org>
+
+ Fixes bug #13850.
+
+ * gettext.php (gettext_reader): check $Reader->error as well.
+
+2005-07-29 Danilo Å egan <danilo@gnome.org>
+
+ * Makefile (VERSION): Up to 1.0.4.
+
+2005-07-29 Danilo Å egan <danilo@gnome.org>
+
+ Fixes bug #13771.
+
+ * gettext.php (gettext_reader->get_plural_forms): Plural forms
+ header extraction regex change. Reported by Edgar Gonzales.
+
+2005-02-28 Danilo Å egan <dsegan@gmx.net>
+
+ * AUTHORS: Added Nico to the list.
+
+ * Makefile (VERSION): Up to 1.0.3.
+
+ * README: Updated.
+
+2005-02-28 Danilo Å egan <dsegan@gmx.net>
+
+ * gettext.php: Added pre-loading, code documentation, and many
+ code clean-ups by Nico Kaiser <nico@siriux.net>.
+
+2005-02-28 Danilo Å egan <dsegan@gmx.net>
+
+ * streams.php (FileReader.read): Handle read($bytes = 0).
+
+ * examples/pigs.php: Prefix gettext function names with T or T_.
+
+ * examples/update: Use the same keywords T_ and T_ngettext.
+
+ * streams.php: Added CachedFileReader.
+
+2003-11-11 Danilo Å egan <dsegan@gmx.net>
+
+ * gettext.php: Added hashing to find_string.
+
+2003-11-01 Danilo Å egan <dsegan@gmx.net>
+
+ * Makefile (DIST_FILES): Replaced LICENSE with COPYING.
+ (VERSION): Up to 1.0.2.
+
+ * AUTHORS: Minor edits.
+
+ * README: Minor edits.
+
+ * COPYING: Removed LICENSE, added this file.
+
+ * gettext.php: Added copyright notice and disclaimer.
+ * streams.php: Same.
+ * examples/pigs.php: Same.
+
+2003-10-23 Danilo Å egan <dsegan@gmx.net>
+
+ * Makefile: Upped version to 1.0.1.
+
+ * gettext.php (gettext_reader): Remove a call to set_total_plurals.
+ (set_total_plurals): Removed unused function for some better days.
+
+2003-10-23 Danilo Å egan <dsegan@gmx.net>
+
+ * Makefile: Added, version 1.0.0.
+
+ * examples/*: Added an example of usage.
+
+ * README: Described all the crap.
+
+2003-10-22 Danilo Å egan <dsegan@gmx.net>
+
+ * gettext.php: Plural forms implemented too.
+
+ * streams.php: Added FileReader for direct access to files (no
+ need to keep file in memory).
+
+ * gettext.php: It works, except for plural forms.
+
+ * streams.php: Created abstract class StreamReader.
+ Added StringReader class.
+
+ * gettext.php: Started writing gettext_reader.
+
diff --git a/extlib/php-gettext/README b/extlib/php-gettext/README
new file mode 100644
index 000000000..c7525e29c
--- /dev/null
+++ b/extlib/php-gettext/README
@@ -0,0 +1,189 @@
+PHP-gettext 1.0
+
+Copyright 2003, 2006 -- Danilo "angry with PHP[1]" Segan
+Licensed under GPLv2 (or any later version, see COPYING)
+
+[1] PHP is actually cyrillic, and translates roughly to
+ "works-doesn't-work" (UTF-8: Ради-Ðе-Ради)
+
+
+Introduction
+
+ How many times did you look for a good translation tool, and
+ found out that gettext is best for the job? Many times.
+
+ How many times did you try to use gettext in PHP, but failed
+ miserably, because either your hosting provider didn't support
+ it, or the server didn't have adequate locale? Many times.
+
+ Well, this is a solution to your needs. It allows using gettext
+ tools for managing translations, yet it doesn't require gettext
+ library at all. It parses generated MO files directly, and thus
+ might be a bit slower than the (maybe provided) gettext library.
+
+ PHP-gettext is a simple reader for GNU gettext MO files. Those
+ are binary containers for translations, produced by GNU msgfmt.
+
+Why?
+
+ I got used to having gettext work even without gettext
+ library. It's there in my favourite language Python, so I was
+ surprised that I couldn't find it in PHP. I even Googled for it,
+ but to no avail.
+
+ So, I said, what the heck, I'm going to write it for this
+ disguisting language of PHP, because I'm often constrained to it.
+
+Features
+
+ o Support for simple translations
+ Just define a simple alias for translate() function (suggested
+ use of _() or gettext(); see provided example).
+
+ o Support for ngettext calls (plural forms, see a note under bugs)
+ You may also use plural forms. Translations in MO files need to
+ provide this, and they must also provide "plural-forms" header.
+ Please see 'info gettext' for more details.
+
+ o Support for reading straight files, or strings (!!!)
+ Since I can imagine many different backends for reading in the MO
+ file data, I used imaginary abstract class StreamReader to do all
+ the input (check streams.php). For your convenience, I've already
+ provided two classes for reading files: FileReader and
+ StringReader (CachedFileReader is a combination of the two: it
+ loads entire file contents into a string, and then works on that).
+ See example below for usage. You can for instance use StringReader
+ when you read in data from a database, or you can create your own
+ derivative of StreamReader for anything you like.
+
+
+Bugs
+
+ Plural-forms field in MO header (translation for empty string,
+ i.e. "") is treated according to PHP syntactic rules (it's
+ eval()ed). Since these should actually follow C syntax, there are
+ some problems.
+
+ For instance, I'm used to using this:
+ Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : \
+ n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;
+ but it fails with PHP (it sets $plural=2 instead of 0 for $n==1).
+
+ The fix is usually simple, but I'm lazy to go into the details of
+ PHP operator precedence, and maybe try to fix it. In here, I had
+ to put everything after the first ':' in parenthesis:
+ Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : \
+ (n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);
+ That works, and I'm satisfied.
+
+ Besides this one, there are probably a bunch of other bugs, since
+ I hate PHP (did I mention it already? no? strange), and don't
+ know it very well. So, feel free to fix any of those and report
+ them back to me at <danilo@kvota.net>.
+
+Usage
+
+ Put files streams.php and gettext.php somewhere you can load them
+ from, and require 'em in where you want to use them.
+
+ Then, create one 'stream reader' (a class that provides functions
+ like read(), seekto(), currentpos() and length()) which will
+ provide data for the 'gettext_reader', with eg.
+ $streamer = new FileStream('data.mo');
+
+ Then, use that as a parameter to gettext_reader constructor:
+ $wohoo = new gettext_reader($streamer);
+
+ If you want to disable pre-loading of entire message catalog in
+ memory (if, for example, you have a multi-thousand message catalog
+ which you'll use only occasionally), use "false" for second
+ parameter to gettext_reader constructor:
+ $wohoo = new gettext_reader($streamer, false);
+
+ From now on, you have all the benefits of gettext data at your
+ disposal, so may run:
+ print $wohoo->translate("This is a test");
+ print $wohoo->ngettext("%d bird", "%d birds", $birds);
+
+ You might need to pass parameter "-k" to xgettext to make it
+ extract all the strings. In above example, try with
+ xgettext -ktranslate -kngettext:1,2 file.php
+ what should create messages.po which contains two messages for
+ translation.
+
+ I suggest creating simple aliases for these functions (see
+ example/pigs.php for how do I do it, which means it's probably a
+ bad way).
+
+
+Usage with gettext.inc (standard gettext interfaces emulation)
+
+ Check example in examples/pig_dropin.php, basically you include
+ gettext.inc and use all the standard gettext interfaces as
+ documented on:
+
+ http://www.php.net/gettext
+
+ The only catch is that you can check return value of setlocale()
+ to see if your locale is system supported or not.
+
+
+Example
+
+ See in examples/ subdirectory. There are a couple of files.
+ pigs.php is an example, serbian.po is a translation to Serbian
+ language, and serbian.mo is generated with
+ msgfmt -o serbian.mo serbian.po
+ There is also simple "update" script that can be used to generate
+ POT file and to update the translation using msgmerge.
+
+Interesting TODO:
+
+ o Try to parse "plural-forms" header field, and to follow C syntax
+ rules. This won't be easy.
+
+Boring TODO:
+
+ o Learn PHP and fix bugs, slowness and other stuff resulting from
+ my lack of knowledge (but *maybe*, it's not my knowledge that is
+ bad, but PHP itself ;-).
+
+ (This is mostly done thanks to Nico Kaiser.)
+
+ o Try to use hash tables in MO files: with pre-loading, would it
+ be useful at all?
+
+Never-asked-questions:
+
+ o Why did you mark this as version 1.0 when this is the first code
+ release?
+
+ Well, it's quite simple. I consider that the first released thing
+ should be labeled "version 1" (first, right?). Zero is there to
+ indicate that there's zero improvement and/or change compared to
+ "version 1".
+
+ I plan to use version numbers 1.0.* for small bugfixes, and to
+ release 1.1 as "first stable release of version 1".
+
+ This may trick someone that this is actually useful software, but
+ as with any other free software, I take NO RESPONSIBILITY for
+ creating such a masterpiece that will smoke crack, trash your
+ hard disk, and make lasers in your CD device dance to the tune of
+ Mozart's 40th Symphony (there is one like that, right?).
+
+ o Can I...?
+
+ Yes, you can. This is free software (as in freedom, free speech),
+ and you might do whatever you wish with it, provided you do not
+ limit freedom of others (GPL).
+
+ I'm considering licensing this under LGPL, but I *do* want
+ *every* PHP-gettext user to contribute and respect ideas of free
+ software, so don't count on it happening anytime soon.
+
+ I'm sorry that I'm taking away your freedom of taking others'
+ freedom away, but I believe that's neglible as compared to what
+ freedoms you could take away. ;-)
+
+ Uhm, whatever.
diff --git a/extlib/php-gettext/gettext.inc b/extlib/php-gettext/gettext.inc
new file mode 100644
index 000000000..eb94b256a
--- /dev/null
+++ b/extlib/php-gettext/gettext.inc
@@ -0,0 +1,318 @@
+<?php
+/*
+ Copyright (c) 2005 Steven Armstrong <sa at c-area dot ch>
+
+ Drop in replacement for native gettext.
+
+ This file is part of PHP-gettext.
+
+ PHP-gettext is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ PHP-gettext is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with PHP-gettext; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+/*
+LC_CTYPE 0
+LC_NUMERIC 1
+LC_TIME 2
+LC_COLLATE 3
+LC_MONETARY 4
+LC_MESSAGES 5
+LC_ALL 6
+*/
+
+require('streams.php');
+require('gettext.php');
+
+
+// Variables
+
+global $text_domains, $default_domain, $LC_CATEGORIES, $EMULATEGETTEXT, $CURRENTLOCALE;
+$text_domains = array();
+$default_domain = 'messages';
+$LC_CATEGORIES = array('LC_CTYPE', 'LC_NUMERIC', 'LC_TIME', 'LC_COLLATE', 'LC_MONETARY', 'LC_MESSAGES', 'LC_ALL');
+$EMULATEGETTEXT = 0;
+$CURRENTLOCALE = '';
+
+
+// Utility functions
+
+/**
+ * Utility function to get a StreamReader for the given text domain.
+ */
+function _get_reader($domain=null, $category=5, $enable_cache=true) {
+ global $text_domains, $default_domain, $LC_CATEGORIES;
+ if (!isset($domain)) $domain = $default_domain;
+ if (!isset($text_domains[$domain]->l10n)) {
+ // get the current locale
+ $locale = _setlocale(LC_MESSAGES, 0);
+ $p = isset($text_domains[$domain]->path) ? $text_domains[$domain]->path : './';
+ $path = $p . "$locale/". $LC_CATEGORIES[$category] ."/$domain.mo";
+ if (file_exists($path)) {
+ $input = new FileReader($path);
+ }
+ else {
+ $input = null;
+ }
+ $text_domains[$domain]->l10n = new gettext_reader($input, $enable_cache);
+ }
+ return $text_domains[$domain]->l10n;
+}
+
+/**
+ * Returns whether we are using our emulated gettext API or PHP built-in one.
+ */
+function locale_emulation() {
+ global $EMULATEGETTEXT;
+ return $EMULATEGETTEXT;
+}
+
+/**
+ * Checks if the current locale is supported on this system.
+ */
+function _check_locale() {
+ global $EMULATEGETTEXT;
+ return !$EMULATEGETTEXT;
+}
+
+/**
+ * Get the codeset for the given domain.
+ */
+function _get_codeset($domain=null) {
+ global $text_domains, $default_domain, $LC_CATEGORIES;
+ if (!isset($domain)) $domain = $default_domain;
+ return (isset($text_domains[$domain]->codeset))? $text_domains[$domain]->codeset : ini_get('mbstring.internal_encoding');
+}
+
+/**
+ * Convert the given string to the encoding set by bind_textdomain_codeset.
+ */
+function _encode($text) {
+ $source_encoding = mb_detect_encoding($text);
+ $target_encoding = _get_codeset();
+ if ($source_encoding != $target_encoding) {
+ return mb_convert_encoding($text, $target_encoding, $source_encoding);
+ }
+ else {
+ return $text;
+ }
+}
+
+
+
+
+// Custom implementation of the standard gettext related functions
+
+/**
+ * Sets a requested locale, if needed emulates it.
+ */
+function _setlocale($category, $locale) {
+ global $CURRENTLOCALE, $EMULATEGETTEXT;
+ if ($locale === 0) { // use === to differentiate between string "0"
+ if ($CURRENTLOCALE != '')
+ return $CURRENTLOCALE;
+ else
+ // obey LANG variable, maybe extend to support all of LC_* vars
+ // even if we tried to read locale without setting it first
+ return _setlocale($category, $CURRENTLOCALE);
+ } else {
+ $ret = 0;
+ if (function_exists('setlocale')) // I don't know if this ever happens ;)
+ $ret = setlocale($category, $locale);
+ if (($ret and $locale == '') or ($ret == $locale)) {
+ $EMULATEGETTEXT = 0;
+ $CURRENTLOCALE = $ret;
+ } else {
+ if ($locale == '') // emulate variable support
+ $CURRENTLOCALE = getenv('LANG');
+ else
+ $CURRENTLOCALE = $locale;
+ $EMULATEGETTEXT = 1;
+ }
+ return $CURRENTLOCALE;
+ }
+}
+
+/**
+ * Sets the path for a domain.
+ */
+function _bindtextdomain($domain, $path) {
+ global $text_domains;
+ // ensure $path ends with a slash
+ if ($path[strlen($path) - 1] != '/') $path .= '/';
+ elseif ($path[strlen($path) - 1] != '\\') $path .= '\\';
+ $text_domains[$domain]->path = $path;
+}
+
+/**
+ * Specify the character encoding in which the messages from the DOMAIN message catalog will be returned.
+ */
+function _bind_textdomain_codeset($domain, $codeset) {
+ global $text_domains;
+ $text_domains[$domain]->codeset = $codeset;
+}
+
+/**
+ * Sets the default domain.
+ */
+function _textdomain($domain) {
+ global $default_domain;
+ $default_domain = $domain;
+}
+
+/**
+ * Lookup a message in the current domain.
+ */
+function _gettext($msgid) {
+ $l10n = _get_reader();
+ //return $l10n->translate($msgid);
+ return _encode($l10n->translate($msgid));
+}
+/**
+ * Alias for gettext.
+ */
+function __($msgid) {
+ return _gettext($msgid);
+}
+/**
+ * Plural version of gettext.
+ */
+function _ngettext($single, $plural, $number) {
+ $l10n = _get_reader();
+ //return $l10n->ngettext($single, $plural, $number);
+ return _encode($l10n->ngettext($single, $plural, $number));
+}
+
+/**
+ * Override the current domain.
+ */
+function _dgettext($domain, $msgid) {
+ $l10n = _get_reader($domain);
+ //return $l10n->translate($msgid);
+ return _encode($l10n->translate($msgid));
+}
+/**
+ * Plural version of dgettext.
+ */
+function _dngettext($domain, $single, $plural, $number) {
+ $l10n = _get_reader($domain);
+ //return $l10n->ngettext($single, $plural, $number);
+ return _encode($l10n->ngettext($single, $plural, $number));
+}
+
+/**
+ * Overrides the domain and category for a single lookup.
+ */
+function _dcgettext($domain, $msgid, $category) {
+ $l10n = _get_reader($domain, $category);
+ //return $l10n->translate($msgid);
+ return _encode($l10n->translate($msgid));
+}
+/**
+ * Plural version of dcgettext.
+ */
+function _dcngettext($domain, $single, $plural, $number, $category) {
+ $l10n = _get_reader($domain, $category);
+ //return $l10n->ngettext($single, $plural, $number);
+ return _encode($l10n->ngettext($single, $plural, $number));
+}
+
+
+
+// Wrappers to use if the standard gettext functions are available, but the current locale is not supported by the system.
+// Use the standard impl if the current locale is supported, use the custom impl otherwise.
+
+function T_setlocale($category, $locale) {
+ return _setlocale($category, $locale);
+}
+
+function T_bindtextdomain($domain, $path) {
+ if (_check_locale()) return bindtextdomain($domain, $path);
+ else return _bindtextdomain($domain, $path);
+}
+function T_bind_textdomain_codeset($domain, $codeset) {
+ // bind_textdomain_codeset is available only in PHP 4.2.0+
+ if (_check_locale() and function_exists('bind_textdomain_codeset')) return bind_textdomain_codeset($domain, $codeset);
+ else return _bind_textdomain_codeset($domain, $codeset);
+}
+function T_textdomain($domain) {
+ if (_check_locale()) return textdomain($domain);
+ else return _textdomain($domain);
+}
+function T_gettext($msgid) {
+ if (_check_locale()) return gettext($msgid);
+ else return _gettext($msgid);
+}
+function T_($msgid) {
+ if (_check_locale()) return _($msgid);
+ return __($msgid);
+}
+function T_ngettext($single, $plural, $number) {
+ if (_check_locale()) return ngettext($single, $plural, $number);
+ else return _ngettext($single, $plural, $number);
+}
+function T_dgettext($domain, $msgid) {
+ if (_check_locale()) return dgettext($domain, $msgid);
+ else return _dgettext($domain, $msgid);
+}
+function T_dngettext($domain, $single, $plural, $number) {
+ if (_check_locale()) return dngettext($domain, $single, $plural, $number);
+ else return _dngettext($domain, $single, $plural, $number);
+}
+function T_dcgettext($domain, $msgid, $category) {
+ if (_check_locale()) return dcgettext($domain, $msgid, $category);
+ else return _dcgettext($domain, $msgid, $category);
+}
+function T_dcngettext($domain, $single, $plural, $number, $category) {
+ if (_check_locale()) return dcngettext($domain, $single, $plural, $number, $category);
+ else return _dcngettext($domain, $single, $plural, $number, $category);
+}
+
+
+
+// Wrappers used as a drop in replacement for the standard gettext functions
+
+if (!function_exists('gettext')) {
+ function bindtextdomain($domain, $path) {
+ return _bindtextdomain($domain, $path);
+ }
+ function bind_textdomain_codeset($domain, $codeset) {
+ return _bind_textdomain_codeset($domain, $codeset);
+ }
+ function textdomain($domain) {
+ return _textdomain($domain);
+ }
+ function gettext($msgid) {
+ return _gettext($msgid);
+ }
+ function _($msgid) {
+ return __($msgid);
+ }
+ function ngettext($single, $plural, $number) {
+ return _ngettext($single, $plural, $number);
+ }
+ function dgettext($domain, $msgid) {
+ return _dgettext($domain, $msgid);
+ }
+ function dngettext($domain, $single, $plural, $number) {
+ return _dngettext($domain, $single, $plural, $number);
+ }
+ function dcgettext($domain, $msgid, $category) {
+ return _dcgettext($domain, $msgid, $category);
+ }
+ function dcngettext($domain, $single, $plural, $number, $category) {
+ return _dcngettext($domain, $single, $plural, $number, $category);
+ }
+}
+
+?> \ No newline at end of file
diff --git a/extlib/php-gettext/gettext.php b/extlib/php-gettext/gettext.php
new file mode 100644
index 000000000..ad94a987b
--- /dev/null
+++ b/extlib/php-gettext/gettext.php
@@ -0,0 +1,358 @@
+<?php
+/*
+ Copyright (c) 2003 Danilo Segan <danilo@kvota.net>.
+ Copyright (c) 2005 Nico Kaiser <nico@siriux.net>
+
+ This file is part of PHP-gettext.
+
+ PHP-gettext is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ PHP-gettext is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with PHP-gettext; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+/**
+ * Provides a simple gettext replacement that works independently from
+ * the system's gettext abilities.
+ * It can read MO files and use them for translating strings.
+ * The files are passed to gettext_reader as a Stream (see streams.php)
+ *
+ * This version has the ability to cache all strings and translations to
+ * speed up the string lookup.
+ * While the cache is enabled by default, it can be switched off with the
+ * second parameter in the constructor (e.g. whenusing very large MO files
+ * that you don't want to keep in memory)
+ */
+class gettext_reader {
+ //public:
+ var $error = 0; // public variable that holds error code (0 if no error)
+
+ //private:
+ var $BYTEORDER = 0; // 0: low endian, 1: big endian
+ var $STREAM = NULL;
+ var $short_circuit = false;
+ var $enable_cache = false;
+ var $originals = NULL; // offset of original table
+ var $translations = NULL; // offset of translation table
+ var $pluralheader = NULL; // cache header field for plural forms
+ var $total = 0; // total string count
+ var $table_originals = NULL; // table for original strings (offsets)
+ var $table_translations = NULL; // table for translated strings (offsets)
+ var $cache_translations = NULL; // original -> translation mapping
+
+
+ /* Methods */
+
+
+ /**
+ * Reads a 32bit Integer from the Stream
+ *
+ * @access private
+ * @return Integer from the Stream
+ */
+ function readint() {
+ if ($this->BYTEORDER == 0) {
+ // low endian
+ return array_shift(unpack('V', $this->STREAM->read(4)));
+ } else {
+ // big endian
+ return array_shift(unpack('N', $this->STREAM->read(4)));
+ }
+ }
+
+ /**
+ * Reads an array of Integers from the Stream
+ *
+ * @param int count How many elements should be read
+ * @return Array of Integers
+ */
+ function readintarray($count) {
+ if ($this->BYTEORDER == 0) {
+ // low endian
+ return unpack('V'.$count, $this->STREAM->read(4 * $count));
+ } else {
+ // big endian
+ return unpack('N'.$count, $this->STREAM->read(4 * $count));
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param object Reader the StreamReader object
+ * @param boolean enable_cache Enable or disable caching of strings (default on)
+ */
+ function gettext_reader($Reader, $enable_cache = true) {
+ // If there isn't a StreamReader, turn on short circuit mode.
+ if (! $Reader || isset($Reader->error) ) {
+ $this->short_circuit = true;
+ return;
+ }
+
+ // Caching can be turned off
+ $this->enable_cache = $enable_cache;
+
+ // $MAGIC1 = (int)0x950412de; //bug in PHP 5
+ $MAGIC1 = (int) - 1794895138;
+ // $MAGIC2 = (int)0xde120495; //bug
+ $MAGIC2 = (int) - 569244523;
+
+ $this->STREAM = $Reader;
+ $magic = $this->readint();
+ if ($magic == $MAGIC1) {
+ $this->BYTEORDER = 0;
+ } elseif ($magic == $MAGIC2) {
+ $this->BYTEORDER = 1;
+ } else {
+ $this->error = 1; // not MO file
+ return false;
+ }
+
+ // FIXME: Do we care about revision? We should.
+ $revision = $this->readint();
+
+ $this->total = $this->readint();
+ $this->originals = $this->readint();
+ $this->translations = $this->readint();
+ }
+
+ /**
+ * Loads the translation tables from the MO file into the cache
+ * If caching is enabled, also loads all strings into a cache
+ * to speed up translation lookups
+ *
+ * @access private
+ */
+ function load_tables() {
+ if (is_array($this->cache_translations) &&
+ is_array($this->table_originals) &&
+ is_array($this->table_translations))
+ return;
+
+ /* get original and translations tables */
+ $this->STREAM->seekto($this->originals);
+ $this->table_originals = $this->readintarray($this->total * 2);
+ $this->STREAM->seekto($this->translations);
+ $this->table_translations = $this->readintarray($this->total * 2);
+
+ if ($this->enable_cache) {
+ $this->cache_translations = array ();
+ /* read all strings in the cache */
+ for ($i = 0; $i < $this->total; $i++) {
+ $this->STREAM->seekto($this->table_originals[$i * 2 + 2]);
+ $original = $this->STREAM->read($this->table_originals[$i * 2 + 1]);
+ $this->STREAM->seekto($this->table_translations[$i * 2 + 2]);
+ $translation = $this->STREAM->read($this->table_translations[$i * 2 + 1]);
+ $this->cache_translations[$original] = $translation;
+ }
+ }
+ }
+
+ /**
+ * Returns a string from the "originals" table
+ *
+ * @access private
+ * @param int num Offset number of original string
+ * @return string Requested string if found, otherwise ''
+ */
+ function get_original_string($num) {
+ $length = $this->table_originals[$num * 2 + 1];
+ $offset = $this->table_originals[$num * 2 + 2];
+ if (! $length)
+ return '';
+ $this->STREAM->seekto($offset);
+ $data = $this->STREAM->read($length);
+ return (string)$data;
+ }
+
+ /**
+ * Returns a string from the "translations" table
+ *
+ * @access private
+ * @param int num Offset number of original string
+ * @return string Requested string if found, otherwise ''
+ */
+ function get_translation_string($num) {
+ $length = $this->table_translations[$num * 2 + 1];
+ $offset = $this->table_translations[$num * 2 + 2];
+ if (! $length)
+ return '';
+ $this->STREAM->seekto($offset);
+ $data = $this->STREAM->read($length);
+ return (string)$data;
+ }
+
+ /**
+ * Binary search for string
+ *
+ * @access private
+ * @param string string
+ * @param int start (internally used in recursive function)
+ * @param int end (internally used in recursive function)
+ * @return int string number (offset in originals table)
+ */
+ function find_string($string, $start = -1, $end = -1) {
+ if (($start == -1) or ($end == -1)) {
+ // find_string is called with only one parameter, set start end end
+ $start = 0;
+ $end = $this->total;
+ }
+ if (abs($start - $end) <= 1) {
+ // We're done, now we either found the string, or it doesn't exist
+ $txt = $this->get_original_string($start);
+ if ($string == $txt)
+ return $start;
+ else
+ return -1;
+ } else if ($start > $end) {
+ // start > end -> turn around and start over
+ return $this->find_string($string, $end, $start);
+ } else {
+ // Divide table in two parts
+ $half = (int)(($start + $end) / 2);
+ $cmp = strcmp($string, $this->get_original_string($half));
+ if ($cmp == 0)
+ // string is exactly in the middle => return it
+ return $half;
+ else if ($cmp < 0)
+ // The string is in the upper half
+ return $this->find_string($string, $start, $half);
+ else
+ // The string is in the lower half
+ return $this->find_string($string, $half, $end);
+ }
+ }
+
+ /**
+ * Translates a string
+ *
+ * @access public
+ * @param string string to be translated
+ * @return string translated string (or original, if not found)
+ */
+ function translate($string) {
+ if ($this->short_circuit)
+ return $string;
+ $this->load_tables();
+
+ if ($this->enable_cache) {
+ // Caching enabled, get translated string from cache
+ if (array_key_exists($string, $this->cache_translations))
+ return $this->cache_translations[$string];
+ else
+ return $string;
+ } else {
+ // Caching not enabled, try to find string
+ $num = $this->find_string($string);
+ if ($num == -1)
+ return $string;
+ else
+ return $this->get_translation_string($num);
+ }
+ }
+
+ /**
+ * Get possible plural forms from MO header
+ *
+ * @access private
+ * @return string plural form header
+ */
+ function get_plural_forms() {
+ // lets assume message number 0 is header
+ // this is true, right?
+ $this->load_tables();
+
+ // cache header field for plural forms
+ if (! is_string($this->pluralheader)) {
+ if ($this->enable_cache) {
+ $header = $this->cache_translations[""];
+ } else {
+ $header = $this->get_translation_string(0);
+ }
+ if (eregi("plural-forms: ([^\n]*)\n", $header, $regs))
+ $expr = $regs[1];
+ else
+ $expr = "nplurals=2; plural=n == 1 ? 0 : 1;";
+ $this->pluralheader = $expr;
+ }
+ return $this->pluralheader;
+ }
+
+ /**
+ * Detects which plural form to take
+ *
+ * @access private
+ * @param n count
+ * @return int array index of the right plural form
+ */
+ function select_string($n) {
+ $string = $this->get_plural_forms();
+ $string = str_replace('nplurals',"\$total",$string);
+ $string = str_replace("n",$n,$string);
+ $string = str_replace('plural',"\$plural",$string);
+
+ $total = 0;
+ $plural = 0;
+
+ eval("$string");
+ if ($plural >= $total) $plural = $total - 1;
+ return $plural;
+ }
+
+ /**
+ * Plural version of gettext
+ *
+ * @access public
+ * @param string single
+ * @param string plural
+ * @param string number
+ * @return translated plural form
+ */
+ function ngettext($single, $plural, $number) {
+ if ($this->short_circuit) {
+ if ($number != 1)
+ return $plural;
+ else
+ return $single;
+ }
+
+ // find out the appropriate form
+ $select = $this->select_string($number);
+
+ // this should contains all strings separated by NULLs
+ $key = $single.chr(0).$plural;
+
+
+ if ($this->enable_cache) {
+ if (! array_key_exists($key, $this->cache_translations)) {
+ return ($number != 1) ? $plural : $single;
+ } else {
+ $result = $this->cache_translations[$key];
+ $list = explode(chr(0), $result);
+ return $list[$select];
+ }
+ } else {
+ $num = $this->find_string($key);
+ if ($num == -1) {
+ return ($number != 1) ? $plural : $single;
+ } else {
+ $result = $this->get_translation_string($num);
+ $list = explode(chr(0), $result);
+ return $list[$select];
+ }
+ }
+ }
+
+}
+
+?>
diff --git a/extlib/php-gettext/streams.php b/extlib/php-gettext/streams.php
new file mode 100644
index 000000000..3eafa7482
--- /dev/null
+++ b/extlib/php-gettext/streams.php
@@ -0,0 +1,167 @@
+<?php
+/*
+ Copyright (c) 2003, 2005 Danilo Segan <danilo@kvota.net>.
+
+ This file is part of PHP-gettext.
+
+ PHP-gettext is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ PHP-gettext is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with PHP-gettext; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+
+// Simple class to wrap file streams, string streams, etc.
+// seek is essential, and it should be byte stream
+class StreamReader {
+ // should return a string [FIXME: perhaps return array of bytes?]
+ function read($bytes) {
+ return false;
+ }
+
+ // should return new position
+ function seekto($position) {
+ return false;
+ }
+
+ // returns current position
+ function currentpos() {
+ return false;
+ }
+
+ // returns length of entire stream (limit for seekto()s)
+ function length() {
+ return false;
+ }
+}
+
+class StringReader {
+ var $_pos;
+ var $_str;
+
+ function StringReader($str='') {
+ $this->_str = $str;
+ $this->_pos = 0;
+ }
+
+ function read($bytes) {
+ $data = substr($this->_str, $this->_pos, $bytes);
+ $this->_pos += $bytes;
+ if (strlen($this->_str)<$this->_pos)
+ $this->_pos = strlen($this->_str);
+
+ return $data;
+ }
+
+ function seekto($pos) {
+ $this->_pos = $pos;
+ if (strlen($this->_str)<$this->_pos)
+ $this->_pos = strlen($this->_str);
+ return $this->_pos;
+ }
+
+ function currentpos() {
+ return $this->_pos;
+ }
+
+ function length() {
+ return strlen($this->_str);
+ }
+
+}
+
+
+class FileReader {
+ var $_pos;
+ var $_fd;
+ var $_length;
+
+ function FileReader($filename) {
+ if (file_exists($filename)) {
+
+ $this->_length=filesize($filename);
+ $this->_pos = 0;
+ $this->_fd = fopen($filename,'rb');
+ if (!$this->_fd) {
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
+ }
+ } else {
+ $this->error = 2; // File doesn't exist
+ return false;
+ }
+ }
+
+ function read($bytes) {
+ if ($bytes) {
+ fseek($this->_fd, $this->_pos);
+
+ // PHP 5.1.1 does not read more than 8192 bytes in one fread()
+ // the discussions at PHP Bugs suggest it's the intended behaviour
+ $data = '';
+ while ($bytes > 0) {
+ $chunk = fread($this->_fd, $bytes);
+ $data .= $chunk;
+ $bytes -= strlen($chunk);
+ }
+ $this->_pos = ftell($this->_fd);
+
+ return $data;
+ } else return '';
+ }
+
+ function seekto($pos) {
+ fseek($this->_fd, $pos);
+ $this->_pos = ftell($this->_fd);
+ return $this->_pos;
+ }
+
+ function currentpos() {
+ return $this->_pos;
+ }
+
+ function length() {
+ return $this->_length;
+ }
+
+ function close() {
+ fclose($this->_fd);
+ }
+
+}
+
+// Preloads entire file in memory first, then creates a StringReader
+// over it (it assumes knowledge of StringReader internals)
+class CachedFileReader extends StringReader {
+ function CachedFileReader($filename) {
+ if (file_exists($filename)) {
+
+ $length=filesize($filename);
+ $fd = fopen($filename,'rb');
+
+ if (!$fd) {
+ $this->error = 3; // Cannot read file, probably permissions
+ return false;
+ }
+ $this->_str = fread($fd, $length);
+ fclose($fd);
+
+ } else {
+ $this->error = 2; // File doesn't exist
+ return false;
+ }
+ }
+}
+
+
+?> \ No newline at end of file
diff --git a/htaccess.sample b/htaccess.sample
index 942e98334..37eb8e01e 100644
--- a/htaccess.sample
+++ b/htaccess.sample
@@ -1,7 +1,7 @@
<IfModule mod_rewrite.c>
RewriteEngine On
- # NOTE: change this to your actual Laconica path; may be "/".
+ # NOTE: change this to your actual StatusNet path; may be "/".
RewriteBase /mublog/
diff --git a/index.php b/index.php
index 69c0bc1b2..362ab3cd3 100644
--- a/index.php
+++ b/index.php
@@ -1,7 +1,7 @@
<?php
/**
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -18,7 +18,8 @@
*/
define('INSTALLDIR', dirname(__FILE__));
-define('LACONICA', true);
+define('STATUSNET', true);
+define('LACONICA', true); // compatibility
require_once INSTALLDIR . '/lib/common.php';
@@ -31,7 +32,13 @@ function getPath($req)
&& array_key_exists('p', $req)) {
return $req['p'];
} else if (array_key_exists('PATH_INFO', $_SERVER)) {
- return $_SERVER['PATH_INFO'];
+ $path = $_SERVER['PATH_INFO'];
+ $script = $_SERVER['SCRIPT_NAME'];
+ if (substr($path, 0, mb_strlen($script)) == $script) {
+ return substr($path, mb_strlen($script));
+ } else {
+ return $path;
+ }
} else {
return null;
}
@@ -73,7 +80,7 @@ function handleError($error)
exit(-1);
}
-function checkMirror($action_obj)
+function checkMirror($action_obj, $args)
{
global $config;
@@ -93,7 +100,7 @@ function checkMirror($action_obj)
// on the master DB
$config['db']['database_rw'] = $config['db']['database'];
- $config['db']['ini_rw'] = INSTALLDIR.'/classes/laconica.ini';
+ $config['db']['ini_rw'] = INSTALLDIR.'/classes/statusnet.ini';
foreach ($alwaysRW as $table) {
$config['db']['table_'.$table] = 'rw';
@@ -107,8 +114,27 @@ function checkMirror($action_obj)
function main()
{
+ // fake HTTP redirects using lighttpd's 404 redirects
+ if (strpos($_SERVER['SERVER_SOFTWARE'], 'lighttpd') !== false) {
+ $_lighty_url = $base_url.$_SERVER['REQUEST_URI'];
+ $_lighty_url = @parse_url($_lighty_url);
+
+ if ($_lighty_url['path'] != '/index.php' && $_lighty_url['path'] != '/') {
+ $_lighty_path = preg_replace('/^'.preg_quote(common_config('site','path')).'\//', '', substr($_lighty_url['path'], 1));
+ $_SERVER['QUERY_STRING'] = 'p='.$_lighty_path;
+ if ($_lighty_url['query'])
+ $_SERVER['QUERY_STRING'] .= '&'.$_lighty_url['query'];
+ parse_str($_lighty_url['query'], $_lighty_query);
+ foreach ($_lighty_query as $key => $val) {
+ $_GET[$key] = $_REQUEST[$key] = $val;
+ }
+ $_GET['p'] = $_REQUEST['p'] = $_lighty_path;
+ }
+ }
+ $_SERVER['REDIRECT_URL'] = preg_replace("/\?.+$/", "", $_SERVER['REQUEST_URI']);
+
// quick check for fancy URL auto-detection support in installer.
- if (isset($_SERVER['REDIRECT_URL']) && ((dirname($_SERVER['REQUEST_URI']) . '/check-fancy') === $_SERVER['REDIRECT_URL'])) {
+ if (isset($_SERVER['REDIRECT_URL']) && (preg_replace("/^\/$/","",(dirname($_SERVER['REQUEST_URI']))) . '/check-fancy') === $_SERVER['REDIRECT_URL']) {
die("Fancy URL support detection succeeded. We suggest you enable this to get fancy (pretty) URLs.");
}
global $user, $action;
@@ -163,12 +189,36 @@ function main()
// If the site is private, and they're not on one of the "public"
// parts of the site, redirect to login
- if (!$user && common_config('site', 'private') &&
- !in_array($action, array('login', 'openidlogin', 'finishopenidlogin',
- 'recoverpassword', 'api', 'doc', 'register')) &&
- !preg_match('/rss$/', $action)) {
- common_redirect(common_local_url('login'));
- return;
+ if (!$user && common_config('site', 'private')) {
+ $public_actions = array('openidlogin', 'finishopenidlogin',
+ 'recoverpassword', 'api', 'doc',
+ 'opensearch');
+ $login_action = 'openidlogin';
+ if (!common_config('site', 'openidonly')) {
+ $public_actions[] = 'login';
+ $public_actions[] = 'register';
+ $login_action = 'login';
+ }
+ if (!in_array($action, $public_actions) &&
+ !preg_match('/rss$/', $action)) {
+
+ // set returnto
+ $rargs =& common_copy_args($args);
+ unset($rargs['action']);
+ if (common_config('site', 'fancy')) {
+ unset($rargs['p']);
+ }
+ if (array_key_exists('submit', $rargs)) {
+ unset($rargs['submit']);
+ }
+ foreach (array_keys($_COOKIE) as $cookie) {
+ unset($rargs[$cookie]);
+ }
+ common_set_returnto(common_local_url($action, $rargs));
+
+ common_redirect(common_local_url($login_action));
+ return;
+ }
}
$action_class = ucfirst($action).'Action';
@@ -179,7 +229,7 @@ function main()
} else {
$action_obj = new $action_class();
- checkMirror($action_obj);
+ checkMirror($action_obj, $args);
try {
if ($action_obj->prepare($args)) {
diff --git a/install.php b/install.php
index 1d3a531c5..30dd34496 100644
--- a/install.php
+++ b/install.php
@@ -1,7 +1,7 @@
<?php
/**
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -19,18 +19,208 @@
define('INSTALLDIR', dirname(__FILE__));
+$external_libraries=array(
+ array(
+ 'name'=>'gettext',
+ 'url'=>'http://us.php.net/manual/en/book.gettext.php',
+ 'check_function'=>'gettext'
+ ),
+ array(
+ 'name'=>'PEAR',
+ 'url'=>'http://pear.php.net/',
+ 'deb'=>'php-pear',
+ 'include'=>'PEAR.php',
+ 'check_class'=>'PEAR'
+ ),
+ array(
+ 'name'=>'DB',
+ 'pear'=>'DB',
+ 'url'=>'http://pear.php.net/package/DB',
+ 'deb'=>'php-db',
+ 'include'=>'DB/common.php',
+ 'check_class'=>'DB_common'
+ ),
+ array(
+ 'name'=>'DB_DataObject',
+ 'pear'=>'DB_DataObject',
+ 'url'=>'http://pear.php.net/package/DB_DataObject',
+ 'include'=>'DB/DataObject.php',
+ 'check_class'=>'DB_DataObject'
+ ),
+ array(
+ 'name'=>'Console_Getopt',
+ 'pear'=>'Console_Getopt',
+ 'url'=>'http://pear.php.net/package/Console_Getopt',
+ 'include'=>'Console/Getopt.php',
+ 'check_class'=>'Console_Getopt'
+ ),
+ array(
+ 'name'=>'Facebook API',
+ 'url'=>'http://developers.facebook.com/',
+ 'include'=>'facebook/facebook.php',
+ 'check_class'=>'Facebook'
+ ),
+ array(
+ 'name'=>'htmLawed',
+ 'url'=>'http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed',
+ 'include'=>'htmLawed/htmLawed.php',
+ 'check_function'=>'htmLawed'
+ ),
+ array(
+ 'name'=>'HTTP_Request',
+ 'pear'=>'HTTP_Request',
+ 'url'=>'http://pear.php.net/package/HTTP_Request',
+ 'deb'=>'php-http-request',
+ 'include'=>'HTTP/Request.php',
+ 'check_class'=>'HTTP_Request'
+ ),
+ array(
+ 'name'=>'Mail',
+ 'pear'=>'Mail',
+ 'url'=>'http://pear.php.net/package/Mail',
+ 'deb'=>'php-mail',
+ 'include'=>'Mail.php',
+ 'check_class'=>'Mail'
+ ),
+ array(
+ 'name'=>'Mail_mimeDecode',
+ 'pear'=>'Mail_mimeDecode',
+ 'url'=>'http://pear.php.net/package/Mail_mimeDecode',
+ 'deb'=>'php-mail-mimedecode',
+ 'include'=>'Mail/mimeDecode.php',
+ 'check_class'=>'Mail_mimeDecode'
+ ),
+ array(
+ 'name'=>'Mime_Type',
+ 'pear'=>'Mime_Type',
+ 'url'=>'http://pear.php.net/package/Mime_Type',
+ 'include'=>'MIME/Type.php',
+ 'check_class'=>'Mime_Type'
+ ),
+ array(
+ 'name'=>'Net_URL_Mapper',
+ 'pear'=>'Net_URL_Mapper',
+ 'url'=>'http://pear.php.net/package/Net_URL_Mapper',
+ 'include'=>'Net/URL/Mapper.php',
+ 'check_class'=>'Net_URL_Mapper'
+ ),
+ array(
+ 'name'=>'Net_Socket',
+ 'pear'=>'Net_Socket',
+ 'url'=>'http://pear.php.net/package/Net_Socket',
+ 'deb'=>'php-net-socket',
+ 'include'=>'Net/Socket.php',
+ 'check_class'=>'Net_Socket'
+ ),
+ array(
+ 'name'=>'Net_SMTP',
+ 'pear'=>'Net_SMTP',
+ 'url'=>'http://pear.php.net/package/Net_SMTP',
+ 'deb'=>'php-net-smtp',
+ 'include'=>'Net/SMTP.php',
+ 'check_class'=>'Net_SMTP'
+ ),
+ array(
+ 'name'=>'Net_URL',
+ 'pear'=>'Net_URL',
+ 'url'=>'http://pear.php.net/package/Net_URL',
+ 'deb'=>'php-net-url',
+ 'include'=>'Net/URL.php',
+ 'check_class'=>'Net_URL'
+ ),
+ array(
+ 'name'=>'Net_URL2',
+ 'pear'=>'Net_URL2',
+ 'url'=>'http://pear.php.net/package/Net_URL2',
+ 'include'=>'Net/URL2.php',
+ 'check_class'=>'Net_URL2'
+ ),
+ array(
+ 'name'=>'Services_oEmbed',
+ 'pear'=>'Services_oEmbed',
+ 'url'=>'http://pear.php.net/package/Services_oEmbed',
+ 'include'=>'Services/oEmbed.php',
+ 'check_class'=>'Services_oEmbed'
+ ),
+ array(
+ 'name'=>'Stomp',
+ 'url'=>'http://stomp.codehaus.org/PHP',
+ 'include'=>'Stomp.php',
+ 'check_class'=>'Stomp'
+ ),
+ array(
+ 'name'=>'System_Command',
+ 'pear'=>'System_Command',
+ 'url'=>'http://pear.php.net/package/System_Command',
+ 'include'=>'System/Command.php',
+ 'check_class'=>'System_Command'
+ ),
+ array(
+ 'name'=>'XMPPHP',
+ 'url'=>'http://code.google.com/p/xmpphp',
+ 'include'=>'XMPPHP/XMPP.php',
+ 'check_class'=>'XMPPHP_XMPP'
+ ),
+ array(
+ 'name'=>'PHP Markdown',
+ 'url'=>'http://www.michelf.com/projects/php-markdown/',
+ 'include'=>'markdown.php',
+ 'check_class'=>'Markdown_Parser'
+ ),
+ array(
+ 'name'=>'OAuth',
+ 'url'=>'http://code.google.com/p/oauth-php',
+ 'include'=>'OAuth.php',
+ 'check_class'=>'OAuthRequest'
+ ),
+ array(
+ 'name'=>'Validate',
+ 'pear'=>'Validate',
+ 'url'=>'http://pear.php.net/package/Validate',
+ 'include'=>'Validate.php',
+ 'check_class'=>'Validate'
+ )
+);
+
function main()
{
if (!checkPrereqs())
{
return;
}
-
- if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- handlePost();
+
+ if (isset($_GET['checklibs'])) {
+ showLibs();
} else {
- showForm();
+ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ handlePost();
+ } else {
+ showForm();
+ }
+ }
+}
+
+function haveExternalLibrary($external_library)
+{
+ if(isset($external_library['include']) && ! haveIncludeFile($external_library['include'])){
+ return false;
+ }
+ if(isset($external_library['check_function']) && ! function_exists($external_library['check_function'])){
+ return false;
+ }
+ if(isset($external_library['check_class']) && ! class_exists($external_library['check_class'])){
+ return false;
}
+ return true;
+}
+
+// Attempt to include a PHP file and report if it worked, while
+// suppressing the annoying warning messages on failure.
+function haveIncludeFile($filename) {
+ $old = error_reporting(error_reporting() & ~E_WARNING);
+ $ok = include_once($filename);
+ error_reporting($old);
+ return $ok;
}
function checkPrereqs()
@@ -49,8 +239,7 @@ function checkPrereqs()
}
$reqs = array('gd', 'curl',
- 'xmlwriter', 'mbstring',
- 'gettext');
+ 'xmlwriter', 'mbstring','tidy');
foreach ($reqs as $req) {
if (!checkExtension($req)) {
@@ -77,7 +266,7 @@ function checkPrereqs()
if (!is_writable($fileFullPath)) {
?><p class="error">Cannot write <?php echo $fileSubdir; ?> directory: <code><?php echo $fileFullPath; ?></code></p>
<p>On your server, try this command: <code>chmod a+w <?php echo $fileFullPath; ?></code></p>
- <?
+ <?php
$pass = false;
}
}
@@ -87,12 +276,82 @@ function checkPrereqs()
function checkExtension($name)
{
- if (!extension_loaded($name)) {
- if (!dl($name.'.so')) {
- return false;
+ if (extension_loaded($name)) {
+ return true;
+ } elseif (function_exists('dl') && ini_get('enable_dl') && !ini_get('safe_mode')) {
+ // dl will throw a fatal error if it's disabled or we're in safe mode.
+ // More fun, it may not even exist under some SAPIs in 5.3.0 or later...
+ $soname = $name . '.' . PHP_SHLIB_SUFFIX;
+ if (PHP_SHLIB_SUFFIX == 'dll') {
+ $soname = "php_" . $soname;
+ }
+ return @dl($soname);
+ } else {
+ return false;
+ }
+}
+
+function showLibs()
+{
+ global $external_libraries;
+ $present_libraries=array();
+ $absent_libraries=array();
+ foreach($external_libraries as $external_library){
+ if(haveExternalLibrary($external_library)){
+ $present_libraries[]=$external_library;
+ }else{
+ $absent_libraries[]=$external_library;
}
}
- return true;
+ echo<<<E_O_T
+ <div class="instructions">
+ <p>Laconica comes bundled with a number of libraries required for the application to work. However, it is best that you use PEAR or you distribution to manage
+ libraries instead, as they tend to provide security updates faster, and may offer improved performance.</p>
+ <p>On Debian based distributions, such as Ubuntu, use a package manager (such as &quot;aptitude&quot;, &quot;apt-get&quot;, and &quot;synaptic&quot;) to install the package listed.</p>
+ <p>On RPM based distributions, such as Red Hat, Fedora, CentOS, Scientific Linux, Yellow Dog Linux and Oracle Enterprise Linux, use a package manager (such as &quot;yum&quot;, &quot;apt-rpm&quot;, and &quot;up2date&quot;) to install the package listed.</p>
+ <p>On servers without a package manager (such as Windows), or if the library is not packaged for your distribution, you can use PHP's PEAR to install the library. Simply run &quot;pear install &lt;name&gt;&quot;.</p>
+ </div>
+ <h2>Absent Libraries</h2>
+ <ul id="absent_libraries">
+E_O_T;
+ foreach($absent_libraries as $library)
+ {
+ echo '<li>';
+ if(isset($library['url'])){
+ echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
+ }else{
+ echo htmlentities($library['name']);
+ }
+ echo '<ul>';
+ if(isset($library['deb'])){
+ echo '<li class="deb package">deb: <a href="apt:' . urlencode($library['deb']) . '">' . htmlentities($library['deb']) . '</a></li>';
+ }
+ if(isset($library['rpm'])){
+ echo '<li class="rpm package">rpm: ' . htmlentities($library['rpm']) . '</li>';
+ }
+ if(isset($library['pear'])){
+ echo '<li class="pear package">pear: ' . htmlentities($library['pear']) . '</li>';
+ }
+ echo '</ul>';
+ }
+ echo<<<E_O_T
+ </ul>
+ <h2>Installed Libraries</h2>
+ <ul id="present_libraries">
+E_O_T;
+ foreach($present_libraries as $library)
+ {
+ echo '<li>';
+ if(isset($library['url'])){
+ echo '<a href=">'.$library['url'].'">'.htmlentities($library['name']).'</a>';
+ }else{
+ echo htmlentities($library['name']);
+ }
+ echo '</li>';
+ }
+ echo<<<E_O_T
+ </ul>
+E_O_T;
}
function showForm()
@@ -106,6 +365,7 @@ function showForm()
<dd>
<div class="instructions">
<p>Enter your database connection information below to initialize the database.</p>
+ <p>Laconica bundles a number of libraries for ease of installation. <a href="?checklibs=true">You can see what bundled libraries you are using, versus what libraries are installed on your server.</a>
</div>
</dd>
</dl>
@@ -130,7 +390,7 @@ function showForm()
<p class="form_guide">Database hostname</p>
</li>
<li>
-
+
<label for="dbtype">Type</label>
<input type="radio" name="dbtype" id="fancy-mysql" value="mysql" checked='checked' /> MySQL<br />
<input type="radio" name="dbtype" id="dbtype-pgsql" value="pgsql" /> PostgreSQL<br />
@@ -163,7 +423,7 @@ E_O_T;
function updateStatus($status, $error=false)
{
?>
- <li <?php echo ($error) ? 'class="error"': ''; ?>><?print $status;?></li>
+ <li <?php echo ($error) ? 'class="error"': ''; ?>><?php echo $status;?></li>
<?php
}
@@ -180,6 +440,9 @@ function handlePost()
$password = $_POST['password'];
$sitename = $_POST['sitename'];
$fancy = !empty($_POST['fancy']);
+ $server = $_SERVER['HTTP_HOST'];
+ $path = substr(dirname($_SERVER['PHP_SELF']), 1);
+
?>
<dl class="system_notice">
<dt>Page notice</dt>
@@ -217,22 +480,46 @@ function handlePost()
showForm();
return;
}
-
+
+ // FIXME: use PEAR::DB or PDO instead of our own switch
+
switch($dbtype) {
- case 'mysql': mysql_db_installer($host, $database, $username, $password, $sitename);
- break;
- case 'pgsql': pgsql_db_installer($host, $database, $username, $password, $sitename);
- break;
- default:
+ case 'mysql':
+ $db = mysql_db_installer($host, $database, $username, $password);
+ break;
+ case 'pgsql':
+ $db = pgsql_db_installer($host, $database, $username, $password);
+ break;
+ default:
+ }
+
+ if (!$db) {
+ // database connection failed, do not move on to create config file.
+ return false;
+ }
+
+ updateStatus("Writing config file...");
+ $res = writeConf($sitename, $server, $path, $fancy, $db);
+
+ if (!$res) {
+ updateStatus("Can't write config file.", true);
+ showForm();
+ return;
}
- if ($path) $path .= '/';
- updateStatus("You can visit your <a href='/$path'>new Laconica site</a>.");
+
+ /*
+ TODO https needs to be considered
+ */
+ $link = "http://".$server.'/'.$path;
+
+ updateStatus("StatusNet has been installed at $link");
+ updateStatus("You can visit your <a href='$link'>new StatusNet site</a>.");
?>
<?php
}
-function pgsql_db_installer($host, $database, $username, $password, $sitename) {
+function pgsql_db_installer($host, $database, $username, $password) {
$connstring = "dbname=$database host=$host user=$username";
//No password would mean trust authentication used.
@@ -243,15 +530,29 @@ function pgsql_db_installer($host, $database, $username, $password, $sitename) {
updateStatus("Checking database...");
$conn = pg_connect($connstring);
+ if ($conn ===false) {
+ updateStatus("Failed to connect to database: $connstring");
+ showForm();
+ return false;
+ }
+
+ //ensure database encoding is UTF8
+ $record = pg_fetch_object(pg_query($conn, 'SHOW server_encoding'));
+ if ($record->server_encoding != 'UTF8') {
+ updateStatus("StatusNet requires UTF8 character encoding. Your database is ". htmlentities($record->server_encoding));
+ showForm();
+ return false;
+ }
+
updateStatus("Running database script...");
//wrap in transaction;
pg_query($conn, 'BEGIN');
- $res = runDbScript(INSTALLDIR.'/db/laconica_pg.sql', $conn, 'pgsql');
-
+ $res = runDbScript(INSTALLDIR.'/db/statusnet_pg.sql', $conn, 'pgsql');
+
if ($res === false) {
updateStatus("Can't run database script.", true);
showForm();
- return;
+ return false;
}
foreach (array('sms_carrier' => 'SMS carrier',
'notice_source' => 'notice source',
@@ -262,29 +563,24 @@ function pgsql_db_installer($host, $database, $username, $password, $sitename) {
if ($res === false) {
updateStatus(sprintf("Can't run %d script.", $name), true);
showForm();
- return;
+ return false;
}
}
pg_query($conn, 'COMMIT');
- updateStatus("Writing config file...");
if (empty($password)) {
$sqlUrl = "pgsql://$username@$host/$database";
}
else {
$sqlUrl = "pgsql://$username:$password@$host/$database";
}
- $res = writeConf($sitename, $sqlUrl, $fancy, 'pgsql');
- if (!$res) {
- updateStatus("Can't write config file.", true);
- showForm();
- return;
- }
- updateStatus("Done!");
-
+
+ $db = array('type' => 'pgsql', 'database' => $sqlUrl);
+
+ return $db;
}
-function mysql_db_installer($host, $database, $username, $password, $sitename) {
+function mysql_db_installer($host, $database, $username, $password) {
updateStatus("Starting installation...");
updateStatus("Checking database...");
@@ -292,21 +588,21 @@ function mysql_db_installer($host, $database, $username, $password, $sitename) {
if (!$conn) {
updateStatus("Can't connect to server '$host' as '$username'.", true);
showForm();
- return;
+ return false;
}
updateStatus("Changing to database...");
$res = mysql_select_db($database, $conn);
if (!$res) {
updateStatus("Can't change to database.", true);
showForm();
- return;
+ return false;
}
updateStatus("Running database script...");
- $res = runDbScript(INSTALLDIR.'/db/laconica.sql', $conn);
+ $res = runDbScript(INSTALLDIR.'/db/statusnet.sql', $conn);
if ($res === false) {
updateStatus("Can't run database script.", true);
showForm();
- return;
+ return false;
}
foreach (array('sms_carrier' => 'SMS carrier',
'notice_source' => 'notice source',
@@ -317,35 +613,44 @@ function mysql_db_installer($host, $database, $username, $password, $sitename) {
if ($res === false) {
updateStatus(sprintf("Can't run %d script.", $name), true);
showForm();
- return;
+ return false;
}
}
-
- updateStatus("Writing config file...");
+
$sqlUrl = "mysqli://$username:$password@$host/$database";
- $res = writeConf($sitename, $sqlUrl, $fancy);
- if (!$res) {
- updateStatus("Can't write config file.", true);
- showForm();
- return;
- }
- updateStatus("Done!");
- }
-function writeConf($sitename, $sqlUrl, $fancy, $type='mysql')
+ $db = array('type' => 'mysql', 'database' => $sqlUrl);
+ return $db;
+}
+
+function writeConf($sitename, $server, $path, $fancy, $db)
{
- $res = file_put_contents(INSTALLDIR.'/config.php',
- "<?php\n".
- "if (!defined('LACONICA')) { exit(1); }\n\n".
- "\$config['site']['name'] = \"$sitename\";\n\n".
- ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
- "\$config['db']['database'] = \"$sqlUrl\";\n\n".
- ($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n" .
- "\$config['db']['type'] = \"$type\";\n\n" : '').
- "?>");
+ // assemble configuration file in a string
+ $cfg = "<?php\n".
+ "if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }\n\n".
+
+ // site name
+ "\$config['site']['name'] = '$sitename';\n\n".
+
+ // site location
+ "\$config['site']['server'] = '$server';\n".
+ "\$config['site']['path'] = '$path'; \n\n".
+
+ // checks if fancy URLs are enabled
+ ($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
+
+ // database
+ "\$config['db']['database'] = '{$db['database']}';\n\n".
+ ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
+ "\$config['db']['type'] = '{$db['type']}';\n\n".
+
+ "?>";
+ // write configuration file out to install directory
+ $res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
+
return $res;
}
-function runDbScript($filename, $conn, $type='mysql')
+function runDbScript($filename, $conn, $type = 'mysql')
{
$sql = trim(file_get_contents($filename));
$stmts = explode(';', $sql);
@@ -354,13 +659,25 @@ function runDbScript($filename, $conn, $type='mysql')
if (!mb_strlen($stmt)) {
continue;
}
- if ($type == 'mysql') {
- $res = mysql_query($stmt, $conn);
- } elseif ($type=='pgsql') {
- $res = pg_query($conn, $stmt);
+ // FIXME: use PEAR::DB or PDO instead of our own switch
+ switch ($type) {
+ case 'mysql':
+ $res = mysql_query($stmt, $conn);
+ if ($res === false) {
+ $error = mysql_error();
+ }
+ break;
+ case 'pgsql':
+ $res = pg_query($conn, $stmt);
+ if ($res === false) {
+ $error = pg_last_error();
+ }
+ break;
+ default:
+ updateStatus("runDbScript() error: unknown database type ". $type ." provided.");
}
if ($res === false) {
- updateStatus("FAILED SQL: $stmt");
+ updateStatus("ERROR ($error) for SQL '$stmt'");
return $res;
}
}
@@ -369,12 +686,10 @@ function runDbScript($filename, $conn, $type='mysql')
?>
<?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
-<!DOCTYPE html
-PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
<head>
- <title>Install Laconica</title>
+ <title>Install StatusNet</title>
<link rel="shortcut icon" href="favicon.ico"/>
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
@@ -388,14 +703,14 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
<div id="header">
<address id="site_contact" class="vcard">
<a class="url home bookmark" href=".">
- <img class="logo photo" src="theme/default/logo.png" alt="Laconica"/>
- <span class="fn org">Laconica</span>
+ <img class="logo photo" src="theme/default/logo.png" alt="StatusNet"/>
+ <span class="fn org">StatusNet</span>
</a>
</address>
</div>
<div id="core">
<div id="content">
- <h1>Install Laconica</h1>
+ <h1>Install StatusNet</h1>
<?php main(); ?>
</div>
</div>
diff --git a/js/facebookapp.js b/js/facebookapp.js
index f0696c19e..5deb6e42b 100644
--- a/js/facebookapp.js
+++ b/js/facebookapp.js
@@ -1,6 +1,6 @@
/*
-* Laconica - a distributed open-source microblogging tool
-* Copyright (C) 2008, Controlez-Vous, Inc.
+* StatusNet - a distributed open-source microblogging tool
+* Copyright (C) 2008, StatusNet, Inc.
*
* 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
diff --git a/js/identica-badge.js b/js/identica-badge.js
index ffa55ae93..49c42b70c 100644
--- a/js/identica-badge.js
+++ b/js/identica-badge.js
@@ -119,7 +119,7 @@
$.s.className = trueName;
$.s.h = document.createElement('H3');
$.s.h.a = document.createElement('A');
- $.s.h.a.target = '_laconica';
+ $.s.h.a.target = '_statusnet';
$.s.h.appendChild($.s.h.a);
$.s.appendChild($.s.h);
$.s.r = document.createElement('UL');
@@ -184,11 +184,11 @@
var icon = document.createElement('A');
if (r[i] && r[i].url) {
icon.href = r[i].url;
- icon.target = '_laconica';
+ icon.target = '_statusnet';
icon.title = 'Visit ' + r[i].screen_name + ' at ' + r[i].url;
} else {
icon.href = 'http://' + $.a.server + '/' + r[i].screen_name;
- icon.target = '_laconica';
+ icon.target = '_statusnet';
icon.title = 'Visit ' + r[i].screen_name + ' at http://' + $.a.server + '/' + r[i].screen_name;
}
@@ -215,14 +215,14 @@
var date_link = document.createElement('A');
date_link.innerHTML = r[i].status.created_at.split(/\+/)[0];
date_link.href = 'http://' + $.a.server + '/notice/' + r[i].status.id;
- date_link.target = '_laconica';
+ date_link.target = '_statusnet';
updated.appendChild(date_link);
if (r[i].status.in_reply_to_status_id) {
updated.appendChild(document.createTextNode(' in reply to '));
var in_reply_to = document.createElement('A');
in_reply_to.innerHTML = r[i].status.in_reply_to_status_id;
in_reply_to.href = 'http://' + $.a.server + '/notice/' + r[i].status.in_reply_to_status_id;
- in_reply_to.target = '_laconica';
+ in_reply_to.target = '_statusnet';
updated.appendChild(in_reply_to);
}
} else {
@@ -233,9 +233,9 @@
if (r[i].status && r[i].status.text) {
var raw = r[i].status.text;
var cooked = raw;
- cooked = cooked.replace(/http:\/\/([^ ]+)/g, "<a href=\"http://$1\" target=\"_laconica\">http://$1</a>");
- cooked = cooked.replace(/@([\w*]+)/g, '@<a href="http://' + $.a.server + '/$1" target=\"_laconica\">$1</a>');
- cooked = cooked.replace(/#([\w*]+)/g, '#<a href="http://' + $.a.server + '/tag/$1" target="_laconica">$1</a>');
+ cooked = cooked.replace(/http:\/\/([^ ]+)/g, "<a href=\"http://$1\" target=\"_statusnet\">http://$1</a>");
+ cooked = cooked.replace(/@([\w*]+)/g, '@<a href="http://' + $.a.server + '/$1" target=\"_statusnet\">$1</a>');
+ cooked = cooked.replace(/#([\w*]+)/g, '#<a href="http://' + $.a.server + '/tag/$1" target="_statusnet">$1</a>');
p.innerHTML = cooked;
}
li.appendChild(p);
diff --git a/js/jcrop/jquery.Jcrop.go.js b/js/jcrop/jquery.Jcrop.go.js
index 4e1cbfd1e..5739f676d 100644
--- a/js/jcrop/jquery.Jcrop.go.js
+++ b/js/jcrop/jquery.Jcrop.go.js
@@ -1,10 +1,10 @@
/** Init for Jcrop library and page setup
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
$(function(){
diff --git a/js/jcrop/jquery.Jcrop.min.js b/js/jcrop/jquery.Jcrop.min.js
new file mode 100644
index 000000000..9002b9787
--- /dev/null
+++ b/js/jcrop/jquery.Jcrop.min.js
@@ -0,0 +1,163 @@
+/**
+ * Jcrop v.0.9.8 (minimized)
+ * (c) 2008 Kelly Hallman and DeepLiquid.com
+ * More information: http://deepliquid.com/content/Jcrop.html
+ * Released under MIT License - this header must remain with code
+ */
+
+
+(function($){$.Jcrop=function(obj,opt)
+{var obj=obj,opt=opt;if(typeof(obj)!=='object')obj=$(obj)[0];if(typeof(opt)!=='object')opt={};if(!('trackDocument'in opt))
+{opt.trackDocument=$.browser.msie?false:true;if($.browser.msie&&$.browser.version.split('.')[0]=='8')
+opt.trackDocument=true;}
+if(!('keySupport'in opt))
+opt.keySupport=$.browser.msie?false:true;var defaults={trackDocument:false,baseClass:'jcrop',addClass:null,bgColor:'black',bgOpacity:.6,borderOpacity:.4,handleOpacity:.5,handlePad:5,handleSize:9,handleOffset:5,edgeMargin:14,aspectRatio:0,keySupport:true,cornerHandles:true,sideHandles:true,drawBorders:true,dragEdges:true,boxWidth:0,boxHeight:0,boundary:8,animationDelay:20,swingSpeed:3,allowSelect:true,allowMove:true,allowResize:true,minSelect:[0,0],maxSize:[0,0],minSize:[0,0],onChange:function(){},onSelect:function(){}};var options=defaults;setOptions(opt);var $origimg=$(obj);var $img=$origimg.clone().removeAttr('id').css({position:'absolute'});$img.width($origimg.width());$img.height($origimg.height());$origimg.after($img).hide();presize($img,options.boxWidth,options.boxHeight);var boundx=$img.width(),boundy=$img.height(),$div=$('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({position:'relative',backgroundColor:options.bgColor}).insertAfter($origimg).append($img);;if(options.addClass)$div.addClass(options.addClass);var $img2=$('<img />').attr('src',$img.attr('src')).css('position','absolute').width(boundx).height(boundy);var $img_holder=$('<div />').width(pct(100)).height(pct(100)).css({zIndex:310,position:'absolute',overflow:'hidden'}).append($img2);var $hdl_holder=$('<div />').width(pct(100)).height(pct(100)).css('zIndex',320);var $sel=$('<div />').css({position:'absolute',zIndex:300}).insertBefore($img).append($img_holder,$hdl_holder);var bound=options.boundary;var $trk=newTracker().width(boundx+(bound*2)).height(boundy+(bound*2)).css({position:'absolute',top:px(-bound),left:px(-bound),zIndex:290}).mousedown(newSelection);var xlimit,ylimit,xmin,ymin;var xscale,yscale,enabled=true;var docOffset=getPos($img),btndown,lastcurs,dimmed,animating,shift_down;var Coords=function()
+{var x1=0,y1=0,x2=0,y2=0,ox,oy;function setPressed(pos)
+{var pos=rebound(pos);x2=x1=pos[0];y2=y1=pos[1];};function setCurrent(pos)
+{var pos=rebound(pos);ox=pos[0]-x2;oy=pos[1]-y2;x2=pos[0];y2=pos[1];};function getOffset()
+{return[ox,oy];};function moveOffset(offset)
+{var ox=offset[0],oy=offset[1];if(0>x1+ox)ox-=ox+x1;if(0>y1+oy)oy-=oy+y1;if(boundy<y2+oy)oy+=boundy-(y2+oy);if(boundx<x2+ox)ox+=boundx-(x2+ox);x1+=ox;x2+=ox;y1+=oy;y2+=oy;};function getCorner(ord)
+{var c=getFixed();switch(ord)
+{case'ne':return[c.x2,c.y];case'nw':return[c.x,c.y];case'se':return[c.x2,c.y2];case'sw':return[c.x,c.y2];}};function getFixed()
+{if(!options.aspectRatio)return getRect();var aspect=options.aspectRatio,min_x=options.minSize[0]/xscale,min_y=options.minSize[1]/yscale,max_x=options.maxSize[0]/xscale,max_y=options.maxSize[1]/yscale,rw=x2-x1,rh=y2-y1,rwa=Math.abs(rw),rha=Math.abs(rh),real_ratio=rwa/rha,xx,yy;if(max_x==0){max_x=boundx*10}
+if(max_y==0){max_y=boundy*10}
+if(real_ratio<aspect)
+{yy=y2;w=rha*aspect;xx=rw<0?x1-w:w+x1;if(xx<0)
+{xx=0;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}
+else if(xx>boundx)
+{xx=boundx;h=Math.abs((xx-x1)/aspect);yy=rh<0?y1-h:h+y1;}}
+else
+{xx=x2;h=rwa/aspect;yy=rh<0?y1-h:y1+h;if(yy<0)
+{yy=0;w=Math.abs((yy-y1)*aspect);xx=rw<0?x1-w:w+x1;}
+else if(yy>boundy)
+{yy=boundy;w=Math.abs(yy-y1)*aspect;xx=rw<0?x1-w:w+x1;}}
+if(xx>x1){if(xx-x1<min_x){xx=x1+min_x;}else if(xx-x1>max_x){xx=x1+max_x;}
+if(yy>y1){yy=y1+(xx-x1)/aspect;}else{yy=y1-(xx-x1)/aspect;}}else if(xx<x1){if(x1-xx<min_x){xx=x1-min_x}else if(x1-xx>max_x){xx=x1-max_x;}
+if(yy>y1){yy=y1+(x1-xx)/aspect;}else{yy=y1-(x1-xx)/aspect;}}
+if(xx<0){x1-=xx;xx=0;}else if(xx>boundx){x1-=xx-boundx;xx=boundx;}
+if(yy<0){y1-=yy;yy=0;}else if(yy>boundy){y1-=yy-boundy;yy=boundy;}
+return last=makeObj(flipCoords(x1,y1,xx,yy));};function rebound(p)
+{if(p[0]<0)p[0]=0;if(p[1]<0)p[1]=0;if(p[0]>boundx)p[0]=boundx;if(p[1]>boundy)p[1]=boundy;return[p[0],p[1]];};function flipCoords(x1,y1,x2,y2)
+{var xa=x1,xb=x2,ya=y1,yb=y2;if(x2<x1)
+{xa=x2;xb=x1;}
+if(y2<y1)
+{ya=y2;yb=y1;}
+return[Math.round(xa),Math.round(ya),Math.round(xb),Math.round(yb)];};function getRect()
+{var xsize=x2-x1;var ysize=y2-y1;if(xlimit&&(Math.abs(xsize)>xlimit))
+x2=(xsize>0)?(x1+xlimit):(x1-xlimit);if(ylimit&&(Math.abs(ysize)>ylimit))
+y2=(ysize>0)?(y1+ylimit):(y1-ylimit);if(ymin&&(Math.abs(ysize)<ymin))
+y2=(ysize>0)?(y1+ymin):(y1-ymin);if(xmin&&(Math.abs(xsize)<xmin))
+x2=(xsize>0)?(x1+xmin):(x1-xmin);if(x1<0){x2-=x1;x1-=x1;}
+if(y1<0){y2-=y1;y1-=y1;}
+if(x2<0){x1-=x2;x2-=x2;}
+if(y2<0){y1-=y2;y2-=y2;}
+if(x2>boundx){var delta=x2-boundx;x1-=delta;x2-=delta;}
+if(y2>boundy){var delta=y2-boundy;y1-=delta;y2-=delta;}
+if(x1>boundx){var delta=x1-boundy;y2-=delta;y1-=delta;}
+if(y1>boundy){var delta=y1-boundy;y2-=delta;y1-=delta;}
+return makeObj(flipCoords(x1,y1,x2,y2));};function makeObj(a)
+{return{x:a[0],y:a[1],x2:a[2],y2:a[3],w:a[2]-a[0],h:a[3]-a[1]};};return{flipCoords:flipCoords,setPressed:setPressed,setCurrent:setCurrent,getOffset:getOffset,moveOffset:moveOffset,getCorner:getCorner,getFixed:getFixed};}();var Selection=function()
+{var start,end,dragmode,awake,hdep=370;var borders={};var handle={};var seehandles=false;var hhs=options.handleOffset;if(options.drawBorders){borders={top:insertBorder('hline').css('top',$.browser.msie?px(-1):px(0)),bottom:insertBorder('hline'),left:insertBorder('vline'),right:insertBorder('vline')};}
+if(options.dragEdges){handle.t=insertDragbar('n');handle.b=insertDragbar('s');handle.r=insertDragbar('e');handle.l=insertDragbar('w');}
+options.sideHandles&&createHandles(['n','s','e','w']);options.cornerHandles&&createHandles(['sw','nw','ne','se']);function insertBorder(type)
+{var jq=$('<div />').css({position:'absolute',opacity:options.borderOpacity}).addClass(cssClass(type));$img_holder.append(jq);return jq;};function dragDiv(ord,zi)
+{var jq=$('<div />').mousedown(createDragger(ord)).css({cursor:ord+'-resize',position:'absolute',zIndex:zi});$hdl_holder.append(jq);return jq;};function insertHandle(ord)
+{return dragDiv(ord,hdep++).css({top:px(-hhs+1),left:px(-hhs+1),opacity:options.handleOpacity}).addClass(cssClass('handle'));};function insertDragbar(ord)
+{var s=options.handleSize,o=hhs,h=s,w=s,t=o,l=o;switch(ord)
+{case'n':case's':w=pct(100);break;case'e':case'w':h=pct(100);break;}
+return dragDiv(ord,hdep++).width(w).height(h).css({top:px(-t+1),left:px(-l+1)});};function createHandles(li)
+{for(i in li)handle[li[i]]=insertHandle(li[i]);};function moveHandles(c)
+{var midvert=Math.round((c.h/2)-hhs),midhoriz=Math.round((c.w/2)-hhs),north=west=-hhs+1,east=c.w-hhs,south=c.h-hhs,x,y;'e'in handle&&handle.e.css({top:px(midvert),left:px(east)})&&handle.w.css({top:px(midvert)})&&handle.s.css({top:px(south),left:px(midhoriz)})&&handle.n.css({left:px(midhoriz)});'ne'in handle&&handle.ne.css({left:px(east)})&&handle.se.css({top:px(south),left:px(east)})&&handle.sw.css({top:px(south)});'b'in handle&&handle.b.css({top:px(south)})&&handle.r.css({left:px(east)});};function moveto(x,y)
+{$img2.css({top:px(-y),left:px(-x)});$sel.css({top:px(y),left:px(x)});};function resize(w,h)
+{$sel.width(w).height(h);};function refresh()
+{var c=Coords.getFixed();Coords.setPressed([c.x,c.y]);Coords.setCurrent([c.x2,c.y2]);updateVisible();};function updateVisible()
+{if(awake)return update();};function update()
+{var c=Coords.getFixed();resize(c.w,c.h);moveto(c.x,c.y);options.drawBorders&&borders['right'].css({left:px(c.w-1)})&&borders['bottom'].css({top:px(c.h-1)});seehandles&&moveHandles(c);awake||show();options.onChange(unscale(c));};function show()
+{$sel.show();$img.css('opacity',options.bgOpacity);awake=true;};function release()
+{disableHandles();$sel.hide();$img.css('opacity',1);awake=false;};function showHandles()
+{if(seehandles)
+{moveHandles(Coords.getFixed());$hdl_holder.show();}};function enableHandles()
+{seehandles=true;if(options.allowResize)
+{moveHandles(Coords.getFixed());$hdl_holder.show();return true;}};function disableHandles()
+{seehandles=false;$hdl_holder.hide();};function animMode(v)
+{(animating=v)?disableHandles():enableHandles();};function done()
+{animMode(false);refresh();};var $track=newTracker().mousedown(createDragger('move')).css({cursor:'move',position:'absolute',zIndex:360})
+$img_holder.append($track);disableHandles();return{updateVisible:updateVisible,update:update,release:release,refresh:refresh,setCursor:function(cursor){$track.css('cursor',cursor);},enableHandles:enableHandles,enableOnly:function(){seehandles=true;},showHandles:showHandles,disableHandles:disableHandles,animMode:animMode,done:done};}();var Tracker=function()
+{var onMove=function(){},onDone=function(){},trackDoc=options.trackDocument;if(!trackDoc)
+{$trk.mousemove(trackMove).mouseup(trackUp).mouseout(trackUp);}
+function toFront()
+{$trk.css({zIndex:450});if(trackDoc)
+{$(document).mousemove(trackMove).mouseup(trackUp);}}
+function toBack()
+{$trk.css({zIndex:290});if(trackDoc)
+{$(document).unbind('mousemove',trackMove).unbind('mouseup',trackUp);}}
+function trackMove(e)
+{onMove(mouseAbs(e));};function trackUp(e)
+{e.preventDefault();e.stopPropagation();if(btndown)
+{btndown=false;onDone(mouseAbs(e));options.onSelect(unscale(Coords.getFixed()));toBack();onMove=function(){};onDone=function(){};}
+return false;};function activateHandlers(move,done)
+{btndown=true;onMove=move;onDone=done;toFront();return false;};function setCursor(t){$trk.css('cursor',t);};$img.before($trk);return{activateHandlers:activateHandlers,setCursor:setCursor};}();var KeyManager=function()
+{var $keymgr=$('<input type="radio" />').css({position:'absolute',left:'-30px'}).keypress(parseKey).blur(onBlur),$keywrap=$('<div />').css({position:'absolute',overflow:'hidden'}).append($keymgr);function watchKeys()
+{if(options.keySupport)
+{$keymgr.show();$keymgr.focus();}};function onBlur(e)
+{$keymgr.hide();};function doNudge(e,x,y)
+{if(options.allowMove){Coords.moveOffset([x,y]);Selection.updateVisible();};e.preventDefault();e.stopPropagation();};function parseKey(e)
+{if(e.ctrlKey)return true;shift_down=e.shiftKey?true:false;var nudge=shift_down?10:1;switch(e.keyCode)
+{case 37:doNudge(e,-nudge,0);break;case 39:doNudge(e,nudge,0);break;case 38:doNudge(e,0,-nudge);break;case 40:doNudge(e,0,nudge);break;case 27:Selection.release();break;case 9:return true;}
+return nothing(e);};if(options.keySupport)$keywrap.insertBefore($img);return{watchKeys:watchKeys};}();function px(n){return''+parseInt(n)+'px';};function pct(n){return''+parseInt(n)+'%';};function cssClass(cl){return options.baseClass+'-'+cl;};function getPos(obj)
+{var pos=$(obj).offset();return[pos.left,pos.top];};function mouseAbs(e)
+{return[(e.pageX-docOffset[0]),(e.pageY-docOffset[1])];};function myCursor(type)
+{if(type!=lastcurs)
+{Tracker.setCursor(type);lastcurs=type;}};function startDragMode(mode,pos)
+{docOffset=getPos($img);Tracker.setCursor(mode=='move'?mode:mode+'-resize');if(mode=='move')
+return Tracker.activateHandlers(createMover(pos),doneSelect);var fc=Coords.getFixed();var opp=oppLockCorner(mode);var opc=Coords.getCorner(oppLockCorner(opp));Coords.setPressed(Coords.getCorner(opp));Coords.setCurrent(opc);Tracker.activateHandlers(dragmodeHandler(mode,fc),doneSelect);};function dragmodeHandler(mode,f)
+{return function(pos){if(!options.aspectRatio)switch(mode)
+{case'e':pos[1]=f.y2;break;case'w':pos[1]=f.y2;break;case'n':pos[0]=f.x2;break;case's':pos[0]=f.x2;break;}
+else switch(mode)
+{case'e':pos[1]=f.y+1;break;case'w':pos[1]=f.y+1;break;case'n':pos[0]=f.x+1;break;case's':pos[0]=f.x+1;break;}
+Coords.setCurrent(pos);Selection.update();};};function createMover(pos)
+{var lloc=pos;KeyManager.watchKeys();return function(pos)
+{Coords.moveOffset([pos[0]-lloc[0],pos[1]-lloc[1]]);lloc=pos;Selection.update();};};function oppLockCorner(ord)
+{switch(ord)
+{case'n':return'sw';case's':return'nw';case'e':return'nw';case'w':return'ne';case'ne':return'sw';case'nw':return'se';case'se':return'nw';case'sw':return'ne';};};function createDragger(ord)
+{return function(e){if(options.disabled)return false;if((ord=='move')&&!options.allowMove)return false;btndown=true;startDragMode(ord,mouseAbs(e));e.stopPropagation();e.preventDefault();return false;};};function presize($obj,w,h)
+{var nw=$obj.width(),nh=$obj.height();if((nw>w)&&w>0)
+{nw=w;nh=(w/$obj.width())*$obj.height();}
+if((nh>h)&&h>0)
+{nh=h;nw=(h/$obj.height())*$obj.width();}
+xscale=$obj.width()/nw;yscale=$obj.height()/nh;$obj.width(nw).height(nh);};function unscale(c)
+{return{x:parseInt(c.x*xscale),y:parseInt(c.y*yscale),x2:parseInt(c.x2*xscale),y2:parseInt(c.y2*yscale),w:parseInt(c.w*xscale),h:parseInt(c.h*yscale)};};function doneSelect(pos)
+{var c=Coords.getFixed();if(c.w>options.minSelect[0]&&c.h>options.minSelect[1])
+{Selection.enableHandles();Selection.done();}
+else
+{Selection.release();}
+Tracker.setCursor(options.allowSelect?'crosshair':'default');};function newSelection(e)
+{if(options.disabled)return false;if(!options.allowSelect)return false;btndown=true;docOffset=getPos($img);Selection.disableHandles();myCursor('crosshair');var pos=mouseAbs(e);Coords.setPressed(pos);Tracker.activateHandlers(selectDrag,doneSelect);KeyManager.watchKeys();Selection.update();e.stopPropagation();e.preventDefault();return false;};function selectDrag(pos)
+{Coords.setCurrent(pos);Selection.update();};function newTracker()
+{var trk=$('<div></div>').addClass(cssClass('tracker'));$.browser.msie&&trk.css({opacity:0,backgroundColor:'white'});return trk;};function animateTo(a)
+{var x1=a[0]/xscale,y1=a[1]/yscale,x2=a[2]/xscale,y2=a[3]/yscale;if(animating)return;var animto=Coords.flipCoords(x1,y1,x2,y2);var c=Coords.getFixed();var animat=initcr=[c.x,c.y,c.x2,c.y2];var interv=options.animationDelay;var x=animat[0];var y=animat[1];var x2=animat[2];var y2=animat[3];var ix1=animto[0]-initcr[0];var iy1=animto[1]-initcr[1];var ix2=animto[2]-initcr[2];var iy2=animto[3]-initcr[3];var pcent=0;var velocity=options.swingSpeed;Selection.animMode(true);var animator=function()
+{return function()
+{pcent+=(100-pcent)/velocity;animat[0]=x+((pcent/100)*ix1);animat[1]=y+((pcent/100)*iy1);animat[2]=x2+((pcent/100)*ix2);animat[3]=y2+((pcent/100)*iy2);if(pcent<100)animateStart();else Selection.done();if(pcent>=99.8)pcent=100;setSelectRaw(animat);};}();function animateStart()
+{window.setTimeout(animator,interv);};animateStart();};function setSelect(rect)
+{setSelectRaw([rect[0]/xscale,rect[1]/yscale,rect[2]/xscale,rect[3]/yscale]);};function setSelectRaw(l)
+{Coords.setPressed([l[0],l[1]]);Coords.setCurrent([l[2],l[3]]);Selection.update();};function setOptions(opt)
+{if(typeof(opt)!='object')opt={};options=$.extend(options,opt);if(typeof(options.onChange)!=='function')
+options.onChange=function(){};if(typeof(options.onSelect)!=='function')
+options.onSelect=function(){};};function tellSelect()
+{return unscale(Coords.getFixed());};function tellScaled()
+{return Coords.getFixed();};function setOptionsNew(opt)
+{setOptions(opt);interfaceUpdate();};function disableCrop()
+{options.disabled=true;Selection.disableHandles();Selection.setCursor('default');Tracker.setCursor('default');};function enableCrop()
+{options.disabled=false;interfaceUpdate();};function cancelCrop()
+{Selection.done();Tracker.activateHandlers(null,null);};function destroy()
+{$div.remove();$origimg.show();};function interfaceUpdate(alt)
+{options.allowResize?alt?Selection.enableOnly():Selection.enableHandles():Selection.disableHandles();Tracker.setCursor(options.allowSelect?'crosshair':'default');Selection.setCursor(options.allowMove?'move':'default');$div.css('backgroundColor',options.bgColor);if('setSelect'in options){setSelect(opt.setSelect);Selection.done();delete(options.setSelect);}
+if('trueSize'in options){xscale=options.trueSize[0]/boundx;yscale=options.trueSize[1]/boundy;}
+xlimit=options.maxSize[0]||0;ylimit=options.maxSize[1]||0;xmin=options.minSize[0]||0;ymin=options.minSize[1]||0;if('outerImage'in options)
+{$img.attr('src',options.outerImage);delete(options.outerImage);}
+Selection.refresh();};$hdl_holder.hide();interfaceUpdate(true);var api={animateTo:animateTo,setSelect:setSelect,setOptions:setOptionsNew,tellSelect:tellSelect,tellScaled:tellScaled,disable:disableCrop,enable:enableCrop,cancel:cancelCrop,focus:KeyManager.watchKeys,getBounds:function(){return[boundx*xscale,boundy*yscale];},getWidgetSize:function(){return[boundx,boundy];},release:Selection.release,destroy:destroy};$origimg.data('Jcrop',api);return api;};$.fn.Jcrop=function(options)
+{function attachWhenDone(from)
+{var loadsrc=options.useImg||from.src;var img=new Image();img.onload=function(){$.Jcrop(from,options);};img.src=loadsrc;};if(typeof(options)!=='object')options={};this.each(function()
+{if($(this).data('Jcrop'))
+{if(options=='api')return $(this).data('Jcrop');else $(this).data('Jcrop').setOptions(options);}
+else attachWhenDone(this);});return this;};})(jQuery); \ No newline at end of file
diff --git a/js/jcrop/jquery.Jcrop.pack.js b/js/jcrop/jquery.Jcrop.pack.js
deleted file mode 100644
index aa82e8abe..000000000
--- a/js/jcrop/jquery.Jcrop.pack.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
- * Jcrop v.0.9.5 (packed)
- * (c) 2008 Kelly Hallman and DeepLiquid.com
- * More information: http://deepliquid.com/content/Jcrop.html
- * Released under MIT License - this header must remain with code
- */
-
-eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('$.1n=7(G,F){d G=G,F=F;g(1p(G)!==\'2d\')G=$(G)[0];g(1p(F)!==\'2d\')F={};g(!(\'2x\'1a F))F.2x=$.3d.3e?K:M;g(!(\'2c\'1a F))F.2c=$.3d.3e?K:M;d 4f={2x:K,3W:\'4C\',1f:4D,3T:\'4Y\',3x:.6,3O:.4,3P:.5,53:5,3N:9,3D:5,51:14,25:0,2c:M,3I:M,3B:M,30:M,3A:M,49:0,4p:0,4k:8,3V:20,3X:3,2f:K,3n:[0,0],2z:[0,0],2O:[0,0],2D:7(){},2G:7(){}};d j=4f;21(F);d $I=$(G).B({16:\'1b\'});47($I,j.49,j.4p);d S=$I.W(),L=$I.U(),$12=$(\'<12 />\').W(S).U(L).1f(1L(\'4F\')).B({16:\'4H\',4B:j.3T});g(j.1f)$12.1f(j.1f);$I.54($12);d $34=$(\'<I />\').3Y(\'2N\',$I.3Y(\'2N\')).B(\'16\',\'1b\').W(S).U(L);d $2C=$(\'<12 />\').W(1t(V)).U(1t(V)).B({1l:59,16:\'1b\',4o:\'4g\'}).1P($34);d $2g=$(\'<12 />\').W(1t(V)).U(1t(V)).B({1l:5b});d $28=$(\'<12 />\').B({16:\'1b\',1l:55}).3U($I).1P($2C,$2g);d 23=j.4k;d $1S=$(\'<12 />\').1f(1L(\'3v\')).W(S+(23*2)).U(L+(23*2)).B({16:\'1b\',R:D(-23),P:D(-23),1l:3R,1z:0}).3q(48);d 1I,1Q;d 2u=2Q(G),1q,1B,3i,58,3h,1O;g(\'36\'1a j){1I=j.36[0]/S;1Q=j.36[1]/L}d E=7(){d A=0,u=0,q=0,m=0,Z,Y;7 1A(z){d z=2T(z);q=A=z[0];m=u=z[1]};7 1y(z){d z=2T(z);Z=z[0]-q;Y=z[1]-m;q=z[0];m=z[1]};7 3f(){k[Z,Y]};7 2b(2y){d Z=2y[0],Y=2y[1];g(0>A+Z)Z-=Z+A;g(0>u+Y)Y-=Y+u;g(L<m+Y)Y+=L-(m+Y);g(S<q+Z)Z+=S-(q+Z);A+=Z;q+=Z;u+=Y;m+=Y};7 2K(T){d c=Q();1E(T){C\'1s\':k[c.q,c.y];C\'11\':k[c.x,c.y];C\'2e\':k[c.q,c.m];C\'1M\':k[c.x,c.m]}};7 Q(){g(!j.25&&!1B)k 3F();d 1k=j.25?j.25:1B,5c=j.2O,4u=j.2z,1V=q-A,1Z=m-u,3c=N.17(1V),3j=N.17(1Z),3M=3c/3j,15,13;g(3M<1k){13=m;w=3j*1k;15=1V<0?A-w:w+A;g(15<0){15=0;h=N.17((15-A)/1k);13=1Z<0?u-h:h+u}1g g(15>S){15=S;h=N.17((15-A)/1k);13=1Z<0?u-h:h+u}}1g{15=q;h=3c/1k;13=1Z<0?u-h:u+h;g(13<0){13=0;w=N.17((13-u)*1k);15=1V<0?A-w:w+A}1g g(13>L){13=L;w=N.17(13-u)*1k;15=1V<0?A-w:w+A}}k 4E=3g(1F(A,u,15,13))};7 2T(p){g(p[0]<0)p[0]=0;g(p[1]<0)p[1]=0;g(p[0]>S)p[0]=S;g(p[1]>L)p[1]=L;k[p[0],p[1]]};7 1F(A,u,q,m){d 2R=A,3r=q,3o=u,3l=m;g(q<A){2R=q;3r=A}g(m<u){3o=m;3l=u}k[N.1K(2R),N.1K(3o),N.1K(3r),N.1K(3l)]};7 3F(){d 1U=q-A;d 22=m-u;g(2q&&(N.17(1U)>2q))q=(1U>0)?(A+2q):(A-2q);g(2n&&(N.17(22)>2n))m=(22>0)?(u+2n):(u-2n);g(2i&&(N.17(22)<2i))m=(22>0)?(u+2i):(u-2i);g(2m&&(N.17(1U)<2m))q=(1U>0)?(A+2m):(A-2m);g(A<0){q-=A;A-=A}g(u<0){m-=u;u-=u}g(q<0){A-=q;q-=q}g(m<0){u-=m;m-=m}g(q>S){d X=q-S;A-=X;q-=X}g(m>L){d X=m-L;u-=X;m-=X}g(A>S){d X=A-L;m-=X;u-=X}g(u>L){d X=u-L;m-=X;u-=X}k 3g(1F(A,u,q,m))};7 3g(a){k{x:a[0],y:a[1],q:a[2],m:a[3],w:a[2]-a[0],h:a[3]-a[1]}};k{1F:1F,1A:1A,1y:1y,3f:3f,2b:2b,2K:2K,Q:Q}}();d J=7(){d 4v,4z,4y,1R,2U=4x;d 2F={};d H={};d 2E=K;d 1i=j.3D;g(j.30){2F={R:1Y(\'3C\').B(\'R\',$.3d.3e?D(-1):D(0)),3Q:1Y(\'3C\'),P:1Y(\'3z\'),3L:1Y(\'3z\')}}g(j.3A){H.t=1W(\'n\');H.b=1W(\'s\');H.r=1W(\'e\');H.l=1W(\'w\')}j.3B&&2Y([\'n\',\'s\',\'e\',\'w\']);j.3I&&2Y([\'1M\',\'11\',\'1s\',\'2e\']);7 1Y(1u){d 1J=$(\'<12 />\').B({16:\'1b\',1z:j.3O}).1f(1L(1u));$2C.1P(1J);k 1J};7 2W(T,3y){d 1J=$(\'<12 />\').3q(3b(T)).B({3p:T+\'-2A\',16:\'1b\',1l:3y});$2g.1P(1J);k 1J};7 3J(T){k 2W(T,2U++).B({R:D(-1i+1),P:D(-1i+1),1z:j.3P}).1f(1L(\'H\'))};7 1W(T){d s=j.3N,o=1i,h=s,w=s,t=o,l=o;1E(T){C\'n\':C\'s\':w=1t(V);O;C\'e\':C\'w\':h=1t(V);O}k 2W(T,2U++).W(w).U(h).B({R:D(-t+1),P:D(-l+1)})};7 2Y(2J){4U(i 1a 2J)H[2J[i]]=3J(2J[i])};7 31(c){d 3a=N.1K((c.h/2)-1i),35=N.1K((c.w/2)-1i),4V=4W=-1i+1,2a=c.w-1i,1X=c.h-1i,x,y;\'e\'1a H&&H.e.B({R:D(3a),P:D(2a)})&&H.w.B({R:D(3a)})&&H.s.B({R:D(1X),P:D(35)})&&H.n.B({P:D(35)});\'1s\'1a H&&H.1s.B({P:D(2a)})&&H.2e.B({R:D(1X),P:D(2a)})&&H.1M.B({R:D(1X)});\'b\'1a H&&H.b.B({R:D(1X)})&&H.r.B({P:D(2a)})};7 3K(x,y){$34.B({R:D(-y),P:D(-x)});$28.B({R:D(y),P:D(x)})};7 2A(w,h){$28.W(w).U(h)};7 3s(){d p=E.Q();E.1A([p.x,p.y]);E.1y([p.q,p.m])};7 2I(){g(1R)k 1e()};7 1e(){d c=E.Q();2A(c.w,c.h);3K(c.x,c.y);j.30&&2F[\'3L\'].B({P:D(c.w-1)})&&2F[\'3Q\'].B({R:D(c.h-1)});2E&&31(c);1R||1w();j.2D(2H(c))};7 1w(){$28.1w();$I.B(\'1z\',j.3x);1R=M};7 1r(){1o();$28.1v();$I.B(\'1z\',1);1R=K};7 1v(){1r();$I.B(\'1z\',1);1R=K};7 2t(){2E=M;31(E.Q());$2g.1w()};7 1o(){2E=K;$2g.1v()};7 2o(v){(3h=v)?1o():2t()};7 1h(){d c=E.Q();2o(K);3s()};1o();$2C.1P($(\'<12 />\').1f(1L(\'3v\')).3q(3b(\'1N\')).B({3p:\'1N\',16:\'1b\',1l:4M,1z:0}));k{2I:2I,1e:1e,1r:1r,1w:1w,1v:1v,2t:2t,1o:1o,2o:2o,1h:1h}}();d 1j=7(){d 2w=7(){},2v=7(){},2L=j.2x;g(!2L){$1S.3k(2B).2S(26).4N(26)}7 4j(){g(2L){$(3t).3k(2B).2S(26)}$1S.B({1l:4G})}7 4i(){g(2L){$(3t).3H(\'3k\',2B).3H(\'2S\',26)}$1S.B({1l:3R})}7 2B(e){2w(2r(e))};7 26(e){e.2j();e.2k();g(1q){1q=K;2v(2r(e));j.2G(2H(E.Q()));4i();2w=7(){};2v=7(){}}k K};7 1G(1N,1h){1q=M;2w=1N;2v=1h;4j();k K};7 1x(t){$1S.B(\'3p\',t)};$I.4s($1S);k{1G:1G,1x:1x}}();d 33=7(){d $24=$(\'<4w 1u="4L" />\').B({16:\'1b\',P:\'-4O\'}).57(43).56(2f).5a(41),$3S=$(\'<12 />\').B({16:\'1b\',4o:\'4g\'}).1P($24);7 2l(){g(j.2c){$24.1w();$24.4Z()}};7 41(e){$24.1v()};7 2f(e){g(!j.2f)k;d 42=1O,1C;1O=e.4Q?M:K;g(42!=1O){g(1O&&1q){1C=E.Q();1B=1C.w/1C.h}1g 1B=0;J.1e()}e.2k();e.2j();k K};7 29(e,x,y){E.2b([x,y]);J.2I();e.2j();e.2k()};7 43(e){g(e.4T)k M;2f(e);d 2h=1O?10:1;1E(e.5d){C 37:29(e,-2h,0);O;C 39:29(e,2h,0);O;C 38:29(e,0,-2h);O;C 40:29(e,0,2h);O;C 27:J.1r();O;C 9:k M}k K};g(j.2c)$3S.3U($I);k{2l:2l}}();7 D(n){k\'\'+1m(n)+\'D\'};7 1t(n){k\'\'+1m(n)+\'%\'};7 1L(44){k j.3W+\'-\'+44};7 2Q(G){d z=$(G).2y();k[z.P,z.R]};7 2r(e){k[(e.4q-2u[0]),(e.4r-2u[1])]};7 46(1u){g(1u!=3i){1j.1x(1u);3i=1u}};7 4a(19,z){2u=2Q(G);1j.1x(19==\'1N\'?19:19+\'-2A\');g(19==\'1N\')k 1j.1G(4e(z),2P);d 1C=E.Q();E.1A(E.2K(4b(19)));1j.1G(45(19,1C),2P)};7 45(19,f){k 7(z){g(!j.25&&!1B)1E(19){C\'e\':z[1]=f.m;O;C\'w\':z[1]=f.m;O;C\'n\':z[0]=f.q;O;C\'s\':z[0]=f.q;O}1g 1E(19){C\'e\':z[1]=f.y+1;O;C\'w\':z[1]=f.y+1;O;C\'n\':z[0]=f.x+1;O;C\'s\':z[0]=f.x+1;O}E.1y(z);J.1e()}};7 4e(z){d 2M=z;33.2l();k 7(z){E.2b([z[0]-2M[0],z[1]-2M[1]]);2M=z;J.1e()}};7 4b(T){1E(T){C\'n\':k\'1M\';C\'s\':k\'11\';C\'e\':k\'11\';C\'w\':k\'1s\';C\'1s\':k\'1M\';C\'11\':k\'2e\';C\'2e\':k\'11\';C\'1M\':k\'1s\'}};7 3b(T){k 7(e){1q=M;4a(T,2r(e));e.2k();e.2j();k K}};7 47($G,w,h){d 11=$G.W(),1H=$G.U();g((11>w)&&w>0){11=w;1H=(w/$G.W())*$G.U()}g((1H>h)&&h>0){1H=h;11=(h/$G.U())*$G.W()}1I=$G.W()/11;1Q=$G.U()/1H;$G.W(11).U(1H)};7 2H(c){k{x:1m(c.x*1I),y:1m(c.y*1Q),q:1m(c.q*1I),m:1m(c.m*1Q),w:1m(c.w*1I),h:1m(c.h*1Q)}};7 2P(z){d c=E.Q();g(c.w>j.3n[0]&&c.h>j.3n[1]){J.2t();J.1h()}1g{J.1r()}1j.1x(\'2X\')};7 48(e){1q=M;2u=2Q(G);J.1r();J.1o();46(\'2X\');E.1A(2r(e));1j.1G(4c,2P);33.2l();e.2k();e.2j();k K};7 4c(z){E.1y(z);J.1e()};7 2Z(a){d A=a[0],u=a[1],q=a[2],m=a[3];g(3h)k;d 2s=E.1F(A,u,q,m);d c=E.Q();d 18=2p=[c.x,c.y,c.q,c.m];d 3w=j.3V;d x=18[0];d y=18[1];d q=18[2];d m=18[3];d 3Z=2s[0]-2p[0];d 4m=2s[1]-2p[1];d 4n=2s[2]-2p[2];d 4l=2s[3]-2p[3];d 1c=0;d 4h=j.3X;J.2o(M);d 3u=7(){k 7(){1c+=(V-1c)/4h;18[0]=x+((1c/V)*3Z);18[1]=y+((1c/V)*4m);18[2]=q+((1c/V)*4n);18[3]=m+((1c/V)*4l);g(1c<V)32();1g J.1h();g(1c>=4K.8)1c=V;1d(18)}}();7 32(){4I.4t(3u,3w)};32()};7 1d(l){E.1A([l[0],l[1]]);E.1y([l[2],l[3]]);J.1e()};7 21(F){g(1p(F)!=\'2d\')F={};j=$.4X(j,F);g(1p(j.2D)!==\'7\')j.2D=7(){};g(1p(j.2G)!==\'7\')j.2G=7(){}};7 3m(){k 2H(E.Q())};7 2V(){k E.Q()};7 3E(F){21(F);g(\'1d\'1a F){1d(F.1d);J.1h()}};g(1p(F)!=\'2d\')F={};g(\'1d\'1a F){1d(F.1d);J.1h()}d 2q=j.2z[0]||0;d 2n=j.2z[1]||0;d 2m=j.2O[0]||0;d 2i=j.2O[1]||0;1j.1x(\'2X\');k{2Z:2Z,1d:1d,21:3E,3m:3m,2V:2V}};$.5e.1n=7(j){7 3G(1D){d 4d=j.4R||1D.2N;d I=4P 4S();d 1D=1D;I.50=7(){$(1D).1v().4A(I);1D.1n=$.1n(I,j)};I.2N=4d};g(1p(j)!==\'2d\')j={};1T.4J(7(){g(\'1n\'1a 1T){g(j==\'52\')k 1T.1n;1g 1T.1n.21(j)}1g 3G(1T)});k 1T};',62,325,'|||||||function||||||var|||if|||options|return||y2||||x2||||y1|||||pos|x1|css|case|px|Coords|opt|obj|handle|img|Selection|false|boundy|true|Math|break|left|getFixed|top|boundx|ord|height|100|width|delta|oy|ox||nw|div|yy||xx|position|abs|animat|mode|in|absolute|pcent|setSelect|update|addClass|else|done|hhs|Tracker|aspect|zIndex|parseInt|Jcrop|disableHandles|typeof|btndown|release|ne|pct|type|hide|show|setCursor|setCurrent|opacity|setPressed|aspectLock|fc|from|switch|flipCoords|activateHandlers|nh|xscale|jq|round|cssClass|sw|move|shift_down|append|yscale|awake|trk|this|xsize|rw|insertDragbar|south|insertBorder|rh||setOptions|ysize|bound|keymgr|aspectRatio|trackUp||sel|doNudge|east|moveOffset|keySupport|object|se|watchShift|hdl_holder|nudge|ymin|preventDefault|stopPropagation|watchKeys|xmin|ylimit|animMode|initcr|xlimit|mouseAbs|animto|enableHandles|docOffset|onDone|onMove|trackDocument|offset|maxSize|resize|trackMove|img_holder|onChange|seehandles|borders|onSelect|unscale|updateVisible|li|getCorner|trackDoc|lloc|src|minSize|doneSelect|getPos|xa|mouseup|rebound|hdep|tellScaled|dragDiv|crosshair|createHandles|animateTo|drawBorders|moveHandles|animateStart|KeyManager|img2|midhoriz|trueSize||||midvert|createDragger|rwa|browser|msie|getOffset|makeObj|animating|lastcurs|rha|mousemove|yb|tellSelect|minSelect|ya|cursor|mousedown|xb|refresh|document|animator|tracker|interv|bgOpacity|zi|vline|dragEdges|sideHandles|hline|handleOffset|setOptionsNew|getRect|attachWhenDone|unbind|cornerHandles|insertHandle|moveto|right|real_ratio|handleSize|borderOpacity|handleOpacity|bottom|290|keywrap|bgColor|insertBefore|animationDelay|baseClass|swingSpeed|attr|ix1||onBlur|init_shift|parseKey|cl|dragmodeHandler|myCursor|presize|newSelection|boxWidth|startDragMode|oppLockCorner|selectDrag|loadsrc|createMover|defaults|hidden|velocity|toBack|toFront|boundary|iy2|iy1|ix2|overflow|boxHeight|pageX|pageY|before|setTimeout|max|start|input|370|dragmode|end|after|backgroundColor|jcrop|null|last|holder|450|relative|window|each|99|radio|360|mouseout|30px|new|shiftKey|useImg|Image|ctrlKey|for|north|west|extend|black|focus|onload|edgeMargin|api|handlePad|wrap|300|keyup|keydown|dimmed|310|blur|320|min|keyCode|fn'.split('|'),0,{}))
diff --git a/js/userdesign.go.js b/js/userdesign.go.js
index dda86294e..eb4dece09 100644
--- a/js/userdesign.go.js
+++ b/js/userdesign.go.js
@@ -1,12 +1,43 @@
/** Init for Farbtastic library and page setup
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
$(document).ready(function() {
+ function InitColors(i, E) {
+ switch (parseInt(E.id.slice(-1))) {
+ case 1: default:
+ $(E).val(rgb2hex($('body').css('background-color')));
+ break;
+ case 2:
+ $(E).val(rgb2hex($('#content').css('background-color')));
+ break;
+ case 3:
+ $(E).val(rgb2hex($('#aside_primary').css('background-color')));
+ break;
+ case 4:
+ $(E).val(rgb2hex($('html body').css('color')));
+ break;
+ case 5:
+ $(E).val(rgb2hex($('a').css('color')));
+ break;
+ }
+ }
+
+ function rgb2hex(rgb) {
+ if (rgb.slice(0,1) == '#') { return rgb; }
+ rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
+ return '#' + dec2hex(rgb[1]) + dec2hex(rgb[2]) + dec2hex(rgb[3]);
+ }
+ /* dec2hex written by R0bb13 <robertorebollo@gmail.com> */
+ function dec2hex(x) {
+ hexDigits = new Array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
+ return isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
+ }
+
function UpdateColors(S) {
C = $(S).val();
switch (parseInt(S.id.slice(-1))) {
@@ -55,7 +86,7 @@ $(document).ready(function() {
f = $.farbtastic('#color-picker', SynchColors);
swatches = $('#settings_design_color .swatch');
-
+ swatches.each(InitColors);
swatches
.each(SynchColors)
.blur(function() {
diff --git a/js/util.js b/js/util.js
index f3ed918cf..2165957c3 100644
--- a/js/util.js
+++ b/js/util.js
@@ -1,6 +1,6 @@
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2008, StatusNet, Inc.
*
* 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
@@ -17,26 +17,51 @@
*/
$(document).ready(function(){
+ var counterBlackout = false;
+
// count character on keyup
function counter(event){
var maxLength = 140;
var currentLength = $("#notice_data-text").val().length;
var remaining = maxLength - currentLength;
var counter = $("#notice_text-count");
- counter.text(remaining);
+
+ if (remaining.toString() != counter.text()) {
+ if (!counterBlackout || remaining == 0) {
+ if (counter.text() != String(remaining)) {
+ counter.text(remaining);
+ }
- if (remaining <= 0) {
- $("#form_notice").addClass("warning");
- } else {
- $("#form_notice").removeClass("warning");
- }
+ if (remaining < 0) {
+ $("#form_notice").addClass("warning");
+ } else {
+ $("#form_notice").removeClass("warning");
+ }
+ // Skip updates for the next 500ms.
+ // On slower hardware, updating on every keypress is unpleasant.
+ if (!counterBlackout) {
+ counterBlackout = true;
+ window.setTimeout(clearCounterBlackout, 500);
+ }
+ }
+ }
+ }
+
+ function clearCounterBlackout() {
+ // Allow keyup events to poke the counter again
+ counterBlackout = false;
+ // Check if the string changed since we last looked
+ counter(null);
}
function submitonreturn(event) {
- if (event.keyCode == 13) {
+ if (event.keyCode == 13 || event.keyCode == 10) {
+ // iPhone sends \n not \r for 'return'
$("#form_notice").submit();
event.preventDefault();
event.stopPropagation();
+ $("#notice_data-text").blur();
+ $("body").focus();
return false;
}
return true;
@@ -57,6 +82,10 @@ $(document).ready(function(){
// XXX: refactor this code
var favoptions = { dataType: 'xml',
+ beforeSubmit: function(data, target, options) {
+ $(target).addClass('processing');
+ return true;
+ },
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
var dis = new_form.id;
var fav = dis.replace('disfavor', 'favor');
@@ -66,6 +95,10 @@ $(document).ready(function(){
};
var disoptions = { dataType: 'xml',
+ beforeSubmit: function(data, target, options) {
+ $(target).addClass('processing');
+ return true;
+ },
success: function(xml) { var new_form = document._importNode($('form', xml).get(0), true);
var fav = new_form.id;
var dis = fav.replace('favor', 'disfavor');
@@ -244,7 +277,7 @@ function NoticeReply() {
$('#content .notice').each(function() {
var notice = $(this)[0];
$($('.notice_reply', notice)[0]).click(function() {
- var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname');
+ var nickname = ($('.author .nickname', notice).length > 0) ? $($('.author .nickname', notice)[0]) : $('.author .nickname.uid');
NoticeReplySet(nickname.text(), $($('.notice_id', notice)[0]).text());
return false;
});
@@ -255,11 +288,16 @@ function NoticeReply() {
function NoticeReplySet(nick,id) {
rgx_username = /^[0-9a-zA-Z\-_.]*$/;
if (nick.match(rgx_username)) {
- replyto = "@" + nick + " ";
- if ($("#notice_data-text").length) {
- $("#notice_data-text").val(replyto);
+ var text = $("#notice_data-text");
+ if (text.length) {
+ replyto = "@" + nick + " ";
+ text.val(replyto + text.val().replace(RegExp(replyto, 'i'), ''));
$("#form_notice input#notice_in-reply-to").val(id);
- $("#notice_data-text").focus();
+ if (text.get(0).setSelectionRange) {
+ var len = text.val().length;
+ text.get(0).setSelectionRange(len,len);
+ text.get(0).focus();
+ }
return false;
}
}
diff --git a/lib/Shorturl_api.php b/lib/Shorturl_api.php
index 22d5b4cb5..6402dbc09 100644
--- a/lib/Shorturl_api.php
+++ b/lib/Shorturl_api.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class ShortUrlApi
{
diff --git a/lib/accountsettingsaction.php b/lib/accountsettingsaction.php
index 4ab50abce..798116163 100644
--- a/lib/accountsettingsaction.php
+++ b/lib/accountsettingsaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for account settings actions
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/settingsaction.php';
* Base class for account settings actions
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
@@ -66,10 +66,10 @@ class AccountSettingsAction extends SettingsAction
* A widget for showing the settings group local nav menu
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
@@ -126,6 +126,10 @@ class AccountSettingsNav extends Widget
$this->action->elementStart('ul', array('class' => 'nav'));
foreach ($menu as $menuaction => $menudesc) {
+ if ($menuaction == 'openidsettings' &&
+ !common_config('openid', 'enabled')) {
+ continue;
+ }
$this->action->menuItem(common_local_url($menuaction),
$menudesc[0],
$menudesc[1],
diff --git a/lib/action.php b/lib/action.php
index 95ee10c64..670eb498c 100644
--- a/lib/action.php
+++ b/lib/action.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for all actions (~views)
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -45,11 +45,11 @@ require_once INSTALLDIR.'/lib/htmloutputter.php';
* model classes to read and write to the database; and doing ouput.
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
@@ -191,38 +191,50 @@ class Action extends HTMLOutputter // lawsuit
function showStylesheets()
{
if (Event::handle('StartShowStyles', array($this))) {
- if (Event::handle('StartShowLaconicaStyles', array($this))) {
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION,
- 'media' => 'screen, projection, tv'));
+
+ // Use old name for StatusNet for compatibility on events
+
+ if (Event::handle('StartShowStatusNetStyles', array($this)) &&
+ Event::handle('StartShowLaconicaStyles', array($this))) {
+ $this->cssLink('css/display.css',null,'screen, projection, tv');
if (common_config('site', 'mobile')) {
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => theme_path('css/mobile.css', 'base') . '?version=' . LACONICA_VERSION,
- // TODO: "handheld" CSS for other mobile devices
- 'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit
+ // TODO: "handheld" CSS for other mobile devices
+ $this->cssLink('css/mobile.css','base','only screen and (max-device-width: 480px)'); // Mobile WebKit
}
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => theme_path('css/print.css', 'base') . '?version=' . LACONICA_VERSION,
- 'media' => 'print'));
+ $this->cssLink('css/print.css','base','print');
+ Event::handle('EndShowStatusNetStyles', array($this));
Event::handle('EndShowLaconicaStyles', array($this));
}
+
if (Event::handle('StartShowUAStyles', array($this))) {
$this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
- 'href="'.theme_path('css/ie.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
+ 'href="'.theme_path('css/ie.css', 'base').'?version='.STATUSNET_VERSION.'" /><![endif]');
foreach (array(6,7) as $ver) {
if (file_exists(theme_file('css/ie'.$ver.'.css', 'base'))) {
// Yes, IE people should be put in jail.
$this->comment('[if lte IE '.$ver.']><link rel="stylesheet" type="text/css" '.
- 'href="'.theme_path('css/ie'.$ver.'.css', 'base').'?version='.LACONICA_VERSION.'" /><![endif]');
+ 'href="'.theme_path('css/ie'.$ver.'.css', 'base').'?version='.STATUSNET_VERSION.'" /><![endif]');
}
}
$this->comment('[if IE]><link rel="stylesheet" type="text/css" '.
- 'href="'.theme_path('css/ie.css', null).'?version='.LACONICA_VERSION.'" /><![endif]');
+ 'href="'.theme_path('css/ie.css', null).'?version='.STATUSNET_VERSION.'" /><![endif]');
Event::handle('EndShowUAStyles', array($this));
}
+
+ if (Event::handle('StartShowDesign', array($this))) {
+
+ $user = common_current_user();
+
+ if (empty($user) || $user->viewdesigns) {
+ $design = $this->getDesign();
+
+ if (!empty($design)) {
+ $design->showCSS($this);
+ }
+ }
+
+ Event::handle('EndShowDesign', array($this));
+ }
Event::handle('EndShowStyles', array($this));
}
}
@@ -236,29 +248,19 @@ class Action extends HTMLOutputter // lawsuit
{
if (Event::handle('StartShowScripts', array($this))) {
if (Event::handle('StartShowJQueryScripts', array($this))) {
- $this->element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/jquery.min.js')),
- ' ');
- $this->element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/jquery.form.js')),
- ' ');
-
- $this->element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/jquery.joverlay.min.js')),
- ' ');
-
+ $this->script('js/jquery.min.js');
+ $this->script('js/jquery.form.js');
+ $this->script('js/jquery.joverlay.min.js');
Event::handle('EndShowJQueryScripts', array($this));
}
- if (Event::handle('StartShowLaconicaScripts', array($this))) {
- $this->element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/xbImportNode.js')),
- ' ');
- $this->element('script', array('type' => 'text/javascript',
- 'src' => common_path('js/util.js?version='.LACONICA_VERSION)),
- ' ');
+ if (Event::handle('StartShowStatusNetScripts', array($this)) &&
+ Event::handle('StartShowLaconicaScripts', array($this))) {
+ $this->script('js/xbImportNode.js');
+ $this->script('js/util.js');
// Frame-busting code to avoid clickjacking attacks.
$this->element('script', array('type' => 'text/javascript'),
'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
+ Event::handle('EndShowStatusNetScripts', array($this));
Event::handle('EndShowLaconicaScripts', array($this));
}
Event::handle('EndShowScripts', array($this));
@@ -406,6 +408,14 @@ class Action extends HTMLOutputter // lawsuit
function showPrimaryNav()
{
$user = common_current_user();
+ $connect = '';
+ if (common_config('xmpp', 'enabled')) {
+ $connect = 'imsettings';
+ } else if (common_config('sms', 'enabled')) {
+ $connect = 'smssettings';
+ } else if (common_config('twitter', 'enabled')) {
+ $connect = 'twittersettings';
+ }
$this->elementStart('dl', array('id' => 'site_nav_global_primary'));
$this->element('dt', null, _('Primary site navigation'));
@@ -417,12 +427,9 @@ class Action extends HTMLOutputter // lawsuit
_('Home'), _('Personal profile and friends timeline'), false, 'nav_home');
$this->menuItem(common_local_url('profilesettings'),
_('Account'), _('Change your email, avatar, password, profile'), false, 'nav_account');
- if (common_config('xmpp', 'enabled')) {
- $this->menuItem(common_local_url('imsettings'),
- _('Connect'), _('Connect to IM, SMS, Twitter'), false, 'nav_connect');
- } else {
- $this->menuItem(common_local_url('smssettings'),
- _('Connect'), _('Connect to SMS, Twitter'), false, 'nav_connect');
+ if ($connect) {
+ $this->menuItem(common_local_url($connect),
+ _('Connect'), _('Connect to services'), false, 'nav_connect');
}
if (common_config('invite', 'enabled')) {
$this->menuItem(common_local_url('invite'),
@@ -435,17 +442,24 @@ class Action extends HTMLOutputter // lawsuit
_('Logout'), _('Logout from the site'), false, 'nav_logout');
}
else {
- if (!common_config('site', 'closed')) {
- $this->menuItem(common_local_url('register'),
- _('Register'), _('Create an account'), false, 'nav_register');
+ if (!common_config('site', 'openidonly')) {
+ if (!common_config('site', 'closed')) {
+ $this->menuItem(common_local_url('register'),
+ _('Register'), _('Create an account'), false, 'nav_register');
+ }
+ $this->menuItem(common_local_url('login'),
+ _('Login'), _('Login to the site'), false, 'nav_login');
+ } else {
+ $this->menuItem(common_local_url('openidlogin'),
+ _('OpenID'), _('Login with OpenID'), false, 'nav_openid');
}
- $this->menuItem(common_local_url('login'),
- _('Login'), _('Login to the site'), false, 'nav_login');
}
$this->menuItem(common_local_url('doc', array('title' => 'help')),
_('Help'), _('Help me!'), false, 'nav_help');
- $this->menuItem(common_local_url('peoplesearch'),
- _('Search'), _('Search for people or text'), false, 'nav_search');
+ if ($user || !common_config('site', 'private')) {
+ $this->menuItem(common_local_url('peoplesearch'),
+ _('Search'), _('Search for people or text'), false, 'nav_search');
+ }
Event::handle('EndPrimaryNav', array($this));
}
$this->elementEnd('ul');
@@ -734,26 +748,26 @@ class Action extends HTMLOutputter // lawsuit
function showLicenses()
{
$this->elementStart('dl', array('id' => 'licenses'));
- $this->showLaconicaLicense();
+ $this->showStatusNetLicense();
$this->showContentLicense();
$this->elementEnd('dl');
}
/**
- * Show Laconica license.
+ * Show StatusNet license.
*
* @return nothing
*/
- function showLaconicaLicense()
+ function showStatusNetLicense()
{
- $this->element('dt', array('id' => 'site_laconica_license'), _('Laconica software license'));
+ $this->element('dt', array('id' => 'site_statusnet_license'), _('StatusNet software license'));
$this->elementStart('dd', null);
if (common_config('site', 'broughtby')) {
$instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%). ');
} else {
$instr = _('**%%site.name%%** is a microblogging service. ');
}
- $instr .= sprintf(_('It runs the [Laconica](http://laconi.ca/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), LACONICA_VERSION);
+ $instr .= sprintf(_('It runs the [StatusNet](http://status.net/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), STATUSNET_VERSION);
$output = common_markup_to_html($instr);
$this->raw($output);
$this->elementEnd('dd');
@@ -767,7 +781,7 @@ class Action extends HTMLOutputter // lawsuit
*/
function showContentLicense()
{
- $this->element('dt', array('id' => 'site_content_license'), _('Laconica software license'));
+ $this->element('dt', array('id' => 'site_content_license'), _('Site content license'));
$this->elementStart('dd', array('id' => 'site_content_license_cc'));
$this->elementStart('p');
$this->element('img', array('id' => 'license_cc',
@@ -867,6 +881,7 @@ class Action extends HTMLOutputter // lawsuit
*/
function handle($argarray=null)
{
+ header('Vary: Accept-Encoding,Cookie');
$lm = $this->lastModified();
$etag = $this->etag();
if ($etag) {
@@ -1074,4 +1089,15 @@ class Action extends HTMLOutputter // lawsuit
{
return null;
}
+
+ /**
+ * A design for this action
+ *
+ * @return Design a design object to use
+ */
+
+ function getDesign()
+ {
+ return Design::siteDesign();
+ }
}
diff --git a/lib/arraywrapper.php b/lib/arraywrapper.php
index a8a12b3bb..8a1cdd96e 100644
--- a/lib/arraywrapper.php
+++ b/lib/arraywrapper.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -25,12 +25,14 @@ class ArrayWrapper
{
var $_items = null;
var $_count = 0;
+ var $N = 0;
var $_i = -1;
function __construct($items)
{
$this->_items = $items;
$this->_count = count($this->_items);
+ $this->N = $this->_count;
}
function fetch()
@@ -76,4 +78,4 @@ class ArrayWrapper
$item =& $this->_items[$this->_i];
return call_user_func_array(array($item, $name), $args);
}
-} \ No newline at end of file
+}
diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php
index f6a1b59d0..51ceca857 100644
--- a/lib/attachmentlist.php
+++ b/lib/attachmentlist.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* widget for displaying a list of notice attachments
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category UI
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,10 +41,10 @@ if (!defined('LACONICA')) {
* data for e.g. the profile page.
*
* @category UI
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see Notice
* @see NoticeListItem
* @see ProfileNoticeList
@@ -127,10 +127,10 @@ class AttachmentList extends Widget
* author info (since that's implicit by the data in the page).
*
* @category UI
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see NoticeList
* @see ProfileNoticeListItem
*/
@@ -340,7 +340,12 @@ class Attachment extends AttachmentListItem
case 'video':
case 'link':
if (!empty($this->oembed->html)) {
- $this->out->raw($this->oembed->html);
+ require_once INSTALLDIR.'/extlib/htmLawed/htmLawed.php';
+ $config = array(
+ 'safe'=>1,
+ 'elements'=>'*+object+embed');
+ $this->out->raw(htmLawed($this->oembed->html,$config));
+ //$this->out->raw($this->oembed->html);
}
break;
diff --git a/lib/attachmentnoticesection.php b/lib/attachmentnoticesection.php
index eb3176376..578c171ff 100644
--- a/lib/attachmentnoticesection.php
+++ b/lib/attachmentnoticesection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* FIXME
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ if (!defined('LACONICA')) {
* These are the widgets that show interesting data about a person * group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AttachmentNoticeSection extends NoticeSection
diff --git a/lib/attachmenttagcloudsection.php b/lib/attachmenttagcloudsection.php
index 50bfceccb..e2f85ae02 100644
--- a/lib/attachmenttagcloudsection.php
+++ b/lib/attachmenttagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Attachment tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Attachment tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AttachmentTagCloudSection extends TagCloudSection
diff --git a/lib/blockform.php b/lib/blockform.php
index af766b823..4820d09af 100644
--- a/lib/blockform.php
+++ b/lib/blockform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for blocking a user
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for blocking a user
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see UnblockForm
*/
diff --git a/lib/channel.php b/lib/channel.php
index 38c1d4d67..3cd168786 100644
--- a/lib/channel.php
+++ b/lib/channel.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class Channel
{
diff --git a/lib/clienterroraction.php b/lib/clienterroraction.php
index 7ddc35eb6..1b98a1064 100644
--- a/lib/clienterroraction.php
+++ b/lib/clienterroraction.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,35 +39,35 @@ require_once INSTALLDIR.'/lib/error.php';
* Class for displaying HTTP client errors
*
* @category Action
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ClientErrorAction extends ErrorAction
{
+ static $status = array(400 => 'Bad Request',
+ 401 => 'Unauthorized',
+ 402 => 'Payment Required',
+ 403 => 'Forbidden',
+ 404 => 'Not Found',
+ 405 => 'Method Not Allowed',
+ 406 => 'Not Acceptable',
+ 407 => 'Proxy Authentication Required',
+ 408 => 'Request Timeout',
+ 409 => 'Conflict',
+ 410 => 'Gone',
+ 411 => 'Length Required',
+ 412 => 'Precondition Failed',
+ 413 => 'Request Entity Too Large',
+ 414 => 'Request-URI Too Long',
+ 415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed');
+
function __construct($message='Error', $code=400)
{
parent::__construct($message, $code);
-
- $this->status = array(400 => 'Bad Request',
- 401 => 'Unauthorized',
- 402 => 'Payment Required',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Request Entity Too Large',
- 414 => 'Request-URI Too Long',
- 415 => 'Unsupported Media Type',
- 416 => 'Requested Range Not Satisfiable',
- 417 => 'Expectation Failed');
$this->default = 400;
}
@@ -91,9 +91,4 @@ class ClientErrorAction extends ErrorAction
$this->showPage();
}
-
- function title()
- {
- return $this->status[$this->code];
- }
}
diff --git a/lib/clientexception.php b/lib/clientexception.php
index 3020d7f50..01c013a01 100644
--- a/lib/clientexception.php
+++ b/lib/clientexception.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* class for a client exception (user error)
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Exception
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ if (!defined('LACONICA')) {
* Subclass of PHP Exception for user errors.
*
* @category Exception
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ClientException extends Exception
diff --git a/lib/command.php b/lib/command.php
index 4e2280bc8..01b14f83e 100644
--- a/lib/command.php
+++ b/lib/command.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/channel.php');
@@ -114,7 +114,6 @@ class StatsCommand extends Command
class FavCommand extends Command
{
-
var $other = null;
function __construct($user, $other)
@@ -158,6 +157,108 @@ class FavCommand extends Command
$channel->output($this->user, _('Notice marked as fave.'));
}
+
+}
+class JoinCommand extends Command
+{
+ var $other = null;
+
+ function __construct($user, $other)
+ {
+ parent::__construct($user);
+ $this->other = $other;
+ }
+
+ function execute($channel)
+ {
+
+ $nickname = common_canonical_nickname($this->other);
+ $group = User_group::staticGet('nickname', $nickname);
+ $cur = $this->user;
+
+ if (!$group) {
+ $channel->error($cur, _('No such group.'));
+ return;
+ }
+
+ if ($cur->isMember($group)) {
+ $channel->error($cur, _('You are already a member of that group'));
+ return;
+ }
+ if (Group_block::isBlocked($group, $cur->getProfile())) {
+ $channel->error($cur, _('You have been blocked from that group by the admin.'));
+ return;
+ }
+
+ $member = new Group_member();
+
+ $member->group_id = $group->id;
+ $member->profile_id = $cur->id;
+ $member->created = common_sql_now();
+
+ $result = $member->insert();
+ if (!$result) {
+ common_log_db_error($member, 'INSERT', __FILE__);
+ $channel->error($cur, sprintf(_('Could not join user %s to group %s'),
+ $cur->nickname, $group->nickname));
+ return;
+ }
+
+ $channel->output($cur, sprintf(_('%s joined group %s'),
+ $cur->nickname,
+ $group->nickname));
+ }
+
+}
+class DropCommand extends Command
+{
+ var $other = null;
+
+ function __construct($user, $other)
+ {
+ parent::__construct($user);
+ $this->other = $other;
+ }
+
+ function execute($channel)
+ {
+
+ $nickname = common_canonical_nickname($this->other);
+ $group = User_group::staticGet('nickname', $nickname);
+ $cur = $this->user;
+
+ if (!$group) {
+ $channel->error($cur, _('No such group.'));
+ return;
+ }
+
+ if (!$cur->isMember($group)) {
+ $channel->error($cur, _('You are not a member of that group.'));
+ return;
+ }
+
+ $member = new Group_member();
+
+ $member->group_id = $group->id;
+ $member->profile_id = $cur->id;
+
+ if (!$member->find(true)) {
+ $channel->error($cur,_('Could not find membership record.'));
+ return;
+ }
+ $result = $member->delete();
+ if (!$result) {
+ common_log_db_error($member, 'INSERT', __FILE__);
+ $channel->error($cur, sprintf(_('Could not remove user %s to group %s'),
+ $cur->nickname, $group->nickname));
+ return;
+ }
+
+ $channel->output($cur, sprintf(_('%s left group %s'),
+ $cur->nickname,
+ $group->nickname));
+ }
+
}
class WhoisCommand extends Command
@@ -392,6 +493,8 @@ class HelpCommand extends Command
"get <nickname> - get last notice from user\n".
"whois <nickname> - get profile info on user\n".
"fav <nickname> - add user's last notice as a 'fave'\n".
+ "join <group> - join group\n".
+ "drop <group> - leave group\n".
"stats - get your stats\n".
"stop - same as 'off'\n".
"quit - same as 'off'\n".
diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php
index 6538d4442..6e4340e5d 100644
--- a/lib/commandinterpreter.php
+++ b/lib/commandinterpreter.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/lib/command.php';
@@ -33,7 +33,7 @@ class CommandInterpreter
# We try to support all the same commands as Twitter, see
# http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands
# There are a few compatibility commands from earlier versions of
- # Laconica
+ # StatusNet
switch(strtolower($cmd)) {
case 'help':
@@ -70,6 +70,26 @@ class CommandInterpreter
} else {
return new OffCommand($user);
}
+ case 'join':
+ if (!$arg) {
+ return null;
+ }
+ list($other, $extra) = explode(' ', $arg, 2);
+ if ($extra) {
+ return null;
+ } else {
+ return new JoinCommand($user, $other);
+ }
+ case 'drop':
+ if (!$arg) {
+ return null;
+ }
+ list($other, $extra) = explode(' ', $arg, 2);
+ if ($extra) {
+ return null;
+ } else {
+ return new DropCommand($user, $other);
+ }
case 'follow':
case 'sub':
if (!$arg) {
diff --git a/lib/common.php b/lib/common.php
index 9d7954fa9..88d77732f 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,9 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-define('LACONICA_VERSION', '0.8.1dev');
+define('STATUSNET_VERSION', '0.8.2dev');
+define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
+
+define('STATUSNET_CODENAME', 'Second Guessing');
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
@@ -47,6 +50,9 @@ require_once('PEAR.php');
require_once('DB/DataObject.php');
require_once('DB/DataObject/Cast.php'); # for dates
+if (!function_exists('gettext')) {
+ require_once("php-gettext/gettext.inc");
+}
require_once(INSTALLDIR.'/lib/language.php');
// This gets included before the config file, so that admin code and plugins
@@ -82,7 +88,7 @@ if (isset($server)) {
if (isset($path)) {
$_path = $path;
} else {
- $_path = array_key_exists('SCRIPT_NAME', $_SERVER) ?
+ $_path = (array_key_exists('SERVER_NAME', $_SERVER) && array_key_exists('SCRIPT_NAME', $_SERVER)) ?
_sn_to_path($_SERVER['SCRIPT_NAME']) :
null;
}
@@ -91,17 +97,9 @@ if (isset($path)) {
$config =
array('site' =>
- array('name' => 'Just another Laconica microblog',
+ array('name' => 'Just another StatusNet microblog',
'server' => $_server,
'theme' => 'default',
- 'design' =>
- array('backgroundcolor' => '#CEE1E9',
- 'contentcolor' => '#FFFFFF',
- 'sidebarcolor' => '#C8D1D5',
- 'textcolor' => '#000000',
- 'linkcolor' => '#002E6E',
- 'backgroundimage' => null,
- 'disposition' => 1),
'path' => $_path,
'logfile' => null,
'logo' => null,
@@ -117,20 +115,21 @@ $config =
'broughtbyurl' => null,
'closed' => false,
'inviteonly' => false,
+ 'openidonly' => false,
'private' => false,
'ssl' => 'never',
'sslserver' => null,
'shorturllength' => 30,
'dupelimit' => 60), # default for same person saying the same thing
'syslog' =>
- array('appname' => 'laconica', # for syslog
+ array('appname' => 'statusnet', # for syslog
'priority' => 'debug', # XXX: currently ignored
'facility' => LOG_USER),
'queue' =>
array('enabled' => false,
'subsystem' => 'db', # default to database, or 'stomp'
'stomp_server' => null,
- 'queue_basename' => 'laconica',
+ 'queue_basename' => 'statusnet',
'stomp_username' => null,
'stomp_password' => null,
),
@@ -177,6 +176,8 @@ $config =
'host' => null, # only set if != server
'debug' => false, # print extra debug info
'public' => array()), # JIDs of users who want to receive the public stream
+ 'openid' =>
+ array('enabled' => true),
'invite' =>
array('enabled' => true),
'sphinx' =>
@@ -191,11 +192,20 @@ $config =
array('piddir' => '/var/run',
'user' => false,
'group' => false),
+ 'emailpost' =>
+ array('enabled' => true),
+ 'sms' =>
+ array('enabled' => true),
+ 'twitter' =>
+ array('enabled' => true),
'twitterbridge' =>
array('enabled' => false),
'integration' =>
- array('source' => 'Laconica', # source attribute for Twitter
+ array('source' => 'StatusNet', # source attribute for Twitter
'taguri' => $_server.',2009'), # base for tag URIs
+ 'twitter' =>
+ array('consumer_key' => null,
+ 'consumer_secret' => null),
'memcached' =>
array('enabled' => false,
'server' => 'localhost',
@@ -211,7 +221,7 @@ $config =
'snapshot' =>
array('run' => 'web',
'frequency' => 10000,
- 'reporturl' => 'http://laconi.ca/stats/report'),
+ 'reporturl' => 'http://status.net/stats/report'),
'attachments' =>
array('server' => null,
'dir' => INSTALLDIR . '/file/',
@@ -261,6 +271,14 @@ $config =
'sessions' =>
array('handle' => false, // whether to handle sessions ourselves
'debug' => false), // debugging output for sessions
+ 'design' =>
+ array('backgroundcolor' => null, // null -> 'use theme default'
+ 'contentcolor' => null,
+ 'sidebarcolor' => null,
+ 'textcolor' => null,
+ 'linkcolor' => null,
+ 'backgroundimage' => null,
+ 'disposition' => null),
);
$config['db'] = &PEAR::getStaticProperty('DB_DataObject','options');
@@ -277,6 +295,10 @@ $config['db'] =
'quote_identifiers' => false,
'type' => 'mysql' );
+// Backward compatibility
+
+$config['site']['design'] =& $config['design'];
+
if (function_exists('date_default_timezone_set')) {
/* Work internally in UTC */
date_default_timezone_set('UTC');
@@ -322,10 +344,14 @@ function addPlugin($name, $attrs = null)
if (isset($conffile)) {
$_config_files = array($conffile);
} else {
- $_config_files = array('/etc/laconica/laconica.php',
+ $_config_files = array('/etc/statusnet/statusnet.php',
+ '/etc/statusnet/laconica.php',
+ '/etc/laconica/laconica.php',
+ '/etc/statusnet/'.$_server.'.php',
'/etc/laconica/'.$_server.'.php');
if (strlen($_path) > 0) {
+ $_config_files[] = '/etc/statusnet/'.$_server.'_'.$_path.'.php';
$_config_files[] = '/etc/laconica/'.$_server.'_'.$_path.'.php';
}
@@ -349,12 +375,18 @@ function _have_config()
// XXX: Throw a conniption if database not installed
-// Fixup for laconica.ini
+// Fixup for statusnet.ini
$_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1);
-if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db'])) {
- $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/laconica.ini';
+if ($_db_name != 'statusnet' && !array_key_exists('ini_'.$_db_name, $config['db'])) {
+ $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/statusnet.ini';
+}
+
+// Ignore openidonly if OpenID is disabled
+
+if (!$config['openid']['enabled']) {
+ $config['site']['openidonly'] = false;
}
// XXX: how many of these could be auto-loaded on use?
diff --git a/lib/connectsettingsaction.php b/lib/connectsettingsaction.php
index 30629680e..2095a7ceb 100644
--- a/lib/connectsettingsaction.php
+++ b/lib/connectsettingsaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for connection settings actions
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/settingsaction.php';
* Base class for connection settings actions
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
@@ -66,10 +66,10 @@ class ConnectSettingsAction extends SettingsAction
* A widget for showing the connect group local nav menu
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
@@ -99,25 +99,27 @@ class ConnectSettingsNav extends Widget
function show()
{
# action => array('prompt', 'title')
- $menu =
- array('imsettings' =>
- array(_('IM'),
- _('Updates by instant messenger (IM)')),
- 'smssettings' =>
- array(_('SMS'),
- _('Updates by SMS')),
- 'twittersettings' =>
- array(_('Twitter'),
- _('Twitter integration options')));
+ $menu = array();
+ if (common_config('xmpp', 'enabled')) {
+ $menu['imsettings'] =
+ array(_('IM'),
+ _('Updates by instant messenger (IM)'));
+ }
+ if (common_config('sms', 'enabled')) {
+ $menu['smssettings'] =
+ array(_('SMS'),
+ _('Updates by SMS'));
+ }
+ if (common_config('twitter', 'enabled')) {
+ $menu['twittersettings'] =
+ array(_('Twitter'),
+ _('Twitter integration options'));
+ }
$action_name = $this->action->trimmed('action');
$this->action->elementStart('ul', array('class' => 'nav'));
foreach ($menu as $menuaction => $menudesc) {
- if ($menuaction == 'imsettings' &&
- !common_config('xmpp', 'enabled')) {
- continue;
- }
$this->action->menuItem(common_local_url($menuaction),
$menudesc[0],
$menudesc[1],
diff --git a/lib/currentuserdesignaction.php b/lib/currentuserdesignaction.php
index 4c7e15a8b..c2f38cd00 100644
--- a/lib/currentuserdesignaction.php
+++ b/lib/currentuserdesignaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for actions that use the current user's design
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,42 +38,19 @@ if (!defined('LACONICA')) {
* design. This superclass returns that design.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
*/
class CurrentUserDesignAction extends Action
{
-
- /**
- * Show the user's design stylesheet
- *
- * @return nothing
- */
-
- function showStylesheets()
- {
- parent::showStylesheets();
-
- $user = common_current_user();
-
- if (empty($user) || $user->viewdesigns) {
- $design = $this->getDesign();
-
- if (!empty($design)) {
- $design->showCSS($this);
- }
- }
- }
-
/**
* A design for this action
*
- * if the user attribute has been set, returns that user's
- * design.
+ * Returns the design preferences for the current user.
*
* @return Design a design object to use
*/
@@ -82,11 +59,15 @@ class CurrentUserDesignAction extends Action
{
$cur = common_current_user();
- if (empty($cur)) {
- return null;
+ if (!empty($cur)) {
+
+ $design = $cur->getDesign();
+
+ if (!empty($design)) {
+ return $design;
+ }
}
- return $cur->getDesign();
+ return parent::getDesign();
}
-
}
diff --git a/lib/daemon.php b/lib/daemon.php
index 231f5414e..4c2491e97 100644
--- a/lib/daemon.php
+++ b/lib/daemon.php
@@ -1,7 +1,7 @@
<?php
/**
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/lib/dberroraction.php b/lib/dberroraction.php
index a04e5f74f..2cb66a022 100644
--- a/lib/dberroraction.php
+++ b/lib/dberroraction.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -42,10 +42,10 @@ require_once INSTALLDIR.'/lib/servererroraction.php';
* to the DB, so we don't trigger it again.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class DBErrorAction extends ServerErrorAction
diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php
index 19aa9f3ae..750300928 100644
--- a/lib/dbqueuemanager.php
+++ b/lib/dbqueuemanager.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Simple-minded queue manager for storing items in the database
*
@@ -20,11 +20,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category QueueManager
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class DBQueueManager extends QueueManager
diff --git a/lib/deleteaction.php b/lib/deleteaction.php
index 91c6487a9..f702820c6 100644
--- a/lib/deleteaction.php
+++ b/lib/deleteaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for deleting things
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/lib/designsettings.php b/lib/designsettings.php
index fbffdb208..820d534f2 100644
--- a/lib/designsettings.php
+++ b/lib/designsettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Change user password
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -42,11 +42,11 @@ require_once INSTALLDIR . '/lib/webcolor.php';
* background images, and fetching a default design
*
* @category Settings
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class DesignSettingsAction extends AccountSettingsAction
@@ -182,7 +182,7 @@ class DesignSettingsAction extends AccountSettingsAction
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
- 'value' => '#' . $bgcolor->hexValue()));
+ 'value' => ''));
$this->elementEnd('li');
$ccolor = new WebColor($design->contentcolor);
@@ -195,7 +195,7 @@ class DesignSettingsAction extends AccountSettingsAction
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
- 'value' => '#' . $ccolor->hexValue()));
+ 'value' => ''));
$this->elementEnd('li');
$sbcolor = new WebColor($design->sidebarcolor);
@@ -208,7 +208,7 @@ class DesignSettingsAction extends AccountSettingsAction
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
- 'value' => '#' . $sbcolor->hexValue()));
+ 'value' => ''));
$this->elementEnd('li');
$tcolor = new WebColor($design->textcolor);
@@ -221,7 +221,7 @@ class DesignSettingsAction extends AccountSettingsAction
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
- 'value' => '#' . $tcolor->hexValue()));
+ 'value' => ''));
$this->elementEnd('li');
$lcolor = new WebColor($design->linkcolor);
@@ -234,7 +234,7 @@ class DesignSettingsAction extends AccountSettingsAction
'class' => 'swatch',
'maxlength' => '7',
'size' => '7',
- 'value' => '#' . $lcolor->hexValue()));
+ 'value' => ''));
$this->elementEnd('li');
} catch (WebColorException $e) {
@@ -311,13 +311,7 @@ class DesignSettingsAction extends AccountSettingsAction
function showStylesheets()
{
parent::showStylesheets();
- $farbtasticStyle =
- common_path('theme/base/css/farbtastic.css?version='.LACONICA_VERSION);
-
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => $farbtasticStyle,
- 'media' => 'screen, projection, tv'));
+ $this->cssLink('css/farbtastic.css','base','screen, projection, tv');
}
/**
@@ -330,13 +324,10 @@ class DesignSettingsAction extends AccountSettingsAction
{
parent::showScripts();
- $farbtasticPack = common_path('js/farbtastic/farbtastic.js');
- $userDesignGo = common_path('js/userdesign.go.js');
+ $this->script('js/farbtastic/farbtastic.js');
+ $this->script('js/userdesign.go.js');
- $this->element('script', array('type' => 'text/javascript',
- 'src' => $farbtasticPack));
- $this->element('script', array('type' => 'text/javascript',
- 'src' => $userDesignGo));
+ $this->autofocus('design_background-image_file');
}
/**
diff --git a/lib/disfavorform.php b/lib/disfavorform.php
index 45a9ddb1d..5b135b38a 100644
--- a/lib/disfavorform.php
+++ b/lib/disfavorform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for disfavoring a notice
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for disfavoring a notice
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see FavorForm
*/
diff --git a/lib/error.php b/lib/error.php
index bbf9987cf..6a9b76be1 100644
--- a/lib/error.php
+++ b/lib/error.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,16 +37,17 @@ if (!defined('LACONICA')) {
* Base class for displaying HTTP errors
*
* @category Action
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ErrorAction extends Action
{
+ static $status = array();
+
var $code = null;
var $message = null;
- var $status = null;
var $default = null;
function __construct($message, $code, $output='php://output', $indent=true)
@@ -72,7 +73,7 @@ class ErrorAction extends Action
$status_string = $this->status[$this->code];
header('HTTP/1.1 '.$this->code.' '.$status_string);
}
-
+
/**
* Display content.
*
@@ -88,20 +89,21 @@ class ErrorAction extends Action
*
* @return page title
*/
+
function title()
{
- return $this->message;
+ return self::$status[$this->code];
}
function isReadOnly($args)
{
return true;
}
-
- function showPage()
+
+ function showPage()
{
parent::showPage();
-
+
// We don't want to have any more output after this
exit();
}
diff --git a/lib/event.php b/lib/event.php
index 4ccee17e6..4819b71b4 100644
--- a/lib/event.php
+++ b/lib/event.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* utilities for defining and running event handlers
*
@@ -20,27 +20,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Event
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/**
* Class for events
*
- * This "class" two static functions for managing events in the Laconica code.
+ * This "class" two static functions for managing events in the StatusNet code.
*
* @category Event
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @todo Define a system for using Event instances
*/
@@ -54,7 +54,7 @@ class Event {
/**
* Add an event handler
*
- * To run some code at a particular point in Laconica processing.
+ * To run some code at a particular point in StatusNet processing.
* Named events include receiving an XMPP message, adding a new notice,
* or showing part of an HTML page.
*
diff --git a/lib/facebookaction.php b/lib/facebookaction.php
index 5be2f2fe6..5cbb9be53 100644
--- a/lib/facebookaction.php
+++ b/lib/facebookaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Low-level generator for HTML
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Faceboook
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA'))
+if (!defined('STATUSNET') && !defined('LACONICA'))
{
exit(1);
}
@@ -95,34 +95,14 @@ class FacebookAction extends Action
function showStylesheets()
{
- // Add a timestamp to the file so Facebook cache wont ignore our changes
- $ts = filemtime(INSTALLDIR.'/theme/base/css/display.css');
-
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts));
-
- $theme = common_config('site', 'theme');
-
- $ts = filemtime(INSTALLDIR. '/theme/' . $theme .'/css/display.css');
-
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => theme_path('css/display.css', null) . '?ts=' . $ts));
-
- $ts = filemtime(INSTALLDIR.'/theme/base/css/facebookapp.css');
-
- $this->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => theme_path('css/facebookapp.css', 'base') . '?ts=' . $ts));
+ $this->cssLink('css/display.css', 'base');
+ $this->cssLink('css/display.css',null,'screen, projection, tv');
+ $this->cssLink('css/facebookapp.css', 'base');
}
function showScripts()
{
- // Add a timestamp to the file so Facebook cache wont ignore our changes
- $ts = filemtime(INSTALLDIR.'/js/facebookapp.js');
-
- $this->element('script', array('src' => common_path('js/facebookapp.js') . '?ts=' . $ts));
+ $this->script('js/facebookapp.js');
}
/**
@@ -277,8 +257,13 @@ class FacebookAction extends Action
$this->elementStart('dd');
$this->elementStart('p');
$this->text(sprintf($loginmsg_part1, common_config('site', 'name')));
- $this->element('a',
- array('href' => common_local_url('register')), _('Register'));
+ if (!common_config('site', 'openidonly')) {
+ $this->element('a',
+ array('href' => common_local_url('register')), _('Register'));
+ } else {
+ $this->element('a',
+ array('href' => common_local_url('openidlogin')), _('Register'));
+ }
$this->text($loginmsg_part2);
$this->elementEnd('p');
$this->elementEnd('dd');
@@ -389,7 +374,7 @@ class FacebookAction extends Action
display:inline-block;
}
- #facebook_laconica_app {
+ #facebook_statusnet_app {
text-indent:-9999px;
height:16px;
width:16px;
@@ -688,7 +673,7 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem
$this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name'];
$this->app_name = $app_props['application_name'];
- $this->out->elementStart('a', array('id' => 'facebook_laconica_app',
+ $this->out->elementStart('a', array('id' => 'facebook_statusnet_app',
'href' => $this->app_uri));
$this->out->text($this->app_name);
$this->out->elementEnd('a');
diff --git a/lib/facebookutil.php b/lib/facebookutil.php
index 85077c254..ad61b6f0a 100644
--- a/lib/facebookutil.php
+++ b/lib/facebookutil.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -36,7 +36,7 @@ function getFacebook()
$facebook = new Facebook($apikey, $secret);
}
- if (!$facebook) {
+ if (empty($facebook)) {
common_log(LOG_ERR, 'Could not make new Facebook client obj!',
__FILE__);
}
@@ -44,71 +44,37 @@ function getFacebook()
return $facebook;
}
-function updateProfileBox($facebook, $flink, $notice) {
- $fbaction = new FacebookAction($output='php://output', $indent=true, $facebook, $flink);
- $fbaction->updateProfileBox($notice);
-}
-
function isFacebookBound($notice, $flink) {
if (empty($flink)) {
return false;
}
+ // Avoid a loop
+
+ if ($notice->source == 'Facebook') {
+ common_log(LOG_INFO, "Skipping notice $notice->id because its " .
+ 'source is Facebook.');
+ return false;
+ }
+
// If the user does not want to broadcast to Facebook, move along
+
if (!($flink->noticesync & FOREIGN_NOTICE_SEND == FOREIGN_NOTICE_SEND)) {
common_log(LOG_INFO, "Skipping notice $notice->id " .
'because user has FOREIGN_NOTICE_SEND bit off.');
return false;
}
- $success = false;
+ // If it's not a reply, or if the user WANTS to send @-replies,
+ // then, yeah, it can go to Facebook.
- // If it's not a reply, or if the user WANTS to send @-replies...
if (!preg_match('/@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) ||
($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) {
-
- $success = true;
-
- // The two condition below are deal breakers:
-
- // Avoid a loop
- if ($notice->source == 'Facebook') {
- common_log(LOG_INFO, "Skipping notice $notice->id because its " .
- 'source is Facebook.');
- $success = false;
- }
-
- $facebook = getFacebook();
- $fbuid = $flink->foreign_id;
-
- try {
-
- // Check to see if the user has given the FB app status update perms
- $result = $facebook->api_client->
- users_hasAppPermission('publish_stream', $fbuid);
-
- if ($result != 1) {
- $result = $facebook->api_client->
- users_hasAppPermission('status_update', $fbuid);
- }
- if ($result != 1) {
- $user = $flink->getUser();
- $msg = "Not sending notice $notice->id to Facebook " .
- "because user $user->nickname hasn't given the " .
- 'Facebook app \'status_update\' or \'publish_stream\' permission.';
- common_debug($msg);
- $success = false;
- }
-
- } catch(FacebookRestClientException $e){
- common_log(LOG_ERR, $e->getMessage());
- $success = false;
- }
-
+ return true;
}
- return $success;
+ return false;
}
@@ -119,112 +85,143 @@ function facebookBroadcastNotice($notice)
if (isFacebookBound($notice, $flink)) {
+ // Okay, we're good to go, update the FB status
+
$status = null;
$fbuid = $flink->foreign_id;
-
$user = $flink->getUser();
-
- // Get the status 'verb' (prefix) the user has set
+ $attachments = $notice->attachments();
try {
- $prefix = $facebook->api_client->
- data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $fbuid);
+
+ // Get the status 'verb' (prefix) the user has set
+
+ // XXX: Does this call count against our per user FB request limit?
+ // If so we should consider storing verb elsewhere or not storing
+
+ $prefix = $facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX,
+ $fbuid);
$status = "$prefix $notice->content";
- } catch(FacebookRestClientException $e) {
- common_log(LOG_WARNING, $e->getMessage());
- common_log(LOG_WARNING,
- 'Unable to get the status verb setting from Facebook ' .
- "for $user->nickname (user id: $user->id).");
- }
+ $can_publish = $facebook->api_client->users_hasAppPermission('publish_stream',
+ $fbuid);
- // Okay, we're good to go, update the FB status
+ $can_update = $facebook->api_client->users_hasAppPermission('status_update',
+ $fbuid);
- try {
- $result = $facebook->api_client->
- users_hasAppPermission('publish_stream', $fbuid);
- if($result == 1){
- // authorized to use the stream api, so use it
- $fbattachment = null;
- $attachments = $notice->attachments();
- if($attachments){
- $fbattachment=array();
- $fbattachment['media']=array();
- //facebook only supports one attachment per item
- $attachment = $attachments[0];
- $fbmedia=array();
- if(strncmp($attachment->mimetype,'image/',strlen('image/'))==0){
- $fbmedia['type']='image';
- $fbmedia['src']=$attachment->url;
- $fbmedia['href']=$attachment->url;
- $fbattachment['media'][]=$fbmedia;
-/* Video doesn't seem to work. The notice never makes it to facebook, and no error is reported.
- }else if(strncmp($attachment->mimetype,'video/',strlen('image/'))==0 || $attachment->mimetype="application/ogg"){
- $fbmedia['type']='video';
- $fbmedia['video_src']=$attachment->url;
- // http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
- // says that preview_img is required... but we have no value to put in it
- // $fbmedia['preview_img']=$attachment->url;
- if($attachment->title){
- $fbmedia['video_title']=$attachment->title;
- }
- $fbmedia['video_type']=$attachment->mimetype;
- $fbattachment['media'][]=$fbmedia;
-*/
- }else if($attachment->mimetype=='audio/mpeg'){
- $fbmedia['type']='mp3';
- $fbmedia['src']=$attachment->url;
- $fbattachment['media'][]=$fbmedia;
- }else if($attachment->mimetype=='application/x-shockwave-flash'){
- $fbmedia['type']='flash';
- // http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
- // says that imgsrc is required... but we have no value to put in it
- // $fbmedia['imgsrc']='';
- $fbmedia['swfsrc']=$attachment->url;
- $fbattachment['media'][]=$fbmedia;
- }else{
- $fbattachment['name']=($attachment->title?$attachment->title:$attachment->url);
- $fbattachment['href']=$attachment->url;
- }
- }
- $facebook->api_client->stream_publish($status, $fbattachment, null, null, $fbuid);
- }else{
+ if (!empty($attachments) && $can_publish == 1) {
+ $fbattachment = format_attachments($attachments);
+ $facebook->api_client->stream_publish($status, $fbattachment,
+ null, null, $fbuid);
+ common_log(LOG_INFO,
+ "Posted notice $notice->id w/attachment " .
+ "to Facebook user's stream (fbuid = $fbuid).");
+ } elseif ($can_update == 1 || $can_publish == 1) {
$facebook->api_client->users_setStatus($status, $fbuid, false, true);
+ common_log(LOG_INFO,
+ "Posted notice $notice->id to Facebook " .
+ "as a status update (fbuid = $fbuid).");
+ } else {
+ $msg = "Not sending notice $notice->id to Facebook " .
+ "because user $user->nickname hasn't given the " .
+ 'Facebook app \'status_update\' or \'publish_stream\' permission.';
+ common_log(LOG_WARNING, $msg);
}
- } catch(FacebookRestClientException $e) {
- common_log(LOG_ERR, $e->getMessage());
- common_log(LOG_ERR,
- 'Unable to update Facebook status for ' .
- "$user->nickname (user id: $user->id)!");
+
+ // Finally, attempt to update the user's profile box
+
+ if ($can_publish == 1 || $can_update == 1) {
+ updateProfileBox($facebook, $flink, $notice);
+ }
+
+ } catch (FacebookRestClientException $e) {
$code = $e->getCode();
- if ($code >= 200) {
+ common_log(LOG_WARNING, 'Facebook returned error code ' .
+ $code . ': ' . $e->getMessage());
+ common_log(LOG_WARNING,
+ 'Unable to update Facebook status for ' .
+ "$user->nickname (user id: $user->id)!");
+
+ if ($code == 200 || $code == 250) {
// 200 The application does not have permission to operate on the passed in uid parameter.
// 250 Updating status requires the extended permission status_update or publish_stream.
// see: http://wiki.developers.facebook.com/index.php/Users.setStatus#Example_Return_XML
remove_facebook_app($flink);
+
+ } else {
+
+ // Try sending again later.
+
+ return false;
}
}
+ }
- // Now try to update the profile box
+ return true;
- try {
- updateProfileBox($facebook, $flink, $notice);
- } catch(FacebookRestClientException $e) {
- common_log(LOG_WARNING, $e->getMessage());
- common_log(LOG_WARNING,
- 'Unable to update Facebook profile box for ' .
- "$user->nickname (user id: $user->id).");
- }
+}
+
+function updateProfileBox($facebook, $flink, $notice) {
+ $fbaction = new FacebookAction($output = 'php://output',
+ $indent = true, $facebook, $flink);
+ $fbaction->updateProfileBox($notice);
+}
+function format_attachments($attachments)
+{
+ $fbattachment = array();
+ $fbattachment['media'] = array();
+
+ foreach($attachments as $attachment)
+ {
+ $fbmedia = get_fbmedia_for_attachment($attachment);
+ if($fbmedia){
+ $fbattachment['media'][]=$fbmedia;
+ }else{
+ $fbattachment['name'] = ($attachment->title ?
+ $attachment->title : $attachment->url);
+ $fbattachment['href'] = $attachment->url;
+ }
+ }
+ if(count($fbattachment['media'])>0){
+ unset($fbattachment['name']);
+ unset($fbattachment['href']);
}
+ return $fbattachment;
+}
- return true;
+/**
+* given an File objects, returns an associative array suitable for Facebook media
+*/
+function get_fbmedia_for_attachment($attachment)
+{
+ $fbmedia = array();
+
+ if (strncmp($attachment->mimetype, 'image/', strlen('image/')) == 0) {
+ $fbmedia['type'] = 'image';
+ $fbmedia['src'] = $attachment->url;
+ $fbmedia['href'] = $attachment->url;
+ } else if ($attachment->mimetype == 'audio/mpeg') {
+ $fbmedia['type'] = 'mp3';
+ $fbmedia['src'] = $attachment->url;
+ }else if ($attachment->mimetype == 'application/x-shockwave-flash') {
+ $fbmedia['type'] = 'flash';
+
+ // http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
+ // says that imgsrc is required... but we have no value to put in it
+ // $fbmedia['imgsrc']='';
+
+ $fbmedia['swfsrc'] = $attachment->url;
+ }else{
+ return false;
+ }
+ return $fbmedia;
}
function remove_facebook_app($flink)
diff --git a/lib/favorform.php b/lib/favorform.php
index f3a7a9756..625df7c8b 100644
--- a/lib/favorform.php
+++ b/lib/favorform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for favoring a notice
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for favoring a notice
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see DisfavorForm
*/
diff --git a/lib/featureduserssection.php b/lib/featureduserssection.php
index 4b9238d47..f0753a25e 100644
--- a/lib/featureduserssection.php
+++ b/lib/featureduserssection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Section for featured users
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Section for featured users
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FeaturedUsersSection extends ProfileSection
diff --git a/lib/feed.php b/lib/feed.php
index 466926844..e9fb6fdff 100644
--- a/lib/feed.php
+++ b/lib/feed.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Data structure for info about syndication feeds (RSS 1.0, RSS 2.0, Atom)
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Feed
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,11 +37,11 @@ if (!defined('LACONICA')) {
* This structure is a helpful container for shipping around information about syndication feeds.
*
* @category Feed
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class Feed
diff --git a/lib/feedlist.php b/lib/feedlist.php
index 927e43c33..9ae83f5e8 100644
--- a/lib/feedlist.php
+++ b/lib/feedlist.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Widget for showing a list of feeds
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ if (!defined('LACONICA')) {
* Typically used for Action::showExportList()
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Action::showExportList()
*/
diff --git a/lib/form.php b/lib/form.php
index f872aef0b..87b7a5cba 100644
--- a/lib/form.php
+++ b/lib/form.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for forms
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,11 +41,11 @@ require_once INSTALLDIR.'/lib/widget.php';
* lets us abstract out the basic features of the form.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
diff --git a/lib/galleryaction.php b/lib/galleryaction.php
index b389fc00f..31e36803a 100644
--- a/lib/galleryaction.php
+++ b/lib/galleryaction.php
@@ -1,7 +1,7 @@
<?php
/**
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -132,13 +132,16 @@ class GalleryAction extends OwnerDesignAction
$this->elementEnd('li');
$this->elementStart('li', array('id'=>'filter_tags_item'));
$this->elementStart('form', array('name' => 'bytag',
- 'id' => 'bytag',
+ 'id' => 'form_filter_bytag',
'action' => common_path('?action=' . $this->trimmed('action')),
'method' => 'post'));
+ $this->elementStart('fieldset');
+ $this->element('legend', null, _('Select tag to filter'));
$this->dropdown('tag', _('Tag'), $content,
_('Choose a tag to narrow list'), false, $tag);
$this->hidden('nickname', $this->user->nickname);
$this->submit('submit', _('Go'));
+ $this->elementEnd('fieldset');
$this->elementEnd('form');
$this->elementEnd('li');
$this->elementEnd('ul');
diff --git a/lib/groupdesignaction.php b/lib/groupdesignaction.php
index 58777c283..3eb3964e8 100644
--- a/lib/groupdesignaction.php
+++ b/lib/groupdesignaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for actions that use the current user's design
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Action
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ if (!defined('LACONICA')) {
* This superclass returns that design.
*
* @category Action
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
*/
class GroupDesignAction extends Action {
@@ -50,26 +50,6 @@ class GroupDesignAction extends Action {
var $group = null;
/**
- * Show the groups's design stylesheet
- *
- * @return nothing
- */
- function showStylesheets()
- {
- parent::showStylesheets();
-
- $user = common_current_user();
-
- if (empty($user) || $user->viewdesigns) {
- $design = $this->getDesign();
-
- if (!empty($design)) {
- $design->showCSS($this);
- }
- }
- }
-
- /**
* A design for this action
*
* if the group attribute has been set, returns that group's
@@ -80,10 +60,12 @@ class GroupDesignAction extends Action {
function getDesign()
{
- if (empty($this->group)) {
- return null;
+ if (!empty($this->group)) {
+ $design = $this->group->getDesign();
+ if (!empty($design)) {
+ return $design;
+ }
}
-
- return $this->group->getDesign();
+ return parent::getDesign();
}
}
diff --git a/lib/groupeditform.php b/lib/groupeditform.php
index fbb39129b..a649c2ee3 100644
--- a/lib/groupeditform.php
+++ b/lib/groupeditform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for editing a group
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for editing a group
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see UnsubscribeForm
*/
diff --git a/lib/grouplist.php b/lib/grouplist.php
index 1ded5160b..b41c5b5f8 100644
--- a/lib/grouplist.php
+++ b/lib/grouplist.php
@@ -1,7 +1,7 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Widget to show a list of groups
*
@@ -21,14 +21,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ define('GROUPS_PER_PAGE', 20);
* Widget to show a list of groups
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupList extends Widget
diff --git a/lib/groupminilist.php b/lib/groupminilist.php
index ae2d237f1..dff81eff5 100644
--- a/lib/groupminilist.php
+++ b/lib/groupminilist.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Widget to show a mini-list of groups
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ define('GROUPS_PER_MINILIST', 27);
* Widget to show a list of groups, good for sidebar
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupMiniList extends GroupList
diff --git a/lib/groupnav.php b/lib/groupnav.php
index 9e530c447..31cf378c8 100644
--- a/lib/groupnav.php
+++ b/lib/groupnav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Tabset for a particular group
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ require_once INSTALLDIR.'/lib/widget.php';
* Shows a group of tabs for a particular user group
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
diff --git a/lib/groupsbymemberssection.php b/lib/groupsbymemberssection.php
index ad4884bf8..19b35eddb 100644
--- a/lib/groupsbymemberssection.php
+++ b/lib/groupsbymemberssection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Groups with the most members section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Groups with the most members section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupsByMembersSection extends GroupSection
diff --git a/lib/groupsbypostssection.php b/lib/groupsbypostssection.php
index dc7925d5e..45d49aba6 100644
--- a/lib/groupsbypostssection.php
+++ b/lib/groupsbypostssection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Groups with the most posts section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Groups with the most posts section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupsByPostsSection extends GroupSection
diff --git a/lib/groupsection.php b/lib/groupsection.php
index c19299493..7327f9e1a 100644
--- a/lib/groupsection.php
+++ b/lib/groupsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for sections showing lists of groups
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ define('GROUPS_PER_SECTION', 6);
* group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupSection extends Section
diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php
index 0e0cbdd63..091cf4845 100644
--- a/lib/grouptagcloudsection.php
+++ b/lib/grouptagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Group tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class GroupTagCloudSection extends TagCloudSection
diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php
index 06603ac05..aa01f6b1d 100644
--- a/lib/htmloutputter.php
+++ b/lib/htmloutputter.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Low-level generator for HTML
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -47,11 +47,11 @@ define('PAGE_TYPE_PREFS',
* HTML-creation class.
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Action
* @see XMLOutputter
@@ -109,10 +109,11 @@ class HTMLOutputter extends XMLOutputter
header('Content-Type: '.$type);
$this->extraHeaders();
-
- $this->startXML('html',
- '-//W3C//DTD XHTML 1.0 Strict//EN',
- 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
+ if( ! substr($type,0,strlen('text/html'))=='text/html' ){
+ // Browsers don't like it when <?xml it output for non-xhtml documents
+ $this->xw->startDocument('1.0', 'UTF-8');
+ }
+ $this->xw->writeDTD('html');
$language = $this->getLanguage();
@@ -339,6 +340,52 @@ class HTMLOutputter extends XMLOutputter
}
/**
+ * output a script (almost always javascript) tag
+ *
+ * @param string $src relative or absolute script path
+ * @param string $type 'type' attribute value of the tag
+ *
+ * @return void
+ */
+ function script($src, $type='text/javascript')
+ {
+ $url = parse_url($src);
+ if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment))
+ {
+ $src = common_path($src) . '?version=' . STATUSNET_VERSION;
+ }
+ $this->element('script', array('type' => $type,
+ 'src' => $src),
+ ' ');
+ }
+
+ /**
+ * output a css link
+ *
+ * @param string $src relative path within the theme directory, or an absolute path
+ * @param string $theme 'theme' that contains the stylesheet
+ * @param string media 'media' attribute of the tag
+ *
+ * @return void
+ */
+ function cssLink($src,$theme=null,$media=null)
+ {
+ $url = parse_url($src);
+ if( empty($url->scheme) && empty($url->host) && empty($url->query) && empty($url->fragment))
+ {
+ if(file_exists(theme_file($src,$theme))){
+ $src = theme_path($src, $theme) . '?version=' . STATUSNET_VERSION;
+ }else{
+ $src = common_path($src);
+ }
+ }
+ $this->element('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css',
+ 'href' => $src,
+ 'media' => $media));
+ }
+
+ /**
* output an HTML textarea and associated elements
*
* @param string $id element ID, must be unique on page
@@ -365,4 +412,29 @@ class HTMLOutputter extends XMLOutputter
$this->element('p', 'form_guide', $instructions);
}
}
+
+
+ /**
+ * Internal script to autofocus the given element on page onload.
+ *
+ * @param string $id element ID, must refer to an existing element
+ *
+ * @return void
+ *
+ */
+ function autofocus($id)
+ {
+ $this->elementStart('script', array('type' => 'text/javascript'));
+ $this->raw('
+ <!--
+ $(document).ready(function() {
+ var el = $("#' . $id . '");
+ if (el.length) {
+ el.focus();
+ }
+ });
+ -->
+ ');
+ $this->elementEnd('script');
+ }
}
diff --git a/lib/imagefile.php b/lib/imagefile.php
index 52e4c4b22..88f461481 100644
--- a/lib/imagefile.php
+++ b/lib/imagefile.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Abstraction for an image file
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Image
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ if (!defined('LACONICA')) {
* Makes it slightly easier to accept an image file from upload.
*
* @category Image
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ImageFile
diff --git a/lib/jabber.php b/lib/jabber.php
index e15076160..3dcdce5db 100644
--- a/lib/jabber.php
+++ b/lib/jabber.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* utility functions for Jabber/GTalk/XMPP messages
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Network
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -67,7 +67,7 @@ function jabber_normalize_jid($jid)
}
/**
- * the JID of the Jabber daemon for this Laconica instance
+ * the JID of the Jabber daemon for this StatusNet instance
*
* @return string JID of the Jabber daemon
*/
@@ -309,7 +309,7 @@ function jabber_special_presence($type, $to=null, $show=null, $status=null)
* who have Jabber addresses, and have Jabber notification enabled, and
* have this subscription enabled for Jabber. It also sends the notice to
* all recipients of @-replies who have Jabber addresses and Jabber notification
- * enabled. This is really the heart of Jabber distribution in Laconica.
+ * enabled. This is really the heart of Jabber distribution in StatusNet.
*
* @param Notice $notice The notice to broadcast
*
diff --git a/lib/joinform.php b/lib/joinform.php
index 1edb2f72d..aefb553aa 100644
--- a/lib/joinform.php
+++ b/lib/joinform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for joining a group
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for joining a group
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see UnsubscribeForm
*/
diff --git a/lib/jsonsearchresultslist.php b/lib/jsonsearchresultslist.php
index 7beea9328..569bfa873 100644
--- a/lib/jsonsearchresultslist.php
+++ b/lib/jsonsearchresultslist.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* widget for displaying a list of notices
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* widget-like class for showing JSON search results
*
* @category Search
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
*/
@@ -147,10 +147,10 @@ class JSONSearchResultsList
* widget for displaying a single JSON search result
*
* @category UI
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see JSONSearchResultsList
*/
@@ -207,7 +207,7 @@ class ResultItem
$replier_profile = null;
if ($this->notice->reply_to) {
- $reply = Notice::staticGet(intval($notice->reply_to));
+ $reply = Notice::staticGet(intval($this->notice->reply_to));
if ($reply) {
$replier_profile = $reply->getProfile();
}
@@ -224,7 +224,7 @@ class ResultItem
$user = User::staticGet('id', $this->profile->id);
- $this->iso_language_code = $this->user->language;
+ $this->iso_language_code = $user->language;
$this->source = $this->getSourceLink($this->notice->source);
diff --git a/lib/language.php b/lib/language.php
index 9ad2d31bd..561a4ddb8 100644
--- a/lib/language.php
+++ b/lib/language.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* utility functions for i18n
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category I18n
- * @package Laconica
+ * @package StatusNet
* @author Matthew Gregg <matthew.gregg@gmail.com>
* @author Ciaran Gultnieks <ciaran@ciarang.com>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/lib/leaveform.php b/lib/leaveform.php
index 696559a25..e63d96ee8 100644
--- a/lib/leaveform.php
+++ b/lib/leaveform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for leaving a group
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for leaving a group
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see UnsubscribeForm
*/
diff --git a/lib/logingroupnav.php b/lib/logingroupnav.php
index f23985f3a..f740e329a 100644
--- a/lib/logingroupnav.php
+++ b/lib/logingroupnav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Menu for login group of actions
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Menu
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/widget.php';
* Menu for login group of actions
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
@@ -72,14 +72,18 @@ class LoginGroupNav extends Widget
// action => array('prompt', 'title')
$menu = array();
- $menu['login'] = array(_('Login'),
- _('Login with a username and password'));
- if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
- $menu['register'] = array(_('Register'),
- _('Sign up for a new account'));
+ if (!common_config('site','openidonly')) {
+ $menu['login'] = array(_('Login'),
+ _('Login with a username and password'));
+ if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
+ $menu['register'] = array(_('Register'),
+ _('Sign up for a new account'));
+ }
+ }
+ if (common_config('openid', 'enabled')) {
+ $menu['openidlogin'] = array(_('OpenID'),
+ _('Login or register with OpenID'));
}
- $menu['openidlogin'] = array(_('OpenID'),
- _('Login or register with OpenID'));
$action_name = $this->action->trimmed('action');
$this->action->elementStart('ul', array('class' => 'nav'));
diff --git a/lib/mail.php b/lib/mail.php
index 262f788ee..5bf4d7425 100644
--- a/lib/mail.php
+++ b/lib/mail.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* utilities for sending email
*
@@ -20,17 +20,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Mail
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @author Robin Millette <millette@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -551,9 +551,9 @@ function mail_notify_fave($other, $user, $notice)
common_init_locale($other->language);
- $subject = sprintf(_('%s added your notice as a favorite'), $bestname);
+ $subject = sprintf(_('%s (@%s) added your notice as a favorite'), $bestname, $user->nickname);
- $body = sprintf(_("%1\$s just added your notice from %2\$s".
+ $body = sprintf(_("%1\$s (@%7\$s) just added your notice from %2\$s".
" as one of their favorites.\n\n" .
"The URL of your notice is:\n\n" .
"%3\$s\n\n" .
@@ -570,7 +570,8 @@ function mail_notify_fave($other, $user, $notice)
$notice->content,
common_local_url('showfavorites',
array('nickname' => $user->nickname)),
- common_config('site', 'name'));
+ common_config('site', 'name'),
+ $user->nickname);
common_init_locale();
mail_to_user($other, $subject, $body);
@@ -596,32 +597,45 @@ function mail_notify_attn($user, $notice)
$bestname = $sender->getBestName();
common_init_locale($user->language);
-
- $subject = sprintf(_('%s sent a notice to your attention'), $bestname);
-
- $body = sprintf(_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
+
+ if ($notice->conversation != $notice->id) {
+ $conversationEmailText = "The full conversation can be read here:\n\n".
+ "\t%5\$s\n\n ";
+ $conversationUrl = common_local_url('conversation',
+ array('id' => $notice->conversation)).'#notice-'.$notice->id;
+ } else {
+ $conversationEmailText = "%5\$s";
+ $conversationUrl = null;
+ }
+
+ $subject = sprintf(_('%s (@%s) sent a notice to your attention'), $bestname, $sender->nickname);
+
+ $body = sprintf(_("%1\$s (@%9\$s) just sent a notice to your attention (an '@-reply') on %2\$s.\n\n".
"The notice is here:\n\n".
"\t%3\$s\n\n" .
"It reads:\n\n".
"\t%4\$s\n\n" .
+ $conversationEmailText .
"You can reply back here:\n\n".
- "\t%5\$s\n\n" .
+ "\t%6\$s\n\n" .
"The list of all @-replies for you here:\n\n" .
- "%6\$s\n\n" .
+ "%7\$s\n\n" .
"Faithfully yours,\n" .
"%2\$s\n\n" .
- "P.S. You can turn off these email notifications here: %7\$s\n"),
- $bestname,
- common_config('site', 'name'),
+ "P.S. You can turn off these email notifications here: %8\$s\n"),
+ $bestname,//%1
+ common_config('site', 'name'),//%2
common_local_url('shownotice',
- array('notice' => $notice->id)),
- $notice->content,
+ array('notice' => $notice->id)),//%3
+ $notice->content,//%4
+ $conversationUrl,//%5
common_local_url('newnotice',
- array('replyto' => $sender->nickname)),
+ array('replyto' => $sender->nickname, 'inreplyto' => $notice->id)),//%6
common_local_url('replies',
- array('nickname' => $user->nickname)),
- common_local_url('emailsettings'));
-
+ array('nickname' => $user->nickname)),//%7
+ common_local_url('emailsettings'), //%8
+ $sender->nickname); //%9
+
common_init_locale();
mail_to_user($user, $subject, $body);
}
@@ -645,13 +659,14 @@ function mail_twitter_bridge_removed($user)
$subject = sprintf(_('Your Twitter bridge has been disabled.'));
- $body = sprintf(_("Hi, %1\$s. We're sorry to inform you that your " .
- 'link to Twitter has been disabled. Your Twitter credentials ' .
- 'have either changed (did you recently change your Twitter ' .
- 'password?) or you have otherwise revoked our access to your ' .
- "Twitter account.\n\n" .
- 'You can re-enable your Twitter bridge by visiting your ' .
- "Twitter settings page:\n\n\t%2\$s\n\n" .
+ $site_name = common_config('site', 'name');
+
+ $body = sprintf(_('Hi, %1$s. We\'re sorry to inform you that your ' .
+ 'link to Twitter has been disabled. We no longer seem to have ' .
+ 'permission to update your Twitter status. (Did you revoke ' .
+ '%3$s\'s access?)' . "\n\n" .
+ 'You can re-enable your Twitter bridge by visiting your ' .
+ "Twitter settings page:\n\n\t%2\$s\n\n" .
"Regards,\n%3\$s\n"),
$profile->getBestName(),
common_local_url('twittersettings'),
@@ -679,17 +694,17 @@ function mail_facebook_app_removed($user)
$site_name = common_config('site', 'name');
$subject = sprintf(
- _('Your %s Facebook application access has been disabled.',
+ _('Your %1$s Facebook application access has been disabled.',
$site_name));
$body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " .
- 'unable to update your Facebook status from %s, and have disabled ' .
+ 'unable to update your Facebook status from %2$s, and have disabled ' .
'the Facebook application for your account. This may be because ' .
'you have removed the Facebook application\'s authorization, or ' .
'have deleted your Facebook account. You can re-enable the ' .
'Facebook application and automatic status updating by ' .
- "re-installing the %1\$s Facebook application.\n\nRegards,\n\n%1\$s"),
- $site_name);
+ "re-installing the %2\$s Facebook application.\n\nRegards,\n\n%2\$s"),
+ $user->nickname, $site_name);
common_init_locale();
return mail_to_user($user, $subject, $body);
diff --git a/lib/mailbox.php b/lib/mailbox.php
index f1f6e98c1..e1d384a06 100644
--- a/lib/mailbox.php
+++ b/lib/mailbox.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* common superclass for direct messages inbox and outbox
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Message
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ define('MESSAGES_PER_PAGE', 20);
* common superclass for direct messages inbox and outbox
*
* @category Message
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see InboxAction
* @see OutboxAction
*/
@@ -213,26 +213,20 @@ class MailboxAction extends CurrentUserDesignAction
}
$this->elementStart('div', 'entry-content');
- $this->elementStart('dl', 'timestamp');
- $this->element('dt', null, _('Published'));
- $this->elementStart('dd', null);
- $dt = common_date_iso8601($message->created);
$this->elementStart('a', array('rel' => 'bookmark',
+ 'class' => 'timestamp',
'href' => $messageurl));
+ $dt = common_date_iso8601($message->created);
$this->element('abbr', array('class' => 'published',
'title' => $dt),
common_date_string($message->created));
$this->elementEnd('a');
- $this->elementEnd('dd');
- $this->elementEnd('dl');
if ($message->source) {
- $this->elementStart('dl', 'device');
- $this->elementStart('dt');
- $this->text(_('From'));
- $this->elementEnd('dt');
- $this->showSource($message->source);
- $this->elementEnd('dl');
+ $this->elementStart('span', 'source');
+ $this->text(_('from'));
+ $this->element('span', 'device', $this->showSource($message->source));
+ $this->elementEnd('span');
}
$this->elementEnd('div');
@@ -277,18 +271,18 @@ class MailboxAction extends CurrentUserDesignAction
case 'mail':
case 'omb':
case 'api':
- $this->element('dd', null, $source_name);
+ $this->element('span', 'device', $source_name);
break;
default:
$ns = Notice_source::staticGet($source);
if ($ns) {
- $this->elementStart('dd', null);
+ $this->elementStart('span', 'device');
$this->element('a', array('href' => $ns->url,
- 'rel' => 'external'),
- $ns->name);
- $this->elementEnd('dd');
+ 'rel' => 'external'),
+ $ns->name);
+ $this->elementEnd('span');
} else {
- $this->element('dd', null, $source_name);
+ $this->out->element('span', 'device', $source_name);
}
break;
}
diff --git a/lib/messageform.php b/lib/messageform.php
index 8ea2b36c2..6431bfdcc 100644
--- a/lib/messageform.php
+++ b/lib/messageform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for posting a direct message
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for posting a direct message
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
diff --git a/lib/microid.php b/lib/microid.php
index 806b7ee7d..e2e7d7607 100644
--- a/lib/microid.php
+++ b/lib/microid.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Microid class
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category ID
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* A class for microids
*
* @category ID
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see http://microid.org/
*/
diff --git a/lib/noticeform.php b/lib/noticeform.php
index 4e2a2edd6..350e37db8 100644
--- a/lib/noticeform.php
+++ b/lib/noticeform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for posting a notice
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Frequently-used form for posting a notice
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
@@ -70,6 +70,12 @@ class NoticeForm extends Form
var $user = null;
/**
+ * The notice being replied to
+ */
+
+ var $inreplyto = null;
+
+ /**
* Constructor
*
* @param HTMLOutputter $out output channel
@@ -77,12 +83,13 @@ class NoticeForm extends Form
* @param string $content content to pre-fill
*/
- function __construct($out=null, $action=null, $content=null, $user=null)
+ function __construct($out=null, $action=null, $content=null, $user=null, $inreplyto=null)
{
parent::__construct($out);
$this->action = $action;
$this->content = $content;
+ $this->inreplyto = $inreplyto;
if ($user) {
$this->user = $user;
@@ -161,7 +168,7 @@ class NoticeForm extends Form
if ($this->action) {
$this->out->hidden('notice_return-to', $this->action, 'returnto');
}
- $this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto');
+ $this->out->hidden('notice_in-reply-to', $this->inreplyto, 'inreplyto');
}
/**
diff --git a/lib/noticelist.php b/lib/noticelist.php
index 44726a17b..d4cd3ff6e 100644
--- a/lib/noticelist.php
+++ b/lib/noticelist.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* widget for displaying a list of notices
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category UI
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -45,10 +45,10 @@ require_once INSTALLDIR.'/lib/attachmentlist.php';
* data for e.g. the profile page.
*
* @category UI
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see Notice
* @see NoticeListItem
* @see ProfileNoticeList
@@ -133,10 +133,10 @@ class NoticeList extends Widget
* author info (since that's implicit by the data in the page).
*
* @category UI
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see NoticeList
* @see ProfileNoticeListItem
*/
@@ -261,7 +261,7 @@ class NoticeListItem extends Widget
$attrs = array('href' => $this->profile->profileurl,
'class' => 'url');
if (!empty($this->profile->fullname)) {
- $attrs['title'] = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
+ $attrs['title'] = $this->profile->fullname . ' (' . $this->profile->nickname . ')';
}
$this->out->elementStart('a', $attrs);
$this->showAvatar();
@@ -350,26 +350,20 @@ class NoticeListItem extends Widget
function showNoticeLink()
{
- $noticeurl = common_local_url('shownotice',
+ if($this->notice->is_local){
+ $noticeurl = common_local_url('shownotice',
array('notice' => $this->notice->id));
- // XXX: we need to figure this out better. Is this right?
- if (strcmp($this->notice->uri, $noticeurl) != 0 &&
- preg_match('/^http/', $this->notice->uri)) {
+ }else{
$noticeurl = $this->notice->uri;
}
- $this->out->elementStart('dl', 'timestamp');
- $this->out->element('dt', null, _('Published'));
- $this->out->elementStart('dd', null);
$this->out->elementStart('a', array('rel' => 'bookmark',
+ 'class' => 'timestamp',
'href' => $noticeurl));
$dt = common_date_iso8601($this->notice->created);
$this->out->element('abbr', array('class' => 'published',
'title' => $dt),
common_date_string($this->notice->created));
-
$this->out->elementEnd('a');
- $this->out->elementEnd('dd');
- $this->out->elementEnd('dl');
}
/**
@@ -384,8 +378,8 @@ class NoticeListItem extends Widget
function showNoticeSource()
{
if ($this->notice->source) {
- $this->out->elementStart('dl', 'device');
- $this->out->element('dt', null, _('From'));
+ $this->out->elementStart('span', 'source');
+ $this->out->text(_('from'));
$source_name = _($this->notice->source);
switch ($this->notice->source) {
case 'web':
@@ -394,22 +388,22 @@ class NoticeListItem extends Widget
case 'omb':
case 'system':
case 'api':
- $this->out->element('dd', null, $source_name);
+ $this->out->element('span', 'device', $source_name);
break;
default:
$ns = Notice_source::staticGet($this->notice->source);
if ($ns) {
- $this->out->elementStart('dd', null);
+ $this->out->elementStart('span', 'device');
$this->out->element('a', array('href' => $ns->url,
'rel' => 'external'),
$ns->name);
- $this->out->elementEnd('dd');
+ $this->out->elementEnd('span');
} else {
- $this->out->element('dd', null, $source_name);
+ $this->out->element('span', 'device', $source_name);
}
break;
}
- $this->out->elementEnd('dl');
+ $this->out->elementEnd('span');
}
}
@@ -424,18 +418,22 @@ class NoticeListItem extends Widget
function showContext()
{
- // XXX: also show context if there are replies to this notice
- if (!empty($this->notice->conversation)
- && $this->notice->conversation != $this->notice->id) {
+ $hasConversation = false;
+ if( !empty($this->notice->conversation)
+ && $this->notice->conversation != $this->notice->id){
+ $hasConversation = true;
+ }else{
+ $conversation = Notice::conversationStream($this->notice->id, 1, 1);
+ if($conversation->N > 0){
+ $hasConversation = true;
+ }
+ }
+ if ($hasConversation){
$convurl = common_local_url('conversation',
array('id' => $this->notice->conversation));
- $this->out->elementStart('dl', 'response');
- $this->out->element('dt', null, _('To'));
- $this->out->elementStart('dd');
- $this->out->element('a', array('href' => $convurl.'#notice-'.$this->notice->id),
+ $this->out->element('a', array('href' => $convurl.'#notice-'.$this->notice->id,
+ 'class' => 'response'),
_('in context'));
- $this->out->elementEnd('dd');
- $this->out->elementEnd('dl');
}
}
@@ -452,18 +450,13 @@ class NoticeListItem extends Widget
{
if (common_logged_in()) {
$reply_url = common_local_url('newnotice',
- array('replyto' => $this->profile->nickname));
-
- $this->out->elementStart('dl', 'notice_reply');
- $this->out->element('dt', null, _('Reply to this notice'));
- $this->out->elementStart('dd');
+ array('replyto' => $this->profile->nickname, 'inreplyto' => $this->notice->id));
$this->out->elementStart('a', array('href' => $reply_url,
+ 'class' => 'notice_reply',
'title' => _('Reply to this notice')));
$this->out->text(_('Reply'));
$this->out->element('span', 'notice_id', $this->notice->id);
$this->out->elementEnd('a');
- $this->out->elementEnd('dd');
- $this->out->elementEnd('dl');
}
}
@@ -479,13 +472,9 @@ class NoticeListItem extends Widget
if ($user && $this->notice->profile_id == $user->id) {
$deleteurl = common_local_url('deletenotice',
array('notice' => $this->notice->id));
- $this->out->elementStart('dl', 'notice_delete');
- $this->out->element('dt', null, _('Delete this notice'));
- $this->out->elementStart('dd');
$this->out->element('a', array('href' => $deleteurl,
+ 'class' => 'notice_delete',
'title' => _('Delete this notice')), _('Delete'));
- $this->out->elementEnd('dd');
- $this->out->elementEnd('dl');
}
}
diff --git a/lib/noticesection.php b/lib/noticesection.php
index ca1432686..b223932ef 100644
--- a/lib/noticesection.php
+++ b/lib/noticesection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for sections showing lists of notices
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ define('NOTICES_PER_SECTION', 6);
* group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class NoticeSection extends Section
diff --git a/lib/nudgeform.php b/lib/nudgeform.php
index 7380462a7..3f13b5846 100644
--- a/lib/nudgeform.php
+++ b/lib/nudgeform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for nudging a user
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for nudging a user
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see DisfavorForm
*/
diff --git a/lib/oauthclient.php b/lib/oauthclient.php
new file mode 100644
index 000000000..f1827726e
--- /dev/null
+++ b/lib/oauthclient.php
@@ -0,0 +1,225 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Base class for doing OAuth calls as a consumer
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once 'OAuth.php';
+
+/**
+ * Exception wrapper for cURL errors
+ *
+ * @category Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ */
+class OAuthClientCurlException extends Exception
+{
+}
+
+/**
+ * Base class for doing OAuth calls as a consumer
+ *
+ * @category Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ */
+class OAuthClient
+{
+ var $consumer;
+ var $token;
+
+ /**
+ * Constructor
+ *
+ * Can be initialized with just consumer key and secret for requesting new
+ * tokens or with additional request token or access token
+ *
+ * @param string $consumer_key consumer key
+ * @param string $consumer_secret consumer secret
+ * @param string $oauth_token user's token
+ * @param string $oauth_token_secret user's secret
+ *
+ * @return nothing
+ */
+ 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);
+ $this->token = null;
+
+ if (isset($oauth_token) && isset($oauth_token_secret)) {
+ $this->token = new OAuthToken($oauth_token, $oauth_token_secret);
+ }
+ }
+
+ /**
+ * Gets a request token from the given url
+ *
+ * @param string $url OAuth endpoint for grabbing request tokens
+ *
+ * @return OAuthToken $token the request token
+ */
+ function getRequestToken($url)
+ {
+ $response = $this->oAuthGet($url);
+ parse_str($response);
+ $token = new OAuthToken($oauth_token, $oauth_token_secret);
+ return $token;
+ }
+
+ /**
+ * Builds a link that can be redirected to in order to
+ * authorize a request token.
+ *
+ * @param string $url endpoint for authorizing request tokens
+ * @param OAuthToken $request_token the request token to be authorized
+ * @param string $oauth_callback optional callback url
+ *
+ * @return string $authorize_url the url to redirect to
+ */
+ function getAuthorizeLink($url, $request_token, $oauth_callback = null)
+ {
+ $authorize_url = $url . '?oauth_token=' .
+ $request_token->key;
+
+ if (isset($oauth_callback)) {
+ $authorize_url .= '&oauth_callback=' . urlencode($oauth_callback);
+ }
+
+ return $authorize_url;
+ }
+
+ /**
+ * Fetches an access token
+ *
+ * @param string $url OAuth endpoint for exchanging authorized request tokens
+ * for access tokens
+ *
+ * @return OAuthToken $token the access token
+ */
+ function getAccessToken($url)
+ {
+ $response = $this->oAuthPost($url);
+ parse_str($response);
+ $token = new OAuthToken($oauth_token, $oauth_token_secret);
+ return $token;
+ }
+
+ /**
+ * Use HTTP GET to make a signed OAuth request
+ *
+ * @param string $url OAuth endpoint
+ *
+ * @return mixed the request
+ */
+ function oAuthGet($url)
+ {
+ $request = OAuthRequest::from_consumer_and_token($this->consumer,
+ $this->token, 'GET', $url, null);
+ $request->sign_request($this->sha1_method,
+ $this->consumer, $this->token);
+
+ return $this->httpRequest($request->to_url());
+ }
+
+ /**
+ * Use HTTP POST to make a signed OAuth request
+ *
+ * @param string $url OAuth endpoint
+ * @param array $params additional post parameters
+ *
+ * @return mixed the request
+ */
+ function oAuthPost($url, $params = null)
+ {
+ $request = OAuthRequest::from_consumer_and_token($this->consumer,
+ $this->token, 'POST', $url, $params);
+ $request->sign_request($this->sha1_method,
+ $this->consumer, $this->token);
+
+ return $this->httpRequest($request->get_normalized_http_url(),
+ $request->to_postdata());
+ }
+
+ /**
+ * Make a HTTP request using cURL.
+ *
+ * @param string $url Where to make the
+ * @param array $params post parameters
+ *
+ * @return mixed the request
+ */
+ function httpRequest($url, $params = null)
+ {
+ $options = array(
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_FAILONERROR => true,
+ CURLOPT_HEADER => false,
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_USERAGENT => 'StatusNet',
+ CURLOPT_CONNECTTIMEOUT => 120,
+ CURLOPT_TIMEOUT => 120,
+ CURLOPT_HTTPAUTH => CURLAUTH_ANY,
+ CURLOPT_SSL_VERIFYPEER => false,
+
+ // Twitter is strict about accepting invalid "Expect" headers
+
+ CURLOPT_HTTPHEADER => array('Expect:')
+ );
+
+ if (isset($params)) {
+ $options[CURLOPT_POST] = true;
+ $options[CURLOPT_POSTFIELDS] = $params;
+ }
+
+ $ch = curl_init($url);
+ curl_setopt_array($ch, $options);
+ $response = curl_exec($ch);
+
+ if ($response === false) {
+ $msg = curl_error($ch);
+ $code = curl_errno($ch);
+ throw new OAuthClientCurlException($msg, $code);
+ }
+
+ curl_close($ch);
+
+ return $response;
+ }
+
+}
diff --git a/lib/oauthstore.php b/lib/oauthstore.php
index f224c6c22..6db07b20f 100644
--- a/lib/oauthstore.php
+++ b/lib/oauthstore.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,11 +17,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/omb.php');
-class LaconicaOAuthDataStore extends OAuthDataStore
+class StatusNetOAuthDataStore extends OAuthDataStore
{
// We keep a record of who's contacted us
diff --git a/lib/omb.php b/lib/omb.php
index 4f6a96095..7dca760c6 100644
--- a/lib/omb.php
+++ b/lib/omb.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once('OAuth.php');
require_once(INSTALLDIR.'/lib/oauthstore.php');
@@ -66,7 +66,7 @@ function omb_oauth_datastore()
{
static $store = null;
if (!$store) {
- $store = new LaconicaOAuthDataStore();
+ $store = new StatusNetOAuthDataStore();
}
return $store;
}
@@ -135,7 +135,7 @@ function omb_broadcast_remote_subscribers($notice)
$posted = array();
while ($rp->fetch()) {
- if (!$posted[$rp->postnoticeurl]) {
+ if (!array_key_exists($rp->postnoticeurl, $posted)) {
common_log(LOG_DEBUG, 'Posting to ' . $rp->postnoticeurl);
if (omb_post_notice_keys($notice, $rp->postnoticeurl, $rp->token, $rp->secret)) {
common_log(LOG_DEBUG, 'Finished to ' . $rp->postnoticeurl);
@@ -202,7 +202,7 @@ function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret)
$result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(),
- array('User-Agent: Laconica/' . LACONICA_VERSION));
+ array('User-Agent: StatusNet/' . STATUSNET_VERSION));
if ($result->status == 403) { # not authorized, don't send again
common_debug('403 result, deleting subscription', __FILE__);
@@ -282,7 +282,7 @@ function omb_update_profile($profile, $remote_profile, $subscription)
$result = $fetcher->post($req->get_normalized_http_url(),
$req->to_postdata(),
- array('User-Agent: Laconica/' . LACONICA_VERSION));
+ array('User-Agent: StatusNet/' . STATUSNET_VERSION));
if (empty($result) || !$result) {
common_debug("Unable to contact " . $req->get_normalized_http_url());
diff --git a/lib/openid.php b/lib/openid.php
index 0b7633284..7a2c46f00 100644
--- a/lib/openid.php
+++ b/lib/openid.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/classes/User_openid.php');
diff --git a/lib/ownerdesignaction.php b/lib/ownerdesignaction.php
index 785b8a93d..d557f10c0 100644
--- a/lib/ownerdesignaction.php
+++ b/lib/ownerdesignaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for actions that use the page owner's design
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ if (!defined('LACONICA')) {
* design.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
*/
@@ -53,26 +53,6 @@ class OwnerDesignAction extends Action {
var $user = null;
/**
- * Show the owner's design stylesheet
- *
- * @return nothing
- */
- function showStylesheets()
- {
- parent::showStylesheets();
-
- $user = common_current_user();
-
- if (empty($user) || $user->viewdesigns) {
- $design = $this->getDesign();
-
- if (!empty($design)) {
- $design->showCSS($this);
- }
- }
- }
-
- /**
* A design for this action
*
* if the user attribute has been set, returns that user's
@@ -83,10 +63,15 @@ class OwnerDesignAction extends Action {
function getDesign()
{
- if (empty($this->user)) {
- return null;
+ if (!empty($this->user)) {
+
+ $design = $this->user->getDesign();
+
+ if (!empty($design)) {
+ return $design;
+ }
}
- return $this->user->getDesign();
+ return parent::getDesign();
}
}
diff --git a/lib/parallelizingdaemon.php b/lib/parallelizingdaemon.php
new file mode 100644
index 000000000..517115de0
--- /dev/null
+++ b/lib/parallelizingdaemon.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Base class for making daemons that can do several tasks in parallel.
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Daemon
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+declare(ticks = 1);
+
+/**
+ * Daemon able to spawn multiple child processes to do work in parallel
+ *
+ * @category Daemon
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class ParallelizingDaemon extends Daemon
+{
+ private $_children = array();
+ private $_interval = 0; // seconds
+ private $_max_children = 0; // maximum number of children
+ private $_debug = false;
+
+ /**
+ * Constructor
+ *
+ * @param string $id the name/id of this daemon
+ * @param int $interval sleep this long before doing everything again
+ * @param int $max_children maximum number of child processes at a time
+ * @param boolean $debug debug output flag
+ *
+ * @return void
+ *
+ **/
+
+ function __construct($id = null, $interval = 60, $max_children = 2,
+ $debug = null)
+ {
+ parent::__construct(true); // daemonize
+
+ $this->_interval = $interval;
+ $this->_max_children = $max_children;
+ $this->_debug = $debug;
+
+ if (isset($id)) {
+ $this->set_id($id);
+ }
+ }
+
+ /**
+ * Run the daemon
+ *
+ * @return void
+ */
+
+ function run()
+ {
+ if (isset($this->_debug)) {
+ echo $this->name() . " - Debugging output enabled.\n";
+ }
+
+ do {
+
+ $objects = $this->getObjects();
+
+ foreach ($objects as $o) {
+
+ // Fork a child for each object
+
+ $pid = pcntl_fork();
+
+ if ($pid == -1) {
+ die ($this->name() . ' - Couldn\'t fork!');
+ }
+
+ if ($pid) {
+
+ // Parent
+
+ if (isset($this->_debug)) {
+ echo $this->name() .
+ " - Forked new child - pid $pid.\n";
+
+ }
+
+ $this->_children[] = $pid;
+
+ } else {
+
+ // Child
+
+ // Do something with each object
+
+ $this->childTask($o);
+
+ exit();
+ }
+
+ // Remove child from ps list as it finishes
+
+ while (($c = pcntl_wait($status, WNOHANG OR WUNTRACED)) > 0) {
+
+ if (isset($this->_debug)) {
+ echo $this->name() . " - Child $c finished.\n";
+ }
+
+ $this->removePs($this->_children, $c);
+ }
+
+ // Wait! We have too many damn kids.
+
+ if (sizeof($this->_children) >= $this->_max_children) {
+
+ if (isset($this->_debug)) {
+ echo $this->name() . " - Too many children. Waiting...\n";
+ }
+
+ if (($c = pcntl_wait($status, WUNTRACED)) > 0) {
+
+ if (isset($this->_debug)) {
+ echo $this->name() .
+ " - Finished waiting for child $c.\n";
+ }
+
+ $this->removePs($this->_children, $c);
+ }
+ }
+ }
+
+ // Remove all children from the process list before restarting
+ while (($c = pcntl_wait($status, WUNTRACED)) > 0) {
+
+ if (isset($this->_debug)) {
+ echo $this->name() . " - Child $c finished.\n";
+ }
+
+ $this->removePs($this->_children, $c);
+ }
+
+ // Rest for a bit
+
+ if (isset($this->_debug)) {
+ echo $this->name() . ' - Waiting ' . $this->_interval .
+ " secs before running again.\n";
+ }
+
+ if ($this->_interval > 0) {
+ sleep($this->_interval);
+ }
+
+ } while (true);
+ }
+
+ /**
+ * Remove a child process from the list of children
+ *
+ * @param array &$plist array of processes
+ * @param int $ps process id
+ *
+ * @return void
+ */
+
+ function removePs(&$plist, $ps)
+ {
+ for ($i = 0; $i < sizeof($plist); $i++) {
+ if ($plist[$i] == $ps) {
+ unset($plist[$i]);
+ $plist = array_values($plist);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Get a list of objects to work on in parallel
+ *
+ * @return array An array of objects to work on
+ */
+
+ function getObjects()
+ {
+ die('Implement ParallelizingDaemon::getObjects().');
+ }
+
+ /**
+ * Do something with each object in parallel
+ *
+ * @param mixed $object data to work on
+ *
+ * @return void
+ */
+
+ function childTask($object)
+ {
+ die("Implement ParallelizingDaemon::childTask($object).");
+ }
+
+} \ No newline at end of file
diff --git a/lib/personalgroupnav.php b/lib/personalgroupnav.php
index acc033667..cdde1feca 100644
--- a/lib/personalgroupnav.php
+++ b/lib/personalgroupnav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for all actions (~views)
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -44,11 +44,11 @@ require_once INSTALLDIR.'/lib/widget.php';
* model classes to read and write to the database; and doing ouput.
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
diff --git a/lib/personaltagcloudsection.php b/lib/personaltagcloudsection.php
index 978153a84..0b29d58ca 100644
--- a/lib/personaltagcloudsection.php
+++ b/lib/personaltagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Personal tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class PersonalTagCloudSection extends TagCloudSection
diff --git a/lib/ping.php b/lib/ping.php
index d26c73417..175bf8440 100644
--- a/lib/ping.php
+++ b/lib/ping.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
function ping_broadcast_notice($notice) {
@@ -47,7 +47,7 @@ function ping_broadcast_notice($notice) {
$context = stream_context_create(array('http' => array('method' => "POST",
'header' =>
"Content-Type: text/xml\r\n".
- "User-Agent: Laconica/".LACONICA_VERSION."\r\n",
+ "User-Agent: StatusNet/".STATUSNET_VERSION."\r\n",
'content' => $req)));
$file = file_get_contents($notify_url, false, $context);
@@ -81,11 +81,11 @@ function ping_broadcast_notice($notice) {
if ($type === 'get') {
$result = $fetcher->get($notify_url . '?' . http_build_query($args),
- array('User-Agent: Laconica/'.LACONICA_VERSION));
+ array('User-Agent: StatusNet/'.STATUSNET_VERSION));
} else {
$result = $fetcher->post($notify_url,
http_build_query($args),
- array('User-Agent: Laconica/'.LACONICA_VERSION));
+ array('User-Agent: StatusNet/'.STATUSNET_VERSION));
}
if ($result->status != '200') {
common_log(LOG_WARNING,
diff --git a/lib/plugin.php b/lib/plugin.php
index 7b2436e54..87d7be5a7 100644
--- a/lib/plugin.php
+++ b/lib/plugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Utility class for plugins
*
@@ -20,21 +20,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
/**
* Base class for plugins
*
- * A base class for Laconica plugins. Mostly a light wrapper around
+ * A base class for StatusNet plugins. Mostly a light wrapper around
* the Event framework.
*
* Subclasses of Plugin will automatically handle an event if they define
@@ -45,10 +45,10 @@ if (!defined('LACONICA')) {
* initialize() and cleanup() methods, respectively.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Event
*/
diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php
index 167a6ff8d..35b914a50 100644
--- a/lib/popularnoticesection.php
+++ b/lib/popularnoticesection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for sections showing lists of notices
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ if (!defined('LACONICA')) {
* group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class PopularNoticeSection extends NoticeSection
diff --git a/lib/profileaction.php b/lib/profileaction.php
index 9e9c79c78..e3a39ad8b 100644
--- a/lib/profileaction.php
+++ b/lib/profileaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Common parent of Personal and Profile actions
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -41,10 +41,10 @@ require_once INSTALLDIR.'/lib/groupminilist.php';
* Abstracts out common code from profile and personal tabs
*
* @category Personal
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ProfileAction extends OwnerDesignAction
diff --git a/lib/profilelist.php b/lib/profilelist.php
index 774538a4b..331430b3e 100644
--- a/lib/profilelist.php
+++ b/lib/profilelist.php
@@ -1,7 +1,7 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Widget to show a list of profiles
*
@@ -21,14 +21,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/widget.php';
* Widget to show a list of profiles
*
* @category Public
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ProfileList extends Widget
diff --git a/lib/profileminilist.php b/lib/profileminilist.php
index 357b4a2db..079170d80 100644
--- a/lib/profileminilist.php
+++ b/lib/profileminilist.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Widget to show a list of profiles
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ define('PROFILES_PER_MINILIST', 27);
* Widget to show a list of profiles, good for sidebar
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ProfileMiniList extends ProfileList
diff --git a/lib/profilesection.php b/lib/profilesection.php
index 9ff243fb5..504b1b7f7 100644
--- a/lib/profilesection.php
+++ b/lib/profilesection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for sections showing lists of people
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ define('PROFILES_PER_SECTION', 6);
* group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ProfileSection extends Section
@@ -97,7 +97,7 @@ class ProfileSection extends Section
$this->out->elementEnd('a');
$this->out->elementEnd('span');
$this->out->elementEnd('td');
- if ($profile->value) {
+ if (isset($profile->value)) {
$this->out->element('td', 'value', $profile->value);
}
diff --git a/lib/publicgroupnav.php b/lib/publicgroupnav.php
index 485d25e20..ae9cbdebb 100644
--- a/lib/publicgroupnav.php
+++ b/lib/publicgroupnav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Menu for public group of actions
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Menu
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,11 +37,11 @@ require_once INSTALLDIR.'/lib/widget.php';
* Menu for public group of actions
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
diff --git a/lib/queuehandler.php b/lib/queuehandler.php
index f11e5bd90..8c65a97c6 100644
--- a/lib/queuehandler.php
+++ b/lib/queuehandler.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/daemon.php');
require_once(INSTALLDIR.'/classes/Queue_item.php');
@@ -75,6 +75,7 @@ class QueueHandler extends Daemon
function run()
{
if (!$this->start()) {
+ $this->log(LOG_WARNING, 'failed to start');
return false;
}
@@ -87,9 +88,15 @@ class QueueHandler extends Daemon
$qm->service($queue, $this);
+ $this->log(LOG_INFO, 'finished servicing the queue');
+
if (!$this->finish()) {
+ $this->log(LOG_WARNING, 'failed to clean up');
return false;
}
+
+ $this->log(LOG_INFO, 'terminating normally');
+
return true;
}
diff --git a/lib/queuemanager.php b/lib/queuemanager.php
index 582c24790..43105b7a8 100644
--- a/lib/queuemanager.php
+++ b/lib/queuemanager.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Abstract class for queue managers
*
@@ -20,12 +20,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category QueueManager
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class QueueManager
diff --git a/lib/router.php b/lib/router.php
index 8e4836497..5529e60ac 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* URL routing utilities
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category URL
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -39,10 +39,10 @@ require_once 'Net/URL/Mapper.php';
* Cheap wrapper around Net_URL_Mapper
*
* @category URL
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class Router
@@ -88,6 +88,10 @@ class Router
$m->connect('doc/:title', array('action' => 'doc'));
+ // Twitter
+
+ $m->connect('twitter/authorization', array('action' => 'twitterauthorization'));
+
// facebook
$m->connect('facebook', array('action' => 'facebookhome'));
@@ -113,6 +117,9 @@ class Router
$m->connect('main/tagother/:id', array('action' => 'tagother'));
+ $m->connect('main/oembed',
+ array('action' => 'oembed'));
+
// these take a code
foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) {
@@ -129,11 +136,6 @@ class Router
$m->connect('index.php?action=' . $action, array('action' => $action));
}
- $m->connect('main/:method',
- array('action' => 'api',
- 'method' => 'oembed(.xml|.json)?',
- 'apiaction' => 'oembed'));
-
// settings
foreach (array('profile', 'avatar', 'password', 'openid', 'im',
@@ -173,6 +175,10 @@ class Router
$m->connect('notice/new?replyto=:replyto',
array('action' => 'newnotice'),
array('replyto' => '[A-Za-z0-9_-]+'));
+ $m->connect('notice/new?replyto=:replyto&inreplyto=:inreplyto',
+ array('action' => 'newnotice'),
+ array('replyto' => '[A-Za-z0-9_-]+'),
+ array('inreplyto' => '[0-9]+'));
$m->connect('notice/:notice/file',
array('action' => 'file'),
@@ -266,12 +272,12 @@ class Router
$m->connect('api/statuses/:method',
array('action' => 'api',
'apiaction' => 'statuses'),
- array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|mentions|show|friends|followers|featured)(\.(atom|rss|xml|json))?'));
+ array('method' => '(public_timeline|home_timeline|friends_timeline|user_timeline|update|replies|mentions|show|friends|followers|featured)(\.(atom|rss|xml|json))?'));
$m->connect('api/statuses/:method/:argument',
array('action' => 'api',
'apiaction' => 'statuses'),
- array('method' => '(|user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
+ array('method' => '(user_timeline|home_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
// users
@@ -393,31 +399,59 @@ class Router
array('action' => 'api',
'apiaction' => 'help'));
- // laconica
+ // statusnet
- $m->connect('api/laconica/:method',
+ $m->connect('api/statusnet/:method',
array('action' => 'api',
- 'apiaction' => 'laconica'));
+ 'apiaction' => 'statusnet'));
+
+ // For older methods, we provide "laconica" base action
$m->connect('api/laconica/:method',
array('action' => 'api',
- 'apiaction' => 'laconica'));
+ 'apiaction' => 'statusnet'));
+
+ // Groups and tags are newer than 0.8.1 so no backward-compatibility
+ // necessary
// Groups
- $m->connect('api/laconica/groups/:method/:argument',
+ //'list' has to be handled differently, as php will not allow a method to be named 'list'
+ $m->connect('api/statusnet/groups/list/:argument',
+ array('action' => 'api',
+ 'method' => 'list_groups',
+ 'apiaction' => 'groups'));
+
+ foreach (array('xml', 'json', 'rss', 'atom') as $e) {
+ $m->connect('api/statusnet/groups/list.' . $e,
+ array('action' => 'api',
+ 'method' => 'list_groups.' . $e,
+ 'apiaction' => 'groups'));
+ }
+
+ $m->connect('api/statusnet/groups/:method',
+ array('action' => 'api',
+ 'apiaction' => 'statuses'),
+ array('method' => '(list_all|)(\.(atom|rss|xml|json))?'));
+
+ $m->connect('api/statuses/:method/:argument',
+ array('action' => 'api',
+ 'apiaction' => 'statuses'),
+ array('method' => '(user_timeline|home_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
+
+ $m->connect('api/statusnet/groups/:method/:argument',
array('action' => 'api',
'apiaction' => 'groups'));
- $m->connect('api/laconica/groups/:method',
+ $m->connect('api/statusnet/groups/:method',
array('action' => 'api',
'apiaction' => 'groups'));
// Tags
- $m->connect('api/laconica/tags/:method/:argument',
+ $m->connect('api/statusnet/tags/:method/:argument',
array('action' => 'api',
'apiaction' => 'tags'));
- $m->connect('api/laconica/tags/:method',
+ $m->connect('api/statusnet/tags/:method',
array('action' => 'api',
'apiaction' => 'tags'));
diff --git a/lib/rssaction.php b/lib/rssaction.php
index 0aca96566..60611e48d 100644
--- a/lib/rssaction.php
+++ b/lib/rssaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for RSS 1.0 feed actions
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Mail
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @author Earle Martin <earle@downlode.org>
- * @copyright 2008-9 Control Yourself, Inc.
+ * @copyright 2008-9 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
define('DEFAULT_RSS_LIMIT', 48);
@@ -102,7 +102,7 @@ class Rss10Action extends Action
if (!isset($_SERVER['PHP_AUTH_USER'])) {
# This header makes basic auth go
- header('WWW-Authenticate: Basic realm="Laconica RSS"');
+ header('WWW-Authenticate: Basic realm="StatusNet RSS"');
# If the user hits cancel -- bam!
$this->show_basic_auth_error();
@@ -244,7 +244,7 @@ class Rss10Action extends Action
$this->element('dc:creator', null, ($profile->fullname) ? $profile->fullname : $profile->nickname);
$this->element('foaf:maker', array('rdf:resource' => $creator_uri));
$this->element('sioc:has_creator', array('rdf:resource' => $creator_uri.'#acct'));
- $this->element('laconica:postIcon', array('rdf:resource' => $profile->avatarUrl()));
+ $this->element('statusnet:postIcon', array('rdf:resource' => $profile->avatarUrl()));
$this->element('cc:licence', array('rdf:resource' => common_config('license', 'url')));
if ($notice->reply_to) {
$replyurl = common_local_url('shownotice', array('notice' => $notice->reply_to));
@@ -353,8 +353,8 @@ class Rss10Action extends Action
'http://rdfs.org/sioc/types#',
'xmlns:rdfs' =>
'http://www.w3.org/2000/01/rdf-schema#',
- 'xmlns:laconica' =>
- 'http://laconi.ca/ont/',
+ 'xmlns:statusnet' =>
+ 'http://status.net/ont/',
'xmlns' => 'http://purl.org/rss/1.0/'));
$this->elementStart('sioc:Site', array('rdf:about' => common_root_url()));
$this->element('sioc:name', null, common_config('site', 'name'));
diff --git a/lib/search_engines.php b/lib/search_engines.php
index 772f41883..69f6ff468 100644
--- a/lib/search_engines.php
+++ b/lib/search_engines.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
class SearchEngine
{
@@ -120,7 +120,7 @@ class MySQLSearch extends SearchEngine
} else if ('identica_notices' === $this->table) {
// Don't show imported notices
- $this->target->whereAdd('notice.is_local != ' . NOTICE_GATEWAY);
+ $this->target->whereAdd('notice.is_local != ' . Notice::GATEWAY);
if (strtolower($q) != $q) {
$this->target->whereAdd("( MATCH(content) AGAINST ('" . addslashes($q) .
diff --git a/lib/searchaction.php b/lib/searchaction.php
index 34fe9373f..0d9f85a8f 100644
--- a/lib/searchaction.php
+++ b/lib/searchaction.php
@@ -5,14 +5,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -28,7 +28,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/searchgroupnav.php';
* Base search action class.
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SearchAction extends Action
{
diff --git a/lib/searchgroupnav.php b/lib/searchgroupnav.php
index 3ba3f9cd9..677365ea9 100644
--- a/lib/searchgroupnav.php
+++ b/lib/searchgroupnav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Menu for search actions
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Menu
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/widget.php';
* Menu for public group of actions
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
diff --git a/lib/section.php b/lib/section.php
index d14575086..53a3a70fa 100644
--- a/lib/section.php
+++ b/lib/section.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for sections (sidebar widgets)
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ require_once INSTALLDIR.'/lib/widget.php';
* group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class Section extends Widget
diff --git a/lib/servererroraction.php b/lib/servererroraction.php
index db7352166..0993a63bc 100644
--- a/lib/servererroraction.php
+++ b/lib/servererroraction.php
@@ -6,14 +6,14 @@
* PHP version 5
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -29,7 +29,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -47,25 +47,30 @@ require_once INSTALLDIR.'/lib/error.php';
* See: http://tools.ietf.org/html/rfc2616#section-10
*
* @category Action
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
+
class ServerErrorAction extends ErrorAction
{
+ static $status = array(500 => 'Internal Server Error',
+ 501 => 'Not Implemented',
+ 502 => 'Bad Gateway',
+ 503 => 'Service Unavailable',
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported');
+
function __construct($message='Error', $code=500)
{
parent::__construct($message, $code);
- $this->status = array(500 => 'Internal Server Error',
- 501 => 'Not Implemented',
- 502 => 'Bad Gateway',
- 503 => 'Service Unavailable',
- 504 => 'Gateway Timeout',
- 505 => 'HTTP Version Not Supported');
-
$this->default = 500;
+
+ // Server errors must be logged.
+
+ common_log(LOG_ERR, "ServerErrorAction: $code $message");
}
// XXX: Should these error actions even be invokable via URI?
@@ -88,9 +93,4 @@ class ServerErrorAction extends ErrorAction
$this->showPage();
}
-
- function title()
- {
- return $this->status[$this->code];
- }
}
diff --git a/lib/serverexception.php b/lib/serverexception.php
index b8ed6846e..7dc9765ad 100644
--- a/lib/serverexception.php
+++ b/lib/serverexception.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* class for a server exception (user error)
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Exception
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ if (!defined('LACONICA')) {
* Subclass of PHP Exception for server errors. The user typically can't fix these.
*
* @category Exception
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class ServerException extends Exception
diff --git a/lib/settingsaction.php b/lib/settingsaction.php
index 17d3a2f64..a1f305f5b 100644
--- a/lib/settingsaction.php
+++ b/lib/settingsaction.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for settings actions
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Base class for settings group of actions
*
* @category Settings
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
diff --git a/lib/snapshot.php b/lib/snapshot.php
index 4b05b502d..ede846e5b 100644
--- a/lib/snapshot.php
+++ b/lib/snapshot.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* A snapshot of site stats that can report itself to headquarters
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Stats
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -36,16 +36,16 @@ if (!defined('LACONICA')) {
*
* This class will collect statistics on the site and report them to
* a statistics server of the admin's choice. (Default is the big one
- * at laconi.ca.)
+ * at status.net.)
*
* It can either be called from a cron job, or run occasionally by the
* Web site.
*
* @category Stats
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
*/
@@ -125,7 +125,7 @@ class Snapshot
// Some basic identification stuff
- $this->stats['version'] = LACONICA_VERSION;
+ $this->stats['version'] = STATUSNET_VERSION;
$this->stats['phpversion'] = phpversion();
$this->stats['name'] = common_config('site', 'name');
$this->stats['root'] = common_root_url();
@@ -181,7 +181,7 @@ class Snapshot
'header' => 'Content-type: '.
'application/x-www-form-urlencoded',
'content' => $postdata,
- 'user_agent' => 'Laconica/'.LACONICA_VERSION
+ 'user_agent' => 'StatusNet/'.STATUSNET_VERSION
)
);
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 46baeb5c7..f059b42f0 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Abstract class for queue managers
*
@@ -20,12 +20,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category QueueManager
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
require_once 'Stomp.php';
diff --git a/lib/subgroupnav.php b/lib/subgroupnav.php
index 520991923..2748b59e1 100644
--- a/lib/subgroupnav.php
+++ b/lib/subgroupnav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Local navigation for subscriptions group of pages
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Subs
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/widget.php';
* Local nav menu for subscriptions, subscribers
*
* @category Subs
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubGroupNav extends Widget
diff --git a/lib/subpeopletagcloudsection.php b/lib/subpeopletagcloudsection.php
index 9f6948dc9..b23a82240 100644
--- a/lib/subpeopletagcloudsection.php
+++ b/lib/subpeopletagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Personal tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubPeopleTagCloudSection extends TagCloudSection
diff --git a/lib/subs.php b/lib/subs.php
index e76023752..68c89c842 100644
--- a/lib/subs.php
+++ b/lib/subs.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once('XMPPHP/XMPP.php');
diff --git a/lib/subscribeform.php b/lib/subscribeform.php
index c65134e46..ae2a6db61 100644
--- a/lib/subscribeform.php
+++ b/lib/subscribeform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for subscribing to a user
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for subscribing to a user
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see UnsubscribeForm
*/
diff --git a/lib/subscriberspeopleselftagcloudsection.php b/lib/subscriberspeopleselftagcloudsection.php
index 115241a53..5a570ae28 100644
--- a/lib/subscriberspeopleselftagcloudsection.php
+++ b/lib/subscriberspeopleselftagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Personal tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubscribersPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
diff --git a/lib/subscriberspeopletagcloudsection.php b/lib/subscriberspeopletagcloudsection.php
index 4dafbc1c7..284996b59 100644
--- a/lib/subscriberspeopletagcloudsection.php
+++ b/lib/subscriberspeopletagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Personal tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubscribersPeopleTagCloudSection extends SubPeopleTagCloudSection
diff --git a/lib/subscriptionlist.php b/lib/subscriptionlist.php
index 23da64cca..89f63e321 100644
--- a/lib/subscriptionlist.php
+++ b/lib/subscriptionlist.php
@@ -1,7 +1,7 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Widget to show a list of profiles
*
@@ -21,14 +21,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Public
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008-2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/profilelist.php';
* Widget to show a list of subscriptions
*
* @category Public
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubscriptionList extends ProfileList
diff --git a/lib/subscriptionspeopleselftagcloudsection.php b/lib/subscriptionspeopleselftagcloudsection.php
index 3896294d2..9be60dfa1 100644
--- a/lib/subscriptionspeopleselftagcloudsection.php
+++ b/lib/subscriptionspeopleselftagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Personal tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubscriptionsPeopleSelfTagCloudSection extends SubPeopleTagCloudSection
diff --git a/lib/subscriptionspeopletagcloudsection.php b/lib/subscriptionspeopletagcloudsection.php
index f9c8672e3..fde24b282 100644
--- a/lib/subscriptionspeopletagcloudsection.php
+++ b/lib/subscriptionspeopletagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Personal tag cloud section
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class SubscriptionsPeopleTagCloudSection extends SubPeopleTagCloudSection
diff --git a/lib/tagcloudsection.php b/lib/tagcloudsection.php
index 62f7d8961..692f5d966 100644
--- a/lib/tagcloudsection.php
+++ b/lib/tagcloudsection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for sections showing tag clouds
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,10 +40,10 @@ define('TAGS_PER_SECTION', 20);
* group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class TagCloudSection extends Section
diff --git a/lib/theme.php b/lib/theme.php
index 2fe6ab69b..08e3e8538 100644
--- a/lib/theme.php
+++ b/lib/theme.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Utilities for theme files and paths
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Paths
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/lib/topposterssection.php b/lib/topposterssection.php
index 1a2ce0014..cbb6a98eb 100644
--- a/lib/topposterssection.php
+++ b/lib/topposterssection.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for sections showing lists of people
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ if (!defined('LACONICA')) {
* group, or site.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class TopPostersSection extends ProfileSection
diff --git a/lib/twitter.php b/lib/twitter.php
index 47af32e61..676c9b20a 100644
--- a/lib/twitter.php
+++ b/lib/twitter.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,83 +17,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
-
-define('TWITTER_SERVICE', 1); // Twitter is foreign_service ID 1
-
-function get_twitter_data($uri, $screen_name, $password)
-{
-
- $options = array(
- CURLOPT_USERPWD => sprintf("%s:%s", $screen_name, $password),
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_FAILONERROR => true,
- CURLOPT_HEADER => false,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_USERAGENT => "Laconica",
- CURLOPT_CONNECTTIMEOUT => 120,
- CURLOPT_TIMEOUT => 120,
- # Twitter is strict about accepting invalid "Expect" headers
- CURLOPT_HTTPHEADER => array('Expect:')
- );
-
- $ch = curl_init($uri);
- curl_setopt_array($ch, $options);
- $data = curl_exec($ch);
- $errmsg = curl_error($ch);
-
- if ($errmsg) {
- common_debug("Twitter bridge - cURL error: $errmsg - trying to load: $uri with user $screen_name.",
- __FILE__);
-
- if (defined('SCRIPT_DEBUG')) {
- print "cURL error: $errmsg - trying to load: $uri with user $screen_name.\n";
- }
- }
-
- curl_close($ch);
-
- return $data;
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
}
-function twitter_json_data($uri, $screen_name, $password)
-{
- $json_data = get_twitter_data($uri, $screen_name, $password);
-
- if (!$json_data) {
- return false;
- }
-
- $data = json_decode($json_data);
-
- if (!$data) {
- return false;
- }
-
- return $data;
-}
-
-function twitter_user_info($screen_name, $password)
-{
- $uri = "http://twitter.com/users/show/$screen_name.json";
- return twitter_json_data($uri, $screen_name, $password);
-}
-
-function twitter_friends_ids($screen_name, $password)
-{
- $uri = "http://twitter.com/friends/ids/$screen_name.json";
- return twitter_json_data($uri, $screen_name, $password);
-}
+define('TWITTER_SERVICE', 1); // Twitter is foreign_service ID 1
function update_twitter_user($twitter_id, $screen_name)
{
$uri = 'http://twitter.com/' . $screen_name;
-
$fuser = new Foreign_user();
$fuser->query('BEGIN');
- // Dropping down to SQL because regular db_object udpate stuff doesn't seem
+ // Dropping down to SQL because regular DB_DataObject udpate stuff doesn't seem
// to work so good with tables that have multiple column primary keys
// Any time we update the uri for a forein user we have to make sure there
@@ -102,35 +39,14 @@ function update_twitter_user($twitter_id, $screen_name)
$qry = 'UPDATE foreign_user set uri = \'\' WHERE uri = ';
$qry .= '\'' . $uri . '\'' . ' AND service = ' . TWITTER_SERVICE;
- $result = $fuser->query($qry);
-
- if ($result) {
- common_debug("Removed uri ($uri) from another foreign_user who was squatting on it.");
- if (defined('SCRIPT_DEBUG')) {
- print("Removed uri ($uri) from another Twitter user who was squatting on it.\n");
- }
- }
+ $fuser->query($qry);
// Update the user
+
$qry = 'UPDATE foreign_user SET nickname = ';
$qry .= '\'' . $screen_name . '\'' . ', uri = \'' . $uri . '\' ';
$qry .= 'WHERE id = ' . $twitter_id . ' AND service = ' . TWITTER_SERVICE;
- $result = $fuser->query($qry);
-
- if (!$result) {
- common_log(LOG_WARNING,
- "Couldn't update foreign_user data for Twitter user: $screen_name");
- common_log_db_error($fuser, 'UPDATE', __FILE__);
- if (defined('SCRIPT_DEBUG')) {
- print "UPDATE failed: for Twitter user: $twitter_id - $screen_name. - ";
- print common_log_objstring($fuser) . "\n";
- $error = &PEAR::getStaticProperty('DB_DataObject','lastError');
- print "DB_DataObject Error: " . $error->getMessage() . "\n";
- }
- return false;
- }
-
$fuser->query('COMMIT');
$fuser->free();
@@ -147,23 +63,22 @@ function add_twitter_user($twitter_id, $screen_name)
// Clear out any bad old foreign_users with the new user's legit URL
// This can happen when users move around or fakester accounts get
// repoed, and things like that.
+
$luser = new Foreign_user();
$luser->uri = $new_uri;
$luser->service = TWITTER_SERVICE;
$result = $luser->delete();
- if ($result) {
+ if (empty($result)) {
common_log(LOG_WARNING,
"Twitter bridge - removed invalid Twitter user squatting on uri: $new_uri");
- if (defined('SCRIPT_DEBUG')) {
- print "Removed invalid Twitter user squatting on uri: $new_uri\n";
- }
}
$luser->free();
unset($luser);
// Otherwise, create a new Twitter user
+
$fuser = new Foreign_user();
$fuser->nickname = $screen_name;
@@ -173,21 +88,12 @@ function add_twitter_user($twitter_id, $screen_name)
$fuser->created = common_sql_now();
$result = $fuser->insert();
- if (!$result) {
+ if (empty($result)) {
common_log(LOG_WARNING,
"Twitter bridge - failed to add new Twitter user: $twitter_id - $screen_name.");
common_log_db_error($fuser, 'INSERT', __FILE__);
- if (defined('SCRIPT_DEBUG')) {
- print "INSERT failed: could not add new Twitter user: $twitter_id - $screen_name. - ";
- print common_log_objstring($fuser) . "\n";
- $error = &PEAR::getStaticProperty('DB_DataObject','lastError');
- print "DB_DataObject Error: " . $error->getMessage() . "\n";
- }
} else {
common_debug("Twitter bridge - Added new Twitter user: $screen_name ($twitter_id).");
- if (defined('SCRIPT_DEBUG')) {
- print "Added new Twitter user: $screen_name ($twitter_id).\n";
- }
}
return $result;
@@ -199,23 +105,20 @@ function save_twitter_user($twitter_id, $screen_name)
// Check to see whether the Twitter user is already in the system,
// and update its screen name and uri if so.
+
$fuser = Foreign_user::getForeignUser($twitter_id, TWITTER_SERVICE);
- if ($fuser) {
+ if (!empty($fuser)) {
$result = true;
// Only update if Twitter screen name has changed
+
if ($fuser->nickname != $screen_name) {
$result = update_twitter_user($twitter_id, $screen_name);
common_debug('Twitter bridge - Updated nickname (and URI) for Twitter user ' .
"$fuser->id to $screen_name, was $fuser->nickname");
-
- if (defined('SCRIPT_DEBUG')) {
- print 'Updated nickname (and URI) for Twitter user ' .
- "$fuser->id to $screen_name, was $fuser->nickname\n";
- }
}
return $result;
@@ -230,119 +133,6 @@ function save_twitter_user($twitter_id, $screen_name)
return true;
}
-function retreive_twitter_friends($twitter_id, $screen_name, $password)
-{
- $friends = array();
-
- $uri = "http://twitter.com/statuses/friends/$twitter_id.json?page=";
- $friends_ids = twitter_friends_ids($screen_name, $password);
-
- if (!$friends_ids) {
- return $friends;
- }
-
- if (defined('SCRIPT_DEBUG')) {
- print "Twitter 'social graph' ids method says $screen_name has " .
- count($friends_ids) . " friends.\n";
- }
-
- // Calculate how many pages to get...
- $pages = ceil(count($friends_ids) / 100);
-
- if ($pages == 0) {
- common_log(LOG_WARNING,
- "Twitter bridge - $screen_name seems to have no friends.");
- if (defined('SCRIPT_DEBUG')) {
- print "$screen_name seems to have no friends.\n";
- }
- }
-
- for ($i = 1; $i <= $pages; $i++) {
-
- $data = get_twitter_data($uri . $i, $screen_name, $password);
-
- if (!$data) {
- common_log(LOG_WARNING,
- "Twitter bridge - Couldn't retrieve page $i of $screen_name's friends.");
- if (defined('SCRIPT_DEBUG')) {
- print "Couldn't retrieve page $i of $screen_name's friends.\n";
- }
- continue;
- }
-
- $more_friends = json_decode($data);
-
- if (!$more_friends) {
-
- common_log(LOG_WARNING,
- "Twitter bridge - No data for page $i of $screen_name's friends.");
- if (defined('SCRIPT_DEBUG')) {
- print "No data for page $i of $screen_name's friends.\n";
- }
- continue;
- }
-
- $friends = array_merge($friends, $more_friends);
- }
-
- return $friends;
-}
-
-function save_twitter_friends($user, $twitter_id, $screen_name, $password)
-{
-
- $friends = retreive_twitter_friends($twitter_id, $screen_name, $password);
-
- if (empty($friends)) {
- common_debug("Twitter bridge - Couldn't get friends data from Twitter for $screen_name.");
- if (defined('SCRIPT_DEBUG')) {
- print "Couldn't get friends data from Twitter for $screen_name.\n";
- }
- return false;
- }
-
- foreach ($friends as $friend) {
-
- $friend_name = $friend->screen_name;
- $friend_id = (int) $friend->id;
-
- // Update or create the Foreign_user record
- if (!save_twitter_user($friend_id, $friend_name)) {
- common_log(LOG_WARNING,
- "Twitter bridge - couldn't save $screen_name's friend, $friend_name.");
- if (defined('SCRIPT_DEBUG')) {
- print "Couldn't save $screen_name's friend, $friend_name.\n";
- }
- continue;
- }
-
- // Check to see if there's a related local user
- $flink = Foreign_link::getByForeignID($friend_id, 1);
-
- if ($flink) {
-
- // Get associated user and subscribe her
- $friend_user = User::staticGet('id', $flink->user_id);
- if (!empty($friend_user)) {
- $result = subs_subscribe_to($user, $friend_user);
-
- if ($result === true) {
- common_debug("Twitter bridge - subscribed $friend_user->nickname to $user->nickname.");
- if (defined('SCRIPT_DEBUG')) {
- print("Subscribed $friend_user->nickname to $user->nickname.\n");
- }
- } else {
- if (defined('SCRIPT_DEBUG')) {
- print "$result ($friend_user->nickname to $user->nickname)\n";
- }
- }
- }
- }
- }
-
- return true;
-}
-
function is_twitter_bound($notice, $flink) {
// Check to see if notice should go to Twitter
@@ -351,7 +141,7 @@ function is_twitter_bound($notice, $flink) {
// If it's not a Twitter-style reply, or if the user WANTS to send replies.
if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) ||
($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) {
- return true;
+ return true;
}
}
@@ -360,107 +150,125 @@ function is_twitter_bound($notice, $flink) {
function broadcast_twitter($notice)
{
-
$flink = Foreign_link::getByUserID($notice->profile_id,
- TWITTER_SERVICE);
+ TWITTER_SERVICE);
if (is_twitter_bound($notice, $flink)) {
+ if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
+ return broadcast_oauth($notice, $flink);
+ } else {
+ return broadcast_basicauth($notice, $flink);
+ }
+ }
- $fuser = $flink->getForeignUser();
- $twitter_user = $fuser->nickname;
- $twitter_password = $flink->credentials;
- $uri = 'http://www.twitter.com/statuses/update.json';
-
- // XXX: Hack to get around PHP cURL's use of @ being a a meta character
- $statustxt = preg_replace('/^@/', ' @', $notice->content);
-
- $options = array(
- CURLOPT_USERPWD => "$twitter_user:$twitter_password",
- CURLOPT_POST => true,
- CURLOPT_POSTFIELDS =>
- array(
- 'status' => $statustxt,
- 'source' => common_config('integration', 'source')
- ),
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_FAILONERROR => true,
- CURLOPT_HEADER => false,
- CURLOPT_FOLLOWLOCATION => true,
- CURLOPT_USERAGENT => "Laconica",
- CURLOPT_CONNECTTIMEOUT => 120, // XXX: How long should this be?
- CURLOPT_TIMEOUT => 120,
+ return true;
+}
- # Twitter is strict about accepting invalid "Expect" headers
- CURLOPT_HTTPHEADER => array('Expect:')
- );
+function broadcast_oauth($notice, $flink) {
- $ch = curl_init($uri);
- curl_setopt_array($ch, $options);
- $data = curl_exec($ch);
- $errmsg = curl_error($ch);
- $errno = curl_errno($ch);
+ $user = $flink->getUser();
+ $statustxt = format_status($notice);
+ $token = TwitterOAuthClient::unpackToken($flink->credentials);
+ $client = new TwitterOAuthClient($token->key, $token->secret);
+ $status = null;
+
+ try {
+ $status = $client->statusesUpdate($statustxt);
+ } catch (OAuthClientCurlException $e) {
+ return process_error($e, $flink);
+ }
- if (!empty($errmsg)) {
- common_debug("cURL error ($errno): $errmsg - " .
- "trying to send notice for $twitter_user.",
- __FILE__);
+ if (empty($status)) {
- $user = $flink->getUser();
+ // This could represent a failure posting,
+ // or the Twitter API might just be behaving flakey.
- if ($errmsg == 'The requested URL returned error: 401') {
- common_debug(sprintf('User %s (user id: %s) ' .
- 'has bad Twitter credentials!',
- $user->nickname, $user->id));
+ $errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
+ 'trying to send update for %1$s (user id %2$s).',
+ $user->nickname, $user->id);
+ common_log(LOG_WARNING, $errmsg);
- // Bad credentials we need to delete the foreign_link
- // to Twitter and inform the user.
+ return false;
+ }
- remove_twitter_link($flink);
+ // Notice crossed the great divide
- return true;
+ $msg = sprintf('Twitter bridge - posted notice %s to Twitter using OAuth.',
+ $notice->id);
+ common_log(LOG_INFO, $msg);
- } else {
+ return true;
+}
- // Some other error happened, so we should try to
- // send again later
+function broadcast_basicauth($notice, $flink)
+{
+ $user = $flink->getUser();
- return false;
- }
+ $statustxt = format_status($notice);
- }
+ $client = new TwitterBasicAuthClient($flink);
+ $status = null;
- curl_close($ch);
+ try {
+ $status = $client->statusesUpdate($statustxt);
+ } catch (BasicAuthCurlException $e) {
+ return process_error($e, $flink);
+ }
- if (empty($data)) {
- common_debug("No data returned by Twitter's " .
- "API trying to send update for $twitter_user",
- __FILE__);
+ if (empty($status)) {
- // XXX: Not sure this represents a failure to send, but it
- // probably does
+ $errmsg = sprintf('Twitter bridge - No data returned by Twitter API when ' .
+ 'trying to send update for %1$s (user id %2$s).',
+ $user->nickname, $user->id);
+ common_log(LOG_WARNING, $errmsg);
- return false;
+ return false;
+ }
- } else {
+ $msg = sprintf('Twitter bridge - posted notice %s to Twitter using basic auth.',
+ $notice->id);
+ common_log(LOG_INFO, $msg);
- // Twitter should return a status
- $status = json_decode($data);
+ return true;
+}
- if (empty($status)) {
- common_debug("Unexpected data returned by Twitter " .
- " API trying to send update for $twitter_user",
- __FILE__);
+function process_error($e, $flink)
+{
+ $user = $flink->getUser();
+ $errmsg = $e->getMessage();
+ $delivered = false;
+
+ switch($errmsg) {
+ case 'The requested URL returned error: 401':
+ $logmsg = sprintf('Twiter bridge - User %1$s (user id: %2$s) has an invalid ' .
+ 'Twitter screen_name/password combo or an invalid acesss token.',
+ $user->nickname, $user->id);
+ $delivered = true;
+ remove_twitter_link($flink);
+ break;
+ case 'The requested URL returned error: 403':
+ $logmsg = sprintf('Twitter bridge - User %1$s (user id: %2$s) has exceeded ' .
+ 'his/her Twitter request limit.',
+ $user->nickname, $user->id);
+ break;
+ default:
+ $logmsg = sprintf('Twitter bridge - cURL error trying to send notice to Twitter ' .
+ 'for user %1$s (user id: %2$s) - ' .
+ 'code: %3$s message: %4$s.',
+ $user->nickname, $user->id,
+ $e->getCode(), $e->getMessage());
+ break;
+ }
- // XXX: Again, this could represent a failure posting
- // or the Twitter API might just be behaving flakey.
- // We're treating it as a failure to post.
+ common_log(LOG_WARNING, $logmsg);
- return false;
- }
- }
- }
+ return $delivered;
+}
- return true;
+function format_status($notice)
+{
+ // XXX: Hack to get around PHP cURL's use of @ being a a meta character
+ return preg_replace('/^@/', ' @', $notice->content);
}
function remove_twitter_link($flink)
@@ -468,29 +276,31 @@ function remove_twitter_link($flink)
$user = $flink->getUser();
common_log(LOG_INFO, 'Removing Twitter bridge Foreign link for ' .
- "user $user->nickname (user id: $user->id).");
+ "user $user->nickname (user id: $user->id).");
$result = $flink->delete();
if (empty($result)) {
common_log(LOG_ERR, 'Could not remove Twitter bridge ' .
- "Foreign_link for $user->nickname (user id: $user->id)!");
+ "Foreign_link for $user->nickname (user id: $user->id)!");
common_log_db_error($flink, 'DELETE', __FILE__);
}
// Notify the user that her Twitter bridge is down
- $result = mail_twitter_bridge_removed($user);
+ if (isset($user->email)) {
- if (!$result) {
+ $result = mail_twitter_bridge_removed($user);
- $msg = 'Unable to send email to notify ' .
- "$user->nickname (user id: $user->id) " .
- 'that their Twitter bridge link was ' .
- 'removed!';
+ if (!$result) {
- common_log(LOG_WARNING, $msg);
+ $msg = 'Unable to send email to notify ' .
+ "$user->nickname (user id: $user->id) " .
+ 'that their Twitter bridge link was ' .
+ 'removed!';
+
+ common_log(LOG_WARNING, $msg);
+ }
}
}
-
diff --git a/lib/twitterapi.php b/lib/twitterapi.php
index b2602e77c..3bac400e2 100644
--- a/lib/twitterapi.php
+++ b/lib/twitterapi.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -88,7 +88,7 @@ class TwitterapiAction extends Action
Avatar::defaultImage(AVATAR_STREAM_SIZE);
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
- $twitter_user['protected'] = false; # not supported by Laconica yet
+ $twitter_user['protected'] = false; # not supported by StatusNet yet
$twitter_user['followers_count'] = $profile->subscriberCount();
// To be supported soon...
@@ -159,7 +159,7 @@ class TwitterapiAction extends Action
$twitter_status = array();
$twitter_status['text'] = $notice->content;
- $twitter_status['truncated'] = false; # Not possible on Laconica
+ $twitter_status['truncated'] = false; # Not possible on StatusNet
$twitter_status['created_at'] = $this->date_twitter($notice->created);
$twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ?
intval($notice->reply_to) : null;
@@ -188,20 +188,20 @@ class TwitterapiAction extends Action
// Enclosures
$attachments = $notice->attachments();
- $enclosures = array();
- foreach ($attachments as $attachment) {
- if ($attachment->isEnclosure()) {
- $enclosure = array();
- $enclosure['url'] = $attachment->url;
- $enclosure['mimetype'] = $attachment->mimetype;
- $enclosure['size'] = $attachment->size;
- $enclosures[] = $enclosure;
- }
- }
+ if (!empty($attachments)) {
- if (!empty($enclosures)) {
- $twitter_status['attachments'] = $enclosures;
+ $twitter_status['attachments'] = array();
+
+ foreach ($attachments as $attachment) {
+ if ($attachment->isEnclosure()) {
+ $enclosure = array();
+ $enclosure['url'] = $attachment->url;
+ $enclosure['mimetype'] = $attachment->mimetype;
+ $enclosure['size'] = $attachment->size;
+ $twitter_status['attachments'][] = $enclosure;
+ }
+ }
}
if ($include_user) {
@@ -213,6 +213,44 @@ class TwitterapiAction extends Action
return $twitter_status;
}
+ function twitter_group_array($group)
+ {
+ $twitter_group=array();
+ $twitter_group['id']=$group->id;
+ $twitter_group['url']=$group->permalink();
+ $twitter_group['nickname']=$group->nickname;
+ $twitter_group['fullname']=$group->fullname;
+ $twitter_group['homepage_url']=$group->homepage_url;
+ $twitter_group['original_logo']=$group->original_logo;
+ $twitter_group['homepage_logo']=$group->homepage_logo;
+ $twitter_group['stream_logo']=$group->stream_logo;
+ $twitter_group['mini_logo']=$group->mini_logo;
+ $twitter_group['homepage']=$group->homepage;
+ $twitter_group['description']=$group->description;
+ $twitter_group['location']=$group->location;
+ $twitter_group['created']=$this->date_twitter($group->created);
+ $twitter_group['modified']=$this->date_twitter($group->modified);
+ return $twitter_group;
+ }
+
+ function twitter_rss_group_array($group)
+ {
+ $entry = array();
+ $entry['content']=$group->description;
+ $entry['title']=$group->nickname;
+ $entry['link']=$group->permalink();
+ $entry['published']=common_date_iso8601($group->created);
+ $entry['updated']==common_date_iso8601($group->modified);
+ $taguribase = common_config('integration', 'groupuri');
+ $entry['id'] = "group:$groupuribase:$entry[link]";
+
+ $entry['description'] = $entry['content'];
+ $entry['pubDate'] = common_date_rfc2822($group->created);
+ $entry['guid'] = $entry['link'];
+
+ return $entry;
+ }
+
function twitter_rss_entry_array($notice)
{
$profile = $notice->getProfile();
@@ -413,6 +451,15 @@ class TwitterapiAction extends Action
$this->elementEnd('status');
}
+ function show_twitter_xml_group($twitter_group)
+ {
+ $this->elementStart('group');
+ foreach($twitter_group as $element => $value) {
+ $this->element($element, null, $value);
+ }
+ $this->elementEnd('group');
+ }
+
function show_twitter_xml_user($twitter_user, $role='user')
{
$this->elementStart($role);
@@ -450,12 +497,12 @@ class TwitterapiAction extends Action
$this->element('link', null, $entry['link']);
# RSS only supports 1 enclosure per item
- if($entry['enclosures']){
+ if(array_key_exists('enclosures', $entry) and !empty($entry['enclosures'])){
$enclosure = $entry['enclosures'][0];
$this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null);
}
-
- if($entry['tags']){
+
+ if(array_key_exists('tags', $entry)){
foreach($entry['tags'] as $tag){
$this->element('category', null,$tag);
}
@@ -615,6 +662,65 @@ class TwitterapiAction extends Action
}
+ function show_rss_groups($group, $title, $link, $subtitle)
+ {
+
+ $this->init_document('rss');
+
+ $this->elementStart('channel');
+ $this->element('title', null, $title);
+ $this->element('link', null, $link);
+ $this->element('description', null, $subtitle);
+ $this->element('language', null, 'en-us');
+ $this->element('ttl', null, '40');
+
+ if (is_array($group)) {
+ foreach ($group as $g) {
+ $twitter_group = $this->twitter_rss_group_array($g);
+ $this->show_twitter_rss_item($twitter_group);
+ }
+ } else {
+ while ($group->fetch()) {
+ $twitter_group = $this->twitter_rss_group_array($group);
+ $this->show_twitter_rss_item($twitter_group);
+ }
+ }
+
+ $this->elementEnd('channel');
+ $this->end_twitter_rss();
+ }
+
+ function show_atom_groups($group, $title, $id, $link, $subtitle=null, $selfuri=null)
+ {
+
+ $this->init_document('atom');
+
+ $this->element('title', null, $title);
+ $this->element('id', null, $id);
+ $this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null);
+
+ if (!is_null($selfuri)) {
+ $this->element('link', array('href' => $selfuri,
+ 'rel' => 'self', 'type' => 'application/atom+xml'), null);
+ }
+
+ $this->element('updated', null, common_date_iso8601('now'));
+ $this->element('subtitle', null, $subtitle);
+
+ if (is_array($group)) {
+ foreach ($group as $g) {
+ $this->raw($g->asAtomEntry());
+ }
+ } else {
+ while ($group->fetch()) {
+ $this->raw($group->asAtomEntry());
+ }
+ }
+
+ $this->end_document('atom');
+
+ }
+
function show_json_timeline($notice)
{
@@ -639,6 +745,114 @@ class TwitterapiAction extends Action
$this->end_document('json');
}
+ function show_json_groups($group)
+ {
+
+ $this->init_document('json');
+
+ $groups = array();
+
+ if (is_array($group)) {
+ foreach ($group as $g) {
+ $twitter_group = $this->twitter_group_array($g);
+ array_push($groups, $twitter_group);
+ }
+ } else {
+ while ($group->fetch()) {
+ $twitter_group = $this->twitter_group_array($group);
+ array_push($groups, $twitter_group);
+ }
+ }
+
+ $this->show_json_objects($groups);
+
+ $this->end_document('json');
+ }
+
+ function show_xml_groups($group)
+ {
+
+ $this->init_document('xml');
+ $this->elementStart('groups', array('type' => 'array'));
+
+ if (is_array($group)) {
+ foreach ($group as $g) {
+ $twitter_group = $this->twitter_group_array($g);
+ $this->show_twitter_xml_group($twitter_group);
+ }
+ } else {
+ while ($group->fetch()) {
+ $twitter_group = $this->twitter_group_array($group);
+ $this->show_twitter_xml_group($twitter_group);
+ }
+ }
+
+ $this->elementEnd('groups');
+ $this->end_document('xml');
+ }
+
+ function show_twitter_xml_users($user)
+ {
+
+ $this->init_document('xml');
+ $this->elementStart('users', array('type' => 'array'));
+
+ if (is_array($user)) {
+ foreach ($group as $g) {
+ $twitter_user = $this->twitter_user_array($g);
+ $this->show_twitter_xml_user($twitter_user,'user');
+ }
+ } else {
+ while ($user->fetch()) {
+ $twitter_user = $this->twitter_user_array($user);
+ $this->show_twitter_xml_user($twitter_user);
+ }
+ }
+
+ $this->elementEnd('users');
+ $this->end_document('xml');
+ }
+
+ function show_json_users($user)
+ {
+
+ $this->init_document('json');
+
+ $users = array();
+
+ if (is_array($user)) {
+ foreach ($user as $u) {
+ $twitter_user = $this->twitter_user_array($u);
+ array_push($users, $twitter_user);
+ }
+ } else {
+ while ($user->fetch()) {
+ $twitter_user = $this->twitter_user_array($user);
+ array_push($users, $twitter_user);
+ }
+ }
+
+ $this->show_json_objects($users);
+
+ $this->end_document('json');
+ }
+
+ function show_single_json_group($group)
+ {
+ $this->init_document('json');
+ $twitter_group = $this->twitter_group_array($group);
+ $this->show_json_objects($twitter_group);
+ $this->end_document('json');
+ }
+
+ function show_single_xml_group($group)
+ {
+ $this->init_document('xml');
+ $twitter_group = $this->twitter_group_array($group);
+ $this->show_twitter_xml_group($twitter_group);
+ $this->end_document('xml');
+ }
+
// Anyone know what date format this is?
// Twitter's dates look like this: "Mon Jul 14 23:52:38 +0000 2008" -- Zach
function date_twitter($dt)
@@ -725,35 +939,16 @@ class TwitterapiAction extends Action
function clientError($msg, $code = 400, $content_type = 'json')
{
-
- static $status = array(400 => 'Bad Request',
- 401 => 'Unauthorized',
- 402 => 'Payment Required',
- 403 => 'Forbidden',
- 404 => 'Not Found',
- 405 => 'Method Not Allowed',
- 406 => 'Not Acceptable',
- 407 => 'Proxy Authentication Required',
- 408 => 'Request Timeout',
- 409 => 'Conflict',
- 410 => 'Gone',
- 411 => 'Length Required',
- 412 => 'Precondition Failed',
- 413 => 'Request Entity Too Large',
- 414 => 'Request-URI Too Long',
- 415 => 'Unsupported Media Type',
- 416 => 'Requested Range Not Satisfiable',
- 417 => 'Expectation Failed');
-
$action = $this->trimmed('action');
common_debug("User error '$code' on '$action': $msg", __FILE__);
- if (!array_key_exists($code, $status)) {
+ if (!array_key_exists($code, ClientErrorAction::$status)) {
$code = 400;
}
- $status_string = $status[$code];
+ $status_string = ClientErrorAction::$status[$code];
+
header('HTTP/1.1 '.$code.' '.$status_string);
if ($content_type == 'xml') {
@@ -772,6 +967,35 @@ class TwitterapiAction extends Action
}
+ function serverError($msg, $code = 500, $content_type = 'json')
+ {
+ $action = $this->trimmed('action');
+
+ common_debug("Server error '$code' on '$action': $msg", __FILE__);
+
+ if (!array_key_exists($code, ServerErrorAction::$status)) {
+ $code = 400;
+ }
+
+ $status_string = ServerErrorAction::$status[$code];
+
+ header('HTTP/1.1 '.$code.' '.$status_string);
+
+ if ($content_type == 'xml') {
+ $this->init_document('xml');
+ $this->elementStart('hash');
+ $this->element('error', null, $msg);
+ $this->element('request', null, $_SERVER['REQUEST_URI']);
+ $this->elementEnd('hash');
+ $this->end_document('xml');
+ } else {
+ $this->init_document('json');
+ $error_array = array('error' => $msg, 'request' => $_SERVER['REQUEST_URI']);
+ print(json_encode($error_array));
+ $this->end_document('json');
+ }
+ }
+
function init_twitter_rss()
{
$this->startXML();
@@ -799,9 +1023,9 @@ class TwitterapiAction extends Action
$this->endXML();
}
- function show_profile($profile, $content_type='xml', $notice=null)
+ function show_profile($profile, $content_type='xml', $notice=null, $includeStatuses=true)
{
- $profile_array = $this->twitter_user_array($profile, true);
+ $profile_array = $this->twitter_user_array($profile, $includeStatuses);
switch ($content_type) {
case 'xml':
$this->show_twitter_xml_user($profile_array);
diff --git a/lib/twitterbasicauthclient.php b/lib/twitterbasicauthclient.php
new file mode 100644
index 000000000..fd331fbdc
--- /dev/null
+++ b/lib/twitterbasicauthclient.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class for doing OAuth calls against Twitter
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Exception wrapper for cURL errors
+ *
+ * @category Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ */
+class BasicAuthCurlException extends Exception
+{
+}
+
+/**
+ * Class for talking to the Twitter API with HTTP Basic Auth.
+ *
+ * @category Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ */
+class TwitterBasicAuthClient
+{
+ var $screen_name = null;
+ var $password = null;
+
+ /**
+ * constructor
+ *
+ * @param Foreign_link $flink a Foreign_link storing the
+ * Twitter user's password, etc.
+ */
+ function __construct($flink)
+ {
+ $fuser = $flink->getForeignUser();
+ $this->screen_name = $fuser->nickname;
+ $this->password = $flink->credentials;
+ }
+
+ /**
+ * Calls Twitter's /statuses/update API method
+ *
+ * @param string $status text of the status
+ * @param int $in_reply_to_status_id optional id of the status it's
+ * a reply to
+ *
+ * @return mixed the status
+ */
+ function statusesUpdate($status, $in_reply_to_status_id = null)
+ {
+ $url = 'https://twitter.com/statuses/update.json';
+ $params = array('status' => $status,
+ 'source' => common_config('integration', 'source'),
+ 'in_reply_to_status_id' => $in_reply_to_status_id);
+ $response = $this->httpRequest($url, $params);
+ $status = json_decode($response);
+ return $status;
+ }
+
+ /**
+ * Calls Twitter's /statuses/friends_timeline API method
+ *
+ * @param int $since_id show statuses after this id
+ * @param int $max_id show statuses before this id
+ * @param int $cnt number of statuses to show
+ * @param int $page page number
+ *
+ * @return mixed an array of statuses
+ */
+ function statusesFriendsTimeline($since_id = null, $max_id = null,
+ $cnt = null, $page = null)
+ {
+ $url = 'https://twitter.com/statuses/friends_timeline.json';
+ $params = array('since_id' => $since_id,
+ 'max_id' => $max_id,
+ 'count' => $cnt,
+ 'page' => $page);
+ $qry = http_build_query($params);
+
+ if (!empty($qry)) {
+ $url .= "?$qry";
+ }
+
+ $response = $this->httpRequest($url);
+ $statuses = json_decode($response);
+ return $statuses;
+ }
+
+ /**
+ * Calls Twitter's /statuses/friends API method
+ *
+ * @param int $id id of the user whom you wish to see friends of
+ * @param int $user_id numerical user id
+ * @param int $screen_name screen name
+ * @param int $page page number
+ *
+ * @return mixed an array of twitter users and their latest status
+ */
+ function statusesFriends($id = null, $user_id = null, $screen_name = null,
+ $page = null)
+ {
+ $url = "https://twitter.com/statuses/friends.json";
+
+ $params = array('id' => $id,
+ 'user_id' => $user_id,
+ 'screen_name' => $screen_name,
+ 'page' => $page);
+ $qry = http_build_query($params);
+
+ if (!empty($qry)) {
+ $url .= "?$qry";
+ }
+
+ $response = $this->httpRequest($url);
+ $friends = json_decode($response);
+ return $friends;
+ }
+
+ /**
+ * Calls Twitter's /statuses/friends/ids API method
+ *
+ * @param int $id id of the user whom you wish to see friends of
+ * @param int $user_id numerical user id
+ * @param int $screen_name screen name
+ * @param int $page page number
+ *
+ * @return mixed a list of ids, 100 per page
+ */
+ function friendsIds($id = null, $user_id = null, $screen_name = null,
+ $page = null)
+ {
+ $url = "https://twitter.com/friends/ids.json";
+
+ $params = array('id' => $id,
+ 'user_id' => $user_id,
+ 'screen_name' => $screen_name,
+ 'page' => $page);
+ $qry = http_build_query($params);
+
+ if (!empty($qry)) {
+ $url .= "?$qry";
+ }
+
+ $response = $this->httpRequest($url);
+ $ids = json_decode($response);
+ return $ids;
+ }
+
+ /**
+ * Make a HTTP request using cURL.
+ *
+ * @param string $url Where to make the request
+ * @param array $params post parameters
+ *
+ * @return mixed the request
+ */
+ function httpRequest($url, $params = null, $auth = true)
+ {
+ $options = array(
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_FAILONERROR => true,
+ CURLOPT_HEADER => false,
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_USERAGENT => 'StatusNet',
+ CURLOPT_CONNECTTIMEOUT => 120,
+ CURLOPT_TIMEOUT => 120,
+ CURLOPT_HTTPAUTH => CURLAUTH_ANY,
+ CURLOPT_SSL_VERIFYPEER => false,
+
+ // Twitter is strict about accepting invalid "Expect" headers
+
+ CURLOPT_HTTPHEADER => array('Expect:')
+ );
+
+ if (isset($params)) {
+ $options[CURLOPT_POST] = true;
+ $options[CURLOPT_POSTFIELDS] = $params;
+ }
+
+ if ($auth) {
+ $options[CURLOPT_USERPWD] = $this->screen_name .
+ ':' . $this->password;
+ }
+
+ $ch = curl_init($url);
+ curl_setopt_array($ch, $options);
+ $response = curl_exec($ch);
+
+ if ($response === false) {
+ $msg = curl_error($ch);
+ $code = curl_errno($ch);
+ throw new BasicAuthCurlException($msg, $code);
+ }
+
+ curl_close($ch);
+
+ return $response;
+ }
+
+}
diff --git a/lib/twitteroauthclient.php b/lib/twitteroauthclient.php
new file mode 100644
index 000000000..e37fa05f0
--- /dev/null
+++ b/lib/twitteroauthclient.php
@@ -0,0 +1,229 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Class for doing OAuth calls against Twitter
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * Class for talking to the Twitter API with OAuth.
+ *
+ * @category Integration
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ *
+ */
+class TwitterOAuthClient extends OAuthClient
+{
+ public static $requestTokenURL = 'https://twitter.com/oauth/request_token';
+ public static $authorizeURL = 'https://twitter.com/oauth/authorize';
+ public static $accessTokenURL = 'https://twitter.com/oauth/access_token';
+
+ /**
+ * Constructor
+ *
+ * @param string $oauth_token the user's token
+ * @param string $oauth_token_secret the user's token secret
+ *
+ * @return nothing
+ */
+ function __construct($oauth_token = null, $oauth_token_secret = null)
+ {
+ $consumer_key = common_config('twitter', 'consumer_key');
+ $consumer_secret = common_config('twitter', 'consumer_secret');
+
+ parent::__construct($consumer_key, $consumer_secret,
+ $oauth_token, $oauth_token_secret);
+ }
+
+ // XXX: the following two functions are to support the horrible hack
+ // of using the credentils field in Foreign_link to store both
+ // the access token and token secret. This hack should go away with
+ // 0.9, in which we can make DB changes and add a new column for the
+ // token itself.
+
+ static function packToken($token)
+ {
+ return implode(chr(0), array($token->key, $token->secret));
+ }
+
+ static function unpackToken($str)
+ {
+ $vals = explode(chr(0), $str);
+ return new OAuthToken($vals[0], $vals[1]);
+ }
+
+ static function isPackedToken($str)
+ {
+ if (strpos($str, chr(0)) === false) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Builds a link to Twitter's endpoint for authorizing a request token
+ *
+ * @param OAuthToken $request_token token to authorize
+ *
+ * @return the link
+ */
+ function getAuthorizeLink($request_token)
+ {
+ return parent::getAuthorizeLink(self::$authorizeURL,
+ $request_token,
+ common_local_url('twitterauthorization'));
+ }
+
+ /**
+ * Calls Twitter's /account/verify_credentials API method
+ *
+ * @return mixed the Twitter user
+ */
+ function verifyCredentials()
+ {
+ $url = 'https://twitter.com/account/verify_credentials.json';
+ $response = $this->oAuthGet($url);
+ $twitter_user = json_decode($response);
+ return $twitter_user;
+ }
+
+ /**
+ * Calls Twitter's /stutuses/update API method
+ *
+ * @param string $status text of the status
+ * @param int $in_reply_to_status_id optional id of the status it's
+ * a reply to
+ *
+ * @return mixed the status
+ */
+ function statusesUpdate($status, $in_reply_to_status_id = null)
+ {
+ $url = 'https://twitter.com/statuses/update.json';
+ $params = array('status' => $status,
+ 'in_reply_to_status_id' => $in_reply_to_status_id);
+ $response = $this->oAuthPost($url, $params);
+ $status = json_decode($response);
+ return $status;
+ }
+
+ /**
+ * Calls Twitter's /stutuses/friends_timeline API method
+ *
+ * @param int $since_id show statuses after this id
+ * @param int $max_id show statuses before this id
+ * @param int $cnt number of statuses to show
+ * @param int $page page number
+ *
+ * @return mixed an array of statuses
+ */
+ function statusesFriendsTimeline($since_id = null, $max_id = null,
+ $cnt = null, $page = null)
+ {
+
+ $url = 'https://twitter.com/statuses/friends_timeline.json';
+ $params = array('since_id' => $since_id,
+ 'max_id' => $max_id,
+ 'count' => $cnt,
+ 'page' => $page);
+ $qry = http_build_query($params);
+
+ if (!empty($qry)) {
+ $url .= "?$qry";
+ }
+
+ $response = $this->oAuthGet($url);
+ $statuses = json_decode($response);
+ return $statuses;
+ }
+
+ /**
+ * Calls Twitter's /stutuses/friends API method
+ *
+ * @param int $id id of the user whom you wish to see friends of
+ * @param int $user_id numerical user id
+ * @param int $screen_name screen name
+ * @param int $page page number
+ *
+ * @return mixed an array of twitter users and their latest status
+ */
+ function statusesFriends($id = null, $user_id = null, $screen_name = null,
+ $page = null)
+ {
+ $url = "https://twitter.com/statuses/friends.json";
+
+ $params = array('id' => $id,
+ 'user_id' => $user_id,
+ 'screen_name' => $screen_name,
+ 'page' => $page);
+ $qry = http_build_query($params);
+
+ if (!empty($qry)) {
+ $url .= "?$qry";
+ }
+
+ $response = $this->oAuthGet($url);
+ $friends = json_decode($response);
+ return $friends;
+ }
+
+ /**
+ * Calls Twitter's /stutuses/friends/ids API method
+ *
+ * @param int $id id of the user whom you wish to see friends of
+ * @param int $user_id numerical user id
+ * @param int $screen_name screen name
+ * @param int $page page number
+ *
+ * @return mixed a list of ids, 100 per page
+ */
+ function friendsIds($id = null, $user_id = null, $screen_name = null,
+ $page = null)
+ {
+ $url = "https://twitter.com/friends/ids.json";
+
+ $params = array('id' => $id,
+ 'user_id' => $user_id,
+ 'screen_name' => $screen_name,
+ 'page' => $page);
+ $qry = http_build_query($params);
+
+ if (!empty($qry)) {
+ $url .= "?$qry";
+ }
+
+ $response = $this->oAuthGet($url);
+ $ids = json_decode($response);
+ return $ids;
+ }
+
+}
diff --git a/lib/unblockform.php b/lib/unblockform.php
index 6a8831b29..f1343757c 100644
--- a/lib/unblockform.php
+++ b/lib/unblockform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for unblocking a user
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for unblocking a user
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see BlockForm
*/
diff --git a/lib/unqueuemanager.php b/lib/unqueuemanager.php
index 515461072..3cdad0b54 100644
--- a/lib/unqueuemanager.php
+++ b/lib/unqueuemanager.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* A queue manager interface for just doing things immediately
*
@@ -20,12 +20,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category QueueManager
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class UnQueueManager
@@ -79,7 +79,7 @@ class UnQueueManager
function _isLocal($notice)
{
- return ($notice->is_local == NOTICE_LOCAL_PUBLIC ||
- $notice->is_local == NOTICE_LOCAL_NONPUBLIC);
+ return ($notice->is_local == Notice::LOCAL_PUBLIC ||
+ $notice->is_local == Notice::LOCAL_NONPUBLIC);
}
} \ No newline at end of file
diff --git a/lib/unsubscribeform.php b/lib/unsubscribeform.php
index ce91a1340..cb6a87515 100644
--- a/lib/unsubscribeform.php
+++ b/lib/unsubscribeform.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Form for unsubscribing from a user
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR.'/lib/form.php';
* Form for unsubscribing from a user
*
* @category Form
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see SubscribeForm
*/
diff --git a/lib/util.php b/lib/util.php
index c7c82dba2..b831859e9 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -54,12 +54,12 @@ function common_init_language()
$language = common_language();
// So we don't have to make people install the gettext locales
$locale_set = common_init_locale($language);
- bindtextdomain("laconica", common_config('site','locale_path'));
- bind_textdomain_codeset("laconica", "UTF-8");
- textdomain("laconica");
+ bindtextdomain("statusnet", common_config('site','locale_path'));
+ bind_textdomain_codeset("statusnet", "UTF-8");
+ textdomain("statusnet");
setlocale(LC_CTYPE, 'C');
if(!$locale_set) {
- common_log(LOG_INFO,'Language requested:'.$language.' - locale could not be set:',__FILE__);
+ common_log(LOG_INFO, 'Language requested:' . $language . ' - locale could not be set. Perhaps that system locale is not installed.', __FILE__);
}
}
@@ -140,7 +140,7 @@ function common_have_session()
function common_ensure_session()
{
$c = null;
- if (array_key_exists(session_name, $_COOKIE)) {
+ if (array_key_exists(session_name(), $_COOKIE)) {
$c = $_COOKIE[session_name()];
}
if (!common_have_session()) {
@@ -404,7 +404,7 @@ function common_render_text($text)
$r = preg_replace('/[\x{0}-\x{8}\x{b}-\x{c}\x{e}-\x{19}]/', '', $r);
$r = common_replace_urls_callback($r, 'common_linkify');
- $r = preg_replace('/(^|\(|\[|\s+)#([\pL\pN_\-\.]{1,64})/e', "'\\1#'.common_tag_link('\\2')", $r);
+ $r = preg_replace('/(^|\&quot\;|\'|\(|\[|\{|\s+)#([\pL\pN_\-\.]{1,64})/e', "'\\1#'.common_tag_link('\\2')", $r);
// XXX: machine tags
return $r;
}
@@ -412,87 +412,107 @@ function common_render_text($text)
function common_replace_urls_callback($text, $callback, $notice_id = null) {
// Start off with a regex
$regex = '#'.
- '(?:'.
+ '(?:^|[\s\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'.
+ '('.
'(?:'.
- '(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|irc)://'.
- '|'.
- '(?:mailto|aim|tel|xmpp):'.
+ '(?:'. //Known protocols
+ '(?:'.
+ '(?:(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|irc)://)'.
+ '|'.
+ '(?:(?:mailto|aim|tel|xmpp):)'.
+ ')'.
+ '(?:[\pN\pL\-\_\+\%\~]+(?::[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
+ '(?:'.
+ '(?:'.
+ '\[[\pN\pL\-\_\:\.]+(?<![\.\:])\]'. //[dns]
+ ')|(?:'.
+ '[\pN\pL\-\_\:\.]+(?<![\.\:])'. //dns
+ ')'.
+ ')'.
+ ')'.
+ '|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'. //IPv4
+ '|(?:'. //IPv6
+ '\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?<!:)'.
+ ')|(?:'. //DNS
+ '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?'. //user:pass@
+ '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'.
+ //tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
+ '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीकà¥à¤·à¤¾|XN--80AKHBYKNJ4F|иÑпытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிடà¯à®šà¯ˆ|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZW|local|loc|onion)'.
+ ')(?![\pN\pL\-\_])'.
')'.
- '[^.\s]+\.[^\s]+'.
- '|'.
- '(?:[^.\s/:]+\.)+'.
- '(?:museum|travel|[a-z]{2,4})'.
- '(?:[:/][^\s]*)?'.
+ '(?:'.
+ '(?:\:\d+)?'. //:port
+ '(?:/[\pN\pL$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'\"@]*)?'. // /path
+ '(?:\?[\pN\pL\$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'\"@\/]*)?'. // ?query string
+ '(?:\#[\pN\pL$\[\]\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\+\'\"\@/\?\#]*)?'. // #fragment
+ ')(?<![\?\.\,\#\,])'.
')'.
- '#ix';
- preg_match_all($regex, $text, $matches);
-
- // Then clean up what the regex left behind
- $offset = 0;
- foreach($matches[0] as $orig_url) {
- $url = htmlspecialchars_decode($orig_url);
-
- // Make sure we didn't pick up an email address
- if (preg_match('#^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$#i', $url)) continue;
-
- // Remove surrounding punctuation
- $url = trim($url, '.?!,;:\'"`([<');
-
- // Remove surrounding parens and the like
- preg_match('/[)\]>]+$/', $url, $trailing);
- if (isset($trailing[0])) {
- preg_match_all('/[(\[<]/', $url, $opened);
- preg_match_all('/[)\]>]/', $url, $closed);
- $unopened = count($closed[0]) - count($opened[0]);
-
- // Make sure not to take off more closing parens than there are at the end
- $unopened = ($unopened > mb_strlen($trailing[0])) ? mb_strlen($trailing[0]):$unopened;
-
- $url = ($unopened > 0) ? mb_substr($url, 0, $unopened * -1):$url;
+ '#ixu';
+ //preg_match_all($regex,$text,$matches);
+ //print_r($matches);
+ return preg_replace_callback($regex, curry('callback_helper',$callback,$notice_id) ,$text);
+}
+
+function callback_helper($matches, $callback, $notice_id) {
+ $url=$matches[1];
+ $left = strpos($matches[0],$url);
+ $right = $left+strlen($url);
+
+ $groupSymbolSets=array(
+ array(
+ 'left'=>'(',
+ 'right'=>')'
+ ),
+ array(
+ 'left'=>'[',
+ 'right'=>']'
+ ),
+ array(
+ 'left'=>'{',
+ 'right'=>'}'
+ )
+ );
+ $cannotEndWith=array('.','?',',','#');
+ $original_url=$url;
+ do{
+ $original_url=$url;
+ foreach($groupSymbolSets as $groupSymbolSet){
+ if(substr($url,-1)==$groupSymbolSet['right']){
+ $group_left_count = substr_count($url,$groupSymbolSet['left']);
+ $group_right_count = substr_count($url,$groupSymbolSet['right']);
+ if($group_left_count<$group_right_count){
+ $right-=1;
+ $url=substr($url,0,-1);
+ }
+ }
}
-
- // Remove trailing punctuation again (in case there were some inside parens)
- $url = rtrim($url, '.?!,;:\'"`');
-
- // Make sure we didn't capture part of the next sentence
- preg_match('#((?:[^.\s/]+\.)+)(museum|travel|[a-z]{2,4})#i', $url, $url_parts);
-
- // Were the parts capitalized any?
- $last_part = (mb_strtolower($url_parts[2]) !== $url_parts[2]) ? true:false;
- $prev_part = (mb_strtolower($url_parts[1]) !== $url_parts[1]) ? true:false;
-
- // If the first part wasn't cap'd but the last part was, we captured too much
- if ((!$prev_part && $last_part)) {
- $url = mb_substr($url, 0 , mb_strpos($url, '.'.$url_parts['2'], 0));
+ if(in_array(substr($url,-1),$cannotEndWith)){
+ $right-=1;
+ $url=substr($url,0,-1);
}
+ }while($original_url!=$url);
- // Capture the new TLD
- preg_match('#((?:[^.\s/]+\.)+)(museum|travel|[a-z]{2,4})#i', $url, $url_parts);
-
- $tlds = array('ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zw');
-
- if (!in_array($url_parts[2], $tlds)) continue;
-
- // Make sure we didn't capture a hash tag
- if (strpos($url, '#') === 0) continue;
-
- // Put the url back the way we found it.
- $url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url);
-
- // Call user specified func
- if (empty($notice_id)) {
- $modified_url = call_user_func($callback, $url);
- } else {
- $modified_url = call_user_func($callback, array($url, $notice_id));
- }
-
- // Replace it!
- $start = mb_strpos($text, $url, $offset);
- $text = mb_substr($text, 0, $start).$modified_url.mb_substr($text, $start + mb_strlen($url), mb_strlen($text));
- $offset = $start + mb_strlen($modified_url);
+ if(empty($notice_id)){
+ $result = call_user_func_array($callback,$url);
+ }else{
+ $result = call_user_func_array($callback, array(array($url,$notice_id)) );
}
+ return substr($matches[0],0,$left) . $result . substr($matches[0],$right);
+}
- return $text;
+function curry($fn) {
+ //TODO switch to a PHP 5.3 function closure based approach if PHP 5.3 is used
+ $args = func_get_args();
+ array_shift($args);
+ $id = uniqid('_partial');
+ $GLOBALS[$id] = array($fn, $args);
+ return create_function('',
+ '$args = func_get_args(); '.
+ 'return call_user_func_array('.
+ '$GLOBALS["'.$id.'"][0],'.
+ 'array_merge('.
+ '$args,'.
+ '$GLOBALS["'.$id.'"][1]));');
}
function common_linkify($url) {
@@ -500,6 +520,11 @@ function common_linkify($url) {
// functions
$url = htmlspecialchars_decode($url);
+ if(strpos($url, '@') !== false && strpos($url, ':') === false) {
+ //url is an email address without the mailto: protocol
+ return XMLStringer::estring('a', array('href' => "mailto:$url", 'rel' => 'external'), $url);
+ }
+
$canon = File_redirection::_canonUrl($url);
$longurl_data = File_redirection::where($url);
@@ -517,42 +542,31 @@ function common_linkify($url) {
$attachment_id = null;
$has_thumb = false;
- // Check to see whether there's a filename associated with this URL.
- // If there is, it's an upload and qualifies as an attachment
+ // Check to see whether this is a known "attachment" URL.
- $localfile = File::staticGet('url', $longurl);
+ $f = File::staticGet('url', $longurl);
- if (!empty($localfile)) {
- if (isset($localfile->filename)) {
- $is_attachment = true;
- $attachment_id = $localfile->id;
- }
+ if (empty($f)) {
+ // XXX: this writes to the database. :<
+ $f = File::processNew($longurl);
}
- // if this URL is an attachment, then we set class='attachment' and id='attahcment-ID'
- // where ID is the id of the attachment for the given URL.
- //
- // we need a better test telling what can be shown as an attachment
- // we're currently picking up oembeds only.
- // I think the best option is another file_view table in the db
- // and associated dbobject.
-
- $query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'";
- $file = new File;
- $file->query($query);
- $file->fetch();
-
- if (!empty($file->file_id)) {
- $is_attachment = true;
- $attachment_id = $file->file_id;
-
- $query = "select file_thumbnail.file_id as file_id from file join file_thumbnail on file.id = file_thumbnail.file_id where file.url='$longurl'";
- $file2 = new File;
- $file2->query($query);
- $file2->fetch();
-
- if (!empty($file2)) {
- $has_thumb = true;
+ if (!empty($f)) {
+ if ($f->isEnclosure()) {
+ $is_attachment = true;
+ $attachment_id = $f->id;
+ } else {
+ $foe = File_oembed::staticGet('file_id', $f->id);
+ if (!empty($foe)) {
+ // if it has OEmbed info, it's an attachment, too
+ $is_attachment = true;
+ $attachment_id = $f->id;
+
+ $thumb = File_thumbnail::staticGet('file_id', $f->id);
+ if (!empty($thumb)) {
+ $has_thumb = true;
+ }
+ }
}
}
@@ -595,7 +609,8 @@ function common_tag_link($tag)
function common_canonical_tag($tag)
{
- return strtolower(str_replace(array('-', '_', '.'), '', $tag));
+ $tag = mb_convert_case($tag, MB_CASE_LOWER, "UTF-8");
+ return str_replace(array('-', '_', '.'), '', $tag);
}
function common_valid_profile_tag($str)
@@ -883,8 +898,8 @@ function common_enqueue_notice($notice)
$transports[] = 'jabber';
}
- if ($notice->is_local == NOTICE_LOCAL_PUBLIC ||
- $notice->is_local == NOTICE_LOCAL_NONPUBLIC) {
+ if ($notice->is_local == Notice::LOCAL_PUBLIC ||
+ $notice->is_local == Notice::LOCAL_NONPUBLIC) {
$transports = array_merge($transports, $localTransports);
if ($xmpp) {
$transports[] = 'public';
@@ -1288,7 +1303,7 @@ function common_cache_key($extra)
$base_key = common_keyize(common_config('site', 'name'));
}
- return 'laconica:' . $base_key . ':' . $extra;
+ return 'statusnet:' . $base_key . ':' . $extra;
}
function common_keyize($str)
@@ -1351,7 +1366,7 @@ function common_shorten_url($long_url)
$curlh = curl_init();
curl_setopt($curlh, CURLOPT_CONNECTTIMEOUT, 20); // # seconds to wait
- curl_setopt($curlh, CURLOPT_USERAGENT, 'Laconica');
+ curl_setopt($curlh, CURLOPT_USERAGENT, 'StatusNet');
curl_setopt($curlh, CURLOPT_RETURNTRANSFER, true);
switch($svc) {
@@ -1409,20 +1424,21 @@ function common_client_ip()
return null;
}
- if ($_SERVER['HTTP_X_FORWARDED_FOR']) {
- if ($_SERVER['HTTP_CLIENT_IP']) {
+ if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
+ if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
$proxy = $_SERVER['HTTP_CLIENT_IP'];
} else {
$proxy = $_SERVER['REMOTE_ADDR'];
}
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
- if ($_SERVER['HTTP_CLIENT_IP']) {
+ $proxy = null;
+ if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} else {
$ip = $_SERVER['REMOTE_ADDR'];
}
}
- return array($ip, $proxy);
+ return array($proxy, $ip);
}
diff --git a/lib/webcolor.php b/lib/webcolor.php
index f3ca6e94a..6fa603fa2 100644
--- a/lib/webcolor.php
+++ b/lib/webcolor.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for deleting things
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Personal
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/lib/widget.php b/lib/widget.php
index c70505c44..0258c8649 100644
--- a/lib/widget.php
+++ b/lib/widget.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Base class for UI widgets
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ if (!defined('LACONICA')) {
* lists, notice lists, navigation menus (tabsets) and common forms.
*
* @category Widget
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see HTMLOutputter
*/
diff --git a/lib/xmloutputter.php b/lib/xmloutputter.php
index 64935da40..5f06e491d 100644
--- a/lib/xmloutputter.php
+++ b/lib/xmloutputter.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Low-level generator for XML
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -40,11 +40,11 @@ if (!defined('LACONICA')) {
* an element.
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see Action
* @see HTMLOutputter
*/
diff --git a/lib/xmlstringer.php b/lib/xmlstringer.php
index 951b13b67..b505e40d3 100644
--- a/lib/xmlstringer.php
+++ b/lib/xmlstringer.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Generator for in-memory XML
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -35,10 +35,10 @@ if (!defined('LACONICA')) {
* Create in-memory XML
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
* @see Action
* @see HTMLOutputter
*/
diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php
index 77d476c30..f28fc9088 100644
--- a/lib/xmppqueuehandler.php
+++ b/lib/xmppqueuehandler.php
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) { exit(1); }
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/queuehandler.php');
@@ -38,14 +38,20 @@ class XmppQueueHandler extends QueueHandler
function start()
{
# Low priority; we don't want to receive messages
+
$this->log(LOG_INFO, "INITIALIZE");
$this->conn = jabber_connect($this->_id.$this->transport());
- if ($this->conn) {
- $this->conn->addEventHandler('message', 'forward_message', $this);
- $this->conn->addEventHandler('reconnect', 'handle_reconnect', $this);
- $this->conn->setReconnectTimeout(600);
- jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', -1);
+
+ if (empty($this->conn)) {
+ $this->log(LOG_ERR, "Couldn't connect to server.");
+ return false;
}
+
+ $this->conn->addEventHandler('message', 'forward_message', $this);
+ $this->conn->addEventHandler('reconnect', 'handle_reconnect', $this);
+ $this->conn->setReconnectTimeout(600);
+ jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', -1);
+
return !is_null($this->conn);
}
@@ -56,6 +62,8 @@ class XmppQueueHandler extends QueueHandler
function handle_reconnect(&$pl)
{
+ $this->log(LOG_NOTICE, 'reconnected');
+
$this->conn->processUntil('session_start');
$this->conn->presence(null, 'available', null, 'available', -1);
}
diff --git a/lighttpd.conf.example b/lighttpd.conf.example
new file mode 100644
index 000000000..b8baafc9e
--- /dev/null
+++ b/lighttpd.conf.example
@@ -0,0 +1,2 @@
+# Add this line to lighttpd.conf to enable pseudo-rewrites using 404s
+server.error-handler-404 = "/index.php"
diff --git a/locale/bg_BG/LC_MESSAGES/laconica.mo b/locale/bg_BG/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 4aa8804c5..000000000
--- a/locale/bg_BG/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/bg_BG/LC_MESSAGES/statusnet.mo b/locale/bg_BG/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..8cfa1523d
--- /dev/null
+++ b/locale/bg_BG/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/bg_BG/LC_MESSAGES/laconica.po b/locale/bg_BG/LC_MESSAGES/statusnet.po
index 3ad602175..c0bc8379f 100644
--- a/locale/bg_BG/LC_MESSAGES/laconica.po
+++ b/locale/bg_BG/LC_MESSAGES/statusnet.po
@@ -1,13 +1,13 @@
-# #-#-#-#-# laconica.pot (Laconica 0.6.4) #-#-#-#-#
-# Laconica Bulgarian translation.
+# #-#-#-#-# statusnet.pot (StatusNet 0.6.4) #-#-#-#-#
+# StatusNet Bulgarian translation.
# Copyright (C) 2008
-# This file is distributed under the same license as the Laconica package.
+# This file is distributed under the same license as the StatusNet package.
# Yasen Pramatarov <yasen@lindeas.com>, 2008
-# Stoyan Zhekov <laconica@zh.otherinbox.com>, 2008
+# Stoyan Zhekov <statusnet@zh.otherinbox.com>, 2008
#
msgid ""
msgstr ""
-"Project-Id-Version: Laconica 0.6.4\n"
+"Project-Id-Version: StatusNet 0.6.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-25 16:24+0000\n"
"PO-Revision-Date: 2009-06-27 18:04+0000\n"
@@ -276,8 +276,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -302,7 +302,7 @@ msgstr "Ðе е открит методът в API."
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1143,11 +1143,11 @@ msgstr "Покани за нови потребители"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Ползва [Laconica](http://laconi.ca/) верÑÐ¸Ñ %s, ÑиÑтема за микроблогване, "
+"Ползва [StatusNet](http://status.net/) верÑÐ¸Ñ %s, ÑиÑтема за микроблогване, "
"доÑтъпна под [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)."
@@ -4537,8 +4537,8 @@ msgid "Secondary site navigation"
msgstr "Ðбонаменти"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Лиценз на програмата Laconica"
+msgid "StatusNet software license"
+msgstr "Лиценз на програмата StatusNet"
#: lib/action.php:630
msgid "All "
diff --git a/locale/ca_ES/LC_MESSAGES/laconica.mo b/locale/ca_ES/LC_MESSAGES/statusnet.mo
index 993d020da..aadf38da9 100644
--- a/locale/ca_ES/LC_MESSAGES/laconica.mo
+++ b/locale/ca_ES/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ca_ES/LC_MESSAGES/laconica.po b/locale/ca_ES/LC_MESSAGES/statusnet.po
index b835a7a8f..44944c8ba 100644
--- a/locale/ca_ES/LC_MESSAGES/laconica.po
+++ b/locale/ca_ES/LC_MESSAGES/statusnet.po
@@ -276,8 +276,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -302,7 +302,7 @@ msgstr "No s'ha trobat el mètode API!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1146,11 +1146,11 @@ msgstr "Invitar nous usuaris"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Utilitza el software de microblogging [Laconica](http://laconi.ca), versió %"
+"Utilitza el software de microblogging [StatusNet](http://status.net), versió %"
"s, disponible sota la [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)."
@@ -4543,8 +4543,8 @@ msgid "Secondary site navigation"
msgstr "Navegació del lloc secundària"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Llicència del programari Laconica"
+msgid "StatusNet software license"
+msgstr "Llicència del programari StatusNet"
#: lib/action.php:630
msgid "All "
diff --git a/locale/cs_CZ/LC_MESSAGES/laconica.mo b/locale/cs_CZ/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 790f5eb26..000000000
--- a/locale/cs_CZ/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/cs_CZ/LC_MESSAGES/statusnet.mo b/locale/cs_CZ/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..e126daaf0
--- /dev/null
+++ b/locale/cs_CZ/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/cs_CZ/LC_MESSAGES/laconica.po b/locale/cs_CZ/LC_MESSAGES/statusnet.po
index 9fce8edcd..aee74f1af 100644
--- a/locale/cs_CZ/LC_MESSAGES/laconica.po
+++ b/locale/cs_CZ/LC_MESSAGES/statusnet.po
@@ -241,8 +241,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -267,7 +267,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1087,11 +1087,11 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Běží na [Laconica](http://laconi.ca/) mikroblogovací program, verze %s, "
+"Běží na [StatusNet](http://status.net/) mikroblogovací program, verze %s, "
"dostupná pod [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)."
@@ -4486,7 +4486,7 @@ msgid "Secondary site navigation"
msgstr "Odběry"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/de_DE/LC_MESSAGES/laconica.mo b/locale/de_DE/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 684fa131c..000000000
--- a/locale/de_DE/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/de_DE/LC_MESSAGES/statusnet.mo b/locale/de_DE/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..fe6072c1b
--- /dev/null
+++ b/locale/de_DE/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/de_DE/LC_MESSAGES/laconica.po b/locale/de_DE/LC_MESSAGES/statusnet.po
index 5e1f346af..ed0252879 100644
--- a/locale/de_DE/LC_MESSAGES/laconica.po
+++ b/locale/de_DE/LC_MESSAGES/statusnet.po
@@ -277,8 +277,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -303,7 +303,7 @@ msgstr "API-Methode nicht gefunden!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1150,11 +1150,11 @@ msgstr "Lade neue Leute ein"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-" Es wird mit der Microbloggingsoftware [Laconica](http://laconi.ca/) "
+" Es wird mit der Microbloggingsoftware [StatusNet](http://status.net/) "
"(Version %s) betrieben, die unter der [GNU Affero General Public License]"
"(http://www.fsf.org/licensing/licenses/agpl-3.0.html) erhältlich ist."
@@ -4750,8 +4750,8 @@ msgstr "Unternavigation"
#: lib/action.php:602 lib/action.php:623
#, fuzzy
-msgid "Laconica software license"
-msgstr "Laconica Software Lizenz"
+msgid "StatusNet software license"
+msgstr "StatusNet Software Lizenz"
#: lib/action.php:630
#, fuzzy
diff --git a/locale/el_GR/LC_MESSAGES/laconica.mo b/locale/el_GR/LC_MESSAGES/statusnet.mo
index 071ea3bc5..071ea3bc5 100644
--- a/locale/el_GR/LC_MESSAGES/laconica.mo
+++ b/locale/el_GR/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/el_GR/LC_MESSAGES/laconica.po b/locale/el_GR/LC_MESSAGES/statusnet.po
index ccbeb34b9..314dd358c 100644
--- a/locale/el_GR/LC_MESSAGES/laconica.po
+++ b/locale/el_GR/LC_MESSAGES/statusnet.po
@@ -228,8 +228,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -254,7 +254,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1069,7 +1069,7 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
@@ -4369,7 +4369,7 @@ msgid "Secondary site navigation"
msgstr ""
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/en_GB/LC_MESSAGES/laconica.mo b/locale/en_GB/LC_MESSAGES/statusnet.mo
index 93ff37f9d..11eacc9ac 100644
--- a/locale/en_GB/LC_MESSAGES/laconica.mo
+++ b/locale/en_GB/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/en_GB/LC_MESSAGES/laconica.po b/locale/en_GB/LC_MESSAGES/statusnet.po
index 4e261723f..a105d2b86 100644
--- a/locale/en_GB/LC_MESSAGES/laconica.po
+++ b/locale/en_GB/LC_MESSAGES/statusnet.po
@@ -1,4 +1,4 @@
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -273,8 +273,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -299,7 +299,7 @@ msgstr "API method not found!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1150,11 +1150,11 @@ msgstr "Invite new users"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public Licence](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
@@ -4534,8 +4534,8 @@ msgid "Secondary site navigation"
msgstr "Secondary site navigation"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Laconica software licence"
+msgid "StatusNet software license"
+msgstr "StatusNet software licence"
#: lib/action.php:630
msgid "All "
diff --git a/locale/es/LC_MESSAGES/laconica.mo b/locale/es/LC_MESSAGES/laconica.mo
deleted file mode 100644
index ba764b52d..000000000
--- a/locale/es/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/es/LC_MESSAGES/statusnet.mo b/locale/es/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..ab03d12e0
--- /dev/null
+++ b/locale/es/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/es/LC_MESSAGES/laconica.po b/locale/es/LC_MESSAGES/statusnet.po
index 20c0c0490..c0e69e3a7 100644
--- a/locale/es/LC_MESSAGES/laconica.po
+++ b/locale/es/LC_MESSAGES/statusnet.po
@@ -279,8 +279,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -305,7 +305,7 @@ msgstr "¡No se encontró el método de la API!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1151,11 +1151,11 @@ msgstr "Invitar nuevos usuarios:"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Usa el software de microblogueo [Laconica](http://laconi.ca), versión %s, "
+"Usa el software de microblogueo [StatusNet](http://status.net), versión %s, "
"disponible bajo la [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)."
@@ -4618,8 +4618,8 @@ msgid "Secondary site navigation"
msgstr "Navegación de sitio secundario"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Licencia de software de Laconica"
+msgid "StatusNet software license"
+msgstr "Licencia de software de StatusNet"
#: lib/action.php:630
msgid "All "
diff --git a/locale/fi/LC_MESSAGES/laconica.mo b/locale/fi/LC_MESSAGES/statusnet.mo
index afbe91f21..7e64ddb00 100644
--- a/locale/fi/LC_MESSAGES/laconica.mo
+++ b/locale/fi/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/fi/LC_MESSAGES/laconica.po b/locale/fi/LC_MESSAGES/statusnet.po
index aadccd9a0..5a53dd2df 100644
--- a/locale/fi/LC_MESSAGES/laconica.po
+++ b/locale/fi/LC_MESSAGES/statusnet.po
@@ -281,8 +281,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -307,7 +307,7 @@ msgstr "API-metodia ei löytynyt!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1168,11 +1168,11 @@ msgstr "Kutsu uusia käyttäjiä"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Sivusto käyttää [Laconica](http://laconi.ca/) mikroblogausohjelmistoa, "
+"Sivusto käyttää [StatusNet](http://status.net/) mikroblogausohjelmistoa, "
"versio %s, saatavilla lisenssillä [GNU Affero General Public "
"License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
@@ -4596,8 +4596,8 @@ msgid "Secondary site navigation"
msgstr "Toissijainen sivunavigointi"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Laconica-ohjelmiston lisenssi"
+msgid "StatusNet software license"
+msgstr "StatusNet-ohjelmiston lisenssi"
#: lib/action.php:630
msgid "All "
diff --git a/locale/fr_FR/LC_MESSAGES/laconica.mo b/locale/fr_FR/LC_MESSAGES/laconica.mo
deleted file mode 100644
index d7c7ded01..000000000
--- a/locale/fr_FR/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/fr_FR/LC_MESSAGES/statusnet.mo b/locale/fr_FR/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..f26b8708d
--- /dev/null
+++ b/locale/fr_FR/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/fr_FR/LC_MESSAGES/laconica.po b/locale/fr_FR/LC_MESSAGES/statusnet.po
index 58fd29067..23365960b 100644
--- a/locale/fr_FR/LC_MESSAGES/laconica.po
+++ b/locale/fr_FR/LC_MESSAGES/statusnet.po
@@ -1,12 +1,12 @@
-# #-#-#-#-# laconica-no-duplicates.po (0.43) #-#-#-#-#
-# French translations for Laconica package
-# Traductions françaises du paquet Laconica.
+# #-#-#-#-# statusnet-no-duplicates.po (0.43) #-#-#-#-#
+# French translations for StatusNet package
+# Traductions françaises du paquet StatusNet.
# Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the Laconica package.
+# This file is distributed under the same license as the StatusNet package.
# Florian Birée <florian@biree.name>, 2008.
# For translation choices and other informations, please read
-# <http://dev.filyb.info/laconica/wiki/french-translation>
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# <http://dev.filyb.info/statusnet/wiki/french-translation>
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -326,8 +326,8 @@ msgstr ""
#: actions/twitapifavorites.php:102
#: actions/twitapifriendships.php:121
#: actions/twitapihelp.php:44
-#: actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151
+#: actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151
#: actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147
#: actions/twitapistatuses.php:228
@@ -372,7 +372,7 @@ msgstr "Méthode API non trouvée !"
#: actions/twitapidirect_messages.php:184
#: actions/twitapifavorites.php:143
#: actions/twitapihelp.php:52
-#: actions/twitapilaconica.php:172
+#: actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31
#: actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
@@ -958,9 +958,9 @@ msgstr "Erreur de base de donnée en insérant le hashtag : %s"
msgid "DB error inserting reply: %s"
msgstr "Erreur de base de donnée en insérant la réponse :%s"
-# De #-#-#-#-# laconica-no-duplicates.po (0.43) #-#-#-#-#\n
+# De #-#-#-#-# statusnet-no-duplicates.po (0.43) #-#-#-#-#\n
# Nouveau message\n
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#\n
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#\n
# à "Supprimer l'avis"
#: ../actions/deletenotice.php:41
#: actions/deletenotice.php:41
@@ -1440,8 +1440,8 @@ msgstr "Inviter de nouveaux utilisateurs"
#: lib/util.php:277
#: lib/action.php:609
#, php-format
-msgid "It runs the [Laconica](http://laconi.ca/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
-msgstr "Il utilise le logiciel de micro-blogging [Laconica](http://laconi.ca/), version %s, disponible sous la licence [GNU Affero General Public License] (http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
+msgid "It runs the [StatusNet](http://status.net/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
+msgstr "Il utilise le logiciel de micro-blogging [StatusNet](http://status.net/), version %s, disponible sous la licence [GNU Affero General Public License] (http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
#: ../actions/imsettings.php:173
#: actions/imsettings.php:181
@@ -5538,8 +5538,8 @@ msgstr "Navigation secondaire du site"
#: lib/action.php:602
#: lib/action.php:623
-msgid "Laconica software license"
-msgstr "Licence du logiciel Laconica"
+msgid "StatusNet software license"
+msgstr "Licence du logiciel StatusNet"
#: lib/action.php:630
msgid "All "
@@ -5742,9 +5742,9 @@ msgstr "%1$s a ajouté votre statut depuis %2$s"
msgid "From"
msgstr "De"
-# De #-#-#-#-# laconica-no-duplicates.po (0.43) #-#-#-#-#\n
+# De #-#-#-#-# statusnet-no-duplicates.po (0.43) #-#-#-#-#\n
# Nouveau message\n
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#\n
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#\n
# à "Supprimer l'avis"
#: lib/messageform.php:110
msgid "Send a direct notice"
@@ -5771,18 +5771,18 @@ msgstr "Répondre à ce statut"
msgid "Reply"
msgstr "Répondre"
-# De #-#-#-#-# laconica-no-duplicates.po (0.43) #-#-#-#-#\n
+# De #-#-#-#-# statusnet-no-duplicates.po (0.43) #-#-#-#-#\n
# Nouveau message\n
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#\n
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#\n
# à "Supprimer l'avis"
#: lib/noticelist.php:471
#: lib/noticelist.php:474
msgid "Delete this notice"
msgstr "Supprimer ce statut"
-# De #-#-#-#-# laconica-no-duplicates.po (0.43) #-#-#-#-#\n
+# De #-#-#-#-# statusnet-no-duplicates.po (0.43) #-#-#-#-#\n
# Nouveau message\n
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#\n
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#\n
# à "Supprimer l'avis"
#: lib/noticelist.php:474
msgid "Delete"
@@ -5895,11 +5895,11 @@ msgid "Unsubscribe from this user"
msgstr "Ne plus suivre cet utilisateur"
#~ msgid ""
-#~ "It runs the [Laconica](http://laconi.ca/) microblogging software, version "
+#~ "It runs the [StatusNet](http://status.net/) microblogging software, version "
#~ "%s, available under the [GNU Affero General Public License] (http://www."
#~ "fsf.org/licensing/licenses/agpl-3.0.html)."
#~ msgstr ""
-#~ "Il utilise le logiciel de micro-blogging [Laconica](http://laconi.ca/), "
+#~ "Il utilise le logiciel de micro-blogging [StatusNet](http://status.net/), "
#~ "version %s, disponible sous la licence [GNU Affero General Public "
#~ "License] (http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
diff --git a/locale/he_IL/LC_MESSAGES/laconica.mo b/locale/he_IL/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 797c88305..000000000
--- a/locale/he_IL/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/he_IL/LC_MESSAGES/statusnet.mo b/locale/he_IL/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..fce14f20a
--- /dev/null
+++ b/locale/he_IL/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/he_IL/LC_MESSAGES/laconica.po b/locale/he_IL/LC_MESSAGES/statusnet.po
index 3b5501244..8d43dfeaa 100644
--- a/locale/he_IL/LC_MESSAGES/laconica.po
+++ b/locale/he_IL/LC_MESSAGES/statusnet.po
@@ -1,13 +1,13 @@
-# #-#-#-#-# laconica.pot (PACKAGE VERSION) #-#-#-#-#
-# Hebrew translation for Laconica
+# #-#-#-#-# statusnet.pot (PACKAGE VERSION) #-#-#-#-#
+# Hebrew translation for StatusNet
# ×ª×¨×’×•× ×œ×¢×‘×¨×™×ª של ל×קוניה
# Copyright (C) 2008 COPYRIGHT HOLDER
# כל הזכויות שמורות, 2008
-# This file is distributed under the same license as the Laconica package.
+# This file is distributed under the same license as the StatusNet package.
# קובץ ×–×” מופץ תחת רשיון ×–×”×” לזה של החבילה ל×קוניקה
# Hezy Amiel ×—×–×™ עמי×ל <open@hezyamiel.com>, 2008.
#
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -247,8 +247,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -273,7 +273,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1089,11 +1089,11 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"×”×•× ×¤×•×¢×œ על תוכנת המיקרובלוג [](http://laconi.caל×קוניקה/) ל×קוניקה, גירסה %"
+"×”×•× ×¤×•×¢×œ על תוכנת המיקרובלוג [](http://status.netל×קוניקה/) ל×קוניקה, גירסה %"
"s, המופצת תחת רשיון [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)"
@@ -4476,7 +4476,7 @@ msgid "Secondary site navigation"
msgstr "הרשמות"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/it_IT/LC_MESSAGES/laconica.mo b/locale/it_IT/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 3b17f71d0..000000000
--- a/locale/it_IT/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/it_IT/LC_MESSAGES/statusnet.mo b/locale/it_IT/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..95764f1e2
--- /dev/null
+++ b/locale/it_IT/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/it_IT/LC_MESSAGES/laconica.po b/locale/it_IT/LC_MESSAGES/statusnet.po
index 13a629b69..1a59adf85 100644
--- a/locale/it_IT/LC_MESSAGES/laconica.po
+++ b/locale/it_IT/LC_MESSAGES/statusnet.po
@@ -1,12 +1,12 @@
-# Italian translation of laconica
-# Copyright (C) 2008 THE laconica'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the laconica package.
+# Italian translation of statusnet
+# Copyright (C) 2008 THE statusnet'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the statusnet package.
# Milo Casagrande <milo@ubuntu.com>, 2008
#
#
msgid ""
msgstr ""
-"Project-Id-Version: laconica\n"
+"Project-Id-Version: statusnet\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-25 16:24+0000\n"
"PO-Revision-Date: 2009-06-04 14:09+0000\n"
@@ -286,8 +286,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -312,7 +312,7 @@ msgstr "Metodo delle API non trovato!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1159,11 +1159,11 @@ msgstr "Invita nuovi utenti"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Gestito dal software di micro-blog [Laconica](http://laconi.ca/), versione "
+"Gestito dal software di micro-blog [StatusNet](http://status.net/), versione "
"%s, disponibile sotto licenza [GNU Affero General Public "
"License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
@@ -4582,8 +4582,8 @@ msgid "Secondary site navigation"
msgstr "Esplorazione secondaria del sito"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Licenza del software laconica"
+msgid "StatusNet software license"
+msgstr "Licenza del software statusnet"
#: lib/action.php:630
msgid "All "
diff --git a/locale/ja_JP/LC_MESSAGES/laconica.mo b/locale/ja_JP/LC_MESSAGES/laconica.mo
deleted file mode 100644
index d2f6ae8f5..000000000
--- a/locale/ja_JP/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/ja_JP/LC_MESSAGES/statusnet.mo b/locale/ja_JP/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..86efaaf5d
--- /dev/null
+++ b/locale/ja_JP/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ja_JP/LC_MESSAGES/laconica.po b/locale/ja_JP/LC_MESSAGES/statusnet.po
index e260e585e..bb7d777ba 100644
--- a/locale/ja_JP/LC_MESSAGES/laconica.po
+++ b/locale/ja_JP/LC_MESSAGES/statusnet.po
@@ -1,10 +1,10 @@
-# #-#-#-#-# laconica.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Toshiya TSURU <turutosiya@gmail.com>, 2008
#
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -245,8 +245,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -271,7 +271,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1089,11 +1089,11 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"マイクロブロギングソフト [Laconica](http://laconi.ca/) , ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %s ã§å‹•ã„"
+"マイクロブロギングソフト [StatusNet](http://status.net/) , ãƒãƒ¼ã‚¸ãƒ§ãƒ³ %s ã§å‹•ã„"
"ã¦ã„ã¾ã™ã€‚ ライセンス [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)。"
@@ -4466,7 +4466,7 @@ msgid "Secondary site navigation"
msgstr "サブスクリプション"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/ko_KR/LC_MESSAGES/laconica.mo b/locale/ko_KR/LC_MESSAGES/statusnet.mo
index 7d50135ab..2b177ff86 100644
--- a/locale/ko_KR/LC_MESSAGES/laconica.mo
+++ b/locale/ko_KR/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ko_KR/LC_MESSAGES/laconica.po b/locale/ko_KR/LC_MESSAGES/statusnet.po
index 6dcb6f5c5..7bbdcdcf2 100644
--- a/locale/ko_KR/LC_MESSAGES/laconica.po
+++ b/locale/ko_KR/LC_MESSAGES/statusnet.po
@@ -254,8 +254,8 @@ msgstr "추가한 휴대í°ìœ¼ë¡œ ì¸ì¦ 코드를 보냈습니다. 수신함(ë˜
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -280,7 +280,7 @@ msgstr "API 메서드를 ì°¾ì„ ìˆ˜ 없습니다."
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1100,11 +1100,11 @@ msgstr "새 사용ìžë¥¼ 초대"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"ì´ ì‚¬ì´íŠ¸ëŠ” [Laconica](http://laconi.ca/) 마ì´í¬ë¡œë¸”로깅 소프트웨어 %s ë²„ì „ì„ ì‚¬ìš©í•©ë‹ˆë‹¤. Laconica는 "
+"ì´ ì‚¬ì´íŠ¸ëŠ” [StatusNet](http://status.net/) 마ì´í¬ë¡œë¸”로깅 소프트웨어 %s ë²„ì „ì„ ì‚¬ìš©í•©ë‹ˆë‹¤. StatusNet는 "
"[GNU Affero General Public "
"License](http://www.fsf.org/licensing/licenses/agpl-3.0.html) ë¼ì´ì„ ìŠ¤ì— ë”°ë¼ ì‚¬ìš©í•  수 "
"있습니다."
@@ -4405,7 +4405,7 @@ msgid "Secondary site navigation"
msgstr "ë³´ì¡° 사ì´íŠ¸ 네비게ì´ì…˜"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr "ë¼ì½”니카 소프트웨어 ë¼ì´ì„ ìŠ¤"
#: lib/action.php:630
diff --git a/locale/mk_MK/LC_MESSAGES/laconica.mo b/locale/mk_MK/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 7820a3f7c..000000000
--- a/locale/mk_MK/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/mk_MK/LC_MESSAGES/statusnet.mo b/locale/mk_MK/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..0ac378c79
--- /dev/null
+++ b/locale/mk_MK/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/mk_MK/LC_MESSAGES/laconica.po b/locale/mk_MK/LC_MESSAGES/statusnet.po
index e864f8997..d4c4eb235 100644
--- a/locale/mk_MK/LC_MESSAGES/laconica.po
+++ b/locale/mk_MK/LC_MESSAGES/statusnet.po
@@ -1,10 +1,10 @@
-# #-#-#-#-# laconica.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2008 FREE SOFTWARE MACEDONIA
# This file is distributed under the same license as the PACKAGE package.
# IGOR STAMATOVSKI <igor@slobodensoftver.org.mk>, 2008.
#
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -22,8 +22,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"#-#-#-#-# laconica.pot (PACKAGE VERSION) #-#-#-#-#\n"
-"#-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# statusnet.pot (PACKAGE VERSION) #-#-#-#-#\n"
+"#-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#\n"
#: ../actions/noticesearchrss.php:64 actions/noticesearchrss.php:68
#: actions/noticesearchrss.php:88
@@ -249,8 +249,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -275,7 +275,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1099,11 +1099,11 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Работи на [Laconica](http://laconi.ca/) Ñофтверот за микроблогирање, верзија "
+"Работи на [StatusNet](http://status.net/) Ñофтверот за микроблогирање, верзија "
"%s, доÑтапен пд [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)."
@@ -4501,7 +4501,7 @@ msgid "Secondary site navigation"
msgstr "Претплати"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/nb_NO/LC_MESSAGES/laconica.mo b/locale/nb_NO/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 4cc6b6181..000000000
--- a/locale/nb_NO/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/nb_NO/LC_MESSAGES/statusnet.mo b/locale/nb_NO/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..7e8a05579
--- /dev/null
+++ b/locale/nb_NO/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/nb_NO/LC_MESSAGES/laconica.po b/locale/nb_NO/LC_MESSAGES/statusnet.po
index 424cf4da3..116513857 100644
--- a/locale/nb_NO/LC_MESSAGES/laconica.po
+++ b/locale/nb_NO/LC_MESSAGES/statusnet.po
@@ -1,4 +1,4 @@
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -249,8 +249,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -275,7 +275,7 @@ msgstr "API-metode ikke funnet!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1105,7 +1105,7 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
@@ -4418,7 +4418,7 @@ msgid "Secondary site navigation"
msgstr ""
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/nl_NL/LC_MESSAGES/laconica.mo b/locale/nl_NL/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 270e81b7c..000000000
--- a/locale/nl_NL/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/nl_NL/LC_MESSAGES/statusnet.mo b/locale/nl_NL/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..16ce96d0d
--- /dev/null
+++ b/locale/nl_NL/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/nl_NL/LC_MESSAGES/laconica.po b/locale/nl_NL/LC_MESSAGES/statusnet.po
index 6f2eed6ab..6cc0a52c4 100644
--- a/locale/nl_NL/LC_MESSAGES/laconica.po
+++ b/locale/nl_NL/LC_MESSAGES/statusnet.po
@@ -276,8 +276,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -302,7 +302,7 @@ msgstr "API functie niet gevonden"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1153,11 +1153,11 @@ msgstr "Nodig nieuwe gebruikers uit"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Het draait op de [Laconica](http://laconi.ca/) microbloggingsoftware versie "
+"Het draait op de [StatusNet](http://status.net/) microbloggingsoftware versie "
"%s, beschikbaar onder de [GNU Affero General Public "
"License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
@@ -4564,7 +4564,7 @@ msgid "Secondary site navigation"
msgstr "Abonnementen"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/nn_NO/LC_MESSAGES/laconica.mo b/locale/nn_NO/LC_MESSAGES/statusnet.mo
index f0fc1d620..7dbde4019 100644
--- a/locale/nn_NO/LC_MESSAGES/laconica.mo
+++ b/locale/nn_NO/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/nn_NO/LC_MESSAGES/laconica.po b/locale/nn_NO/LC_MESSAGES/statusnet.po
index ff815409f..4da276adb 100644
--- a/locale/nn_NO/LC_MESSAGES/laconica.po
+++ b/locale/nn_NO/LC_MESSAGES/statusnet.po
@@ -1,9 +1,9 @@
-# nn_NO translation of Laconica.
+# nn_NO translation of StatusNet.
#
#
msgid ""
msgstr ""
-"Project-Id-Version: Laconica 0.6.3\n"
+"Project-Id-Version: StatusNet 0.6.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-25 16:24+0000\n"
"PO-Revision-Date: 2009-03-16 18:52+0000\n"
@@ -268,8 +268,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -294,7 +294,7 @@ msgstr "Fann ikkje API-metode."
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1133,11 +1133,11 @@ msgstr "Invitér nye brukarar"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Den køyrer [Laconica](http://laconi.ca) mikroblogging-programvare, versjon %"
+"Den køyrer [StatusNet](http://status.net) mikroblogging-programvare, versjon %"
"s, tilgjengeleg under [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)."
@@ -4496,8 +4496,8 @@ msgid "Secondary site navigation"
msgstr "Andrenivås side navigasjon"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Laconicas programvarelisens"
+msgid "StatusNet software license"
+msgstr "StatusNets programvarelisens"
#: lib/action.php:630
msgid "All "
diff --git a/locale/pl_PL/LC_MESSAGES/laconica.mo b/locale/pl_PL/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 89cc4d349..000000000
--- a/locale/pl_PL/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/pl_PL/LC_MESSAGES/statusnet.mo b/locale/pl_PL/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..48e5fae7d
--- /dev/null
+++ b/locale/pl_PL/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/pl_PL/LC_MESSAGES/laconica.po b/locale/pl_PL/LC_MESSAGES/statusnet.po
index cf06ef958..e866145b2 100644
--- a/locale/pl_PL/LC_MESSAGES/laconica.po
+++ b/locale/pl_PL/LC_MESSAGES/statusnet.po
@@ -1,10 +1,10 @@
-# #-#-#-#-# laconica.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Paweł Wilk <siefca@gnu.org>, 2008.
#
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -263,8 +263,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -289,7 +289,7 @@ msgstr "metoda API nie znaleziona!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1121,11 +1121,11 @@ msgstr "Zaproś nowych użytkowników"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Działa pod kontrolą oprogramowania [Laconica](http://laconi.ca/) służącego "
+"Działa pod kontrolą oprogramowania [StatusNet](http://status.net/) służącego "
"do prowadzenia mikroblogów, w wersji %s, dostępnego na licencji [GNU Affero "
"General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
@@ -4541,7 +4541,7 @@ msgid "Secondary site navigation"
msgstr "Subskrypcje"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/pt/LC_MESSAGES/laconica.mo b/locale/pt/LC_MESSAGES/laconica.mo
deleted file mode 100644
index e6168a340..000000000
--- a/locale/pt/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/pt/LC_MESSAGES/statusnet.mo b/locale/pt/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..35d7053be
--- /dev/null
+++ b/locale/pt/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/pt/LC_MESSAGES/laconica.po b/locale/pt/LC_MESSAGES/statusnet.po
index 54d484ba8..779d7489e 100644
--- a/locale/pt/LC_MESSAGES/laconica.po
+++ b/locale/pt/LC_MESSAGES/statusnet.po
@@ -273,8 +273,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -299,7 +299,7 @@ msgstr "Método da API não encontrado!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1143,7 +1143,7 @@ msgstr "Convidar novos utilizadores"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
@@ -4433,7 +4433,7 @@ msgid "Secondary site navigation"
msgstr ""
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/pt_BR/LC_MESSAGES/laconica.mo b/locale/pt_BR/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 1f4c5fe27..000000000
--- a/locale/pt_BR/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/pt_BR/LC_MESSAGES/statusnet.mo b/locale/pt_BR/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..9db1638b0
--- /dev/null
+++ b/locale/pt_BR/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/pt_BR/LC_MESSAGES/laconica.po b/locale/pt_BR/LC_MESSAGES/statusnet.po
index ad20e89f6..7fae3f5f3 100644
--- a/locale/pt_BR/LC_MESSAGES/laconica.po
+++ b/locale/pt_BR/LC_MESSAGES/statusnet.po
@@ -1,8 +1,8 @@
-# Translation of Laconica to Brazilian Portuguese
+# Translation of StatusNet to Brazilian Portuguese
# Frederico Goncalves Guimaraes <frederico@teia.bio.br>, 2009.
msgid ""
msgstr ""
-"Project-Id-Version: laconica\n"
+"Project-Id-Version: statusnet\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-25 16:24+0000\n"
"PO-Revision-Date: 2009-07-14 11:24+0000\n"
@@ -274,8 +274,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -300,7 +300,7 @@ msgstr "O método da API não foi encontrado!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1144,11 +1144,11 @@ msgstr "Convidar novos usuários"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Ele funciona sob o software de microblogagem [Laconica](http://laconi.ca/), "
+"Ele funciona sob o software de microblogagem [StatusNet](http://status.net/), "
"versão %s, disponível sob a [GNU Affero General Public License] (http://www."
"fsf.org/licensing/licenses/agpl-3.0.html)."
@@ -4601,7 +4601,7 @@ msgid "Secondary site navigation"
msgstr "Navegação pelas assinaturas"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/ru_RU/LC_MESSAGES/laconica.mo b/locale/ru_RU/LC_MESSAGES/statusnet.mo
index 6ebd0713a..c4066c65e 100644
--- a/locale/ru_RU/LC_MESSAGES/laconica.mo
+++ b/locale/ru_RU/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/ru_RU/LC_MESSAGES/laconica.po b/locale/ru_RU/LC_MESSAGES/statusnet.po
index 8735bacd3..8a553a37f 100644
--- a/locale/ru_RU/LC_MESSAGES/laconica.po
+++ b/locale/ru_RU/LC_MESSAGES/statusnet.po
@@ -1,4 +1,4 @@
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -244,8 +244,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -270,7 +270,7 @@ msgstr "Метод API не найден!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1116,11 +1116,11 @@ msgstr "ПриглаÑить новых пользователей"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Этот ÑÐµÑ€Ð²Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°ÐµÑ‚ при помощи [Laconica](http://laconi.ca/) - программного "
+"Этот ÑÐµÑ€Ð²Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°ÐµÑ‚ при помощи [StatusNet](http://status.net/) - программного "
"обеÑÐ¿ÐµÑ‡ÐµÐ½Ð¸Ñ Ð´Ð»Ñ Ð¼Ð¸ÐºÑ€Ð¾Ð±Ð»Ð¾Ð³Ð¸Ð½Ð³Ð°, верÑии %s, доÑтупного под лицензией [GNU "
"Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-"
"3.0.html)."
@@ -4559,8 +4559,8 @@ msgid "Secondary site navigation"
msgstr "ÐÐ°Ð²Ð¸Ð³Ð°Ñ†Ð¸Ñ Ð¿Ð¾ подпиÑкам"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Laconica лицензиÑ"
+msgid "StatusNet software license"
+msgstr "StatusNet лицензиÑ"
#: lib/action.php:630
msgid "All "
diff --git a/locale/laconica.po b/locale/statusnet.po
index ab8e7458e..c7ac6ac9b 100644
--- a/locale/laconica.po
+++ b/locale/statusnet.po
@@ -247,8 +247,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -286,7 +286,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562 actions/twitapiaccount.php:46
#: actions/twitapiaccount.php:98 actions/twitapiaccount.php:104
@@ -1165,7 +1165,7 @@ msgstr ""
#: lib/action.php:756
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
@@ -4765,7 +4765,7 @@ msgstr ""
#: lib/action.php:602 lib/action.php:623 lib/action.php:699 lib/action.php:720
#: lib/action.php:749 lib/action.php:770
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630 lib/action.php:727 lib/action.php:779
@@ -5230,7 +5230,7 @@ msgstr ""
#, php-format
msgid ""
"This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-"
-"blogging) service based on the Free Software [Laconica](http://laconi.ca/) "
+"blogging) service based on the Free Software [StatusNet](http://status.net/) "
"tool. [Join now](%%action.register%%) to share notices about yourself with "
"friends, family, and colleagues! ([Read more](%%doc.help%%))"
msgstr ""
@@ -5262,7 +5262,7 @@ msgstr ""
msgid ""
"**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en."
"wikipedia.org/wiki/Micro-blogging) service based on the Free Software "
-"[Laconica](http://laconi.ca/) tool. Its members share short messages about "
+"[StatusNet](http://status.net/) tool. Its members share short messages about "
"their life and interests. [Join now](%%%%action.register%%%%) to become part "
"of this group and many more! ([Read more](%%%%doc.help%%%%))"
msgstr ""
@@ -5313,7 +5313,7 @@ msgstr ""
msgid ""
"**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en."
"wikipedia.org/wiki/Micro-blogging) service based on the Free Software "
-"[Laconica](http://laconi.ca/) tool. [Join now](%%%%action.register%%%%) to "
+"[StatusNet](http://status.net/) tool. [Join now](%%%%action.register%%%%) to "
"follow **%s**'s notices and many more! ([Read more](%%%%doc.help%%%%))"
msgstr ""
@@ -5939,7 +5939,7 @@ msgstr ""
#, php-format
msgid ""
"This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-"
-"blogging) service based on the Free Software [Laconica](http://laconi.ca/) "
+"blogging) service based on the Free Software [StatusNet](http://status.net/) "
"tool."
msgstr ""
@@ -6056,7 +6056,7 @@ msgstr ""
msgid ""
"**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en."
"wikipedia.org/wiki/Micro-blogging) service based on the Free Software "
-"[Laconica](http://laconi.ca/) tool. Its members share short messages about "
+"[StatusNet](http://status.net/) tool. Its members share short messages about "
"their life and interests. "
msgstr ""
@@ -6101,7 +6101,7 @@ msgstr ""
msgid ""
"**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en."
"wikipedia.org/wiki/Micro-blogging) service based on the Free Software "
-"[Laconica](http://laconi.ca/) tool. "
+"[StatusNet](http://status.net/) tool. "
msgstr ""
#: actions/subscribers.php:108
diff --git a/locale/sv_SE/LC_MESSAGES/laconica.mo b/locale/sv_SE/LC_MESSAGES/laconica.mo
deleted file mode 100644
index e2a8fa9cc..000000000
--- a/locale/sv_SE/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/sv_SE/LC_MESSAGES/statusnet.mo b/locale/sv_SE/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..ce3c6c1f5
--- /dev/null
+++ b/locale/sv_SE/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/sv_SE/LC_MESSAGES/laconica.po b/locale/sv_SE/LC_MESSAGES/statusnet.po
index 4598be4a2..d0a5001da 100644
--- a/locale/sv_SE/LC_MESSAGES/laconica.po
+++ b/locale/sv_SE/LC_MESSAGES/statusnet.po
@@ -271,8 +271,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -297,7 +297,7 @@ msgstr "API-metoden hittades inte!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1139,11 +1139,11 @@ msgstr "Bjud in nya användare"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Det drivs med [Laconica](http://laconi.ca/) mikroblogging software, version %"
+"Det drivs med [StatusNet](http://status.net/) mikroblogging software, version %"
"s, tillgängligt under [GNU Affero General Public License](http://www.fsf.org/"
"licensing/licenses/agpl-3.0.html)."
@@ -4622,7 +4622,7 @@ msgid "Secondary site navigation"
msgstr "Prenumerationer"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/te_IN/LC_MESSAGES/laconica.mo b/locale/te_IN/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 5cfa0c3fb..000000000
--- a/locale/te_IN/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/te_IN/LC_MESSAGES/statusnet.mo b/locale/te_IN/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..bb837b977
--- /dev/null
+++ b/locale/te_IN/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/te_IN/LC_MESSAGES/laconica.po b/locale/te_IN/LC_MESSAGES/statusnet.po
index e8522f971..4576f3613 100644
--- a/locale/te_IN/LC_MESSAGES/laconica.po
+++ b/locale/te_IN/LC_MESSAGES/statusnet.po
@@ -1,10 +1,10 @@
-# #-#-#-#-# laconica.pot (PACKAGE VERSION) #-#-#-#-#
-# Laconica Telugu Translation
+# #-#-#-#-# statusnet.pot (PACKAGE VERSION) #-#-#-#-#
+# StatusNet Telugu Translation
# Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER
-# This file is distributed under the same license as the Laconica package.
+# This file is distributed under the same license as the StatusNet package.
# Veeven <veeven@gmail.com>, 2008.
#
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -237,8 +237,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -263,7 +263,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1082,7 +1082,7 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
@@ -4437,7 +4437,7 @@ msgid "Secondary site navigation"
msgstr "చందాలà±"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/tr_TR/LC_MESSAGES/laconica.mo b/locale/tr_TR/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 4b8b55022..000000000
--- a/locale/tr_TR/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/tr_TR/LC_MESSAGES/statusnet.mo b/locale/tr_TR/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..e0ef80560
--- /dev/null
+++ b/locale/tr_TR/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/tr_TR/LC_MESSAGES/laconica.po b/locale/tr_TR/LC_MESSAGES/statusnet.po
index cb8bf60e7..e67fbf33c 100644
--- a/locale/tr_TR/LC_MESSAGES/laconica.po
+++ b/locale/tr_TR/LC_MESSAGES/statusnet.po
@@ -1,4 +1,4 @@
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -245,8 +245,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -271,7 +271,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1096,12 +1096,12 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
"nedurum.com [GNU Affero General Public License](http://www.fsf.org/licensing/"
-"licenses/agpl-3.0.html) lisansı ile korunan [Laconica](http://laconi.ca/) "
+"licenses/agpl-3.0.html) lisansı ile korunan [StatusNet](http://status.net/) "
"microbloglama yazılımının %s. versiyonunu kullanmaktadır."
#: ../actions/imsettings.php:173 actions/imsettings.php:181
@@ -4506,7 +4506,7 @@ msgid "Secondary site navigation"
msgstr "Abonelikler"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/locale/uk_UA/LC_MESSAGES/laconica.mo b/locale/uk_UA/LC_MESSAGES/statusnet.mo
index 34818a235..e08dc4e9c 100644
--- a/locale/uk_UA/LC_MESSAGES/laconica.mo
+++ b/locale/uk_UA/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/uk_UA/LC_MESSAGES/laconica.po b/locale/uk_UA/LC_MESSAGES/statusnet.po
index 12809a3f6..55cea21c3 100644
--- a/locale/uk_UA/LC_MESSAGES/laconica.po
+++ b/locale/uk_UA/LC_MESSAGES/statusnet.po
@@ -1,4 +1,4 @@
-# #-#-#-#-# laconica.new.pot (PACKAGE VERSION) #-#-#-#-#
+# #-#-#-#-# statusnet.new.pot (PACKAGE VERSION) #-#-#-#-#
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
@@ -10,7 +10,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-25 16:24+0000\n"
"PO-Revision-Date: 2009-03-12 16:19+0000\n"
-"Last-Translator: Evan Prodromou <evan@controlyourself.ca>\n"
+"Last-Translator: Evan Prodromou <evan@status.net>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -280,8 +280,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -306,7 +306,7 @@ msgstr "API метод не знайдено!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1153,11 +1153,11 @@ msgstr "ЗапроÑити нових кориÑтувачів"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Ð¡ÐµÑ€Ð²Ñ–Ñ Ð¿Ñ€Ð°Ñ†ÑŽÑ” на [Laconica](http://laconi.ca/) - програмному забезпеченні "
+"Ð¡ÐµÑ€Ð²Ñ–Ñ Ð¿Ñ€Ð°Ñ†ÑŽÑ” на [StatusNet](http://status.net/) - програмному забезпеченні "
"Ð´Ð»Ñ Ð¼Ñ–ÐºÑ€Ð¾Ð±Ð»Ð¾Ð³Ñ–Ð², верÑÑ–Ñ %s, доÑтупному під [GNU Affero General Public "
"License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
@@ -4545,8 +4545,8 @@ msgid "Secondary site navigation"
msgstr "ДругорÑдна Ð½Ð°Ð²Ñ–Ð³Ð°Ñ†Ñ–Ñ Ð¿Ð¾ Ñайту"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Ð›Ñ–Ñ†ÐµÐ½Ð·Ñ–Ñ Laconica software"
+msgid "StatusNet software license"
+msgstr "Ð›Ñ–Ñ†ÐµÐ½Ð·Ñ–Ñ StatusNet software"
#: lib/action.php:630
msgid "All "
diff --git a/locale/vi_VN/LC_MESSAGES/laconica.mo b/locale/vi_VN/LC_MESSAGES/laconica.mo
deleted file mode 100644
index b7f5e3c2c..000000000
--- a/locale/vi_VN/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/vi_VN/LC_MESSAGES/statusnet.mo b/locale/vi_VN/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..65add28b4
--- /dev/null
+++ b/locale/vi_VN/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/vi_VN/LC_MESSAGES/laconica.po b/locale/vi_VN/LC_MESSAGES/statusnet.po
index 0b9477a6a..af34d5210 100644
--- a/locale/vi_VN/LC_MESSAGES/laconica.po
+++ b/locale/vi_VN/LC_MESSAGES/statusnet.po
@@ -1,6 +1,6 @@
msgid ""
msgstr ""
-"Project-Id-Version: laconica\n"
+"Project-Id-Version: statusnet\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-25 16:24+0000\n"
"PO-Revision-Date: 2009-05-10 05:27+0000\n"
@@ -271,8 +271,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -297,7 +297,7 @@ msgstr "Phương thức API không tìm thấy!"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1147,11 +1147,11 @@ msgstr "Gá»­i thÆ° má»i đến những ngÆ°á»i chÆ°a có tài khoản"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, fuzzy, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"Äang duÌ€ng [Laconica](http://laconi.ca/), phiên bản %s phát hành theo bản "
+"Äang duÌ€ng [StatusNet](http://status.net/), phiên bản %s phát hành theo bản "
"quyá»n [GNU Affero General Public "
"License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
@@ -4705,7 +4705,7 @@ msgid "Secondary site navigation"
msgstr "Tôi theo"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
@@ -5097,11 +5097,11 @@ msgstr "Ngừng đăng ký từ ngÆ°á»i dùng này"
#~ msgstr "FAQ - Há»i đáp"
#~ msgid ""
-#~ "It runs the [Laconica](http://laconi.ca/) microblogging software, version "
+#~ "It runs the [StatusNet](http://status.net/) microblogging software, version "
#~ "%s, available under the [GNU Affero General Public License] (http://www."
#~ "fsf.org/licensing/licenses/agpl-3.0.html)."
#~ msgstr ""
-#~ "Microblogging [Laconica](http://laconi.ca/), version %s đã có ở [GNU "
+#~ "Microblogging [StatusNet](http://status.net/), version %s đã có ở [GNU "
#~ "Affero General Public License] (http://www.fsf.org/licensing/licenses/"
#~ "agpl-3.0.html)."
@@ -5282,7 +5282,7 @@ msgstr "Ngừng đăng ký từ ngÆ°á»i dùng này"
#~ msgid ""
#~ "To use this [Saigonica version](%%doc.source%%), you must write the "
-#~ "license is of Laconica and has contributions from Saigonica."
+#~ "license is of StatusNet and has contributions from Saigonica."
#~ msgstr ""
#~ "Äể sá»­ dụng [phiên bản Saigonica](%%doc.source%%) này, cần ghi rõ bản "
#~ "quyá»n của Laconia cá»™ng thêm sá»± đóng góp của Saigonica."
diff --git a/locale/zh_CN/LC_MESSAGES/laconica.mo b/locale/zh_CN/LC_MESSAGES/laconica.mo
deleted file mode 100644
index 2d380582a..000000000
--- a/locale/zh_CN/LC_MESSAGES/laconica.mo
+++ /dev/null
Binary files differ
diff --git a/locale/zh_CN/LC_MESSAGES/statusnet.mo b/locale/zh_CN/LC_MESSAGES/statusnet.mo
new file mode 100644
index 000000000..a7a79f40c
--- /dev/null
+++ b/locale/zh_CN/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/zh_CN/LC_MESSAGES/laconica.po b/locale/zh_CN/LC_MESSAGES/statusnet.po
index 5d285122d..529d2f4f8 100644
--- a/locale/zh_CN/LC_MESSAGES/laconica.po
+++ b/locale/zh_CN/LC_MESSAGES/statusnet.po
@@ -258,8 +258,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -284,7 +284,7 @@ msgstr "API 方法未实现ï¼"
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1107,11 +1107,11 @@ msgstr "邀请新用户"
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
-"它è¿è¡Œ[Laconica](http://laconi.ca/)å¾®åšå®¢æœåŠ¡ï¼Œç‰ˆæœ¬ %s,采用[GNU Affero "
+"它è¿è¡Œ[StatusNet](http://status.net/)å¾®åšå®¢æœåŠ¡ï¼Œç‰ˆæœ¬ %s,采用[GNU Affero "
"General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html)"
"授æƒã€‚"
@@ -4528,8 +4528,8 @@ msgid "Secondary site navigation"
msgstr "次项站导航"
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
-msgstr "Laconica软件注册è¯"
+msgid "StatusNet software license"
+msgstr "StatusNet软件注册è¯"
#: lib/action.php:630
msgid "All "
diff --git a/locale/zh_TW/LC_MESSAGES/laconica.mo b/locale/zh_TW/LC_MESSAGES/statusnet.mo
index 5b23372fb..e13548831 100644
--- a/locale/zh_TW/LC_MESSAGES/laconica.mo
+++ b/locale/zh_TW/LC_MESSAGES/statusnet.mo
Binary files differ
diff --git a/locale/zh_TW/LC_MESSAGES/laconica.po b/locale/zh_TW/LC_MESSAGES/statusnet.po
index c6f880623..a94187518 100644
--- a/locale/zh_TW/LC_MESSAGES/laconica.po
+++ b/locale/zh_TW/LC_MESSAGES/statusnet.po
@@ -9,7 +9,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2009-01-25 16:24+0000\n"
"PO-Revision-Date: 2009-03-12 16:21+0000\n"
-"Last-Translator: Evan Prodromou <evan@controlyourself.ca>\n"
+"Last-Translator: Evan Prodromou <evan@status.net>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -237,8 +237,8 @@ msgstr ""
#: actions/twitapiusers.php:55 actions/twitapiaccount.php:37
#: actions/twitapidirect_messages.php:111 actions/twitapifavorites.php:85
#: actions/twitapifavorites.php:102 actions/twitapifriendships.php:121
-#: actions/twitapihelp.php:44 actions/twitapilaconica.php:82
-#: actions/twitapilaconica.php:151 actions/twitapistatuses.php:79
+#: actions/twitapihelp.php:44 actions/twitapistatusnet.php:82
+#: actions/twitapistatusnet.php:151 actions/twitapistatuses.php:79
#: actions/twitapistatuses.php:147 actions/twitapistatuses.php:228
#: actions/twitapistatuses.php:239 actions/twitapistatuses.php:392
#: actions/twitapistatuses.php:402 actions/twitapistatuses.php:429
@@ -263,7 +263,7 @@ msgstr ""
#: actions/twitapistatuses.php:690 actions/twitapiaccount.php:45
#: actions/twitapiaccount.php:97 actions/twitapiaccount.php:103
#: actions/twitapidirect_messages.php:184 actions/twitapifavorites.php:143
-#: actions/twitapihelp.php:52 actions/twitapilaconica.php:172
+#: actions/twitapihelp.php:52 actions/twitapistatusnet.php:172
#: actions/twitapinotifications.php:31 actions/twitapinotifications.php:37
#: actions/twitapistatuses.php:562
msgid "API method under construction."
@@ -1077,7 +1077,7 @@ msgstr ""
#: ../lib/util.php:261 lib/util.php:277 lib/action.php:609
#, php-format
msgid ""
-"It runs the [Laconica](http://laconi.ca/) microblogging software, version %"
+"It runs the [StatusNet](http://status.net/) microblogging software, version %"
"s, available under the [GNU Affero General Public License](http://www.fsf."
"org/licensing/licenses/agpl-3.0.html)."
msgstr ""
@@ -4398,7 +4398,7 @@ msgid "Secondary site navigation"
msgstr ""
#: lib/action.php:602 lib/action.php:623
-msgid "Laconica software license"
+msgid "StatusNet software license"
msgstr ""
#: lib/action.php:630
diff --git a/plugins/Autocomplete/Autocomplete.js b/plugins/Autocomplete/Autocomplete.js
new file mode 100644
index 000000000..3eff685a8
--- /dev/null
+++ b/plugins/Autocomplete/Autocomplete.js
@@ -0,0 +1,37 @@
+$(document).ready(function(){
+ $('#notice_data-text').autocomplete($('address .url')[0].href+'/plugins/Autocomplete/autocomplete.json', {
+ multiple: true,
+ multipleSeparator: " ",
+ minChars: 1,
+ formatItem: function(row, i, max){
+ row = eval("(" + row + ")");
+ switch(row.type)
+ {
+ case 'user':
+ return row.nickname + ' (' + row.fullname + ')';
+ case 'group':
+ return row.nickname + ' (' + row.fullname + ')';
+ }
+ },
+ formatMatch: function(row, i, max){
+ row = eval("(" + row + ")");
+ switch(row.type)
+ {
+ case 'user':
+ return row.nickname;
+ case 'group':
+ return row.nickname;
+ }
+ },
+ formatResult: function(row){
+ row = eval("(" + row + ")");
+ switch(row.type)
+ {
+ case 'user':
+ return '@' + row.nickname;
+ case 'group':
+ return '!' + row.nickname;
+ }
+ }
+ });
+});
diff --git a/plugins/Autocomplete/AutocompletePlugin.php b/plugins/Autocomplete/AutocompletePlugin.php
new file mode 100644
index 000000000..baaec73c1
--- /dev/null
+++ b/plugins/Autocomplete/AutocompletePlugin.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to enable nickname completion in the enter status box
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Craig Andrews http://candrews.integralblue.com
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once(INSTALLDIR.'/plugins/Autocomplete/autocomplete.php');
+
+class AutocompletePlugin extends Plugin
+{
+ function __construct()
+ {
+ parent::__construct();
+ }
+
+ function onEndShowScripts($action){
+ if (common_logged_in()) {
+ $action->script('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js');
+ $action->script('plugins/Autocomplete/Autocomplete.js');
+ }
+ }
+
+ function onEndShowStatusNetStyles($action)
+ {
+ if (common_logged_in()) {
+ $action->cssLink('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.css');
+ }
+ }
+
+ function onRouterInitialized($m)
+ {
+ if (common_logged_in()) {
+ $m->connect('plugins/Autocomplete/autocomplete.json', array('action'=>'autocomplete'));
+ }
+ }
+
+}
+?>
diff --git a/plugins/Autocomplete/autocomplete.php b/plugins/Autocomplete/autocomplete.php
new file mode 100644
index 000000000..aa57b3915
--- /dev/null
+++ b/plugins/Autocomplete/autocomplete.php
@@ -0,0 +1,136 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * List users for autocompletion
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+/**
+ * List users for autocompletion
+ *
+ * This is the form for adding a new g
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+class AutocompleteAction extends Action
+{
+ private $result;
+
+ /**
+ * Last-modified date for page
+ *
+ * When was the content of this page last modified? Based on notice,
+ * profile, avatar.
+ *
+ * @return int last-modified date as unix timestamp
+ */
+ function lastModified()
+ {
+ $max=0;
+ foreach($this->users as $user){
+ $max = max($max,strtotime($user->modified),strtotime($user->profile->modified));
+ }
+ foreach($this->groups as $group){
+ $max = max($max,strtotime($group->modified));
+ }
+ return $max;
+ }
+
+ /**
+ * An entity tag for this page
+ *
+ * Shows the ETag for the page, based on the notice ID and timestamps
+ * for the notice, profile, and avatar. It's weak, since we change
+ * the date text "one hour ago", etc.
+ *
+ * @return string etag
+ */
+ function etag()
+ {
+ return '"' . implode(':', array($this->arg('action'),
+ crc32($this->arg('q')), //the actual string can have funny characters in we don't want showing up in the etag
+ $this->arg('limit'),
+ $this->lastModified())) . '"';
+ }
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->groups=array();
+ $this->users=array();
+ $q = $this->arg('q');
+ $limit = $this->arg('limit');
+ if($limit > 200) $limit=200; //prevent DOS attacks
+ if(substr($q,0,1)=='@'){
+ //user search
+ $q=substr($q,1);
+ $user = new User();
+ $user->limit($limit);
+ $user->whereAdd('nickname like \'' . trim($user->escape($q), '\'') . '%\'');
+ $user->find();
+ while($user->fetch()) {
+ $profile = Profile::staticGet($user->id);
+ $user->profile=$profile;
+ $this->users[]=$user;
+ }
+ }
+ if(substr($q,0,1)=='!'){
+ //group search
+ $q=substr($q,1);
+ $group = new User_group();
+ $group->limit($limit);
+ $group->whereAdd('nickname like \'' . trim($group->escape($q), '\'') . '%\'');
+ $group->find();
+ while($group->fetch()) {
+ $this->groups[]=$group;
+ }
+ }
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $results = array();
+ foreach($this->users as $user){
+ $results[]=array('nickname' => $user->nickname, 'fullname'=> $user->profile->fullname, 'type'=>'user');
+ }
+ foreach($this->groups as $group){
+ $results[]=array('nickname' => $group->nickname, 'fullname'=> $group->fullname, 'type'=>'group');
+ }
+ foreach($results as $result) {
+ print json_encode($result) . "\n";
+ }
+ }
+}
diff --git a/plugins/Autocomplete/jquery-autocomplete/changelog.txt b/plugins/Autocomplete/jquery-autocomplete/changelog.txt
new file mode 100644
index 000000000..94cb5ccde
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/changelog.txt
@@ -0,0 +1,20 @@
+1.0.2
+-----
+* Fixed missing semicolon
+
+1.0.1
+-----
+* Fixed element creation (<ul> to <ul/> and <li> to </li>)
+* Fixed ac_even class (was ac_event)
+* Fixed bgiframe usage: now its really optional
+* Removed the blur-on-return workaround, added a less obtrusive one only for Opera
+* Fixed hold cursor keys: Opera needs keypress, everyone else keydown to scroll through result list when holding cursor key
+* Updated package to jQuery 1.2.5, removing dimensions
+* Fixed multiple-mustMatch: Remove only the last term when no match is found
+* Fixed multiple without mustMatch: Don't select the last active when no match is found (on tab/return)
+* Fixed multiple cursor position: Put cursor at end of input after selecting a value
+
+1.0
+---
+
+* First release. \ No newline at end of file
diff --git a/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.css b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.css
new file mode 100644
index 000000000..91b622833
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.css
@@ -0,0 +1,48 @@
+.ac_results {
+ padding: 0px;
+ border: 1px solid black;
+ background-color: white;
+ overflow: hidden;
+ z-index: 99999;
+}
+
+.ac_results ul {
+ width: 100%;
+ list-style-position: outside;
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.ac_results li {
+ margin: 0px;
+ padding: 2px 5px;
+ cursor: default;
+ display: block;
+ /*
+ if width will be 100% horizontal scrollbar will apear
+ when scroll mode will be used
+ */
+ /*width: 100%;*/
+ font: menu;
+ font-size: 12px;
+ /*
+ it is very important, if line-height not setted or setted
+ in relative units scroll will be broken in firefox
+ */
+ line-height: 16px;
+ overflow: hidden;
+}
+
+.ac_loading {
+ background: white url('indicator.gif') right center no-repeat;
+}
+
+.ac_odd {
+ background-color: #eee;
+}
+
+.ac_over {
+ background-color: #0A246A;
+ color: white;
+}
diff --git a/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.js b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.js
new file mode 100644
index 000000000..5ad9178f8
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.js
@@ -0,0 +1,759 @@
+/*
+ * Autocomplete - jQuery plugin 1.0.2
+ *
+ * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
+ *
+ */
+
+;(function($) {
+
+$.fn.extend({
+ autocomplete: function(urlOrData, options) {
+ var isUrl = typeof urlOrData == "string";
+ options = $.extend({}, $.Autocompleter.defaults, {
+ url: isUrl ? urlOrData : null,
+ data: isUrl ? null : urlOrData,
+ delay: isUrl ? $.Autocompleter.defaults.delay : 10,
+ max: options && !options.scroll ? 10 : 150
+ }, options);
+
+ // if highlight is set to false, replace it with a do-nothing function
+ options.highlight = options.highlight || function(value) { return value; };
+
+ // if the formatMatch option is not specified, then use formatItem for backwards compatibility
+ options.formatMatch = options.formatMatch || options.formatItem;
+
+ return this.each(function() {
+ new $.Autocompleter(this, options);
+ });
+ },
+ result: function(handler) {
+ return this.bind("result", handler);
+ },
+ search: function(handler) {
+ return this.trigger("search", [handler]);
+ },
+ flushCache: function() {
+ return this.trigger("flushCache");
+ },
+ setOptions: function(options){
+ return this.trigger("setOptions", [options]);
+ },
+ unautocomplete: function() {
+ return this.trigger("unautocomplete");
+ }
+});
+
+$.Autocompleter = function(input, options) {
+
+ var KEY = {
+ UP: 38,
+ DOWN: 40,
+ DEL: 46,
+ TAB: 9,
+ RETURN: 13,
+ ESC: 27,
+ COMMA: 188,
+ PAGEUP: 33,
+ PAGEDOWN: 34,
+ BACKSPACE: 8
+ };
+
+ // Create $ object for input element
+ var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass);
+
+ var timeout;
+ var previousValue = "";
+ var cache = $.Autocompleter.Cache(options);
+ var hasFocus = 0;
+ var lastKeyPressCode;
+ var config = {
+ mouseDownOnSelect: false
+ };
+ var select = $.Autocompleter.Select(options, input, selectCurrent, config);
+
+ var blockSubmit;
+
+ // prevent form submit in opera when selecting with return key
+ $.browser.opera && $(input.form).bind("submit.autocomplete", function() {
+ if (blockSubmit) {
+ blockSubmit = false;
+ return false;
+ }
+ });
+
+ // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all
+ $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) {
+ // track last key pressed
+ lastKeyPressCode = event.keyCode;
+ switch(event.keyCode) {
+
+ case KEY.UP:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.prev();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.DOWN:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.next();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGEUP:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.pageUp();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ case KEY.PAGEDOWN:
+ event.preventDefault();
+ if ( select.visible() ) {
+ select.pageDown();
+ } else {
+ onChange(0, true);
+ }
+ break;
+
+ // matches also semicolon
+ case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA:
+ case KEY.TAB:
+ case KEY.RETURN:
+ if( selectCurrent() ) {
+ // stop default to prevent a form submit, Opera needs special handling
+ event.preventDefault();
+ blockSubmit = true;
+ return false;
+ }
+ break;
+
+ case KEY.ESC:
+ select.hide();
+ break;
+
+ default:
+ clearTimeout(timeout);
+ timeout = setTimeout(onChange, options.delay);
+ break;
+ }
+ }).focus(function(){
+ // track whether the field has focus, we shouldn't process any
+ // results if the field no longer has focus
+ hasFocus++;
+ }).blur(function() {
+ hasFocus = 0;
+ if (!config.mouseDownOnSelect) {
+ hideResults();
+ }
+ }).click(function() {
+ // show select when clicking in a focused field
+ if ( hasFocus++ > 1 && !select.visible() ) {
+ onChange(0, true);
+ }
+ }).bind("search", function() {
+ // TODO why not just specifying both arguments?
+ var fn = (arguments.length > 1) ? arguments[1] : null;
+ function findValueCallback(q, data) {
+ var result;
+ if( data && data.length ) {
+ for (var i=0; i < data.length; i++) {
+ if( data[i].result.toLowerCase() == q.toLowerCase() ) {
+ result = data[i];
+ break;
+ }
+ }
+ }
+ if( typeof fn == "function" ) fn(result);
+ else $input.trigger("result", result && [result.data, result.value]);
+ }
+ $.each(trimWords($input.val()), function(i, value) {
+ request(value, findValueCallback, findValueCallback);
+ });
+ }).bind("flushCache", function() {
+ cache.flush();
+ }).bind("setOptions", function() {
+ $.extend(options, arguments[1]);
+ // if we've updated the data, repopulate
+ if ( "data" in arguments[1] )
+ cache.populate();
+ }).bind("unautocomplete", function() {
+ select.unbind();
+ $input.unbind();
+ $(input.form).unbind(".autocomplete");
+ });
+
+
+ function selectCurrent() {
+ var selected = select.selected();
+ if( !selected )
+ return false;
+
+ var v = selected.result;
+ previousValue = v;
+
+ if ( options.multiple ) {
+ var words = trimWords($input.val());
+ if ( words.length > 1 ) {
+ v = words.slice(0, words.length - 1).join( options.multipleSeparator ) + options.multipleSeparator + v;
+ }
+ v += options.multipleSeparator;
+ }
+
+ $input.val(v);
+ hideResultsNow();
+ $input.trigger("result", [selected.data, selected.value]);
+ return true;
+ }
+
+ function onChange(crap, skipPrevCheck) {
+ if( lastKeyPressCode == KEY.DEL ) {
+ select.hide();
+ return;
+ }
+
+ var currentValue = $input.val();
+
+ if ( !skipPrevCheck && currentValue == previousValue )
+ return;
+
+ previousValue = currentValue;
+
+ currentValue = lastWord(currentValue);
+ if ( currentValue.length >= options.minChars) {
+ $input.addClass(options.loadingClass);
+ if (!options.matchCase)
+ currentValue = currentValue.toLowerCase();
+ request(currentValue, receiveData, hideResultsNow);
+ } else {
+ stopLoading();
+ select.hide();
+ }
+ };
+
+ function trimWords(value) {
+ if ( !value ) {
+ return [""];
+ }
+ var words = value.split( options.multipleSeparator );
+ var result = [];
+ $.each(words, function(i, value) {
+ if ( $.trim(value) )
+ result[i] = $.trim(value);
+ });
+ return result;
+ }
+
+ function lastWord(value) {
+ if ( !options.multiple )
+ return value;
+ var words = trimWords(value);
+ return words[words.length - 1];
+ }
+
+ // fills in the input box w/the first match (assumed to be the best match)
+ // q: the term entered
+ // sValue: the first matching result
+ function autoFill(q, sValue){
+ // autofill in the complete box w/the first match as long as the user hasn't entered in more data
+ // if the last user key pressed was backspace, don't autofill
+ if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) {
+ // fill in the value (keep the case the user has typed)
+ $input.val($input.val() + sValue.substring(lastWord(previousValue).length));
+ // select the portion of the value not typed by the user (so the next character will erase)
+ $.Autocompleter.Selection(input, previousValue.length, previousValue.length + sValue.length);
+ }
+ };
+
+ function hideResults() {
+ clearTimeout(timeout);
+ timeout = setTimeout(hideResultsNow, 200);
+ };
+
+ function hideResultsNow() {
+ var wasVisible = select.visible();
+ select.hide();
+ clearTimeout(timeout);
+ stopLoading();
+ if (options.mustMatch) {
+ // call search and run callback
+ $input.search(
+ function (result){
+ // if no value found, clear the input box
+ if( !result ) {
+ if (options.multiple) {
+ var words = trimWords($input.val()).slice(0, -1);
+ $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") );
+ }
+ else
+ $input.val( "" );
+ }
+ }
+ );
+ }
+ if (wasVisible)
+ // position cursor at end of input field
+ $.Autocompleter.Selection(input, input.value.length, input.value.length);
+ };
+
+ function receiveData(q, data) {
+ if ( data && data.length && hasFocus ) {
+ stopLoading();
+ select.display(data, q);
+ autoFill(q, data[0].value);
+ select.show();
+ } else {
+ hideResultsNow();
+ }
+ };
+
+ function request(term, success, failure) {
+ if (!options.matchCase)
+ term = term.toLowerCase();
+ var data = cache.load(term);
+ // recieve the cached data
+ if (data && data.length) {
+ success(term, data);
+ // if an AJAX url has been supplied, try loading the data now
+ } else if( (typeof options.url == "string") && (options.url.length > 0) ){
+
+ var extraParams = {
+ timestamp: +new Date()
+ };
+ $.each(options.extraParams, function(key, param) {
+ extraParams[key] = typeof param == "function" ? param() : param;
+ });
+
+ $.ajax({
+ // try to leverage ajaxQueue plugin to abort previous requests
+ mode: "abort",
+ // limit abortion to this input
+ port: "autocomplete" + input.name,
+ dataType: options.dataType,
+ url: options.url,
+ data: $.extend({
+ q: lastWord(term),
+ limit: options.max
+ }, extraParams),
+ success: function(data) {
+ var parsed = options.parse && options.parse(data) || parse(data);
+ cache.add(term, parsed);
+ success(term, parsed);
+ }
+ });
+ } else {
+ // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match
+ select.emptyList();
+ failure(term);
+ }
+ };
+
+ function parse(data) {
+ var parsed = [];
+ var rows = data.split("\n");
+ for (var i=0; i < rows.length; i++) {
+ var row = $.trim(rows[i]);
+ if (row) {
+ row = row.split("|");
+ parsed[parsed.length] = {
+ data: row,
+ value: row[0],
+ result: options.formatResult && options.formatResult(row, row[0]) || row[0]
+ };
+ }
+ }
+ return parsed;
+ };
+
+ function stopLoading() {
+ $input.removeClass(options.loadingClass);
+ };
+
+};
+
+$.Autocompleter.defaults = {
+ inputClass: "ac_input",
+ resultsClass: "ac_results",
+ loadingClass: "ac_loading",
+ minChars: 1,
+ delay: 400,
+ matchCase: false,
+ matchSubset: true,
+ matchContains: false,
+ cacheLength: 10,
+ max: 100,
+ mustMatch: false,
+ extraParams: {},
+ selectFirst: true,
+ formatItem: function(row) { return row[0]; },
+ formatMatch: null,
+ autoFill: false,
+ width: 0,
+ multiple: false,
+ multipleSeparator: ", ",
+ highlight: function(value, term) {
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>");
+ },
+ scroll: true,
+ scrollHeight: 180
+};
+
+$.Autocompleter.Cache = function(options) {
+
+ var data = {};
+ var length = 0;
+
+ function matchSubset(s, sub) {
+ if (!options.matchCase)
+ s = s.toLowerCase();
+ var i = s.indexOf(sub);
+ if (i == -1) return false;
+ return i == 0 || options.matchContains;
+ };
+
+ function add(q, value) {
+ if (length > options.cacheLength){
+ flush();
+ }
+ if (!data[q]){
+ length++;
+ }
+ data[q] = value;
+ }
+
+ function populate(){
+ if( !options.data ) return false;
+ // track the matches
+ var stMatchSets = {},
+ nullData = 0;
+
+ // no url was specified, we need to adjust the cache length to make sure it fits the local data store
+ if( !options.url ) options.cacheLength = 1;
+
+ // track all options for minChars = 0
+ stMatchSets[""] = [];
+
+ // loop through the array and create a lookup structure
+ for ( var i = 0, ol = options.data.length; i < ol; i++ ) {
+ var rawValue = options.data[i];
+ // if rawValue is a string, make an array otherwise just reference the array
+ rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue;
+
+ var value = options.formatMatch(rawValue, i+1, options.data.length);
+ if ( value === false )
+ continue;
+
+ var firstChar = value.charAt(0).toLowerCase();
+ // if no lookup array for this character exists, look it up now
+ if( !stMatchSets[firstChar] )
+ stMatchSets[firstChar] = [];
+
+ // if the match is a string
+ var row = {
+ value: value,
+ data: rawValue,
+ result: options.formatResult && options.formatResult(rawValue) || value
+ };
+
+ // push the current match into the set list
+ stMatchSets[firstChar].push(row);
+
+ // keep track of minChars zero items
+ if ( nullData++ < options.max ) {
+ stMatchSets[""].push(row);
+ }
+ };
+
+ // add the data items to the cache
+ $.each(stMatchSets, function(i, value) {
+ // increase the cache size
+ options.cacheLength++;
+ // add to the cache
+ add(i, value);
+ });
+ }
+
+ // populate any existing data
+ setTimeout(populate, 25);
+
+ function flush(){
+ data = {};
+ length = 0;
+ }
+
+ return {
+ flush: flush,
+ add: add,
+ populate: populate,
+ load: function(q) {
+ if (!options.cacheLength || !length)
+ return null;
+ /*
+ * if dealing w/local data and matchContains than we must make sure
+ * to loop through all the data collections looking for matches
+ */
+ if( !options.url && options.matchContains ){
+ // track all matches
+ var csub = [];
+ // loop through all the data grids for matches
+ for( var k in data ){
+ // don't search through the stMatchSets[""] (minChars: 0) cache
+ // this prevents duplicates
+ if( k.length > 0 ){
+ var c = data[k];
+ $.each(c, function(i, x) {
+ // if we've got a match, add it to the array
+ if (matchSubset(x.value, q)) {
+ csub.push(x);
+ }
+ });
+ }
+ }
+ return csub;
+ } else
+ // if the exact item exists, use it
+ if (data[q]){
+ return data[q];
+ } else
+ if (options.matchSubset) {
+ for (var i = q.length - 1; i >= options.minChars; i--) {
+ var c = data[q.substr(0, i)];
+ if (c) {
+ var csub = [];
+ $.each(c, function(i, x) {
+ if (matchSubset(x.value, q)) {
+ csub[csub.length] = x;
+ }
+ });
+ return csub;
+ }
+ }
+ }
+ return null;
+ }
+ };
+};
+
+$.Autocompleter.Select = function (options, input, select, config) {
+ var CLASSES = {
+ ACTIVE: "ac_over"
+ };
+
+ var listItems,
+ active = -1,
+ data,
+ term = "",
+ needsInit = true,
+ element,
+ list;
+
+ // Create results
+ function init() {
+ if (!needsInit)
+ return;
+ element = $("<div/>")
+ .hide()
+ .addClass(options.resultsClass)
+ .css("position", "absolute")
+ .appendTo(document.body);
+
+ list = $("<ul/>").appendTo(element).mouseover( function(event) {
+ if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') {
+ active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event));
+ $(target(event)).addClass(CLASSES.ACTIVE);
+ }
+ }).click(function(event) {
+ $(target(event)).addClass(CLASSES.ACTIVE);
+ select();
+ // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus
+ input.focus();
+ return false;
+ }).mousedown(function() {
+ config.mouseDownOnSelect = true;
+ }).mouseup(function() {
+ config.mouseDownOnSelect = false;
+ });
+
+ if( options.width > 0 )
+ element.css("width", options.width);
+
+ needsInit = false;
+ }
+
+ function target(event) {
+ var element = event.target;
+ while(element && element.tagName != "LI")
+ element = element.parentNode;
+ // more fun with IE, sometimes event.target is empty, just ignore it then
+ if(!element)
+ return [];
+ return element;
+ }
+
+ function moveSelect(step) {
+ listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE);
+ movePosition(step);
+ var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE);
+ if(options.scroll) {
+ var offset = 0;
+ listItems.slice(0, active).each(function() {
+ offset += this.offsetHeight;
+ });
+ if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) {
+ list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight());
+ } else if(offset < list.scrollTop()) {
+ list.scrollTop(offset);
+ }
+ }
+ };
+
+ function movePosition(step) {
+ active += step;
+ if (active < 0) {
+ active = listItems.size() - 1;
+ } else if (active >= listItems.size()) {
+ active = 0;
+ }
+ }
+
+ function limitNumberOfItems(available) {
+ return options.max && options.max < available
+ ? options.max
+ : available;
+ }
+
+ function fillList() {
+ list.empty();
+ var max = limitNumberOfItems(data.length);
+ for (var i=0; i < max; i++) {
+ if (!data[i])
+ continue;
+ var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term);
+ if ( formatted === false )
+ continue;
+ var li = $("<li/>").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0];
+ $.data(li, "ac_data", data[i]);
+ }
+ listItems = list.find("li");
+ if ( options.selectFirst ) {
+ listItems.slice(0, 1).addClass(CLASSES.ACTIVE);
+ active = 0;
+ }
+ // apply bgiframe if available
+ if ( $.fn.bgiframe )
+ list.bgiframe();
+ }
+
+ return {
+ display: function(d, q) {
+ init();
+ data = d;
+ term = q;
+ fillList();
+ },
+ next: function() {
+ moveSelect(1);
+ },
+ prev: function() {
+ moveSelect(-1);
+ },
+ pageUp: function() {
+ if (active != 0 && active - 8 < 0) {
+ moveSelect( -active );
+ } else {
+ moveSelect(-8);
+ }
+ },
+ pageDown: function() {
+ if (active != listItems.size() - 1 && active + 8 > listItems.size()) {
+ moveSelect( listItems.size() - 1 - active );
+ } else {
+ moveSelect(8);
+ }
+ },
+ hide: function() {
+ element && element.hide();
+ listItems && listItems.removeClass(CLASSES.ACTIVE);
+ active = -1;
+ },
+ visible : function() {
+ return element && element.is(":visible");
+ },
+ current: function() {
+ return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]);
+ },
+ show: function() {
+ var offset = $(input).offset();
+ element.css({
+ width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(),
+ top: offset.top + input.offsetHeight,
+ left: offset.left
+ }).show();
+ if(options.scroll) {
+ list.scrollTop(0);
+ list.css({
+ maxHeight: options.scrollHeight,
+ overflow: 'auto'
+ });
+
+ if($.browser.msie && typeof document.body.style.maxHeight === "undefined") {
+ var listHeight = 0;
+ listItems.each(function() {
+ listHeight += this.offsetHeight;
+ });
+ var scrollbarsVisible = listHeight > options.scrollHeight;
+ list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight );
+ if (!scrollbarsVisible) {
+ // IE doesn't recalculate width when scrollbar disappears
+ listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) );
+ }
+ }
+
+ }
+ },
+ selected: function() {
+ var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);
+ return selected && selected.length && $.data(selected[0], "ac_data");
+ },
+ emptyList: function (){
+ list && list.empty();
+ },
+ unbind: function() {
+ element && element.remove();
+ }
+ };
+};
+
+$.Autocompleter.Selection = function(field, start, end) {
+ if( field.createTextRange ){
+ var selRange = field.createTextRange();
+ selRange.collapse(true);
+ selRange.moveStart("character", start);
+ selRange.moveEnd("character", end);
+ selRange.select();
+ } else if( field.setSelectionRange ){
+ field.setSelectionRange(start, end);
+ } else {
+ if( field.selectionStart ){
+ field.selectionStart = start;
+ field.selectionEnd = end;
+ }
+ }
+ field.focus();
+};
+
+})(jQuery); \ No newline at end of file
diff --git a/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.min.js b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.min.js
new file mode 100644
index 000000000..c9ddfb220
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.min.js
@@ -0,0 +1,15 @@
+/*
+ * Autocomplete - jQuery plugin 1.0.2
+ *
+ * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
+ *
+ */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){v=words.slice(0,words.length-1).join(options.multipleSeparator)+options.multipleSeparator+v;}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&&currentValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value){return[""];}var words=value.split(options.multipleSeparator);var result=[];$.each(words,function(i,value){if($.trim(value))result[i]=$.trim(value);});return result;}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$.Autocompleter.Selection(input,previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else
+$input.val("");}});}if(wasVisible)$.Autocompleter.Selection(input,input.value.length,input.value.length);};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
+if(data[q]){return data[q];}else
+if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.Autocompleter.Selection=function(field,start,end){if(field.createTextRange){var selRange=field.createTextRange();selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}else if(field.setSelectionRange){field.setSelectionRange(start,end);}else{if(field.selectionStart){field.selectionStart=start;field.selectionEnd=end;}}field.focus();};})(jQuery); \ No newline at end of file
diff --git a/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js
new file mode 100644
index 000000000..271014a2b
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js
@@ -0,0 +1,13 @@
+/*
+ * Autocomplete - jQuery plugin 1.0.2
+ *
+ * Copyright (c) 2007 Dylan Verheul, Dan G. Switzer, Anjesh Tuladhar, Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 5747 2008-06-25 18:30:55Z joern.zaefferer $
+ *
+ */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(3($){$.31.1o({12:3(b,d){5 c=Y b=="1w";d=$.1o({},$.D.1L,{11:c?b:14,w:c?14:b,1D:c?$.D.1L.1D:10,Z:d&&!d.1x?10:3U},d);d.1t=d.1t||3(a){6 a};d.1q=d.1q||d.1K;6 I.K(3(){1E $.D(I,d)})},M:3(a){6 I.X("M",a)},1y:3(a){6 I.15("1y",[a])},20:3(){6 I.15("20")},1Y:3(a){6 I.15("1Y",[a])},1X:3(){6 I.15("1X")}});$.D=3(o,r){5 t={2N:38,2I:40,2D:46,2x:9,2v:13,2q:27,2d:3x,2j:33,2o:34,2e:8};5 u=$(o).3f("12","3c").P(r.24);5 p;5 m="";5 n=$.D.2W(r);5 s=0;5 k;5 h={1z:B};5 l=$.D.2Q(r,o,1U,h);5 j;$.1T.2L&&$(o.2K).X("3S.12",3(){4(j){j=B;6 B}});u.X(($.1T.2L?"3Q":"3N")+".12",3(a){k=a.2F;3L(a.2F){Q t.2N:a.1d();4(l.L()){l.2y()}A{W(0,C)}N;Q t.2I:a.1d();4(l.L()){l.2u()}A{W(0,C)}N;Q t.2j:a.1d();4(l.L()){l.2t()}A{W(0,C)}N;Q t.2o:a.1d();4(l.L()){l.2s()}A{W(0,C)}N;Q r.19&&$.1p(r.R)==","&&t.2d:Q t.2x:Q t.2v:4(1U()){a.1d();j=C;6 B}N;Q t.2q:l.U();N;3A:1I(p);p=1H(W,r.1D);N}}).1G(3(){s++}).3v(3(){s=0;4(!h.1z){2k()}}).2i(3(){4(s++>1&&!l.L()){W(0,C)}}).X("1y",3(){5 c=(1n.7>1)?1n[1]:14;3 23(q,a){5 b;4(a&&a.7){16(5 i=0;i<a.7;i++){4(a[i].M.O()==q.O()){b=a[i];N}}}4(Y c=="3")c(b);A u.15("M",b&&[b.w,b.H])}$.K(1g(u.J()),3(i,a){1R(a,23,23)})}).X("20",3(){n.18()}).X("1Y",3(){$.1o(r,1n[1]);4("w"2G 1n[1])n.1f()}).X("1X",3(){l.1u();u.1u();$(o.2K).1u(".12")});3 1U(){5 b=l.26();4(!b)6 B;5 v=b.M;m=v;4(r.19){5 a=1g(u.J());4(a.7>1){v=a.17(0,a.7-1).2Z(r.R)+r.R+v}v+=r.R}u.J(v);1l();u.15("M",[b.w,b.H]);6 C}3 W(b,c){4(k==t.2D){l.U();6}5 a=u.J();4(!c&&a==m)6;m=a;a=1k(a);4(a.7>=r.22){u.P(r.21);4(!r.1C)a=a.O();1R(a,2V,1l)}A{1B();l.U()}};3 1g(b){4(!b){6[""]}5 d=b.1Z(r.R);5 c=[];$.K(d,3(i,a){4($.1p(a))c[i]=$.1p(a)});6 c}3 1k(a){4(!r.19)6 a;5 b=1g(a);6 b[b.7-1]}3 1A(q,a){4(r.1A&&(1k(u.J()).O()==q.O())&&k!=t.2e){u.J(u.J()+a.48(1k(m).7));$.D.1N(o,m.7,m.7+a.7)}};3 2k(){1I(p);p=1H(1l,47)};3 1l(){5 c=l.L();l.U();1I(p);1B();4(r.2U){u.1y(3(a){4(!a){4(r.19){5 b=1g(u.J()).17(0,-1);u.J(b.2Z(r.R)+(b.7?r.R:""))}A u.J("")}})}4(c)$.D.1N(o,o.H.7,o.H.7)};3 2V(q,a){4(a&&a.7&&s){1B();l.2T(a,q);1A(q,a[0].H);l.1W()}A{1l()}};3 1R(f,d,g){4(!r.1C)f=f.O();5 e=n.2S(f);4(e&&e.7){d(f,e)}A 4((Y r.11=="1w")&&(r.11.7>0)){5 c={45:+1E 44()};$.K(r.2R,3(a,b){c[a]=Y b=="3"?b():b});$.43({42:"41",3Z:"12"+o.3Y,2M:r.2M,11:r.11,w:$.1o({q:1k(f),3X:r.Z},c),3W:3(a){5 b=r.1r&&r.1r(a)||1r(a);n.1h(f,b);d(f,b)}})}A{l.2J();g(f)}};3 1r(c){5 d=[];5 b=c.1Z("\\n");16(5 i=0;i<b.7;i++){5 a=$.1p(b[i]);4(a){a=a.1Z("|");d[d.7]={w:a,H:a[0],M:r.1v&&r.1v(a,a[0])||a[0]}}}6 d};3 1B(){u.1e(r.21)}};$.D.1L={24:"3R",2H:"3P",21:"3O",22:1,1D:3M,1C:B,1a:C,1V:B,1j:10,Z:3K,2U:B,2R:{},1S:C,1K:3(a){6 a[0]},1q:14,1A:B,E:0,19:B,R:", ",1t:3(b,a){6 b.2C(1E 3J("(?![^&;]+;)(?!<[^<>]*)("+a.2C(/([\\^\\$\\(\\)\\[\\]\\{\\}\\*\\.\\+\\?\\|\\\\])/2A,"\\\\$1")+")(?![^<>]*>)(?![^&;]+;)","2A"),"<2z>$1</2z>")},1x:C,1s:3I};$.D.2W=3(g){5 h={};5 j=0;3 1a(s,a){4(!g.1C)s=s.O();5 i=s.3H(a);4(i==-1)6 B;6 i==0||g.1V};3 1h(q,a){4(j>g.1j){18()}4(!h[q]){j++}h[q]=a}3 1f(){4(!g.w)6 B;5 f={},2w=0;4(!g.11)g.1j=1;f[""]=[];16(5 i=0,30=g.w.7;i<30;i++){5 c=g.w[i];c=(Y c=="1w")?[c]:c;5 d=g.1q(c,i+1,g.w.7);4(d===B)1P;5 e=d.3G(0).O();4(!f[e])f[e]=[];5 b={H:d,w:c,M:g.1v&&g.1v(c)||d};f[e].1O(b);4(2w++<g.Z){f[""].1O(b)}};$.K(f,3(i,a){g.1j++;1h(i,a)})}1H(1f,25);3 18(){h={};j=0}6{18:18,1h:1h,1f:1f,2S:3(q){4(!g.1j||!j)6 14;4(!g.11&&g.1V){5 a=[];16(5 k 2G h){4(k.7>0){5 c=h[k];$.K(c,3(i,x){4(1a(x.H,q)){a.1O(x)}})}}6 a}A 4(h[q]){6 h[q]}A 4(g.1a){16(5 i=q.7-1;i>=g.22;i--){5 c=h[q.3F(0,i)];4(c){5 a=[];$.K(c,3(i,x){4(1a(x.H,q)){a[a.7]=x}});6 a}}}6 14}}};$.D.2Q=3(e,g,f,k){5 h={G:"3E"};5 j,y=-1,w,1m="",1M=C,F,z;3 2r(){4(!1M)6;F=$("<3D/>").U().P(e.2H).T("3C","3B").1J(2p.2n);z=$("<3z/>").1J(F).3y(3(a){4(V(a).2m&&V(a).2m.3w()==\'2l\'){y=$("1F",z).1e(h.G).3u(V(a));$(V(a)).P(h.G)}}).2i(3(a){$(V(a)).P(h.G);f();g.1G();6 B}).3t(3(){k.1z=C}).3s(3(){k.1z=B});4(e.E>0)F.T("E",e.E);1M=B}3 V(a){5 b=a.V;3r(b&&b.3q!="2l")b=b.3p;4(!b)6[];6 b}3 S(b){j.17(y,y+1).1e(h.G);2h(b);5 a=j.17(y,y+1).P(h.G);4(e.1x){5 c=0;j.17(0,y).K(3(){c+=I.1i});4((c+a[0].1i-z.1c())>z[0].3o){z.1c(c+a[0].1i-z.3n())}A 4(c<z.1c()){z.1c(c)}}};3 2h(a){y+=a;4(y<0){y=j.1b()-1}A 4(y>=j.1b()){y=0}}3 2g(a){6 e.Z&&e.Z<a?e.Z:a}3 2f(){z.2B();5 b=2g(w.7);16(5 i=0;i<b;i++){4(!w[i])1P;5 a=e.1K(w[i].w,i+1,b,w[i].H,1m);4(a===B)1P;5 c=$("<1F/>").3m(e.1t(a,1m)).P(i%2==0?"3l":"3k").1J(z)[0];$.w(c,"2c",w[i])}j=z.3j("1F");4(e.1S){j.17(0,1).P(h.G);y=0}4($.31.2b)z.2b()}6{2T:3(d,q){2r();w=d;1m=q;2f()},2u:3(){S(1)},2y:3(){S(-1)},2t:3(){4(y!=0&&y-8<0){S(-y)}A{S(-8)}},2s:3(){4(y!=j.1b()-1&&y+8>j.1b()){S(j.1b()-1-y)}A{S(8)}},U:3(){F&&F.U();j&&j.1e(h.G);y=-1},L:3(){6 F&&F.3i(":L")},3h:3(){6 I.L()&&(j.2a("."+h.G)[0]||e.1S&&j[0])},1W:3(){5 a=$(g).3g();F.T({E:Y e.E=="1w"||e.E>0?e.E:$(g).E(),2E:a.2E+g.1i,1Q:a.1Q}).1W();4(e.1x){z.1c(0);z.T({29:e.1s,3e:\'3d\'});4($.1T.3b&&Y 2p.2n.3T.29==="3a"){5 c=0;j.K(3(){c+=I.1i});5 b=c>e.1s;z.T(\'3V\',b?e.1s:c);4(!b){j.E(z.E()-28(j.T("32-1Q"))-28(j.T("32-39")))}}}},26:3(){5 a=j&&j.2a("."+h.G).1e(h.G);6 a&&a.7&&$.w(a[0],"2c")},2J:3(){z&&z.2B()},1u:3(){F&&F.37()}}};$.D.1N=3(b,a,c){4(b.2O){5 d=b.2O();d.36(C);d.35("2P",a);d.4c("2P",c);d.4b()}A 4(b.2Y){b.2Y(a,c)}A{4(b.2X){b.2X=a;b.4a=c}}b.1G()}})(49);',62,261,'|||function|if|var|return|length|||||||||||||||||||||||||data||active|list|else|false|true|Autocompleter|width|element|ACTIVE|value|this|val|each|visible|result|break|toLowerCase|addClass|case|multipleSeparator|moveSelect|css|hide|target|onChange|bind|typeof|max||url|autocomplete||null|trigger|for|slice|flush|multiple|matchSubset|size|scrollTop|preventDefault|removeClass|populate|trimWords|add|offsetHeight|cacheLength|lastWord|hideResultsNow|term|arguments|extend|trim|formatMatch|parse|scrollHeight|highlight|unbind|formatResult|string|scroll|search|mouseDownOnSelect|autoFill|stopLoading|matchCase|delay|new|li|focus|setTimeout|clearTimeout|appendTo|formatItem|defaults|needsInit|Selection|push|continue|left|request|selectFirst|browser|selectCurrent|matchContains|show|unautocomplete|setOptions|split|flushCache|loadingClass|minChars|findValueCallback|inputClass||selected||parseInt|maxHeight|filter|bgiframe|ac_data|COMMA|BACKSPACE|fillList|limitNumberOfItems|movePosition|click|PAGEUP|hideResults|LI|nodeName|body|PAGEDOWN|document|ESC|init|pageDown|pageUp|next|RETURN|nullData|TAB|prev|strong|gi|empty|replace|DEL|top|keyCode|in|resultsClass|DOWN|emptyList|form|opera|dataType|UP|createTextRange|character|Select|extraParams|load|display|mustMatch|receiveData|Cache|selectionStart|setSelectionRange|join|ol|fn|padding|||moveStart|collapse|remove||right|undefined|msie|off|auto|overflow|attr|offset|current|is|find|ac_odd|ac_even|html|innerHeight|clientHeight|parentNode|tagName|while|mouseup|mousedown|index|blur|toUpperCase|188|mouseover|ul|default|absolute|position|div|ac_over|substr|charAt|indexOf|180|RegExp|100|switch|400|keydown|ac_loading|ac_results|keypress|ac_input|submit|style|150|height|success|limit|name|port||abort|mode|ajax|Date|timestamp||200|substring|jQuery|selectionEnd|select|moveEnd'.split('|'),0,{})) \ No newline at end of file
diff --git a/plugins/Autocomplete/jquery-autocomplete/lib/jquery.ajaxQueue.js b/plugins/Autocomplete/jquery-autocomplete/lib/jquery.ajaxQueue.js
new file mode 100644
index 000000000..bdd2e4f82
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/lib/jquery.ajaxQueue.js
@@ -0,0 +1,116 @@
+/**
+ * Ajax Queue Plugin
+ *
+ * Homepage: http://jquery.com/plugins/project/ajaxqueue
+ * Documentation: http://docs.jquery.com/AjaxQueue
+ */
+
+/**
+
+<script>
+$(function(){
+ jQuery.ajaxQueue({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append(html); }
+ });
+ jQuery.ajaxQueue({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append(html); }
+ });
+ jQuery.ajaxSync({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
+ });
+ jQuery.ajaxSync({
+ url: "test.php",
+ success: function(html){ jQuery("ul").append("<b>"+html+"</b>"); }
+ });
+});
+</script>
+<ul style="position: absolute; top: 5px; right: 5px;"></ul>
+
+ */
+/*
+ * Queued Ajax requests.
+ * A new Ajax request won't be started until the previous queued
+ * request has finished.
+ */
+
+/*
+ * Synced Ajax requests.
+ * The Ajax request will happen as soon as you call this method, but
+ * the callbacks (success/error/complete) won't fire until all previous
+ * synced requests have been completed.
+ */
+
+
+(function($) {
+
+ var ajax = $.ajax;
+
+ var pendingRequests = {};
+
+ var synced = [];
+ var syncedData = [];
+
+ $.ajax = function(settings) {
+ // create settings for compatibility with ajaxSetup
+ settings = jQuery.extend(settings, jQuery.extend({}, jQuery.ajaxSettings, settings));
+
+ var port = settings.port;
+
+ switch(settings.mode) {
+ case "abort":
+ if ( pendingRequests[port] ) {
+ pendingRequests[port].abort();
+ }
+ return pendingRequests[port] = ajax.apply(this, arguments);
+ case "queue":
+ var _old = settings.complete;
+ settings.complete = function(){
+ if ( _old )
+ _old.apply( this, arguments );
+ jQuery([ajax]).dequeue("ajax" + port );;
+ };
+
+ jQuery([ ajax ]).queue("ajax" + port, function(){
+ ajax( settings );
+ });
+ return;
+ case "sync":
+ var pos = synced.length;
+
+ synced[ pos ] = {
+ error: settings.error,
+ success: settings.success,
+ complete: settings.complete,
+ done: false
+ };
+
+ syncedData[ pos ] = {
+ error: [],
+ success: [],
+ complete: []
+ };
+
+ settings.error = function(){ syncedData[ pos ].error = arguments; };
+ settings.success = function(){ syncedData[ pos ].success = arguments; };
+ settings.complete = function(){
+ syncedData[ pos ].complete = arguments;
+ synced[ pos ].done = true;
+
+ if ( pos == 0 || !synced[ pos-1 ] )
+ for ( var i = pos; i < synced.length && synced[i].done; i++ ) {
+ if ( synced[i].error ) synced[i].error.apply( jQuery, syncedData[i].error );
+ if ( synced[i].success ) synced[i].success.apply( jQuery, syncedData[i].success );
+ if ( synced[i].complete ) synced[i].complete.apply( jQuery, syncedData[i].complete );
+
+ synced[i] = null;
+ syncedData[i] = null;
+ }
+ };
+ }
+ return ajax.apply(this, arguments);
+ };
+
+})(jQuery); \ No newline at end of file
diff --git a/plugins/Autocomplete/jquery-autocomplete/lib/jquery.bgiframe.min.js b/plugins/Autocomplete/jquery-autocomplete/lib/jquery.bgiframe.min.js
new file mode 100644
index 000000000..7faef4b33
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/lib/jquery.bgiframe.min.js
@@ -0,0 +1,10 @@
+/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * $LastChangedDate: 2007-07-22 01:45:56 +0200 (Son, 22 Jul 2007) $
+ * $Rev: 2447 $
+ *
+ * Version 2.1.1
+ */
+(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&/6.0/.test(navigator.userAgent)){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};})(jQuery); \ No newline at end of file
diff --git a/plugins/Autocomplete/jquery-autocomplete/lib/jquery.js b/plugins/Autocomplete/jquery-autocomplete/lib/jquery.js
new file mode 100644
index 000000000..400531a2d
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/lib/jquery.js
@@ -0,0 +1,3558 @@
+(function(){
+/*
+ * jQuery 1.2.6 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-05-27 21:17:26 +0200 (Di, 27 Mai 2008) $
+ * $Rev: 5700 $
+ */
+
+// Map over jQuery in case of overwrite
+var _jQuery = window.jQuery,
+// Map over the $ in case of overwrite
+ _$ = window.$;
+
+var jQuery = window.jQuery = window.$ = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context );
+};
+
+// A simple way to check for HTML strings or ID strings
+// (both of which we optimize for)
+var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,
+
+// Is it a simple selector
+ isSimple = /^.[^:#\[\.]*$/,
+
+// Will speed up references to undefined, and allows munging its name.
+ undefined;
+
+jQuery.fn = jQuery.prototype = {
+ init: function( selector, context ) {
+ // Make sure that a selection was provided
+ selector = selector || document;
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+ // Handle HTML strings
+ if ( typeof selector == "string" ) {
+ // Are we dealing with HTML string or an ID?
+ var match = quickExpr.exec( selector );
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] )
+ selector = jQuery.clean( [ match[1] ], context );
+
+ // HANDLE: $("#id")
+ else {
+ var elem = document.getElementById( match[3] );
+
+ // Make sure an element was located
+ if ( elem ){
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id != match[3] )
+ return jQuery().find( selector );
+
+ // Otherwise, we inject the element directly into the jQuery object
+ return jQuery( elem );
+ }
+ selector = [];
+ }
+
+ // HANDLE: $(expr, [context])
+ // (which is just equivalent to: $(content).find(expr)
+ } else
+ return jQuery( context ).find( selector );
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) )
+ return jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector );
+
+ return this.setArray(jQuery.makeArray(selector));
+ },
+
+ // The current version of jQuery being used
+ jquery: "1.2.6",
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ // The number of elements contained in the matched element set
+ length: 0,
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == undefined ?
+
+ // Return a 'clean' array
+ jQuery.makeArray( this ) :
+
+ // Return just the object
+ this[ num ];
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+ // Build a new jQuery matched element set
+ var ret = jQuery( elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Force the current matched set of elements to become
+ // the specified array of elements (destroying the stack in the process)
+ // You should use pushStack() in order to do this, but maintain the stack
+ setArray: function( elems ) {
+ // Resetting the length to 0, then using the native Array push
+ // is a super-fast way to populate an object with array-like properties
+ this.length = 0;
+ Array.prototype.push.apply( this, elems );
+
+ return this;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+ var ret = -1;
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem && elem.jquery ? elem[0] : elem
+ , this );
+ },
+
+ attr: function( name, value, type ) {
+ var options = name;
+
+ // Look for the case where we're accessing a style value
+ if ( name.constructor == String )
+ if ( value === undefined )
+ return this[0] && jQuery[ type || "attr" ]( this[0], name );
+
+ else {
+ options = {};
+ options[ name ] = value;
+ }
+
+ // Check to see if we're setting style values
+ return this.each(function(i){
+ // Set all the styles
+ for ( name in options )
+ jQuery.attr(
+ type ?
+ this.style :
+ this,
+ name, jQuery.prop( this, options[ name ], type, i, name )
+ );
+ });
+ },
+
+ css: function( key, value ) {
+ // ignore negative width and height values
+ if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 )
+ value = undefined;
+ return this.attr( key, value, "curCSS" );
+ },
+
+ text: function( text ) {
+ if ( typeof text != "object" && text != null )
+ return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );
+
+ var ret = "";
+
+ jQuery.each( text || this, function(){
+ jQuery.each( this.childNodes, function(){
+ if ( this.nodeType != 8 )
+ ret += this.nodeType != 1 ?
+ this.nodeValue :
+ jQuery.fn.text( [ this ] );
+ });
+ });
+
+ return ret;
+ },
+
+ wrapAll: function( html ) {
+ if ( this[0] )
+ // The elements to wrap the target around
+ jQuery( html, this[0].ownerDocument )
+ .clone()
+ .insertBefore( this[0] )
+ .map(function(){
+ var elem = this;
+
+ while ( elem.firstChild )
+ elem = elem.firstChild;
+
+ return elem;
+ })
+ .append(this);
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ return this.each(function(){
+ jQuery( this ).contents().wrapAll( html );
+ });
+ },
+
+ wrap: function( html ) {
+ return this.each(function(){
+ jQuery( this ).wrapAll( html );
+ });
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, false, function(elem){
+ if (this.nodeType == 1)
+ this.appendChild( elem );
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, true, function(elem){
+ if (this.nodeType == 1)
+ this.insertBefore( elem, this.firstChild );
+ });
+ },
+
+ before: function() {
+ return this.domManip(arguments, false, false, function(elem){
+ this.parentNode.insertBefore( elem, this );
+ });
+ },
+
+ after: function() {
+ return this.domManip(arguments, false, true, function(elem){
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ },
+
+ end: function() {
+ return this.prevObject || jQuery( [] );
+ },
+
+ find: function( selector ) {
+ var elems = jQuery.map(this, function(elem){
+ return jQuery.find( selector, elem );
+ });
+
+ return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ?
+ jQuery.unique( elems ) :
+ elems );
+ },
+
+ clone: function( events ) {
+ // Do the clone
+ var ret = this.map(function(){
+ if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) {
+ // IE copies events bound via attachEvent when
+ // using cloneNode. Calling detachEvent on the
+ // clone will also remove the events from the orignal
+ // In order to get around this, we use innerHTML.
+ // Unfortunately, this means some modifications to
+ // attributes in IE that are actually only stored
+ // as properties will not be copied (such as the
+ // the name attribute on an input).
+ var clone = this.cloneNode(true),
+ container = document.createElement("div");
+ container.appendChild(clone);
+ return jQuery.clean([container.innerHTML])[0];
+ } else
+ return this.cloneNode(true);
+ });
+
+ // Need to set the expando to null on the cloned set if it exists
+ // removeData doesn't work here, IE removes it from the original as well
+ // this is primarily for IE but the data expando shouldn't be copied over in any browser
+ var clone = ret.find("*").andSelf().each(function(){
+ if ( this[ expando ] != undefined )
+ this[ expando ] = null;
+ });
+
+ // Copy the events from the original to the clone
+ if ( events === true )
+ this.find("*").andSelf().each(function(i){
+ if (this.nodeType == 3)
+ return;
+ var events = jQuery.data( this, "events" );
+
+ for ( var type in events )
+ for ( var handler in events[ type ] )
+ jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data );
+ });
+
+ // Return the cloned set
+ return ret;
+ },
+
+ filter: function( selector ) {
+ return this.pushStack(
+ jQuery.isFunction( selector ) &&
+ jQuery.grep(this, function(elem, i){
+ return selector.call( elem, i );
+ }) ||
+
+ jQuery.multiFilter( selector, this ) );
+ },
+
+ not: function( selector ) {
+ if ( selector.constructor == String )
+ // test special case where just one selector is passed in
+ if ( isSimple.test( selector ) )
+ return this.pushStack( jQuery.multiFilter( selector, this, true ) );
+ else
+ selector = jQuery.multiFilter( selector, this );
+
+ var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType;
+ return this.filter(function() {
+ return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector;
+ });
+ },
+
+ add: function( selector ) {
+ return this.pushStack( jQuery.unique( jQuery.merge(
+ this.get(),
+ typeof selector == 'string' ?
+ jQuery( selector ) :
+ jQuery.makeArray( selector )
+ )));
+ },
+
+ is: function( selector ) {
+ return !!selector && jQuery.multiFilter( selector, this ).length > 0;
+ },
+
+ hasClass: function( selector ) {
+ return this.is( "." + selector );
+ },
+
+ val: function( value ) {
+ if ( value == undefined ) {
+
+ if ( this.length ) {
+ var elem = this[0];
+
+ // We need to handle select boxes special
+ if ( jQuery.nodeName( elem, "select" ) ) {
+ var index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type == "select-one";
+
+ // Nothing was selected
+ if ( index < 0 )
+ return null;
+
+ // Loop through all the selected options
+ for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
+ var option = options[ i ];
+
+ if ( option.selected ) {
+ // Get the specifc value for the option
+ value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value;
+
+ // We don't need an array for one selects
+ if ( one )
+ return value;
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+
+ // Everything else, we just grab the value
+ } else
+ return (this[0].value || "").replace(/\r/g, "");
+
+ }
+
+ return undefined;
+ }
+
+ if( value.constructor == Number )
+ value += '';
+
+ return this.each(function(){
+ if ( this.nodeType != 1 )
+ return;
+
+ if ( value.constructor == Array && /radio|checkbox/.test( this.type ) )
+ this.checked = (jQuery.inArray(this.value, value) >= 0 ||
+ jQuery.inArray(this.name, value) >= 0);
+
+ else if ( jQuery.nodeName( this, "select" ) ) {
+ var values = jQuery.makeArray(value);
+
+ jQuery( "option", this ).each(function(){
+ this.selected = (jQuery.inArray( this.value, values ) >= 0 ||
+ jQuery.inArray( this.text, values ) >= 0);
+ });
+
+ if ( !values.length )
+ this.selectedIndex = -1;
+
+ } else
+ this.value = value;
+ });
+ },
+
+ html: function( value ) {
+ return value == undefined ?
+ (this[0] ?
+ this[0].innerHTML :
+ null) :
+ this.empty().append( value );
+ },
+
+ replaceWith: function( value ) {
+ return this.after( value ).remove();
+ },
+
+ eq: function( i ) {
+ return this.slice( i, i + 1 );
+ },
+
+ slice: function() {
+ return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function(elem, i){
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ },
+
+ data: function( key, value ){
+ var parts = key.split(".");
+ parts[1] = parts[1] ? "." + parts[1] : "";
+
+ if ( value === undefined ) {
+ var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
+
+ if ( data === undefined && this.length )
+ data = jQuery.data( this[0], key );
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ } else
+ return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){
+ jQuery.data( this, key, value );
+ });
+ },
+
+ removeData: function( key ){
+ return this.each(function(){
+ jQuery.removeData( this, key );
+ });
+ },
+
+ domManip: function( args, table, reverse, callback ) {
+ var clone = this.length > 1, elems;
+
+ return this.each(function(){
+ if ( !elems ) {
+ elems = jQuery.clean( args, this.ownerDocument );
+
+ if ( reverse )
+ elems.reverse();
+ }
+
+ var obj = this;
+
+ if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) )
+ obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") );
+
+ var scripts = jQuery( [] );
+
+ jQuery.each(elems, function(){
+ var elem = clone ?
+ jQuery( this ).clone( true )[0] :
+ this;
+
+ // execute all scripts after the elements have been injected
+ if ( jQuery.nodeName( elem, "script" ) )
+ scripts = scripts.add( elem );
+ else {
+ // Remove any inner scripts for later evaluation
+ if ( elem.nodeType == 1 )
+ scripts = scripts.add( jQuery( "script", elem ).remove() );
+
+ // Inject the elements into the document
+ callback.call( obj, elem );
+ }
+ });
+
+ scripts.each( evalScript );
+ });
+ }
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+function evalScript( i, elem ) {
+ if ( elem.src )
+ jQuery.ajax({
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+
+ else
+ jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
+
+ if ( elem.parentNode )
+ elem.parentNode.removeChild( elem );
+}
+
+function now(){
+ return +new Date;
+}
+
+jQuery.extend = jQuery.fn.extend = function() {
+ // copy reference to target object
+ var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+ // Handle a deep copy situation
+ if ( target.constructor == Boolean ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target != "object" && typeof target != "function" )
+ target = {};
+
+ // extend jQuery itself if only one argument is passed
+ if ( length == i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ )
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null )
+ // Extend the base object
+ for ( var name in options ) {
+ var src = target[ name ], copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy )
+ continue;
+
+ // Recurse if we're merging object values
+ if ( deep && copy && typeof copy == "object" && !copy.nodeType )
+ target[ name ] = jQuery.extend( deep,
+ // Never move original objects, clone them
+ src || ( copy.length != null ? [ ] : { } )
+ , copy );
+
+ // Don't bring in undefined values
+ else if ( copy !== undefined )
+ target[ name ] = copy;
+
+ }
+
+ // Return the modified object
+ return target;
+};
+
+var expando = "jQuery" + now(), uuid = 0, windowData = {},
+ // exclude the following css properties to add px
+ exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i,
+ // cache defaultView
+ defaultView = document.defaultView || {};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ window.$ = _$;
+
+ if ( deep )
+ window.jQuery = _jQuery;
+
+ return jQuery;
+ },
+
+ // See test/unit/core.js for details concerning this function.
+ isFunction: function( fn ) {
+ return !!fn && typeof fn != "string" && !fn.nodeName &&
+ fn.constructor != Array && /^[\s[]?function/.test( fn + "" );
+ },
+
+ // check if an element is in a (or is an) XML document
+ isXMLDoc: function( elem ) {
+ return elem.documentElement && !elem.body ||
+ elem.tagName && elem.ownerDocument && !elem.ownerDocument.body;
+ },
+
+ // Evalulates a script in a global context
+ globalEval: function( data ) {
+ data = jQuery.trim( data );
+
+ if ( data ) {
+ // Inspired by code by Andrea Giammarchi
+ // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
+ var head = document.getElementsByTagName("head")[0] || document.documentElement,
+ script = document.createElement("script");
+
+ script.type = "text/javascript";
+ if ( jQuery.browser.msie )
+ script.text = data;
+ else
+ script.appendChild( document.createTextNode( data ) );
+
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709).
+ head.insertBefore( script, head.firstChild );
+ head.removeChild( script );
+ }
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase();
+ },
+
+ cache: {},
+
+ data: function( elem, name, data ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // Compute a unique ID for the element
+ if ( !id )
+ id = elem[ expando ] = ++uuid;
+
+ // Only generate the data cache if we're
+ // trying to access or manipulate it
+ if ( name && !jQuery.cache[ id ] )
+ jQuery.cache[ id ] = {};
+
+ // Prevent overriding the named cache with undefined values
+ if ( data !== undefined )
+ jQuery.cache[ id ][ name ] = data;
+
+ // Return the named cache data, or the ID for the element
+ return name ?
+ jQuery.cache[ id ][ name ] :
+ id;
+ },
+
+ removeData: function( elem, name ) {
+ elem = elem == window ?
+ windowData :
+ elem;
+
+ var id = elem[ expando ];
+
+ // If we want to remove a specific section of the element's data
+ if ( name ) {
+ if ( jQuery.cache[ id ] ) {
+ // Remove the section of cache data
+ delete jQuery.cache[ id ][ name ];
+
+ // If we've removed all the data, remove the element's cache
+ name = "";
+
+ for ( name in jQuery.cache[ id ] )
+ break;
+
+ if ( !name )
+ jQuery.removeData( elem );
+ }
+
+ // Otherwise, we want to remove all of the element's data
+ } else {
+ // Clean up the element expando
+ try {
+ delete elem[ expando ];
+ } catch(e){
+ // IE has trouble directly removing the expando
+ // but it's ok with using removeAttribute
+ if ( elem.removeAttribute )
+ elem.removeAttribute( expando );
+ }
+
+ // Completely remove the data cache
+ delete jQuery.cache[ id ];
+ }
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ var name, i = 0, length = object.length;
+
+ if ( args ) {
+ if ( length == undefined ) {
+ for ( name in object )
+ if ( callback.apply( object[ name ], args ) === false )
+ break;
+ } else
+ for ( ; i < length; )
+ if ( callback.apply( object[ i++ ], args ) === false )
+ break;
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( length == undefined ) {
+ for ( name in object )
+ if ( callback.call( object[ name ], name, object[ name ] ) === false )
+ break;
+ } else
+ for ( var value = object[0];
+ i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
+ }
+
+ return object;
+ },
+
+ prop: function( elem, value, type, i, name ) {
+ // Handle executable functions
+ if ( jQuery.isFunction( value ) )
+ value = value.call( elem, i );
+
+ // Handle passing in a number to a CSS property
+ return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ?
+ value + "px" :
+ value;
+ },
+
+ className: {
+ // internal only, use addClass("class")
+ add: function( elem, classNames ) {
+ jQuery.each((classNames || "").split(/\s+/), function(i, className){
+ if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) )
+ elem.className += (elem.className ? " " : "") + className;
+ });
+ },
+
+ // internal only, use removeClass("class")
+ remove: function( elem, classNames ) {
+ if (elem.nodeType == 1)
+ elem.className = classNames != undefined ?
+ jQuery.grep(elem.className.split(/\s+/), function(className){
+ return !jQuery.className.has( classNames, className );
+ }).join(" ") :
+ "";
+ },
+
+ // internal only, use hasClass("class")
+ has: function( elem, className ) {
+ return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1;
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {};
+ // Remember the old values, and insert the new ones
+ for ( var name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ callback.call( elem );
+
+ // Revert the old values
+ for ( var name in options )
+ elem.style[ name ] = old[ name ];
+ },
+
+ css: function( elem, name, force ) {
+ if ( name == "width" || name == "height" ) {
+ var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ];
+
+ function getWH() {
+ val = name == "width" ? elem.offsetWidth : elem.offsetHeight;
+ var padding = 0, border = 0;
+ jQuery.each( which, function() {
+ padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0;
+ border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0;
+ });
+ val -= Math.round(padding + border);
+ }
+
+ if ( jQuery(elem).is(":visible") )
+ getWH();
+ else
+ jQuery.swap( elem, props, getWH );
+
+ return Math.max(0, val);
+ }
+
+ return jQuery.curCSS( elem, name, force );
+ },
+
+ curCSS: function( elem, name, force ) {
+ var ret, style = elem.style;
+
+ // A helper method for determining if an element's values are broken
+ function color( elem ) {
+ if ( !jQuery.browser.safari )
+ return false;
+
+ // defaultView is cached
+ var ret = defaultView.getComputedStyle( elem, null );
+ return !ret || ret.getPropertyValue("color") == "";
+ }
+
+ // We need to handle opacity special in IE
+ if ( name == "opacity" && jQuery.browser.msie ) {
+ ret = jQuery.attr( style, "opacity" );
+
+ return ret == "" ?
+ "1" :
+ ret;
+ }
+ // Opera sometimes will give the wrong display answer, this fixes it, see #2037
+ if ( jQuery.browser.opera && name == "display" ) {
+ var save = style.outline;
+ style.outline = "0 solid black";
+ style.outline = save;
+ }
+
+ // Make sure we're using the right name for getting the float value
+ if ( name.match( /float/i ) )
+ name = styleFloat;
+
+ if ( !force && style && style[ name ] )
+ ret = style[ name ];
+
+ else if ( defaultView.getComputedStyle ) {
+
+ // Only "float" is needed here
+ if ( name.match( /float/i ) )
+ name = "float";
+
+ name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase();
+
+ var computedStyle = defaultView.getComputedStyle( elem, null );
+
+ if ( computedStyle && !color( elem ) )
+ ret = computedStyle.getPropertyValue( name );
+
+ // If the element isn't reporting its values properly in Safari
+ // then some display: none elements are involved
+ else {
+ var swap = [], stack = [], a = elem, i = 0;
+
+ // Locate all of the parent display: none elements
+ for ( ; a && color(a); a = a.parentNode )
+ stack.unshift(a);
+
+ // Go through and make them visible, but in reverse
+ // (It would be better if we knew the exact display type that they had)
+ for ( ; i < stack.length; i++ )
+ if ( color( stack[ i ] ) ) {
+ swap[ i ] = stack[ i ].style.display;
+ stack[ i ].style.display = "block";
+ }
+
+ // Since we flip the display style, we have to handle that
+ // one special, otherwise get the value
+ ret = name == "display" && swap[ stack.length - 1 ] != null ?
+ "none" :
+ ( computedStyle && computedStyle.getPropertyValue( name ) ) || "";
+
+ // Finally, revert the display styles back
+ for ( i = 0; i < swap.length; i++ )
+ if ( swap[ i ] != null )
+ stack[ i ].style.display = swap[ i ];
+ }
+
+ // We should always get a number back from opacity
+ if ( name == "opacity" && ret == "" )
+ ret = "1";
+
+ } else if ( elem.currentStyle ) {
+ var camelCase = name.replace(/\-(\w)/g, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ];
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) {
+ // Remember the original values
+ var left = style.left, rsLeft = elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ style.left = ret || 0;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret;
+ },
+
+ clean: function( elems, context ) {
+ var ret = [];
+ context = context || document;
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if (typeof context.createElement == 'undefined')
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+
+ jQuery.each(elems, function(i, elem){
+ if ( !elem )
+ return;
+
+ if ( elem.constructor == Number )
+ elem += '';
+
+ // Convert html string into DOM nodes
+ if ( typeof elem == "string" ) {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
+ return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
+ all :
+ front + "></" + tag + ">";
+ });
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div");
+
+ var wrap =
+ // option or optgroup
+ !tags.indexOf("<opt") &&
+ [ 1, "<select multiple='multiple'>", "</select>" ] ||
+
+ !tags.indexOf("<leg") &&
+ [ 1, "<fieldset>", "</fieldset>" ] ||
+
+ tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
+ [ 1, "<table>", "</table>" ] ||
+
+ !tags.indexOf("<tr") &&
+ [ 2, "<table><tbody>", "</tbody></table>" ] ||
+
+ // <thead> matched above
+ (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
+ [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||
+
+ !tags.indexOf("<col") &&
+ [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||
+
+ // IE can't serialize <link> and <script> tags normally
+ jQuery.browser.msie &&
+ [ 1, "div<div>", "</div>" ] ||
+
+ [ 0, "", "" ];
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( wrap[0]-- )
+ div = div.lastChild;
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( jQuery.browser.msie ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
+ div.childNodes :
+ [];
+
+ for ( var j = tbody.length - 1; j >= 0 ; --j )
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( /^\s/.test( elem ) )
+ div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
+
+ }
+
+ elem = jQuery.makeArray( div.childNodes );
+ }
+
+ if ( elem.length === 0 && (!jQuery.nodeName( elem, "form" ) && !jQuery.nodeName( elem, "select" )) )
+ return;
+
+ if ( elem[0] == undefined || jQuery.nodeName( elem, "form" ) || elem.options )
+ ret.push( elem );
+
+ else
+ ret = jQuery.merge( ret, elem );
+
+ });
+
+ return ret;
+ },
+
+ attr: function( elem, name, value ) {
+ // don't set attributes on text and comment nodes
+ if (!elem || elem.nodeType == 3 || elem.nodeType == 8)
+ return undefined;
+
+ var notxml = !jQuery.isXMLDoc( elem ),
+ // Whether we are setting (or getting)
+ set = value !== undefined,
+ msie = jQuery.browser.msie;
+
+ // Try to normalize/fix the name
+ name = notxml && jQuery.props[ name ] || name;
+
+ // Only do all the following if this is a node (faster for style)
+ // IE elem.getAttribute passes even for style
+ if ( elem.tagName ) {
+
+ // These attributes require special treatment
+ var special = /href|src|style/.test( name );
+
+ // Safari mis-reports the default selected property of a hidden option
+ // Accessing the parent's selectedIndex property fixes it
+ if ( name == "selected" && jQuery.browser.safari )
+ elem.parentNode.selectedIndex;
+
+ // If applicable, access the attribute via the DOM 0 way
+ if ( name in elem && notxml && !special ) {
+ if ( set ){
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( name == "type" && jQuery.nodeName( elem, "input" ) && elem.parentNode )
+ throw "type property can't be changed";
+
+ elem[ name ] = value;
+ }
+
+ // browsers index elements by id/name on forms, give priority to attributes.
+ if( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) )
+ return elem.getAttributeNode( name ).nodeValue;
+
+ return elem[ name ];
+ }
+
+ if ( msie && notxml && name == "style" )
+ return jQuery.attr( elem.style, "cssText", value );
+
+ if ( set )
+ // convert the value to a string (all browsers do this but IE) see #1070
+ elem.setAttribute( name, "" + value );
+
+ var attr = msie && notxml && special
+ // Some attributes require a special call on IE
+ ? elem.getAttribute( name, 2 )
+ : elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return attr === null ? undefined : attr;
+ }
+
+ // elem is actually elem.style ... set the style
+
+ // IE uses filters for opacity
+ if ( msie && name == "opacity" ) {
+ if ( set ) {
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ elem.zoom = 1;
+
+ // Set the alpha filter to set the opacity
+ elem.filter = (elem.filter || "").replace( /alpha\([^)]*\)/, "" ) +
+ (parseInt( value ) + '' == "NaN" ? "" : "alpha(opacity=" + value * 100 + ")");
+ }
+
+ return elem.filter && elem.filter.indexOf("opacity=") >= 0 ?
+ (parseFloat( elem.filter.match(/opacity=([^)]*)/)[1] ) / 100) + '':
+ "";
+ }
+
+ name = name.replace(/-([a-z])/ig, function(all, letter){
+ return letter.toUpperCase();
+ });
+
+ if ( set )
+ elem[ name ] = value;
+
+ return elem[ name ];
+ },
+
+ trim: function( text ) {
+ return (text || "").replace( /^\s+|\s+$/g, "" );
+ },
+
+ makeArray: function( array ) {
+ var ret = [];
+
+ if( array != null ){
+ var i = array.length;
+ //the window, strings and functions also have 'length'
+ if( i == null || array.split || array.setInterval || array.call )
+ ret[0] = array;
+ else
+ while( i )
+ ret[--i] = array[i];
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, array ) {
+ for ( var i = 0, length = array.length; i < length; i++ )
+ // Use === because on IE, window == document
+ if ( array[ i ] === elem )
+ return i;
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ // We have to loop this way because IE & Opera overwrite the length
+ // expando of getElementsByTagName
+ var i = 0, elem, pos = first.length;
+ // Also, we need to make sure that the correct elements are being returned
+ // (IE returns comment nodes in a '*' query)
+ if ( jQuery.browser.msie ) {
+ while ( elem = second[ i++ ] )
+ if ( elem.nodeType != 8 )
+ first[ pos++ ] = elem;
+
+ } else
+ while ( elem = second[ i++ ] )
+ first[ pos++ ] = elem;
+
+ return first;
+ },
+
+ unique: function( array ) {
+ var ret = [], done = {};
+
+ try {
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ var id = jQuery.data( array[ i ] );
+
+ if ( !done[ id ] ) {
+ done[ id ] = true;
+ ret.push( array[ i ] );
+ }
+ }
+
+ } catch( e ) {
+ ret = array;
+ }
+
+ return ret;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [];
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ )
+ if ( !inv != !callback( elems[ i ], i ) )
+ ret.push( elems[ i ] );
+
+ return ret;
+ },
+
+ map: function( elems, callback ) {
+ var ret = [];
+
+ // Go through the array, translating each of the items to their
+ // new value (or values).
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ var value = callback( elems[ i ], i );
+
+ if ( value != null )
+ ret[ ret.length ] = value;
+ }
+
+ return ret.concat.apply( [], ret );
+ }
+});
+
+var userAgent = navigator.userAgent.toLowerCase();
+
+// Figure out what browser is being used
+jQuery.browser = {
+ version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
+ safari: /webkit/.test( userAgent ),
+ opera: /opera/.test( userAgent ),
+ msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
+ mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
+};
+
+var styleFloat = jQuery.browser.msie ?
+ "styleFloat" :
+ "cssFloat";
+
+jQuery.extend({
+ // Check to see if the W3C box model is being used
+ boxModel: !jQuery.browser.msie || document.compatMode == "CSS1Compat",
+
+ props: {
+ "for": "htmlFor",
+ "class": "className",
+ "float": styleFloat,
+ cssFloat: styleFloat,
+ styleFloat: styleFloat,
+ readonly: "readOnly",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ rowspan: "rowSpan"
+ }
+});
+
+jQuery.each({
+ parent: function(elem){return elem.parentNode;},
+ parents: function(elem){return jQuery.dir(elem,"parentNode");},
+ next: function(elem){return jQuery.nth(elem,2,"nextSibling");},
+ prev: function(elem){return jQuery.nth(elem,2,"previousSibling");},
+ nextAll: function(elem){return jQuery.dir(elem,"nextSibling");},
+ prevAll: function(elem){return jQuery.dir(elem,"previousSibling");},
+ siblings: function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem);},
+ children: function(elem){return jQuery.sibling(elem.firstChild);},
+ contents: function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes);}
+}, function(name, fn){
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = jQuery.map( this, fn );
+
+ if ( selector && typeof selector == "string" )
+ ret = jQuery.multiFilter( selector, ret );
+
+ return this.pushStack( jQuery.unique( ret ) );
+ };
+});
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function(name, original){
+ jQuery.fn[ name ] = function() {
+ var args = arguments;
+
+ return this.each(function(){
+ for ( var i = 0, length = args.length; i < length; i++ )
+ jQuery( args[ i ] )[ original ]( this );
+ });
+ };
+});
+
+jQuery.each({
+ removeAttr: function( name ) {
+ jQuery.attr( this, name, "" );
+ if (this.nodeType == 1)
+ this.removeAttribute( name );
+ },
+
+ addClass: function( classNames ) {
+ jQuery.className.add( this, classNames );
+ },
+
+ removeClass: function( classNames ) {
+ jQuery.className.remove( this, classNames );
+ },
+
+ toggleClass: function( classNames ) {
+ jQuery.className[ jQuery.className.has( this, classNames ) ? "remove" : "add" ]( this, classNames );
+ },
+
+ remove: function( selector ) {
+ if ( !selector || jQuery.filter( selector, [ this ] ).r.length ) {
+ // Prevent memory leaks
+ jQuery( "*", this ).add(this).each(function(){
+ jQuery.event.remove(this);
+ jQuery.removeData(this);
+ });
+ if (this.parentNode)
+ this.parentNode.removeChild( this );
+ }
+ },
+
+ empty: function() {
+ // Remove element nodes and prevent memory leaks
+ jQuery( ">*", this ).remove();
+
+ // Remove any remaining nodes
+ while ( this.firstChild )
+ this.removeChild( this.firstChild );
+ }
+}, function(name, fn){
+ jQuery.fn[ name ] = function(){
+ return this.each( fn, arguments );
+ };
+});
+
+jQuery.each([ "Height", "Width" ], function(i, name){
+ var type = name.toLowerCase();
+
+ jQuery.fn[ type ] = function( size ) {
+ // Get window width or height
+ return this[0] == window ?
+ // Opera reports document.body.client[Width/Height] properly in both quirks and standards
+ jQuery.browser.opera && document.body[ "client" + name ] ||
+
+ // Safari reports inner[Width/Height] just fine (Mozilla and Opera include scroll bar widths)
+ jQuery.browser.safari && window[ "inner" + name ] ||
+
+ // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode
+ document.compatMode == "CSS1Compat" && document.documentElement[ "client" + name ] || document.body[ "client" + name ] :
+
+ // Get document width or height
+ this[0] == document ?
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ Math.max(
+ Math.max(document.body["scroll" + name], document.documentElement["scroll" + name]),
+ Math.max(document.body["offset" + name], document.documentElement["offset" + name])
+ ) :
+
+ // Get or set width or height on the element
+ size == undefined ?
+ // Get width or height on the element
+ (this.length ? jQuery.css( this[0], type ) : null) :
+
+ // Set the width or height on the element (default to pixels if value is unitless)
+ this.css( type, size.constructor == String ? size : size + "px" );
+ };
+});
+
+// Helper function used by the dimensions and offset modules
+function num(elem, prop) {
+ return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
+}var chars = jQuery.browser.safari && parseInt(jQuery.browser.version) < 417 ?
+ "(?:[\\w*_-]|\\\\.)" :
+ "(?:[\\w\u0128-\uFFFF*_-]|\\\\.)",
+ quickChild = new RegExp("^>\\s*(" + chars + "+)"),
+ quickID = new RegExp("^(" + chars + "+)(#)(" + chars + "+)"),
+ quickClass = new RegExp("^([#.]?)(" + chars + "*)");
+
+jQuery.extend({
+ expr: {
+ "": function(a,i,m){return m[2]=="*"||jQuery.nodeName(a,m[2]);},
+ "#": function(a,i,m){return a.getAttribute("id")==m[2];},
+ ":": {
+ // Position Checks
+ lt: function(a,i,m){return i<m[3]-0;},
+ gt: function(a,i,m){return i>m[3]-0;},
+ nth: function(a,i,m){return m[3]-0==i;},
+ eq: function(a,i,m){return m[3]-0==i;},
+ first: function(a,i){return i==0;},
+ last: function(a,i,m,r){return i==r.length-1;},
+ even: function(a,i){return i%2==0;},
+ odd: function(a,i){return i%2;},
+
+ // Child Checks
+ "first-child": function(a){return a.parentNode.getElementsByTagName("*")[0]==a;},
+ "last-child": function(a){return jQuery.nth(a.parentNode.lastChild,1,"previousSibling")==a;},
+ "only-child": function(a){return !jQuery.nth(a.parentNode.lastChild,2,"previousSibling");},
+
+ // Parent Checks
+ parent: function(a){return a.firstChild;},
+ empty: function(a){return !a.firstChild;},
+
+ // Text Check
+ contains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").indexOf(m[3])>=0;},
+
+ // Visibility
+ visible: function(a){return "hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden";},
+ hidden: function(a){return "hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden";},
+
+ // Form attributes
+ enabled: function(a){return !a.disabled;},
+ disabled: function(a){return a.disabled;},
+ checked: function(a){return a.checked;},
+ selected: function(a){return a.selected||jQuery.attr(a,"selected");},
+
+ // Form elements
+ text: function(a){return "text"==a.type;},
+ radio: function(a){return "radio"==a.type;},
+ checkbox: function(a){return "checkbox"==a.type;},
+ file: function(a){return "file"==a.type;},
+ password: function(a){return "password"==a.type;},
+ submit: function(a){return "submit"==a.type;},
+ image: function(a){return "image"==a.type;},
+ reset: function(a){return "reset"==a.type;},
+ button: function(a){return "button"==a.type||jQuery.nodeName(a,"button");},
+ input: function(a){return /input|select|textarea|button/i.test(a.nodeName);},
+
+ // :has()
+ has: function(a,i,m){return jQuery.find(m[3],a).length;},
+
+ // :header
+ header: function(a){return /h\d/i.test(a.nodeName);},
+
+ // :animated
+ animated: function(a){return jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length;}
+ }
+ },
+
+ // The regular expressions that power the parsing engine
+ parse: [
+ // Match: [@value='test'], [@foo]
+ /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
+
+ // Match: :contains('foo')
+ /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
+
+ // Match: :even, :last-child, #id, .class
+ new RegExp("^([:.#]*)(" + chars + "+)")
+ ],
+
+ multiFilter: function( expr, elems, not ) {
+ var old, cur = [];
+
+ while ( expr && expr != old ) {
+ old = expr;
+ var f = jQuery.filter( expr, elems, not );
+ expr = f.t.replace(/^\s*,\s*/, "" );
+ cur = not ? elems = f.r : jQuery.merge( cur, f.r );
+ }
+
+ return cur;
+ },
+
+ find: function( t, context ) {
+ // Quickly handle non-string expressions
+ if ( typeof t != "string" )
+ return [ t ];
+
+ // check to make sure context is a DOM element or a document
+ if ( context && context.nodeType != 1 && context.nodeType != 9)
+ return [ ];
+
+ // Set the correct context (if none is provided)
+ context = context || document;
+
+ // Initialize the search
+ var ret = [context], done = [], last, nodeName;
+
+ // Continue while a selector expression exists, and while
+ // we're no longer looping upon ourselves
+ while ( t && last != t ) {
+ var r = [];
+ last = t;
+
+ t = jQuery.trim(t);
+
+ var foundToken = false,
+
+ // An attempt at speeding up child selectors that
+ // point to a specific element tag
+ re = quickChild,
+
+ m = re.exec(t);
+
+ if ( m ) {
+ nodeName = m[1].toUpperCase();
+
+ // Perform our own iteration and filter
+ for ( var i = 0; ret[i]; i++ )
+ for ( var c = ret[i].firstChild; c; c = c.nextSibling )
+ if ( c.nodeType == 1 && (nodeName == "*" || c.nodeName.toUpperCase() == nodeName) )
+ r.push( c );
+
+ ret = r;
+ t = t.replace( re, "" );
+ if ( t.indexOf(" ") == 0 ) continue;
+ foundToken = true;
+ } else {
+ re = /^([>+~])\s*(\w*)/i;
+
+ if ( (m = re.exec(t)) != null ) {
+ r = [];
+
+ var merge = {};
+ nodeName = m[2].toUpperCase();
+ m = m[1];
+
+ for ( var j = 0, rl = ret.length; j < rl; j++ ) {
+ var n = m == "~" || m == "+" ? ret[j].nextSibling : ret[j].firstChild;
+ for ( ; n; n = n.nextSibling )
+ if ( n.nodeType == 1 ) {
+ var id = jQuery.data(n);
+
+ if ( m == "~" && merge[id] ) break;
+
+ if (!nodeName || n.nodeName.toUpperCase() == nodeName ) {
+ if ( m == "~" ) merge[id] = true;
+ r.push( n );
+ }
+
+ if ( m == "+" ) break;
+ }
+ }
+
+ ret = r;
+
+ // And remove the token
+ t = jQuery.trim( t.replace( re, "" ) );
+ foundToken = true;
+ }
+ }
+
+ // See if there's still an expression, and that we haven't already
+ // matched a token
+ if ( t && !foundToken ) {
+ // Handle multiple expressions
+ if ( !t.indexOf(",") ) {
+ // Clean the result set
+ if ( context == ret[0] ) ret.shift();
+
+ // Merge the result sets
+ done = jQuery.merge( done, ret );
+
+ // Reset the context
+ r = ret = [context];
+
+ // Touch up the selector string
+ t = " " + t.substr(1,t.length);
+
+ } else {
+ // Optimize for the case nodeName#idName
+ var re2 = quickID;
+ var m = re2.exec(t);
+
+ // Re-organize the results, so that they're consistent
+ if ( m ) {
+ m = [ 0, m[2], m[3], m[1] ];
+
+ } else {
+ // Otherwise, do a traditional filter check for
+ // ID, class, and element selectors
+ re2 = quickClass;
+ m = re2.exec(t);
+ }
+
+ m[2] = m[2].replace(/\\/g, "");
+
+ var elem = ret[ret.length-1];
+
+ // Try to do a global search by ID, where we can
+ if ( m[1] == "#" && elem && elem.getElementById && !jQuery.isXMLDoc(elem) ) {
+ // Optimization for HTML document case
+ var oid = elem.getElementById(m[2]);
+
+ // Do a quick check for the existence of the actual ID attribute
+ // to avoid selecting by the name attribute in IE
+ // also check to insure id is a string to avoid selecting an element with the name of 'id' inside a form
+ if ( (jQuery.browser.msie||jQuery.browser.opera) && oid && typeof oid.id == "string" && oid.id != m[2] )
+ oid = jQuery('[@id="'+m[2]+'"]', elem)[0];
+
+ // Do a quick check for node name (where applicable) so
+ // that div#foo searches will be really fast
+ ret = r = oid && (!m[3] || jQuery.nodeName(oid, m[3])) ? [oid] : [];
+ } else {
+ // We need to find all descendant elements
+ for ( var i = 0; ret[i]; i++ ) {
+ // Grab the tag name being searched for
+ var tag = m[1] == "#" && m[3] ? m[3] : m[1] != "" || m[0] == "" ? "*" : m[2];
+
+ // Handle IE7 being really dumb about <object>s
+ if ( tag == "*" && ret[i].nodeName.toLowerCase() == "object" )
+ tag = "param";
+
+ r = jQuery.merge( r, ret[i].getElementsByTagName( tag ));
+ }
+
+ // It's faster to filter by class and be done with it
+ if ( m[1] == "." )
+ r = jQuery.classFilter( r, m[2] );
+
+ // Same with ID filtering
+ if ( m[1] == "#" ) {
+ var tmp = [];
+
+ // Try to find the element with the ID
+ for ( var i = 0; r[i]; i++ )
+ if ( r[i].getAttribute("id") == m[2] ) {
+ tmp = [ r[i] ];
+ break;
+ }
+
+ r = tmp;
+ }
+
+ ret = r;
+ }
+
+ t = t.replace( re2, "" );
+ }
+
+ }
+
+ // If a selector string still exists
+ if ( t ) {
+ // Attempt to filter it
+ var val = jQuery.filter(t,r);
+ ret = r = val.r;
+ t = jQuery.trim(val.t);
+ }
+ }
+
+ // An error occurred with the selector;
+ // just return an empty set instead
+ if ( t )
+ ret = [];
+
+ // Remove the root context
+ if ( ret && context == ret[0] )
+ ret.shift();
+
+ // And combine the results
+ done = jQuery.merge( done, ret );
+
+ return done;
+ },
+
+ classFilter: function(r,m,not){
+ m = " " + m + " ";
+ var tmp = [];
+ for ( var i = 0; r[i]; i++ ) {
+ var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
+ if ( !not && pass || not && !pass )
+ tmp.push( r[i] );
+ }
+ return tmp;
+ },
+
+ filter: function(t,r,not) {
+ var last;
+
+ // Look for common filter expressions
+ while ( t && t != last ) {
+ last = t;
+
+ var p = jQuery.parse, m;
+
+ for ( var i = 0; p[i]; i++ ) {
+ m = p[i].exec( t );
+
+ if ( m ) {
+ // Remove what we just matched
+ t = t.substring( m[0].length );
+
+ m[2] = m[2].replace(/\\/g, "");
+ break;
+ }
+ }
+
+ if ( !m )
+ break;
+
+ // :not() is a special case that can be optimized by
+ // keeping it out of the expression list
+ if ( m[1] == ":" && m[2] == "not" )
+ // optimize if only one selector found (most common case)
+ r = isSimple.test( m[3] ) ?
+ jQuery.filter(m[3], r, true).r :
+ jQuery( r ).not( m[3] );
+
+ // We can get a big speed boost by filtering by class here
+ else if ( m[1] == "." )
+ r = jQuery.classFilter(r, m[2], not);
+
+ else if ( m[1] == "[" ) {
+ var tmp = [], type = m[3];
+
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
+
+ if ( z == null || /href|src|selected/.test(m[2]) )
+ z = jQuery.attr(a,m[2]) || '';
+
+ if ( (type == "" && !!z ||
+ type == "=" && z == m[5] ||
+ type == "!=" && z != m[5] ||
+ type == "^=" && z && !z.indexOf(m[5]) ||
+ type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
+ (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
+ tmp.push( a );
+ }
+
+ r = tmp;
+
+ // We can get a speed boost by handling nth-child here
+ } else if ( m[1] == ":" && m[2] == "nth-child" ) {
+ var merge = {}, tmp = [],
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
+ m[3] == "even" && "2n" || m[3] == "odd" && "2n+1" ||
+ !/\D/.test(m[3]) && "0n+" + m[3] || m[3]),
+ // calculate the numbers (first)n+(last) including if they are negative
+ first = (test[1] + (test[2] || 1)) - 0, last = test[3] - 0;
+
+ // loop through all the elements left in the jQuery object
+ for ( var i = 0, rl = r.length; i < rl; i++ ) {
+ var node = r[i], parentNode = node.parentNode, id = jQuery.data(parentNode);
+
+ if ( !merge[id] ) {
+ var c = 1;
+
+ for ( var n = parentNode.firstChild; n; n = n.nextSibling )
+ if ( n.nodeType == 1 )
+ n.nodeIndex = c++;
+
+ merge[id] = true;
+ }
+
+ var add = false;
+
+ if ( first == 0 ) {
+ if ( node.nodeIndex == last )
+ add = true;
+ } else if ( (node.nodeIndex - last) % first == 0 && (node.nodeIndex - last) / first >= 0 )
+ add = true;
+
+ if ( add ^ not )
+ tmp.push( node );
+ }
+
+ r = tmp;
+
+ // Otherwise, find the expression to execute
+ } else {
+ var fn = jQuery.expr[ m[1] ];
+ if ( typeof fn == "object" )
+ fn = fn[ m[2] ];
+
+ if ( typeof fn == "string" )
+ fn = eval("false||function(a,i){return " + fn + ";}");
+
+ // Execute it against the current filter
+ r = jQuery.grep( r, function(elem, i){
+ return fn(elem, i, m, r);
+ }, not );
+ }
+ }
+
+ // Return an array of filtered elements (r)
+ // and the modified expression string (t)
+ return { r: r, t: t };
+ },
+
+ dir: function( elem, dir ){
+ var matched = [],
+ cur = elem[dir];
+ while ( cur && cur != document ) {
+ if ( cur.nodeType == 1 )
+ matched.push( cur );
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function(cur,result,dir,elem){
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] )
+ if ( cur.nodeType == 1 && ++num == result )
+ break;
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType == 1 && n != elem )
+ r.push( n );
+ }
+
+ return r;
+ }
+});
+/*
+ * A number of helper functions used for managing events.
+ * Many of the ideas behind this code orignated from
+ * Dean Edwards' addEvent library.
+ */
+jQuery.event = {
+
+ // Bind an event to an element
+ // Original by Dean Edwards
+ add: function(elem, types, handler, data) {
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ // For whatever reason, IE has trouble passing the window object
+ // around, causing it to be cloned in the process
+ if ( jQuery.browser.msie && elem.setInterval )
+ elem = window;
+
+ // Make sure that the function being executed has a unique ID
+ if ( !handler.guid )
+ handler.guid = this.guid++;
+
+ // if data is passed, bind to handler
+ if( data != undefined ) {
+ // Create temporary function pointer to original handler
+ var fn = handler;
+
+ // Create unique handler function, wrapped around original handler
+ handler = this.proxy( fn, function() {
+ // Pass arguments and context to original handler
+ return fn.apply(this, arguments);
+ });
+
+ // Store data in unique handler
+ handler.data = data;
+ }
+
+ // Init the element's event structure
+ var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
+ handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
+ // Handle the second event of a trigger and when
+ // an event is called after a page has unloaded
+ if ( typeof jQuery != "undefined" && !jQuery.event.triggered )
+ return jQuery.event.handle.apply(arguments.callee.elem, arguments);
+ });
+ // Add elem as a property of the handle function
+ // This is to prevent a memory leak with non-native
+ // event in IE.
+ handle.elem = elem;
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type) {
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+ handler.type = parts[1];
+
+ // Get the current list of functions bound to this event
+ var handlers = events[type];
+
+ // Init the event handler queue
+ if (!handlers) {
+ handlers = events[type] = {};
+
+ // Check for a special event handler
+ // Only use addEventListener/attachEvent if the special
+ // events handler returns false
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
+ // Bind the global event handler to the element
+ if (elem.addEventListener)
+ elem.addEventListener(type, handle, false);
+ else if (elem.attachEvent)
+ elem.attachEvent("on" + type, handle);
+ }
+ }
+
+ // Add the function to the element's handler list
+ handlers[handler.guid] = handler;
+
+ // Keep track of which events have been used, for global triggering
+ jQuery.event.global[type] = true;
+ });
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ guid: 1,
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function(elem, types, handler) {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return;
+
+ var events = jQuery.data(elem, "events"), ret, index;
+
+ if ( events ) {
+ // Unbind all events for the element
+ if ( types == undefined || (typeof types == "string" && types.charAt(0) == ".") )
+ for ( var type in events )
+ this.remove( elem, type + (types || "") );
+ else {
+ // types is actually an event object here
+ if ( types.type ) {
+ handler = types.handler;
+ types = types.type;
+ }
+
+ // Handle multiple events seperated by a space
+ // jQuery(...).unbind("mouseover mouseout", fn);
+ jQuery.each(types.split(/\s+/), function(index, type){
+ // Namespaced event handlers
+ var parts = type.split(".");
+ type = parts[0];
+
+ if ( events[type] ) {
+ // remove the given handler for the given type
+ if ( handler )
+ delete events[type][handler.guid];
+
+ // remove all handlers for the given type
+ else
+ for ( handler in events[type] )
+ // Handle the removal of namespaced events
+ if ( !parts[1] || events[type][handler].type == parts[1] )
+ delete events[type][handler];
+
+ // remove generic event handler if no more handlers exist
+ for ( ret in events[type] ) break;
+ if ( !ret ) {
+ if ( !jQuery.event.special[type] || jQuery.event.special[type].teardown.call(elem) === false ) {
+ if (elem.removeEventListener)
+ elem.removeEventListener(type, jQuery.data(elem, "handle"), false);
+ else if (elem.detachEvent)
+ elem.detachEvent("on" + type, jQuery.data(elem, "handle"));
+ }
+ ret = null;
+ delete events[type];
+ }
+ }
+ });
+ }
+
+ // Remove the expando if it's no longer used
+ for ( ret in events ) break;
+ if ( !ret ) {
+ var handle = jQuery.data( elem, "handle" );
+ if ( handle ) handle.elem = null;
+ jQuery.removeData( elem, "events" );
+ jQuery.removeData( elem, "handle" );
+ }
+ }
+ },
+
+ trigger: function(type, data, elem, donative, extra) {
+ // Clone the incoming data, if any
+ data = jQuery.makeArray(data);
+
+ if ( type.indexOf("!") >= 0 ) {
+ type = type.slice(0, -1);
+ var exclusive = true;
+ }
+
+ // Handle a global trigger
+ if ( !elem ) {
+ // Only trigger if we've ever bound an event for it
+ if ( this.global[type] )
+ jQuery("*").add([window, document]).trigger(type, data);
+
+ // Handle triggering a single element
+ } else {
+ // don't do events on text and comment nodes
+ if ( elem.nodeType == 3 || elem.nodeType == 8 )
+ return undefined;
+
+ var val, ret, fn = jQuery.isFunction( elem[ type ] || null ),
+ // Check to see if we need to provide a fake event, or not
+ event = !data[0] || !data[0].preventDefault;
+
+ // Pass along a fake event
+ if ( event ) {
+ data.unshift({
+ type: type,
+ target: elem,
+ preventDefault: function(){},
+ stopPropagation: function(){},
+ timeStamp: now()
+ });
+ data[0][expando] = true; // no need to fix fake event
+ }
+
+ // Enforce the right trigger type
+ data[0].type = type;
+ if ( exclusive )
+ data[0].exclusive = true;
+
+ // Trigger the event, it is assumed that "handle" is a function
+ var handle = jQuery.data(elem, "handle");
+ if ( handle )
+ val = handle.apply( elem, data );
+
+ // Handle triggering native .onfoo handlers (and on links since we don't call .click() for links)
+ if ( (!fn || (jQuery.nodeName(elem, 'a') && type == "click")) && elem["on"+type] && elem["on"+type].apply( elem, data ) === false )
+ val = false;
+
+ // Extra functions don't get the custom event object
+ if ( event )
+ data.shift();
+
+ // Handle triggering of extra function
+ if ( extra && jQuery.isFunction( extra ) ) {
+ // call the extra function and tack the current return value on the end for possible inspection
+ ret = extra.apply( elem, val == null ? data : data.concat( val ) );
+ // if anything is returned, give it precedence and have it overwrite the previous value
+ if (ret !== undefined)
+ val = ret;
+ }
+
+ // Trigger the native events (except for clicks on links)
+ if ( fn && donative !== false && val !== false && !(jQuery.nodeName(elem, 'a') && type == "click") ) {
+ this.triggered = true;
+ try {
+ elem[ type ]();
+ // prevent IE from throwing an error for some hidden elements
+ } catch (e) {}
+ }
+
+ this.triggered = false;
+ }
+
+ return val;
+ },
+
+ handle: function(event) {
+ // returned undefined or false
+ var val, ret, namespace, all, handlers;
+
+ event = arguments[0] = jQuery.event.fix( event || window.event );
+
+ // Namespaced event handlers
+ namespace = event.type.split(".");
+ event.type = namespace[0];
+ namespace = namespace[1];
+ // Cache this now, all = true means, any handler
+ all = !namespace && !event.exclusive;
+
+ handlers = ( jQuery.data(this, "events") || {} )[event.type];
+
+ for ( var j in handlers ) {
+ var handler = handlers[j];
+
+ // Filter the functions by class
+ if ( all || handler.type == namespace ) {
+ // Pass in a reference to the handler function itself
+ // So that we can later remove it
+ event.handler = handler;
+ event.data = handler.data;
+
+ ret = handler.apply( this, arguments );
+
+ if ( val !== false )
+ val = ret;
+
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+
+ return val;
+ },
+
+ props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" "),
+
+ fix: function(event) {
+ if ( event[expando] == true )
+ return event;
+
+ // store a copy of the original event object
+ // and "clone" to set read-only properties
+ var originalEvent = event;
+ event = { originalEvent: originalEvent };
+
+ for ( var i = this.props.length, prop; i; ){
+ prop = this.props[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Mark it as fixed
+ event[expando] = true;
+
+ // add preventDefault and stopPropagation since
+ // they will not work on the clone
+ event.preventDefault = function() {
+ // if preventDefault exists run it on the original event
+ if (originalEvent.preventDefault)
+ originalEvent.preventDefault();
+ // otherwise set the returnValue property of the original event to false (IE)
+ originalEvent.returnValue = false;
+ };
+ event.stopPropagation = function() {
+ // if stopPropagation exists run it on the original event
+ if (originalEvent.stopPropagation)
+ originalEvent.stopPropagation();
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ originalEvent.cancelBubble = true;
+ };
+
+ // Fix timeStamp
+ event.timeStamp = event.timeStamp || now();
+
+ // Fix target property, if necessary
+ if ( !event.target )
+ event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
+
+ // check if target is a textnode (safari)
+ if ( event.target.nodeType == 3 )
+ event.target = event.target.parentNode;
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && event.fromElement )
+ event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && event.clientX != null ) {
+ var doc = document.documentElement, body = document.body;
+ event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
+ event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
+ }
+
+ // Add which for key events
+ if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
+ event.which = event.charCode || event.keyCode;
+
+ // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
+ if ( !event.metaKey && event.ctrlKey )
+ event.metaKey = event.ctrlKey;
+
+ // Add which for click: 1 == left; 2 == middle; 3 == right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && event.button )
+ event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
+
+ return event;
+ },
+
+ proxy: function( fn, proxy ){
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || proxy.guid || this.guid++;
+ // So proxy can be declared as an argument
+ return proxy;
+ },
+
+ special: {
+ ready: {
+ setup: function() {
+ // Make sure the ready event is setup
+ bindReady();
+ return;
+ },
+
+ teardown: function() { return; }
+ },
+
+ mouseenter: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseover", jQuery.event.special.mouseenter.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseenter
+ event.type = "mouseenter";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ },
+
+ mouseleave: {
+ setup: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).bind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ teardown: function() {
+ if ( jQuery.browser.msie ) return false;
+ jQuery(this).unbind("mouseout", jQuery.event.special.mouseleave.handler);
+ return true;
+ },
+
+ handler: function(event) {
+ // If we actually just moused on to a sub-element, ignore it
+ if ( withinElement(event, this) ) return true;
+ // Execute the right handlers by setting the event type to mouseleave
+ event.type = "mouseleave";
+ return jQuery.event.handle.apply(this, arguments);
+ }
+ }
+ }
+};
+
+jQuery.fn.extend({
+ bind: function( type, data, fn ) {
+ return type == "unload" ? this.one(type, data, fn) : this.each(function(){
+ jQuery.event.add( this, type, fn || data, fn && data );
+ });
+ },
+
+ one: function( type, data, fn ) {
+ var one = jQuery.event.proxy( fn || data, function(event) {
+ jQuery(this).unbind(event, one);
+ return (fn || data).apply( this, arguments );
+ });
+ return this.each(function(){
+ jQuery.event.add( this, type, one, fn && data);
+ });
+ },
+
+ unbind: function( type, fn ) {
+ return this.each(function(){
+ jQuery.event.remove( this, type, fn );
+ });
+ },
+
+ trigger: function( type, data, fn ) {
+ return this.each(function(){
+ jQuery.event.trigger( type, data, this, true, fn );
+ });
+ },
+
+ triggerHandler: function( type, data, fn ) {
+ return this[0] && jQuery.event.trigger( type, data, this[0], false, fn );
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments, i = 1;
+
+ // link all the functions, so any of them can unbind this click handler
+ while( i < args.length )
+ jQuery.event.proxy( fn, args[i++] );
+
+ return this.click( jQuery.event.proxy( fn, function(event) {
+ // Figure out which function to execute
+ this.lastToggle = ( this.lastToggle || 0 ) % i;
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ this.lastToggle++ ].apply( this, arguments ) || false;
+ }));
+ },
+
+ hover: function(fnOver, fnOut) {
+ return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
+ },
+
+ ready: function(fn) {
+ // Attach the listeners
+ bindReady();
+
+ // If the DOM is already ready
+ if ( jQuery.isReady )
+ // Execute the function immediately
+ fn.call( document, jQuery );
+
+ // Otherwise, remember the function for later
+ else
+ // Add the function to the wait list
+ jQuery.readyList.push( function() { return fn.call(this, jQuery); } );
+
+ return this;
+ }
+});
+
+jQuery.extend({
+ isReady: false,
+ readyList: [],
+ // Handle when the DOM is ready
+ ready: function() {
+ // Make sure that the DOM is not already loaded
+ if ( !jQuery.isReady ) {
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If there are functions bound, to execute
+ if ( jQuery.readyList ) {
+ // Execute all of them
+ jQuery.each( jQuery.readyList, function(){
+ this.call( document );
+ });
+
+ // Reset the list of functions
+ jQuery.readyList = null;
+ }
+
+ // Trigger any bound ready events
+ jQuery(document).triggerHandler("ready");
+ }
+ }
+});
+
+var readyBound = false;
+
+function bindReady(){
+ if ( readyBound ) return;
+ readyBound = true;
+
+ // Mozilla, Opera (see further below for it) and webkit nightlies currently support this event
+ if ( document.addEventListener && !jQuery.browser.opera)
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", jQuery.ready, false );
+
+ // If IE is used and is not in a frame
+ // Continually check to see if the document is ready
+ if ( jQuery.browser.msie && window == top ) (function(){
+ if (jQuery.isReady) return;
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch( error ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+
+ if ( jQuery.browser.opera )
+ document.addEventListener( "DOMContentLoaded", function () {
+ if (jQuery.isReady) return;
+ for (var i = 0; i < document.styleSheets.length; i++)
+ if (document.styleSheets[i].disabled) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ }, false);
+
+ if ( jQuery.browser.safari ) {
+ var numStyles;
+ (function(){
+ if (jQuery.isReady) return;
+ if ( document.readyState != "loaded" && document.readyState != "complete" ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ if ( numStyles === undefined )
+ numStyles = jQuery("style, link[rel=stylesheet]").length;
+ if ( document.styleSheets.length != numStyles ) {
+ setTimeout( arguments.callee, 0 );
+ return;
+ }
+ // and execute any waiting functions
+ jQuery.ready();
+ })();
+ }
+
+ // A fallback to window.onload, that will always work
+ jQuery.event.add( window, "load", jQuery.ready );
+}
+
+jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," +
+ "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," +
+ "submit,keydown,keypress,keyup,error").split(","), function(i, name){
+
+ // Handle event binding
+ jQuery.fn[name] = function(fn){
+ return fn ? this.bind(name, fn) : this.trigger(name);
+ };
+});
+
+// Checks if an event happened on an element within another element
+// Used in jQuery.event.special.mouseenter and mouseleave handlers
+var withinElement = function(event, elem) {
+ // Check if mouse(over|out) are still within the same parent element
+ var parent = event.relatedTarget;
+ // Traverse up the tree
+ while ( parent && parent != elem ) try { parent = parent.parentNode; } catch(error) { parent = elem; }
+ // Return true if we actually just moused on to a sub-element
+ return parent == elem;
+};
+
+// Prevent memory leaks in IE
+// And prevent errors on refresh with events like mouseover in other browsers
+// Window isn't included so as not to unbind existing unload events
+jQuery(window).bind("unload", function() {
+ jQuery("*").add(document).unbind();
+});
+jQuery.fn.extend({
+ // Keep a copy of the old load
+ _load: jQuery.fn.load,
+
+ load: function( url, params, callback ) {
+ if ( typeof url != 'string' )
+ return this._load( url );
+
+ var off = url.indexOf(" ");
+ if ( off >= 0 ) {
+ var selector = url.slice(off, url.length);
+ url = url.slice(0, off);
+ }
+
+ callback = callback || function(){};
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params )
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = null;
+
+ // Otherwise, build a param string
+ } else if( typeof params == 'object' ) {
+ params = jQuery.param( params );
+ type = "POST";
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ complete: function(res, status){
+ // If successful, inject the HTML into all the matched elements
+ if ( status == "success" || status == "notmodified" )
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div/>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(res.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ res.responseText );
+
+ self.each( callback, [res.responseText, status, res] );
+ }
+ });
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param(this.serializeArray());
+ },
+ serializeArray: function() {
+ return this.map(function(){
+ return jQuery.nodeName(this, "form") ?
+ jQuery.makeArray(this.elements) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ (this.checked || /select|textarea/i.test(this.nodeName) ||
+ /text|hidden|password/i.test(this.type));
+ })
+ .map(function(i, elem){
+ var val = jQuery(this).val();
+ return val == null ? null :
+ val.constructor == Array ?
+ jQuery.map( val, function(val, i){
+ return {name: elem.name, value: val};
+ }) :
+ {name: elem.name, value: val};
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","), function(i,o){
+ jQuery.fn[o] = function(f){
+ return this.bind(o, f);
+ };
+});
+
+var jsc = now();
+
+jQuery.extend({
+ get: function( url, data, callback, type ) {
+ // shift arguments if data argument was ommited
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = null;
+ }
+
+ return jQuery.ajax({
+ type: "GET",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get(url, null, callback, "script");
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get(url, data, callback, "json");
+ },
+
+ post: function( url, data, callback, type ) {
+ if ( jQuery.isFunction( data ) ) {
+ callback = data;
+ data = {};
+ }
+
+ return jQuery.ajax({
+ type: "POST",
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ },
+
+ ajaxSetup: function( settings ) {
+ jQuery.extend( jQuery.ajaxSettings, settings );
+ },
+
+ ajaxSettings: {
+ url: location.href,
+ global: true,
+ type: "GET",
+ timeout: 0,
+ contentType: "application/x-www-form-urlencoded",
+ processData: true,
+ async: true,
+ data: null,
+ username: null,
+ password: null,
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ script: "text/javascript, application/javascript",
+ json: "application/json, text/javascript",
+ text: "text/plain",
+ _default: "*/*"
+ }
+ },
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+
+ ajax: function( s ) {
+ // Extend the settings, but re-extend 's' so that it can be
+ // checked again later (in the test suite, specifically)
+ s = jQuery.extend(true, s, jQuery.extend(true, {}, jQuery.ajaxSettings, s));
+
+ var jsonp, jsre = /=\?(&|$)/g, status, data,
+ type = s.type.toUpperCase();
+
+ // convert data if not already a string
+ if ( s.data && s.processData && typeof s.data != "string" )
+ s.data = jQuery.param(s.data);
+
+ // Handle JSONP Parameter Callbacks
+ if ( s.dataType == "jsonp" ) {
+ if ( type == "GET" ) {
+ if ( !s.url.match(jsre) )
+ s.url += (s.url.match(/\?/) ? "&" : "?") + (s.jsonp || "callback") + "=?";
+ } else if ( !s.data || !s.data.match(jsre) )
+ s.data = (s.data ? s.data + "&" : "") + (s.jsonp || "callback") + "=?";
+ s.dataType = "json";
+ }
+
+ // Build temporary JSONP function
+ if ( s.dataType == "json" && (s.data && s.data.match(jsre) || s.url.match(jsre)) ) {
+ jsonp = "jsonp" + jsc++;
+
+ // Replace the =? sequence both in the query string and the data
+ if ( s.data )
+ s.data = (s.data + "").replace(jsre, "=" + jsonp + "$1");
+ s.url = s.url.replace(jsre, "=" + jsonp + "$1");
+
+ // We need to make sure
+ // that a JSONP style response is executed properly
+ s.dataType = "script";
+
+ // Handle JSONP-style loading
+ window[ jsonp ] = function(tmp){
+ data = tmp;
+ success();
+ complete();
+ // Garbage collect
+ window[ jsonp ] = undefined;
+ try{ delete window[ jsonp ]; } catch(e){}
+ if ( head )
+ head.removeChild( script );
+ };
+ }
+
+ if ( s.dataType == "script" && s.cache == null )
+ s.cache = false;
+
+ if ( s.cache === false && type == "GET" ) {
+ var ts = now();
+ // try replacing _= if it is there
+ var ret = s.url.replace(/(\?|&)_=.*?(&|$)/, "$1_=" + ts + "$2");
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ((ret == s.url) ? (s.url.match(/\?/) ? "&" : "?") + "_=" + ts : "");
+ }
+
+ // If data is available, append data to url for get requests
+ if ( s.data && type == "GET" ) {
+ s.url += (s.url.match(/\?/) ? "&" : "?") + s.data;
+
+ // IE likes to send both get and post data, prevent this
+ s.data = null;
+ }
+
+ // Watch for a new set of requests
+ if ( s.global && ! jQuery.active++ )
+ jQuery.event.trigger( "ajaxStart" );
+
+ // Matches an absolute URL, and saves the domain
+ var remote = /^(?:\w+:)?\/\/([^\/?#]+)/;
+
+ // If we're requesting a remote document
+ // and trying to load JSON or Script with a GET
+ if ( s.dataType == "script" && type == "GET"
+ && remote.test(s.url) && remote.exec(s.url)[1] != location.host ){
+ var head = document.getElementsByTagName("head")[0];
+ var script = document.createElement("script");
+ script.src = s.url;
+ if (s.scriptCharset)
+ script.charset = s.scriptCharset;
+
+ // Handle Script loading
+ if ( !jsonp ) {
+ var done = false;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function(){
+ if ( !done && (!this.readyState ||
+ this.readyState == "loaded" || this.readyState == "complete") ) {
+ done = true;
+ success();
+ complete();
+ head.removeChild( script );
+ }
+ };
+ }
+
+ head.appendChild(script);
+
+ // We handle everything using the script element injection
+ return undefined;
+ }
+
+ var requestDone = false;
+
+ // Create the request object; Microsoft failed to properly
+ // implement the XMLHttpRequest in IE7, so we use the ActiveXObject when it is available
+ var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if( s.username )
+ xhr.open(type, s.url, s.async, s.username, s.password);
+ else
+ xhr.open(type, s.url, s.async);
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ // Set the correct header, if data is being sent
+ if ( s.data )
+ xhr.setRequestHeader("Content-Type", s.contentType);
+
+ // Set the If-Modified-Since header, if ifModified mode.
+ if ( s.ifModified )
+ xhr.setRequestHeader("If-Modified-Since",
+ jQuery.lastModified[s.url] || "Thu, 01 Jan 1970 00:00:00 GMT" );
+
+ // Set header so the called script knows that it's an XMLHttpRequest
+ xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
+
+ // Set the Accepts header for the server, depending on the dataType
+ xhr.setRequestHeader("Accept", s.dataType && s.accepts[ s.dataType ] ?
+ s.accepts[ s.dataType ] + ", */*" :
+ s.accepts._default );
+ } catch(e){}
+
+ // Allow custom headers/mimetypes
+ if ( s.beforeSend && s.beforeSend(xhr, s) === false ) {
+ // cleanup active request counter
+ s.global && jQuery.active--;
+ // close opended socket
+ xhr.abort();
+ return false;
+ }
+
+ if ( s.global )
+ jQuery.event.trigger("ajaxSend", [xhr, s]);
+
+ // Wait for a response to come back
+ var onreadystatechange = function(isTimeout){
+ // The transfer is complete and the data is available, or the request timed out
+ if ( !requestDone && xhr && (xhr.readyState == 4 || isTimeout == "timeout") ) {
+ requestDone = true;
+
+ // clear poll interval
+ if (ival) {
+ clearInterval(ival);
+ ival = null;
+ }
+
+ status = isTimeout == "timeout" ? "timeout" :
+ !jQuery.httpSuccess( xhr ) ? "error" :
+ s.ifModified && jQuery.httpNotModified( xhr, s.url ) ? "notmodified" :
+ "success";
+
+ if ( status == "success" ) {
+ // Watch for, and catch, XML document parse errors
+ try {
+ // process the data (runs the xml through httpData regardless of callback)
+ data = jQuery.httpData( xhr, s.dataType, s.dataFilter );
+ } catch(e) {
+ status = "parsererror";
+ }
+ }
+
+ // Make sure that the request was successful or notmodified
+ if ( status == "success" ) {
+ // Cache Last-Modified header, if ifModified mode.
+ var modRes;
+ try {
+ modRes = xhr.getResponseHeader("Last-Modified");
+ } catch(e) {} // swallow exception thrown by FF if header is not available
+
+ if ( s.ifModified && modRes )
+ jQuery.lastModified[s.url] = modRes;
+
+ // JSONP handles its own success callback
+ if ( !jsonp )
+ success();
+ } else
+ jQuery.handleError(s, xhr, status);
+
+ // Fire the complete handlers
+ complete();
+
+ // Stop memory leaks
+ if ( s.async )
+ xhr = null;
+ }
+ };
+
+ if ( s.async ) {
+ // don't attach the handler to the request, just poll it instead
+ var ival = setInterval(onreadystatechange, 13);
+
+ // Timeout checker
+ if ( s.timeout > 0 )
+ setTimeout(function(){
+ // Check to see if the request is still happening
+ if ( xhr ) {
+ // Cancel the request
+ xhr.abort();
+
+ if( !requestDone )
+ onreadystatechange( "timeout" );
+ }
+ }, s.timeout);
+ }
+
+ // Send the data
+ try {
+ xhr.send(s.data);
+ } catch(e) {
+ jQuery.handleError(s, xhr, null, e);
+ }
+
+ // firefox 1.5 doesn't fire statechange for sync requests
+ if ( !s.async )
+ onreadystatechange();
+
+ function success(){
+ // If a local callback was specified, fire it and pass it the data
+ if ( s.success )
+ s.success( data, status );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxSuccess", [xhr, s] );
+ }
+
+ function complete(){
+ // Process result
+ if ( s.complete )
+ s.complete(xhr, status);
+
+ // The request was completed
+ if ( s.global )
+ jQuery.event.trigger( "ajaxComplete", [xhr, s] );
+
+ // Handle the global AJAX counter
+ if ( s.global && ! --jQuery.active )
+ jQuery.event.trigger( "ajaxStop" );
+ }
+
+ // return XMLHttpRequest to allow aborting the request etc.
+ return xhr;
+ },
+
+ handleError: function( s, xhr, status, e ) {
+ // If a local callback was specified, fire it
+ if ( s.error ) s.error( xhr, status, e );
+
+ // Fire the global callback
+ if ( s.global )
+ jQuery.event.trigger( "ajaxError", [xhr, s, e] );
+ },
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Determines if an XMLHttpRequest was successful or not
+ httpSuccess: function( xhr ) {
+ try {
+ // IE error sometimes returns 1223 when it should be 204 so treat it as success, see #1450
+ return !xhr.status && location.protocol == "file:" ||
+ ( xhr.status >= 200 && xhr.status < 300 ) || xhr.status == 304 || xhr.status == 1223 ||
+ jQuery.browser.safari && xhr.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ // Determines if an XMLHttpRequest returns NotModified
+ httpNotModified: function( xhr, url ) {
+ try {
+ var xhrRes = xhr.getResponseHeader("Last-Modified");
+
+ // Firefox always returns 200. check Last-Modified date
+ return xhr.status == 304 || xhrRes == jQuery.lastModified[url] ||
+ jQuery.browser.safari && xhr.status == undefined;
+ } catch(e){}
+ return false;
+ },
+
+ httpData: function( xhr, type, filter ) {
+ var ct = xhr.getResponseHeader("content-type"),
+ xml = type == "xml" || !type && ct && ct.indexOf("xml") >= 0,
+ data = xml ? xhr.responseXML : xhr.responseText;
+
+ if ( xml && data.documentElement.tagName == "parsererror" )
+ throw "parsererror";
+
+ // Allow a pre-filtering function to sanitize the response
+ if( filter )
+ data = filter( data, type );
+
+ // If the type is "script", eval it in global context
+ if ( type == "script" )
+ jQuery.globalEval( data );
+
+ // Get the JavaScript object, if JSON is used.
+ if ( type == "json" )
+ data = eval("(" + data + ")");
+
+ return data;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a ) {
+ var s = [ ];
+
+ function add( key, value ){
+ s[ s.length ] = encodeURIComponent(key) + '=' + encodeURIComponent(value);
+ };
+
+ // If an array was passed in, assume that it is an array
+ // of form elements
+ if ( a.constructor == Array || a.jquery )
+ // Serialize the form elements
+ jQuery.each( a, function(){
+ add( this.name, this.value );
+ });
+
+ // Otherwise, assume that it's an object of key/value pairs
+ else
+ // Serialize the key/values
+ for ( var j in a )
+ // If the value is an array then the key names need to be repeated
+ if ( a[j] && a[j].constructor == Array )
+ jQuery.each( a[j], function(){
+ add( j, this );
+ });
+ else
+ add( j, jQuery.isFunction(a[j]) ? a[j]() : a[j] );
+
+ // Return the resulting serialization
+ return s.join("&").replace(/%20/g, "+");
+ }
+
+});
+jQuery.fn.extend({
+ show: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "show", width: "show", opacity: "show"
+ }, speed, callback) :
+
+ this.filter(":hidden").each(function(){
+ this.style.display = this.oldblock || "";
+ if ( jQuery.css(this,"display") == "none" ) {
+ var elem = jQuery("<" + this.tagName + " />").appendTo("body");
+ this.style.display = elem.css("display");
+ // handle an edge condition where css is - div { display:none; } or similar
+ if (this.style.display == "none")
+ this.style.display = "block";
+ elem.remove();
+ }
+ }).end();
+ },
+
+ hide: function(speed,callback){
+ return speed ?
+ this.animate({
+ height: "hide", width: "hide", opacity: "hide"
+ }, speed, callback) :
+
+ this.filter(":visible").each(function(){
+ this.oldblock = this.oldblock || jQuery.css(this,"display");
+ this.style.display = "none";
+ }).end();
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2 ){
+ return jQuery.isFunction(fn) && jQuery.isFunction(fn2) ?
+ this._toggle.apply( this, arguments ) :
+ fn ?
+ this.animate({
+ height: "toggle", width: "toggle", opacity: "toggle"
+ }, fn, fn2) :
+ this.each(function(){
+ jQuery(this)[ jQuery(this).is(":hidden") ? "show" : "hide" ]();
+ });
+ },
+
+ slideDown: function(speed,callback){
+ return this.animate({height: "show"}, speed, callback);
+ },
+
+ slideUp: function(speed,callback){
+ return this.animate({height: "hide"}, speed, callback);
+ },
+
+ slideToggle: function(speed, callback){
+ return this.animate({height: "toggle"}, speed, callback);
+ },
+
+ fadeIn: function(speed, callback){
+ return this.animate({opacity: "show"}, speed, callback);
+ },
+
+ fadeOut: function(speed, callback){
+ return this.animate({opacity: "hide"}, speed, callback);
+ },
+
+ fadeTo: function(speed,to,callback){
+ return this.animate({opacity: to}, speed, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed(speed, easing, callback);
+
+ return this[ optall.queue === false ? "each" : "queue" ](function(){
+ if ( this.nodeType != 1)
+ return false;
+
+ var opt = jQuery.extend({}, optall), p,
+ hidden = jQuery(this).is(":hidden"), self = this;
+
+ for ( p in prop ) {
+ if ( prop[p] == "hide" && hidden || prop[p] == "show" && !hidden )
+ return opt.complete.call(this);
+
+ if ( p == "height" || p == "width" ) {
+ // Store display property
+ opt.display = jQuery.css(this, "display");
+
+ // Make sure that nothing sneaks out
+ opt.overflow = this.style.overflow;
+ }
+ }
+
+ if ( opt.overflow != null )
+ this.style.overflow = "hidden";
+
+ opt.curAnim = jQuery.extend({}, prop);
+
+ jQuery.each( prop, function(name, val){
+ var e = new jQuery.fx( self, opt, name );
+
+ if ( /toggle|show|hide/.test(val) )
+ e[ val == "toggle" ? hidden ? "show" : "hide" : val ]( prop );
+ else {
+ var parts = val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),
+ start = e.cur(true) || 0;
+
+ if ( parts ) {
+ var end = parseFloat(parts[2]),
+ unit = parts[3] || "px";
+
+ // We need to compute starting value
+ if ( unit != "px" ) {
+ self.style[ name ] = (end || 1) + unit;
+ start = ((end || 1) / e.cur(true)) * start;
+ self.style[ name ] = start + unit;
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] )
+ end = ((parts[1] == "-=" ? -1 : 1) * end) + start;
+
+ e.custom( start, end, unit );
+ } else
+ e.custom( start, val, "" );
+ }
+ });
+
+ // For JS strict compliance
+ return true;
+ });
+ },
+
+ queue: function(type, fn){
+ if ( jQuery.isFunction(type) || ( type && type.constructor == Array )) {
+ fn = type;
+ type = "fx";
+ }
+
+ if ( !type || (typeof type == "string" && !fn) )
+ return queue( this[0], type );
+
+ return this.each(function(){
+ if ( fn.constructor == Array )
+ queue(this, type, fn);
+ else {
+ queue(this, type).push( fn );
+
+ if ( queue(this, type).length == 1 )
+ fn.call(this);
+ }
+ });
+ },
+
+ stop: function(clearQueue, gotoEnd){
+ var timers = jQuery.timers;
+
+ if (clearQueue)
+ this.queue([]);
+
+ this.each(function(){
+ // go in reverse order so anything added to the queue during the loop is ignored
+ for ( var i = timers.length - 1; i >= 0; i-- )
+ if ( timers[i].elem == this ) {
+ if (gotoEnd)
+ // force the next step to be the last
+ timers[i](true);
+ timers.splice(i, 1);
+ }
+ });
+
+ // start the next in the queue if the last step wasn't forced
+ if (!gotoEnd)
+ this.dequeue();
+
+ return this;
+ }
+
+});
+
+var queue = function( elem, type, array ) {
+ if ( elem ){
+
+ type = type || "fx";
+
+ var q = jQuery.data( elem, type + "queue" );
+
+ if ( !q || array )
+ q = jQuery.data( elem, type + "queue", jQuery.makeArray(array) );
+
+ }
+ return q;
+};
+
+jQuery.fn.dequeue = function(type){
+ type = type || "fx";
+
+ return this.each(function(){
+ var q = queue(this, type);
+
+ q.shift();
+
+ if ( q.length )
+ q[0].call( this );
+ });
+};
+
+jQuery.extend({
+
+ speed: function(speed, easing, fn) {
+ var opt = speed && speed.constructor == Object ? speed : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && easing.constructor != Function && easing
+ };
+
+ opt.duration = (opt.duration && opt.duration.constructor == Number ?
+ opt.duration :
+ jQuery.fx.speeds[opt.duration]) || jQuery.fx.speeds.def;
+
+ // Queueing
+ opt.old = opt.complete;
+ opt.complete = function(){
+ if ( opt.queue !== false )
+ jQuery(this).dequeue();
+ if ( jQuery.isFunction( opt.old ) )
+ opt.old.call( this );
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p, n, firstNum, diff ) {
+ return firstNum + diff * p;
+ },
+ swing: function( p, n, firstNum, diff ) {
+ return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;
+ }
+ },
+
+ timers: [],
+ timerId: null,
+
+ fx: function( elem, options, prop ){
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ if ( !options.orig )
+ options.orig = {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+
+ // Simple function for setting a style value
+ update: function(){
+ if ( this.options.step )
+ this.options.step.call( this.elem, this.now, this );
+
+ (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );
+
+ // Set display property to block for height/width animations
+ if ( this.prop == "height" || this.prop == "width" )
+ this.elem.style.display = "block";
+ },
+
+ // Get the current size
+ cur: function(force){
+ if ( this.elem[this.prop] != null && this.elem.style[this.prop] == null )
+ return this.elem[ this.prop ];
+
+ var r = parseFloat(jQuery.css(this.elem, this.prop, force));
+ return r && r > -10000 ? r : parseFloat(jQuery.curCSS(this.elem, this.prop)) || 0;
+ },
+
+ // Start an animation from one number to another
+ custom: function(from, to, unit){
+ this.startTime = now();
+ this.start = from;
+ this.end = to;
+ this.unit = unit || this.unit || "px";
+ this.now = this.start;
+ this.pos = this.state = 0;
+ this.update();
+
+ var self = this;
+ function t(gotoEnd){
+ return self.step(gotoEnd);
+ }
+
+ t.elem = this.elem;
+
+ jQuery.timers.push(t);
+
+ if ( jQuery.timerId == null ) {
+ jQuery.timerId = setInterval(function(){
+ var timers = jQuery.timers;
+
+ for ( var i = 0; i < timers.length; i++ )
+ if ( !timers[i]() )
+ timers.splice(i--, 1);
+
+ if ( !timers.length ) {
+ clearInterval( jQuery.timerId );
+ jQuery.timerId = null;
+ }
+ }, 13);
+ }
+ },
+
+ // Simple 'show' function
+ show: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ this.custom(0, this.cur());
+
+ // Make sure that we start at a small width/height to avoid any
+ // flash of content
+ if ( this.prop == "width" || this.prop == "height" )
+ this.elem.style[this.prop] = "1px";
+
+ // Start by showing the element
+ jQuery(this.elem).show();
+ },
+
+ // Simple 'hide' function
+ hide: function(){
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[this.prop] = jQuery.attr( this.elem.style, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom(this.cur(), 0);
+ },
+
+ // Each step of an animation
+ step: function(gotoEnd){
+ var t = now();
+
+ if ( gotoEnd || t > this.options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ this.options.curAnim[ this.prop ] = true;
+
+ var done = true;
+ for ( var i in this.options.curAnim )
+ if ( this.options.curAnim[i] !== true )
+ done = false;
+
+ if ( done ) {
+ if ( this.options.display != null ) {
+ // Reset the overflow
+ this.elem.style.overflow = this.options.overflow;
+
+ // Reset the display
+ this.elem.style.display = this.options.display;
+ if ( jQuery.css(this.elem, "display") == "none" )
+ this.elem.style.display = "block";
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( this.options.hide )
+ this.elem.style.display = "none";
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( this.options.hide || this.options.show )
+ for ( var p in this.options.curAnim )
+ jQuery.attr(this.elem.style, p, this.options.orig[p]);
+ }
+
+ if ( done )
+ // Execute the complete function
+ this.options.complete.call( this.elem );
+
+ return false;
+ } else {
+ var n = t - this.startTime;
+ this.state = n / this.options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[this.options.easing || (jQuery.easing.swing ? "swing" : "linear")](this.state, n, 0, 1, this.options.duration);
+ this.now = this.start + ((this.end - this.start) * this.pos);
+
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+
+};
+
+jQuery.extend( jQuery.fx, {
+ speeds:{
+ slow: 600,
+ fast: 200,
+ // Default speed
+ def: 400
+ },
+ step: {
+ scrollLeft: function(fx){
+ fx.elem.scrollLeft = fx.now;
+ },
+
+ scrollTop: function(fx){
+ fx.elem.scrollTop = fx.now;
+ },
+
+ opacity: function(fx){
+ jQuery.attr(fx.elem.style, "opacity", fx.now);
+ },
+
+ _default: function(fx){
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+ }
+ }
+});
+// The Offset Method
+// Originally By Brandon Aaron, part of the Dimension Plugin
+// http://jquery.com/plugins/project/dimensions
+jQuery.fn.offset = function() {
+ var left = 0, top = 0, elem = this[0], results;
+
+ if ( elem ) with ( jQuery.browser ) {
+ var parent = elem.parentNode,
+ offsetChild = elem,
+ offsetParent = elem.offsetParent,
+ doc = elem.ownerDocument,
+ safari2 = safari && parseInt(version) < 522 && !/adobeair/i.test(userAgent),
+ css = jQuery.curCSS,
+ fixed = css(elem, "position") == "fixed";
+
+ // Use getBoundingClientRect if available
+ if ( !(mozilla && elem == document.body) && elem.getBoundingClientRect ) {
+ var box = elem.getBoundingClientRect();
+
+ // Add the document scroll offsets
+ add(box.left + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ box.top + Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+
+ // IE adds the HTML element's border, by default it is medium which is 2px
+ // IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
+ // IE 7 standards mode, the border is always 2px
+ // This border/offset is typically represented by the clientLeft and clientTop properties
+ // However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
+ // Therefore this method will be off by 2px in IE while in quirksmode
+ add( -doc.documentElement.clientLeft, -doc.documentElement.clientTop );
+
+ // Otherwise loop through the offsetParents and parentNodes
+ } else {
+
+ // Initial element offsets
+ add( elem.offsetLeft, elem.offsetTop );
+
+ // Get parent offsets
+ while ( offsetParent ) {
+ // Add offsetParent offsets
+ add( offsetParent.offsetLeft, offsetParent.offsetTop );
+
+ // Mozilla and Safari > 2 does not include the border on offset parents
+ // However Mozilla adds the border for table or table cells
+ if ( mozilla && !/^t(able|d|h)$/i.test(offsetParent.tagName) || safari && !safari2 )
+ border( offsetParent );
+
+ // Add the document scroll offsets if position is fixed on any offsetParent
+ if ( !fixed && css(offsetParent, "position") == "fixed" )
+ fixed = true;
+
+ // Set offsetChild to previous offsetParent unless it is the body element
+ offsetChild = /^body$/i.test(offsetParent.tagName) ? offsetChild : offsetParent;
+ // Get next offsetParent
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ // Get parent scroll offsets
+ while ( parent && parent.tagName && !/^body|html$/i.test(parent.tagName) ) {
+ // Remove parent scroll UNLESS that parent is inline or a table to work around Opera inline/table scrollLeft/Top bug
+ if ( !/^inline|table.*$/i.test(css(parent, "display")) )
+ // Subtract parent scroll offsets
+ add( -parent.scrollLeft, -parent.scrollTop );
+
+ // Mozilla does not add the border for a parent that has overflow != visible
+ if ( mozilla && css(parent, "overflow") != "visible" )
+ border( parent );
+
+ // Get next parent
+ parent = parent.parentNode;
+ }
+
+ // Safari <= 2 doubles body offsets with a fixed position element/offsetParent or absolutely positioned offsetChild
+ // Mozilla doubles body offsets with a non-absolutely positioned offsetChild
+ if ( (safari2 && (fixed || css(offsetChild, "position") == "absolute")) ||
+ (mozilla && css(offsetChild, "position") != "absolute") )
+ add( -doc.body.offsetLeft, -doc.body.offsetTop );
+
+ // Add the document scroll offsets if position is fixed
+ if ( fixed )
+ add(Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft),
+ Math.max(doc.documentElement.scrollTop, doc.body.scrollTop));
+ }
+
+ // Return an object with top and left properties
+ results = { top: top, left: left };
+ }
+
+ function border(elem) {
+ add( jQuery.curCSS(elem, "borderLeftWidth", true), jQuery.curCSS(elem, "borderTopWidth", true) );
+ }
+
+ function add(l, t) {
+ left += parseInt(l, 10) || 0;
+ top += parseInt(t, 10) || 0;
+ }
+
+ return results;
+};
+
+
+jQuery.fn.extend({
+ position: function() {
+ var left = 0, top = 0, results;
+
+ if ( this[0] ) {
+ // Get *real* offsetParent
+ var offsetParent = this.offsetParent(),
+
+ // Get correct offsets
+ offset = this.offset(),
+ parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+ // Subtract element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ offset.top -= num( this, 'marginTop' );
+ offset.left -= num( this, 'marginLeft' );
+
+ // Add offsetParent borders
+ parentOffset.top += num( offsetParent, 'borderTopWidth' );
+ parentOffset.left += num( offsetParent, 'borderLeftWidth' );
+
+ // Subtract the two offsets
+ results = {
+ top: offset.top - parentOffset.top,
+ left: offset.left - parentOffset.left
+ };
+ }
+
+ return results;
+ },
+
+ offsetParent: function() {
+ var offsetParent = this[0].offsetParent;
+ while ( offsetParent && (!/^body|html$/i.test(offsetParent.tagName) && jQuery.css(offsetParent, 'position') == 'static') )
+ offsetParent = offsetParent.offsetParent;
+ return jQuery(offsetParent);
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( ['Left', 'Top'], function(i, name) {
+ var method = 'scroll' + name;
+
+ jQuery.fn[ method ] = function(val) {
+ if (!this[0]) return;
+
+ return val != undefined ?
+
+ // Set the scroll offset
+ this.each(function() {
+ this == window || this == document ?
+ window.scrollTo(
+ !i ? val : jQuery(window).scrollLeft(),
+ i ? val : jQuery(window).scrollTop()
+ ) :
+ this[ method ] = val;
+ }) :
+
+ // Return the scroll offset
+ this[0] == window || this[0] == document ?
+ self[ i ? 'pageYOffset' : 'pageXOffset' ] ||
+ jQuery.boxModel && document.documentElement[ method ] ||
+ document.body[ method ] :
+ this[0][ method ];
+ };
+});
+// Create innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each([ "Height", "Width" ], function(i, name){
+
+ var tl = i ? "Left" : "Top", // top or left
+ br = i ? "Right" : "Bottom"; // bottom or right
+
+ // innerHeight and innerWidth
+ jQuery.fn["inner" + name] = function(){
+ return this[ name.toLowerCase() ]() +
+ num(this, "padding" + tl) +
+ num(this, "padding" + br);
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn["outer" + name] = function(margin) {
+ return this["inner" + name]() +
+ num(this, "border" + tl + "Width") +
+ num(this, "border" + br + "Width") +
+ (margin ?
+ num(this, "margin" + tl) + num(this, "margin" + br) : 0);
+ };
+
+});})();
diff --git a/plugins/Autocomplete/jquery-autocomplete/lib/thickbox-compressed.js b/plugins/Autocomplete/jquery-autocomplete/lib/thickbox-compressed.js
new file mode 100644
index 000000000..28364be77
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/lib/thickbox-compressed.js
@@ -0,0 +1,10 @@
+/*
+ * Thickbox 3 - One Box To Rule Them All.
+ * By Cody Lindley (http://www.codylindley.com)
+ * Copyright (c) 2007 cody lindley
+ * Licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php
+*/
+
+var tb_pathToImage = "images/loadingAnimation.gif";
+
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$(o).2S(9(){1u(\'a.18, 3n.18, 3i.18\');1w=1p 1t();1w.L=2H});9 1u(b){$(b).s(9(){6 t=X.Q||X.1v||M;6 a=X.u||X.23;6 g=X.1N||P;19(t,a,g);X.2E();H P})}9 19(d,f,g){3m{3(2t o.v.J.2i==="2g"){$("v","11").r({A:"28%",z:"28%"});$("11").r("22","2Z");3(o.1Y("1F")===M){$("v").q("<U 5=\'1F\'></U><4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}n{3(o.1Y("B")===M){$("v").q("<4 5=\'B\'></4><4 5=\'8\'></4>");$("#B").s(G)}}3(1K()){$("#B").1J("2B")}n{$("#B").1J("2z")}3(d===M){d=""}$("v").q("<4 5=\'K\'><1I L=\'"+1w.L+"\' /></4>");$(\'#K\').2y();6 h;3(f.O("?")!==-1){h=f.3l(0,f.O("?"))}n{h=f}6 i=/\\.2s$|\\.2q$|\\.2m$|\\.2l$|\\.2k$/;6 j=h.1C().2h(i);3(j==\'.2s\'||j==\'.2q\'||j==\'.2m\'||j==\'.2l\'||j==\'.2k\'){1D="";1G="";14="";1z="";1x="";R="";1n="";1r=P;3(g){E=$("a[@1N="+g+"]").36();25(D=0;((D<E.1c)&&(R===""));D++){6 k=E[D].u.1C().2h(i);3(!(E[D].u==f)){3(1r){1z=E[D].Q;1x=E[D].u;R="<1e 5=\'1X\'>&1d;&1d;<a u=\'#\'>2T &2R;</a></1e>"}n{1D=E[D].Q;1G=E[D].u;14="<1e 5=\'1U\'>&1d;&1d;<a u=\'#\'>&2O; 2N</a></1e>"}}n{1r=1b;1n="1t "+(D+1)+" 2L "+(E.1c)}}}S=1p 1t();S.1g=9(){S.1g=M;6 a=2x();6 x=a[0]-1M;6 y=a[1]-1M;6 b=S.z;6 c=S.A;3(b>x){c=c*(x/b);b=x;3(c>y){b=b*(y/c);c=y}}n 3(c>y){b=b*(y/c);c=y;3(b>x){c=c*(x/b);b=x}}13=b+30;1a=c+2G;$("#8").q("<a u=\'\' 5=\'1L\' Q=\'1o\'><1I 5=\'2F\' L=\'"+f+"\' z=\'"+b+"\' A=\'"+c+"\' 23=\'"+d+"\'/></a>"+"<4 5=\'2D\'>"+d+"<4 5=\'2C\'>"+1n+14+R+"</4></4><4 5=\'2A\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4>");$("#Z").s(G);3(!(14==="")){9 12(){3($(o).N("s",12)){$(o).N("s",12)}$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1D,1G,g);H P}$("#1U").s(12)}3(!(R==="")){9 1i(){$("#8").C();$("v").q("<4 5=\'8\'></4>");19(1z,1x,g);H P}$("#1X").s(1i)}o.1h=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}n 3(I==3k){3(!(R=="")){o.1h="";1i()}}n 3(I==3j){3(!(14=="")){o.1h="";12()}}};16();$("#K").C();$("#1L").s(G);$("#8").r({Y:"T"})};S.L=f}n{6 l=f.2r(/^[^\\?]+\\??/,\'\');6 m=2p(l);13=(m[\'z\']*1)+30||3h;1a=(m[\'A\']*1)+3g||3f;W=13-30;V=1a-3e;3(f.O(\'2j\')!=-1){1E=f.1B(\'3d\');$("#15").C();3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\' Q=\'1o\'>1l</a> 1k 1j 1s</4></4><U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\' > </U>")}n{$("#B").N();$("#8").q("<U 1W=\'0\' 2d=\'0\' L=\'"+1E[0]+"\' 5=\'15\' 1v=\'15"+1f.2c(1f.1y()*2b)+"\' 1g=\'1m()\' J=\'z:"+(W+29)+"p;A:"+(V+17)+"p;\'> </U>")}}n{3($("#8").r("Y")!="T"){3(m[\'1A\']!="1b"){$("#8").q("<4 5=\'2f\'><4 5=\'1H\'>"+d+"</4><4 5=\'2e\'><a u=\'#\' 5=\'Z\'>1l</a> 1k 1j 1s</4></4><4 5=\'F\' J=\'z:"+W+"p;A:"+V+"p\'></4>")}n{$("#B").N();$("#8").q("<4 5=\'F\' 3c=\'3b\' J=\'z:"+W+"p;A:"+V+"p;\'></4>")}}n{$("#F")[0].J.z=W+"p";$("#F")[0].J.A=V+"p";$("#F")[0].3a=0;$("#1H").11(d)}}$("#Z").s(G);3(f.O(\'37\')!=-1){$("#F").q($(\'#\'+m[\'26\']).1T());$("#8").24(9(){$(\'#\'+m[\'26\']).q($("#F").1T())});16();$("#K").C();$("#8").r({Y:"T"})}n 3(f.O(\'2j\')!=-1){16();3($.1q.35){$("#K").C();$("#8").r({Y:"T"})}}n{$("#F").34(f+="&1y="+(1p 33().32()),9(){16();$("#K").C();1u("#F a.18");$("#8").r({Y:"T"})})}}3(!m[\'1A\']){o.21=9(e){3(e==M){I=2w.2v}n{I=e.2u}3(I==27){G()}}}}31(e){}}9 1m(){$("#K").C();$("#8").r({Y:"T"})}9 G(){$("#2Y").N("s");$("#Z").N("s");$("#8").2X("2W",9(){$(\'#8,#B,#1F\').2V("24").N().C()});$("#K").C();3(2t o.v.J.2i=="2g"){$("v","11").r({A:"1Z",z:"1Z"});$("11").r("22","")}o.1h="";o.21="";H P}9 16(){$("#8").r({2U:\'-\'+20((13/2),10)+\'p\',z:13+\'p\'});3(!(1V.1q.2Q&&1V.1q.2P<7)){$("#8").r({38:\'-\'+20((1a/2),10)+\'p\'})}}9 2p(a){6 b={};3(!a){H b}6 c=a.1B(/[;&]/);25(6 i=0;i<c.1c;i++){6 d=c[i].1B(\'=\');3(!d||d.1c!=2){39}6 e=2a(d[0]);6 f=2a(d[1]);f=f.2r(/\\+/g,\' \');b[e]=f}H b}9 2x(){6 a=o.2M;6 w=1S.2o||1R.2o||(a&&a.1Q)||o.v.1Q;6 h=1S.1P||1R.1P||(a&&a.2n)||o.v.2n;1O=[w,h];H 1O}9 1K(){6 a=2K.2J.1C();3(a.O(\'2I\')!=-1&&a.O(\'3o\')!=-1){H 1b}}',62,211,'|||if|div|id|var||TB_window|function||||||||||||||else|document|px|append|css|click||href|body||||width|height|TB_overlay|remove|TB_Counter|TB_TempArray|TB_ajaxContent|tb_remove|return|keycode|style|TB_load|src|null|unbind|indexOf|false|title|TB_NextHTML|imgPreloader|block|iframe|ajaxContentH|ajaxContentW|this|display|TB_closeWindowButton||html|goPrev|TB_WIDTH|TB_PrevHTML|TB_iframeContent|tb_position||thickbox|tb_show|TB_HEIGHT|true|length|nbsp|span|Math|onload|onkeydown|goNext|Esc|or|close|tb_showIframe|TB_imageCount|Close|new|browser|TB_FoundURL|Key|Image|tb_init|name|imgLoader|TB_NextURL|random|TB_NextCaption|modal|split|toLowerCase|TB_PrevCaption|urlNoQuery|TB_HideSelect|TB_PrevURL|TB_ajaxWindowTitle|img|addClass|tb_detectMacXFF|TB_ImageOff|150|rel|arrayPageSize|innerHeight|clientWidth|self|window|children|TB_prev|jQuery|frameborder|TB_next|getElementById|auto|parseInt|onkeyup|overflow|alt|unload|for|inlineId||100||unescape|1000|round|hspace|TB_closeAjaxWindow|TB_title|undefined|match|maxHeight|TB_iframe|bmp|gif|png|clientHeight|innerWidth|tb_parseQuery|jpeg|replace|jpg|typeof|which|keyCode|event|tb_getPageSize|show|TB_overlayBG|TB_closeWindow|TB_overlayMacFFBGHack|TB_secondLine|TB_caption|blur|TB_Image|60|tb_pathToImage|mac|userAgent|navigator|of|documentElement|Prev|lt|version|msie|gt|ready|Next|marginLeft|trigger|fast|fadeOut|TB_imageOff|hidden||catch|getTime|Date|load|safari|get|TB_inline|marginTop|continue|scrollTop|TB_modal|class|TB_|45|440|40|630|input|188|190|substr|try|area|firefox'.split('|'),0,{})) \ No newline at end of file
diff --git a/plugins/Autocomplete/jquery-autocomplete/lib/thickbox.css b/plugins/Autocomplete/jquery-autocomplete/lib/thickbox.css
new file mode 100644
index 000000000..d24b9bedf
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/lib/thickbox.css
@@ -0,0 +1,163 @@
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> global settings needed for thickbox <<<-----------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+*{padding: 0; margin: 0;}
+
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> thickbox specific link and font settings <<<------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+#TB_window {
+ font: 12px Arial, Helvetica, sans-serif;
+ color: #333333;
+}
+
+#TB_secondLine {
+ font: 10px Arial, Helvetica, sans-serif;
+ color:#666666;
+}
+
+#TB_window a:link {color: #666666;}
+#TB_window a:visited {color: #666666;}
+#TB_window a:hover {color: #000;}
+#TB_window a:active {color: #666666;}
+#TB_window a:focus{color: #666666;}
+
+/* ----------------------------------------------------------------------------------------------------------------*/
+/* ---------->>> thickbox settings <<<-----------------------------------------------------------------------------*/
+/* ----------------------------------------------------------------------------------------------------------------*/
+#TB_overlay {
+ position: fixed;
+ z-index:100;
+ top: 0px;
+ left: 0px;
+ height:100%;
+ width:100%;
+}
+
+.TB_overlayMacFFBGHack {background: url(macFFBgHack.png) repeat;}
+.TB_overlayBG {
+ background-color:#000;
+ filter:alpha(opacity=75);
+ -moz-opacity: 0.75;
+ opacity: 0.75;
+}
+
+* html #TB_overlay { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_window {
+ position: fixed;
+ background: #ffffff;
+ z-index: 102;
+ color:#000000;
+ display:none;
+ border: 4px solid #525252;
+ text-align:left;
+ top:50%;
+ left:50%;
+}
+
+* html #TB_window { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_window img#TB_Image {
+ display:block;
+ margin: 15px 0 0 15px;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ border-top: 1px solid #666;
+ border-left: 1px solid #666;
+}
+
+#TB_caption{
+ height:25px;
+ padding:7px 30px 10px 25px;
+ float:left;
+}
+
+#TB_closeWindow{
+ height:25px;
+ padding:11px 25px 10px 0;
+ float:right;
+}
+
+#TB_closeAjaxWindow{
+ padding:7px 10px 5px 0;
+ margin-bottom:1px;
+ text-align:right;
+ float:right;
+}
+
+#TB_ajaxWindowTitle{
+ float:left;
+ padding:7px 0 5px 10px;
+ margin-bottom:1px;
+}
+
+#TB_title{
+ background-color:#e8e8e8;
+ height:27px;
+}
+
+#TB_ajaxContent{
+ clear:both;
+ padding:2px 15px 15px 15px;
+ overflow:auto;
+ text-align:left;
+ line-height:1.4em;
+}
+
+#TB_ajaxContent.TB_modal{
+ padding:15px;
+}
+
+#TB_ajaxContent p{
+ padding:5px 0px 5px 0px;
+}
+
+#TB_load{
+ position: fixed;
+ display:none;
+ height:13px;
+ width:208px;
+ z-index:103;
+ top: 50%;
+ left: 50%;
+ margin: -6px 0 0 -104px; /* -height/2 0 0 -width/2 */
+}
+
+* html #TB_load { /* ie6 hack */
+position: absolute;
+margin-top: expression(0 - parseInt(this.offsetHeight / 2) + (TBWindowMargin = document.documentElement && document.documentElement.scrollTop || document.body.scrollTop) + 'px');
+}
+
+#TB_HideSelect{
+ z-index:99;
+ position:fixed;
+ top: 0;
+ left: 0;
+ background-color:#fff;
+ border:none;
+ filter:alpha(opacity=0);
+ -moz-opacity: 0;
+ opacity: 0;
+ height:100%;
+ width:100%;
+}
+
+* html #TB_HideSelect { /* ie6 hack */
+ position: absolute;
+ height: expression(document.body.scrollHeight > document.body.offsetHeight ? document.body.scrollHeight : document.body.offsetHeight + 'px');
+}
+
+#TB_iframeContent{
+ clear:both;
+ border:none;
+ margin-bottom:-1px;
+ margin-top:1px;
+ _margin-bottom:1px;
+}
diff --git a/plugins/Autocomplete/jquery-autocomplete/todo b/plugins/Autocomplete/jquery-autocomplete/todo
new file mode 100644
index 000000000..a8f03afc9
--- /dev/null
+++ b/plugins/Autocomplete/jquery-autocomplete/todo
@@ -0,0 +1,166 @@
+TODO
+
+- test formatItem implementation that returns (clickable) anchors
+- bug: handle del key; eg. type a letter, remove it using del, type same letter again: nothing happens
+- handle up/down keys in textarea (prevent default while select is open?)
+- docs: max:0 works, too, "removing" it(??)
+- fix ac_loading/options.loadingClass
+- support/enable request urls like foo/bar/10 instead of foo/q=10
+- urlencode request term before passing to $.ajax/data; evaluate why $.ajax doesn't handle that itself, if at all; try with umlauts, russian/danish/chinese characeters (see validate)
+- test what happens when an element gets focused programmatically (maybe even before then autcomplete is applied)
+- check if blur on selecting can be removed
+- fix keyhandling to ignore metakeys, eg. shift; especially important for chinese characters that need more then one key
+- enhance mustMatch: provide event/callback when a value gets deleted
+- handle tab key different then enter, eg. don't blur field or prevent default, just let it move on; in any case, no need to blur the field when selecting a value via tab, unlike return
+- prevent redundant requests on
+ - superstring returned no result, no need to query again for substring, eg. pete returned nothing, peter won't either
+ - previous query mustn't be requested again, eg. pete returns 10 lines, peter nothing, backspace to pete should get the 10 lines from cache (may need TimeToLive setting for cache to invalidate it)
+- incorporate improvements and suggestions by Hector: http://beta.winserver.com/public/test/MultiSuggestTest.wct
+- json support: An optional JSON format, that assumes a certain JSON format as default and just looks for a dataType "json" to be activated; [records], where each record is { id:String, label:String, moreOptionalValues... }
+- accept callback as first argument to let users implement their own dynamic data (no caching) - consider async API
+- allow users to keep their incomplete value when pressing tab, just mimic the default-browser-autocomplete: tab doesn't select any proposed value -> tab closes the select and works normal otherwise
+- small bug in your autocomplete, When setting autoFill:true I would expect formatResult to be called on autofill, it seems not to be the case.
+- add a callback to allow decoding the response
+- allow modification of not-last value in multiple-fields
+@option Number size Limit the number of items to show at once. Default:
+@option Function parse - TEST AND DOCUMENT ME
+- add option to display selectbox on focus
+
+$input.bind("show", function() {
+ if ( !select.visible() ) {
+ onChange(0, true);
+ }
+});
+
+- reference: http://capxous.com/
+ - add "try ..." hints to demo
+ - check out demos
+- reference: http://createwebapp.com/demo/
+
+- add option to hide selectbox when no match is found - see comment by Ian on plugin page (14. Juli 2007 04:31)
+- add example for reinitializing an autocomplete using unbind()
+
+- Add option to pass through additional arguments to $.ajax, like type to use POST instead of GET
+
+ - I found out that the problem with UTF-8 not being correctly sent can be solved on the server side by applying (PHP) rawurldecode() function, which decodes the Unicode characters sent by GET method and therefore URL-encoded.
+-> add that hint to docs and examples
+
+But I am trying this with these three values: “foo barâ€, “foo fooâ€, and “foo farâ€, and if I enter “b†(or “baâ€) nothing matches, if I enter “f†all three do match, and if I enter “fa†the last one matches.
+The problem seems to be that the cache is implemented with a first-character hashtable, so only after matching the first character, the latter ones are searched for.
+
+xml example:
+<script type="text/javascript">
+ function parseXML(data) {
+ var results = [];
+ var branches = $(data).find('item');
+ $(branches).each(function() {
+ var text = $.trim($(this).find('text').text());
+ var value = $.trim($(this).find('value').text());
+ //console.log(text);
+ //console.log(value);
+ results[results.length] = {'data': this, 'result': value, 'value': text};
+ });
+ $(results).each(function() {
+ //console.log('value', this.value);
+ //console.log('text', this.text);
+ });
+ //console.log(results);
+ return results;
+ };
+ $(YourOojHere).autocomplete(SERVER_AJAX_URL, {parse: parseXML});
+ </script>
+<?xml version="1.0"?>
+<ajaxresponse>
+ <item>
+ <text>
+ <![CDATA[<b>FreeNode:</b> irc.freenode.net:6667]]>
+ </text>
+ <value><![CDATA[irc.freenode.net:6667]]></value>
+ </item><item>
+ <text>
+ <![CDATA[<b>irc.oftc.net</b>:6667]]>
+ </text>
+ <value><![CDATA[irc.oftc.net:6667]]></value>
+ </item><item>
+ <text>
+ <![CDATA[<b>irc.undernet.org</b>:6667]]>
+ </text>
+ <value><![CDATA[irc.undernet.org:6667]]></value>
+ </item>
+</ajaxresponse>
+
+
+
+Hi all,
+
+I use Autocomplete 1.0 Alpha mostly for form inputs bound to foreign
+key columns. For instance I have a user_position table with two
+columns: user_id and position_id. On new appointment form I have two
+autocomplete text inputs with the following code:
+
+ <input type="text" id="user_id" class="ac_input" tabindex="1" />
+ <input type="text" id="position_id" class="ac_input" tabindex="2" />
+
+As you can see the inputs do not have a name attribute, and when the
+form is submitted their values are not sent, which is all right since
+they will contain strings like:
+
+ 'John Doe'
+ 'Sales Manager'
+
+whereas our backend expects something like:
+
+ 23
+ 14
+
+which are the user_id for John Doe and position_id for Sales Manager.
+To send these values I have two hidden inputs in the form like this:
+
+ <input type="hidden" name="user_id" value="">
+ <input type="hidden" name="position_id" value="">
+
+Also I have the following code in the $().ready function:
+
+ $("#user_id").result(function(event, data, formatted) {
+ $("input[@name=user_id]").val(data[1]);
+ });
+ $("#position_id").result(function(event, data, formatted) {
+ $("input[@name=position_id]").val(data[1]);
+ });
+
+As could be seen these functions stuff user_id and position_id values
+(in our example 23 and 14) into the hidden inputs, and when the form
+is submitted these values are sent:
+
+ user_id = 23
+ position_id = 14
+
+The backend script then takes care of adding a record to our
+user_position table containing those values.
+
+I wonder how could the plugin code be modified to simplify the setup
+by taking care of adding hidden inputs and updating the value of
+hidden inputs as default behavior. I have successfully attempted a
+simpler solution - writing a wrapper to perform these additional tasks
+and invoke autocomplete as well. I hope my intention is clear enough,
+if not, this is exactly the expected outcome:
+
+Before:
+
+ <script type="text/javascript"
+ src="jquery.autocomplete-modified.js"></script>
+ <input type="text" name="user_id" class="ac_input" tabindex="1" />
+
+After:
+
+ <input type="text" id="user_id" class="ac_input" tabindex="1" />
+ <input type="hidden" name="user_id" value="23">
+
+
+Last word, I know this looks like a tall order, and I do not hope
+someone will make a complete working mod for me, but rather would very
+much appreciate helpful advise and directions.
+
+Many thanks in advance
+Majid
+
diff --git a/plugins/Autocomplete/readme.txt b/plugins/Autocomplete/readme.txt
new file mode 100644
index 000000000..1db4c6565
--- /dev/null
+++ b/plugins/Autocomplete/readme.txt
@@ -0,0 +1,8 @@
+Autocomplete allows users to autocomplete screen names in @ replies. When an "@" is typed into the notice text area, an autocomplete box is displayed populated with the user's friends' screen names.
+
+Note: This plugin doesn't work if the site is in Private mode, i.e. when $config['site']['private'] is set to true.
+
+Installation
+============
+Add "addPlugin('Autocomplete');" to the bottom of your config.php
+That's it!
diff --git a/plugins/BlogspamNetPlugin.php b/plugins/BlogspamNetPlugin.php
index d9372bcd5..c14569746 100644
--- a/plugins/BlogspamNetPlugin.php
+++ b/plugins/BlogspamNetPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to check submitted notices with blogspam.net
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET')) {
exit(1);
}
@@ -45,10 +45,10 @@ define('BLOGSPAMNETPLUGIN_VERSION', '0.1');
* hits, but it's better than nothing.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Event
*/
@@ -139,6 +139,6 @@ class BlogspamNetPlugin extends Plugin
function userAgent()
{
- return 'BlogspamNetPlugin/'.BLOGSPAMNETPLUGIN_VERSION . ' Laconica/' . LACONICA_VERSION;
+ return 'BlogspamNetPlugin/'.BLOGSPAMNETPLUGIN_VERSION . ' StatusNet/' . STATUSNET_VERSION;
}
}
diff --git a/plugins/Comet/CometPlugin.php b/plugins/Comet/CometPlugin.php
index 1735d2b15..300d1e9a2 100644
--- a/plugins/Comet/CometPlugin.php
+++ b/plugins/Comet/CometPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to do "real time" updates using Comet/Bayeux
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/plugins/Realtime/RealtimePlugin.php';
* Plugin to do realtime updates using Comet
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class CometPlugin extends RealtimePlugin
diff --git a/plugins/FBConnect/FBCLoginGroupNav.php b/plugins/FBConnect/FBCLoginGroupNav.php
index 6eb09c3c0..6e12c2040 100644
--- a/plugins/FBConnect/FBCLoginGroupNav.php
+++ b/plugins/FBConnect/FBCLoginGroupNav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Menu for login group of actions
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Menu
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR . '/lib/widget.php';
* Menu for login group of actions
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
diff --git a/plugins/FBConnect/FBCSettingsNav.php b/plugins/FBConnect/FBCSettingsNav.php
index 8b8411853..29724d6bd 100644
--- a/plugins/FBConnect/FBCSettingsNav.php
+++ b/plugins/FBConnect/FBCSettingsNav.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Menu for login group of actions
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Menu
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,11 +38,11 @@ require_once INSTALLDIR . '/lib/widget.php';
* A widget for showing the connect group local nav menu
*
* @category Output
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Widget
*/
diff --git a/plugins/FBConnect/FBC_XDReceiver.php b/plugins/FBConnect/FBC_XDReceiver.php
index 57c98b4f1..2bc790d5a 100644
--- a/plugins/FBConnect/FBC_XDReceiver.php
+++ b/plugins/FBConnect/FBC_XDReceiver.php
@@ -1,6 +1,6 @@
<?php
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -47,9 +47,7 @@ class FBC_XDReceiverAction extends Action
header('Expires:');
header('Pragma:');
- $this->startXML('html',
- '-//W3C//DTD XHTML 1.0 Strict//EN',
- 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
+ $this->startXML('html');
$language = $this->getLanguage();
@@ -58,10 +56,7 @@ class FBC_XDReceiverAction extends Action
'lang' => $language));
$this->elementStart('head');
$this->element('title', null, 'cross domain receiver page');
- $this->element('script',
- array('src' =>
- 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js',
- 'type' => 'text/javascript'), '');
+ $this->script('http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.debug.js');
$this->elementEnd('head');
$this->elementStart('body');
$this->elementEnd('body');
diff --git a/plugins/FBConnect/FBConnectAuth.php b/plugins/FBConnect/FBConnectAuth.php
index 3cf9fefc1..647d5def8 100644
--- a/plugins/FBConnect/FBConnectAuth.php
+++ b/plugins/FBConnect/FBConnectAuth.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to enable Facebook Connect
*
@@ -20,38 +20,36 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
require_once INSTALLDIR . '/plugins/FBConnect/FBConnectPlugin.php';
class FBConnectauthAction extends Action
{
-
var $fbuid = null;
var $fb_fields = null;
function prepare($args) {
parent::prepare($args);
- try {
+ $this->fbuid = getFacebook()->get_loggedin_user();
- $this->fbuid = getFacebook()->get_loggedin_user();
+ if ($this->fbuid > 0) {
+ $this->fb_fields = $this->getFacebookFields($this->fbuid,
+ array('first_name', 'last_name', 'name'));
+ } else {
+ list($proxy, $ip) = common_client_ip();
- if ($this->fbuid > 0) {
- $this->fb_fields = $this->getFacebookFields($this->fbuid,
- array('first_name', 'last_name', 'name'));
- } else {
- common_debug("No Facebook User found.");
- }
+ common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
+ "Failed auth attempt, proxy = $proxy, ip = $ip.");
- } catch (Exception $e) {
- common_log(LOG_WARNING, 'Problem getting Facebook uid: ' .
- $e->getMessage());
+ $this->clientError(_('You must be logged into Facebook to ' .
+ 'use Facebook Connect.'));
}
return true;
@@ -69,8 +67,9 @@ class FBConnectauthAction extends Action
if (!empty($flink)) {
// User already has a linked Facebook account and shouldn't be here
- common_debug('There is already a local user (' . $flink->user_id .
- ') linked with this Facebook (' . $this->fbuid . ').');
+ common_debug('Facebook Connect Plugin - ' .
+ 'There is already a local user (' . $flink->user_id .
+ ') linked with this Facebook (' . $this->fbuid . ').');
// We don't want these cookies
getFacebook()->clear_cookie_state();
@@ -101,7 +100,8 @@ class FBConnectauthAction extends Action
} else if ($this->arg('connect')) {
$this->connectNewUser();
} else {
- common_debug(print_r($this->args, true), __FILE__);
+ common_debug('Facebook Connect Plugin - ' .
+ print_r($this->args, true));
$this->showForm(_('Something weird happened.'),
$this->trimmed('newname'));
}
@@ -211,7 +211,6 @@ class FBConnectauthAction extends Action
function createNewUser()
{
-
if (common_config('site', 'closed')) {
$this->clientError(_('Registration not allowed.'));
return;
@@ -238,7 +237,7 @@ class FBConnectauthAction extends Action
if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64,
- 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
+ 'format' => NICKNAME_FMT))) {
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
return;
}
@@ -274,7 +273,8 @@ class FBConnectauthAction extends Action
common_set_user($user);
common_real_login(true);
- common_debug("Registered new user $user->id from Facebook user $this->fbuid");
+ common_debug('Facebook Connect Plugin - ' .
+ "Registered new user $user->id from Facebook user $this->fbuid");
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
303);
@@ -292,8 +292,9 @@ class FBConnectauthAction extends Action
$user = User::staticGet('nickname', $nickname);
- if ($user) {
- common_debug("Legit user to connect to Facebook: $nickname");
+ if (!empty($user)) {
+ common_debug('Facebook Connect Plugin - ' .
+ "Legit user to connect to Facebook: $nickname");
}
$result = $this->flinkUser($user->id, $this->fbuid);
@@ -303,7 +304,8 @@ class FBConnectauthAction extends Action
return;
}
- common_debug("Connected Facebook user $this->fbuid to local user $user->id");
+ common_debug('Facebook Connnect Plugin - ' .
+ "Connected Facebook user $this->fbuid to local user $user->id");
common_set_user($user);
common_real_login(true);
@@ -317,12 +319,13 @@ class FBConnectauthAction extends Action
$result = $this->flinkUser($user->id, $this->fbuid);
- if (!$result) {
+ if (empty($result)) {
$this->serverError(_('Error connecting user to Facebook.'));
return;
}
- common_debug("Connected Facebook user $this->fbuid to local user $user->id");
+ common_debug('Facebook Connect Plugin - ' .
+ "Connected Facebook user $this->fbuid to local user $user->id");
// Return to Facebook connection settings tab
common_redirect(common_local_url('FBConnectSettings'), 303);
@@ -330,16 +333,18 @@ class FBConnectauthAction extends Action
function tryLogin()
{
- common_debug("Trying Facebook Login...");
+ common_debug('Facebook Connect Plugin - ' .
+ "Trying login for Facebook user $this->fbuid.");
$flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_CONNECT_SERVICE);
- if ($flink) {
+ if (!empty($flink)) {
$user = $flink->getUser();
if (!empty($user)) {
- common_debug("Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)");
+ common_debug('Facebook Connect Plugin - ' .
+ "Logged in Facebook user $flink->foreign_id as user $user->id ($user->nickname)");
common_set_user($user);
common_real_login(true);
@@ -348,7 +353,8 @@ class FBConnectauthAction extends Action
} else {
- common_debug("No flink found for fbuid: $this->fbuid");
+ common_debug('Facebook Connect Plugin - ' .
+ "No flink found for fbuid: $this->fbuid - new user");
$this->showForm(null, $this->bestNewNickname());
}
@@ -418,7 +424,7 @@ class FBConnectauthAction extends Action
{
if (!Validate::string($str, array('min_length' => 1,
'max_length' => 64,
- 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
+ 'format' => NICKNAME_FMT))) {
return false;
}
if (!User::allowed_nickname($str)) {
@@ -444,7 +450,8 @@ class FBConnectauthAction extends Action
return reset($infos);
} catch (Exception $e) {
- common_log(LOG_WARNING, "Facebook client failure when requesting " .
+ common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
+ "Facebook client failure when requesting " .
join(",", $fields) . " on uid " . $fb_uid .
" : ". $e->getMessage());
return null;
diff --git a/plugins/FBConnect/FBConnectLogin.php b/plugins/FBConnect/FBConnectLogin.php
index 205086cd8..5696d8848 100644
--- a/plugins/FBConnect/FBConnectLogin.php
+++ b/plugins/FBConnect/FBConnectLogin.php
@@ -1,6 +1,6 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
+ * StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2008, Controlez-Vous, Inc.
*
* This program is free software: you can redistribute it and/or modify
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
diff --git a/plugins/FBConnect/FBConnectPlugin.css b/plugins/FBConnect/FBConnectPlugin.css
index e52675459..49217bf13 100644
--- a/plugins/FBConnect/FBConnectPlugin.css
+++ b/plugins/FBConnect/FBConnectPlugin.css
@@ -1,10 +1,10 @@
/** Styles for Facebook logo and Facebook user profile avatar.
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
#site_nav_global_primary #nav_fb {
diff --git a/plugins/FBConnect/FBConnectPlugin.php b/plugins/FBConnect/FBConnectPlugin.php
index 2e32ad198..593b49b4e 100644
--- a/plugins/FBConnect/FBConnectPlugin.php
+++ b/plugins/FBConnect/FBConnectPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to enable Facebook Connect
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -45,10 +45,10 @@ require_once INSTALLDIR . '/plugins/FBConnect/FBC_XDReceiver.php';
* Plugin to enable Facebook Connect
*
* @category Plugin
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FBConnectPlugin extends Plugin
@@ -82,9 +82,7 @@ class FBConnectPlugin extends Plugin
$action->extraHeaders();
- $action->startXML('html',
- '-//W3C//DTD XHTML 1.0 Strict//EN',
- 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd');
+ $action->startXML('html');
$language = $action->getLanguage();
@@ -118,15 +116,13 @@ class FBConnectPlugin extends Plugin
// but we actually do, for IE and Safari. Gar.
$html = sprintf('<script type="text/javascript">
- window.onload = function () {
+ $(document).ready(function () {
FB_RequireFeatures(
["XFBML"],
function() {
- FB.init("%s", "../xd_receiver.html",
- {"doNotUseCachedConnectState":true });
-
+ FB.init("%s", "../xd_receiver.html");
}
- ); }
+ ); });
function goto_login() {
window.location = "%s";
@@ -148,22 +144,15 @@ class FBConnectPlugin extends Plugin
function onEndShowFooter($action)
{
if ($this->reqFbScripts($action)) {
-
- $action->element('script',
- array('type' => 'text/javascript',
- 'src' => 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php'),
- '');
+ $action->script('http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php');
}
}
- function onEndShowLaconicaStyles($action)
+ function onEndShowStatusNetStyles($action)
{
if ($this->reqFbScripts($action)) {
-
- $action->element('link', array('rel' => 'stylesheet',
- 'type' => 'text/css',
- 'href' => common_path('plugins/FBConnect/FBConnectPlugin.css')));
+ $action->cssLink('plugins/FBConnect/FBConnectPlugin.css');
}
}
@@ -222,10 +211,10 @@ class FBConnectPlugin extends Plugin
try {
$facebook = getFacebook();
- $fbuid = $facebook->api_client->users_getLoggedInUser();
+ $fbuid = $facebook->get_loggedin_user();
} catch (Exception $e) {
- common_log(LOG_WARNING,
+ common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
'Problem getting Facebook user: ' .
$e->getMessage());
}
@@ -353,7 +342,7 @@ class FBConnectPlugin extends Plugin
}
function onStartLogout($action)
- {
+{
$action->logout();
$fbuid = $this->loggedIn();
@@ -362,8 +351,9 @@ class FBConnectPlugin extends Plugin
$facebook = getFacebook();
$facebook->expire_session();
} catch (Exception $e) {
- common_log(LOG_WARNING, 'Could\'t logout of Facebook: ' .
- $e->getMessage());
+ common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
+ 'Could\'t logout of Facebook: ' .
+ $e->getMessage());
}
}
@@ -387,7 +377,8 @@ class FBConnectPlugin extends Plugin
}
} catch (Exception $e) {
- common_log(LOG_WARNING, "Facebook client failure requesting profile pic!");
+ common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
+ "Facebook client failure requesting profile pic!");
}
return $url;
diff --git a/plugins/FBConnect/FBConnectSettings.php b/plugins/FBConnect/FBConnectSettings.php
index 034ecebae..911c56787 100644
--- a/plugins/FBConnect/FBConnectSettings.php
+++ b/plugins/FBConnect/FBConnectSettings.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Facebook Connect settings
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Settings
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/lib/connectsettingsaction.php';
* Facebook Connect settings action
*
* @category Settings
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class FBConnectSettingsAction extends ConnectSettingsAction
@@ -186,9 +186,9 @@ class FBConnectSettingsAction extends ConnectSettingsAction
$facebook->clear_cookie_state();
} catch (Exception $e) {
- common_log(LOG_WARNING,
- 'Couldn\'t clear Facebook cookies: ' .
- $e->getMessage());
+ common_log(LOG_WARNING, 'Facebook Connect Plugin - ' .
+ 'Couldn\'t clear Facebook cookies: ' .
+ $e->getMessage());
}
$this->showForm(_('You have disconnected from Facebook.'), true);
diff --git a/plugins/FBConnect/README b/plugins/FBConnect/README
index 914b774cb..77d57eff9 100644
--- a/plugins/FBConnect/README
+++ b/plugins/FBConnect/README
@@ -1,18 +1,18 @@
-This plugin allows you to utilize Facebook Connect with Laconica.
+This plugin allows you to utilize Facebook Connect with StatusNet.
Supported Facebook Connect features:
- Authenticate (register/login/logout -- works similar to OpenID)
-- Associate an existing Laconica account with a Facebook account
-- Disconnect a Facebook account from a Laconica account
+- Associate an existing StatusNet account with a Facebook account
+- Disconnect a Facebook account from a StatusNet account
Future planned functionality:
-- Invite Facebook friends to use your Laconica installation
-- Auto-subscribe Facebook friends already using Laconica
-- Share Laconica favorite notices to your Facebook stream
+- Invite Facebook friends to use your StatusNet installation
+- Auto-subscribe Facebook friends already using StatusNet
+- Share StatusNet favorite notices to your Facebook stream
To use the plugin you will need to configure a Facebook application
-to point to your Laconica installation (see the Installation section
+to point to your StatusNet installation (see the Installation section
below).
Installation
@@ -26,16 +26,16 @@ Facebook developer wiki:
http://wiki.developers.facebook.com/index.php/Connect/Setting_Up_Your_Site
-If you already are using the build-in Laconica Facebook application,
+If you already are using the build-in StatusNet Facebook application,
you can modify your existing application's configuration using the
Facebook Developer Application on Facebook. Use it to edit your
application settings, and under the 'Connect' tab, change the 'Connect
-URL' to be the main URL for your Laconica site. E.g.:
+URL' to be the main URL for your StatusNet site. E.g.:
- http://SITE/PATH_TO_LACONICA/
+ http://SITE/PATH_TO_STATUSNET/
After you application is created and configured, you'll need to add its
-API key and secret to your Laconica config.php file:
+API key and secret to your StatusNet config.php file:
$config['facebook']['apikey'] = 'APIKEY';
$config['facebook']['secret'] = 'SECRET';
@@ -43,16 +43,15 @@ API key and secret to your Laconica config.php file:
Finally, to enable the plugin, add the following stanza to your
config.php:
- require_once(INSTALLDIR.'/plugins/FBConnect/FBConnectPlugin.php');
- $fbc = new FBConnectPlugin();
+ addPlugin('FBConnect');
To try out the plugin, fire up your browser and connect to:
- http://SITE/PATH_TO_LACONICA/main/facebooklogin
+ http://SITE/PATH_TO_STATUSNET/main/facebooklogin
or, if you do not have fancy URLs turned on:
- http://SITE/PATH_TO_LACONICA/index.php/main/facebooklogin
+ http://SITE/PATH_TO_STATUSNET/index.php/main/facebooklogin
You should see a page with a blue button that says: "Connect with
Facebook".
@@ -63,10 +62,10 @@ Connect/Disconnect existing account
If the Facebook Connect plugin is enabled, there will be a new Facebook
Connect Settings tab under each user's Connect menu. Users can connect
and disconnect to their Facebook accounts from it. Note: Before a user
-can disconnect from Facebook, she must set a normal Laconica password.
+can disconnect from Facebook, she must set a normal StatusNet password.
Otherwise, she might not be able to login in to her account in the
future. This is usually only required for users who have used Facebook
-Connect to register their Laconica account, and therefore haven't
+Connect to register their StatusNet account, and therefore haven't
already set a local password.
Helpful links
diff --git a/plugins/GoogleAnalyticsPlugin.php b/plugins/GoogleAnalyticsPlugin.php
index 1ecbb664e..7f3d209ee 100644
--- a/plugins/GoogleAnalyticsPlugin.php
+++ b/plugins/GoogleAnalyticsPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to use Google Analytics
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET')) {
exit(1);
}
@@ -40,10 +40,10 @@ if (!defined('LACONICA')) {
* Piwik (http://www.piwik.org/) instead!
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Event
*/
diff --git a/plugins/InfiniteScroll/InfiniteScrollPlugin.php b/plugins/InfiniteScroll/InfiniteScrollPlugin.php
new file mode 100644
index 000000000..5928c007f
--- /dev/null
+++ b/plugins/InfiniteScroll/InfiniteScrollPlugin.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to enable Infinite Scrolling
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Craig Andrews <candrews@integralblue.com>
+ * @copyright 2009 Craig Andrews http://candrews.integralblue.com
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+class InfiniteScrollPlugin extends Plugin
+{
+ function __construct()
+ {
+ parent::__construct();
+ }
+
+ function onEndShowScripts($action)
+ {
+ $action->script('plugins/InfiniteScroll/jquery.infinitescroll.js');
+ $action->script('plugins/InfiniteScroll/infinitescroll.js');
+ }
+}
diff --git a/plugins/InfiniteScroll/ajax-loader.gif b/plugins/InfiniteScroll/ajax-loader.gif
new file mode 100644
index 000000000..a576ecd5e
--- /dev/null
+++ b/plugins/InfiniteScroll/ajax-loader.gif
Binary files differ
diff --git a/plugins/InfiniteScroll/infinitescroll.js b/plugins/InfiniteScroll/infinitescroll.js
new file mode 100644
index 000000000..ae4d53d09
--- /dev/null
+++ b/plugins/InfiniteScroll/infinitescroll.js
@@ -0,0 +1,15 @@
+jQuery(document).ready(function($){
+ $('notices_primary').infinitescroll({
+ debug: true,
+ infiniteScroll : false,
+ nextSelector : "li.nav_next a",
+ loadingImg : $('address .url')[0].href+'plugins/InfiniteScroll/ajax-loader.gif',
+ text : "<em>Loading the next set of posts...</em>",
+ donetext : "<em>Congratulations, you\'ve reached the end of the Internet.</em>",
+ navSelector : "div.pagination",
+ contentSelector : "#notices_primary ol.notices",
+ itemSelector : "#notices_primary ol.notices li"
+ },function(){
+ NoticeAttachments();
+ });
+});
diff --git a/plugins/InfiniteScroll/jquery.infinitescroll.js b/plugins/InfiniteScroll/jquery.infinitescroll.js
new file mode 100644
index 000000000..ec31bb086
--- /dev/null
+++ b/plugins/InfiniteScroll/jquery.infinitescroll.js
@@ -0,0 +1,261 @@
+
+/*!
+// Infinite Scroll jQuery plugin
+// copyright Paul Irish, licensed GPL & MIT
+// version 1.2.090804
+
+// home and docs: http://www.infinite-scroll.com
+*/
+
+// todo: add preloading option.
+
+;(function($){
+
+ $.fn.infinitescroll = function(options,callback){
+
+ // console log wrapper.
+ function debug(){
+ if (opts.debug) { window.console && console.log.call(console,arguments)}
+ }
+
+ // grab each selector option and see if any fail.
+ function areSelectorsValid(opts){
+ for (var key in opts){
+ if (key.indexOf && key.indexOf('Selector') && $(opts[key]).length === 0){
+ debug('Your ' + key + ' found no elements.');
+ return false;
+ }
+ return true;
+ }
+ }
+
+
+ // find the number to increment in the path.
+ function determinePath(path){
+
+ path.match(relurl) ? path.match(relurl)[2] : path;
+
+ // there is a 2 in the url surrounded by slashes, e.g. /page/2/
+ if ( path.match(/^(.*?)\b2\b(.*?$)/) ){
+ path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
+ } else
+ // if there is any 2 in the url at all.
+ if (path.match(/^(.*?)2(.*?$)/)){
+ debug('Trying backup next selector parse technique. Treacherous waters here, matey.');
+ path = path.match(/^(.*?)2(.*?$)/).slice(1);
+ } else {
+ debug('Sorry, we couldn\'t parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.');
+ props.isInvalidPage = true; //prevent it from running on this page.
+ }
+
+ return path;
+ }
+
+
+ // 'document' means the full document usually, but sometimes the content of the overflow'd div in local mode
+ function getDocumentHeight(){
+ // weird doubletouch of scrollheight because http://soulpass.com/2006/07/24/ie-and-scrollheight/
+ return opts.localMode ? ($(props.container)[0].scrollHeight && $(props.container)[0].scrollHeight)
+ // needs to be document's height. (not props.container's) html's height is wrong in IE.
+ : $(document).height()
+ }
+
+
+
+ function isNearBottom(opts,props){
+
+ // distance remaining in the scroll
+ // computed as: document height - distance already scroll - viewport height - buffer
+ var pixelsFromWindowBottomToBottom = getDocumentHeight() -
+ (opts.localMode ? $(props.container).scrollTop() :
+ // have to do this bs because safari doesnt report a scrollTop on the html element
+ ($(props.container).scrollTop() || $(props.container.ownerDocument.body).scrollTop())) -
+ $(opts.localMode ? props.container : window).height();
+
+ debug('math:',pixelsFromWindowBottomToBottom, props.pixelsFromNavToBottom);
+
+ // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
+ return (pixelsFromWindowBottomToBottom - opts.bufferPx < props.pixelsFromNavToBottom);
+ }
+
+ function showDoneMsg(){
+ props.loadingMsg
+ .find('img').hide()
+ .parent()
+ .find('div').html(opts.donetext).animate({opacity: 1},2000).fadeOut('normal');
+
+ // user provided callback when done
+ opts.errorCallback();
+ }
+
+ function infscrSetup(path,opts,props,callback){
+
+ if (props.isDuringAjax || props.isInvalidPage || props.isDone) return;
+
+ if ( opts.infiniteScroll && !isNearBottom(opts,props) ) return;
+
+ // we dont want to fire the ajax multiple times
+ props.isDuringAjax = true;
+
+ // show the loading message and hide the previous/next links
+ props.loadingMsg.appendTo( opts.contentSelector ).show();
+ if(opts.infiniteScroll) $( opts.navSelector ).hide();
+
+ // increment the URL bit. e.g. /page/3/
+ props.currPage++;
+
+ debug('heading into ajax',path);
+
+ // if we're dealing with a table we can't use DIVs
+ var box = $(opts.contentSelector).is('table') ? $('<tbody/>') : $('<div/>');
+
+ box
+ .attr('id','infscr-page-'+props.currPage)
+ .addClass('infscr-pages')
+ .appendTo( opts.contentSelector )
+ .load( path.join( props.currPage ) + ' ' + opts.itemSelector,null,function(){
+
+ // if we've hit the last page...
+ if (props.isDone){
+ showDoneMsg();
+ return false;
+
+ } else {
+
+ // if it didn't return anything
+ if (box.children().length == 0){
+ // fake an ajaxError so we can quit.
+ $.event.trigger( "ajaxError", [{status:404}] );
+ }
+
+ // fadeout currently makes the <em>'d text ugly in IE6
+ props.loadingMsg.fadeOut('normal' );
+
+ // smooth scroll to ease in the new content
+ if (opts.animate){
+ var scrollTo = $(window).scrollTop() + $('#infscr-loading').height() + opts.extraScrollPx + 'px';
+ $('html,body').animate({scrollTop: scrollTo}, 800,function(){ props.isDuringAjax = false; });
+ }
+
+ // pass in the new DOM element as context for the callback
+ callback.call( box[0] );
+
+ if (!opts.animate) props.isDuringAjax = false; // once the call is done, we can allow it again.
+ }
+ }); // end of load()
+
+
+ } // end of infscrSetup()
+
+
+
+
+ // lets get started.
+
+ var opts = $.extend({}, $.infinitescroll.defaults, options);
+ var props = $.infinitescroll; // shorthand
+ callback = callback || function(){};
+
+ if (!areSelectorsValid(opts)){ return false; }
+
+ // we doing this on an overflow:auto div?
+ props.container = opts.localMode ? this : document.documentElement;
+
+ // contentSelector we'll use for our .load()
+ opts.contentSelector = opts.contentSelector || this;
+
+
+ // get the relative URL - everything past the domain name.
+ var relurl = /(.*?\/\/).*?(\/.*)/;
+ var path = $(opts.nextSelector).attr('href');
+
+
+ if (!path) { debug('Navigation selector not found'); return; }
+
+ // set the path to be a relative URL from root.
+ path = determinePath(path);
+
+
+ // reset scrollTop in case of page refresh:
+ if (opts.localMode) $(props.container)[0].scrollTop = 0;
+
+ // distance from nav links to bottom
+ // computed as: height of the document + top offset of container - top offset of nav link
+ props.pixelsFromNavToBottom = getDocumentHeight() +
+ $(props.container).offset().top -
+ $(opts.navSelector).offset().top;
+
+ // define loading msg
+ props.loadingMsg = $('<div id="infscr-loading" style="text-align: center;"><img alt="Loading..." src="'+
+ opts.loadingImg+'" /><div>'+opts.loadingText+'</div></div>');
+ // preload the image
+ (new Image()).src = opts.loadingImg;
+
+
+
+ // set up our bindings
+ $(document).ajaxError(function(e,xhr,opt){
+ debug('Page not found. Self-destructing...');
+
+ // die if we're out of pages.
+ if (xhr.status == 404){
+ showDoneMsg();
+ props.isDone = true;
+ $(opts.localMode ? this : window).unbind('scroll.infscr');
+ }
+ });
+
+ if(opts.infiniteScroll){
+ // bind scroll handler to element (if its a local scroll) or window
+ $(opts.localMode ? this : window)
+ .bind('scroll.infscr', function(){ infscrSetup(path,opts,props,callback); } )
+ .trigger('scroll.infscr'); // trigger the event, in case it's a short page
+ }else{
+ $(opts.nextSelector).click(
+ function(){
+ infscrSetup(path,opts,props,callback);
+ return false;
+ }
+ );
+ }
+
+
+ return this;
+
+ } // end of $.fn.infinitescroll()
+
+
+
+ // options and read-only properties object
+
+ $.infinitescroll = {
+ defaults : {
+ debug : false,
+ infiniteScroll : true,
+ preload : false,
+ nextSelector : "div.navigation a:first",
+ loadingImg : "http://www.infinite-scroll.com/loading.gif",
+ loadingText : "<em>Loading the next set of posts...</em>",
+ donetext : "<em>Congratulations, you've reached the end of the internet.</em>",
+ navSelector : "div.navigation",
+ contentSelector : null, // not really a selector. :) it's whatever the method was called on..
+ extraScrollPx : 150,
+ itemSelector : "div.post",
+ animate : false,
+ localMode : false,
+ bufferPx : 40,
+ errorCallback : function(){}
+ },
+ loadingImg : undefined,
+ loadingMsg : undefined,
+ container : undefined,
+ currPage : 1,
+ currDOMChunk : null, // defined in setup()'s load()
+ isDuringAjax : false,
+ isInvalidPage : false,
+ isDone : false // for when it goes all the way through the archive.
+ };
+
+
+
+})(jQuery);
diff --git a/plugins/InfiniteScroll/jquery.infinitescroll.min.js b/plugins/InfiniteScroll/jquery.infinitescroll.min.js
new file mode 100644
index 000000000..04c75c456
--- /dev/null
+++ b/plugins/InfiniteScroll/jquery.infinitescroll.min.js
@@ -0,0 +1,8 @@
+/*
+// Infinite Scroll jQuery plugin
+// copyright Paul Irish, licensed GPL & MIT
+// version 1.2.090804
+
+// home and docs: http://www.infinite-scroll.com
+*/
+(function(A){A.fn.infinitescroll=function(N,L){function E(){if(B.debug){window.console&&console.log.call(console,arguments)}}function G(P){for(var O in P){if(O.indexOf&&O.indexOf("Selector")&&A(P[O]).length===0){E("Your "+O+" found no elements.");return false}return true}}function K(O){O.match(C)?O.match(C)[2]:O;if(O.match(/^(.*?)\b2\b(.*?$)/)){O=O.match(/^(.*?)\b2\b(.*?$)/).slice(1)}else{if(O.match(/^(.*?)2(.*?$)/)){E("Trying backup next selector parse technique. Treacherous waters here, matey.");O=O.match(/^(.*?)2(.*?$)/).slice(1)}else{E("Sorry, we couldn't parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.");H.isInvalidPage=true}}return O}function I(){return B.localMode?(A(H.container)[0].scrollHeight&&A(H.container)[0].scrollHeight):A(document).height()}function F(Q,P){var O=I()-(Q.localMode?A(P.container).scrollTop():(A(P.container).scrollTop()||A(P.container.ownerDocument.body).scrollTop()))-A(Q.localMode?P.container:window).height();E("math:",O,P.pixelsFromNavToBottom);return(O-Q.bufferPx<P.pixelsFromNavToBottom)}function J(){H.loadingMsg.find("img").hide().parent().find("div").html(B.donetext).animate({opacity:1},2000).fadeOut("normal");B.errorCallback()}function D(R,Q,O,S){if(O.isDuringAjax||O.isInvalidPage||O.isDone){return }if(!F(Q,O)){return }O.isDuringAjax=true;O.loadingMsg.appendTo(Q.contentSelector).show();A(Q.navSelector).hide();O.currPage++;E("heading into ajax",R);var P=A(Q.contentSelector).is("table")?A("<tbody/>"):A("<div/>");P.attr("id","infscr-page-"+O.currPage).addClass("infscr-pages").appendTo(Q.contentSelector).load(R.join(O.currPage)+" "+Q.itemSelector,null,function(){if(O.isDone){J();return false}else{if(P.children().length==0){A.event.trigger("ajaxError",[{status:404}])}O.loadingMsg.fadeOut("normal");if(Q.animate){var T=A(window).scrollTop()+A("#infscr-loading").height()+Q.extraScrollPx+"px";A("html,body").animate({scrollTop:T},800,function(){O.isDuringAjax=false})}S.call(P[0]);if(!Q.animate){O.isDuringAjax=false}}})}var B=A.extend({},A.infinitescroll.defaults,N);var H=A.infinitescroll;L=L||function(){};if(!G(B)){return false}H.container=B.localMode?this:document.documentElement;B.contentSelector=B.contentSelector||this;var C=/(.*?\/\/).*?(\/.*)/;var M=A(B.nextSelector).attr("href");if(!M){E("Navigation selector not found");return }M=K(M);if(B.localMode){A(H.container)[0].scrollTop=0}H.pixelsFromNavToBottom=I()+A(H.container).offset().top-A(B.navSelector).offset().top;H.loadingMsg=A('<div id="infscr-loading" style="text-align: center;"><img alt="Loading..." src="'+B.loadingImg+'" /><div>'+B.loadingText+"</div></div>");(new Image()).src=B.loadingImg;A(document).ajaxError(function(P,Q,O){E("Page not found. Self-destructing...");if(Q.status==404){J();H.isDone=true;A(B.localMode?this:window).unbind("scroll.infscr")}});A(B.localMode?this:window).bind("scroll.infscr",function(){D(M,B,H,L)}).trigger("scroll.infscr");return this};A.infinitescroll={defaults:{debug:false,preload:false,nextSelector:"div.navigation a:first",loadingImg:"http://www.infinite-scroll.com/loading.gif",loadingText:"<em>Loading the next set of posts...</em>",donetext:"<em>Congratulations, you've reached the end of the internet.</em>",navSelector:"div.navigation",contentSelector:null,extraScrollPx:150,itemSelector:"div.post",animate:false,localMode:false,bufferPx:40,errorCallback:function(){}},loadingImg:undefined,loadingMsg:undefined,container:undefined,currPage:1,currDOMChunk:null,isDuringAjax:false,isInvalidPage:false,isDone:false}})(jQuery); \ No newline at end of file
diff --git a/plugins/InfiniteScroll/readme.txt b/plugins/InfiniteScroll/readme.txt
new file mode 100644
index 000000000..2428cc69a
--- /dev/null
+++ b/plugins/InfiniteScroll/readme.txt
@@ -0,0 +1,6 @@
+Infinite Scroll adds the following functionality to your StatusNet installation: When a user scrolls towards the bottom of the page, the next page of notices is automatically retrieved and appended. This means they never need to click "Next Page", which dramatically increases stickiness.
+
+Installation
+============
+Add "addPlugin('InfiniteScroll');" to the bottom of your config.php
+That's it!
diff --git a/plugins/LinkbackPlugin.php b/plugins/LinkbackPlugin.php
index 93a0294c4..60f7a60c7 100644
--- a/plugins/LinkbackPlugin.php
+++ b/plugins/LinkbackPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to do linkbacks for notices containing links
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET')) {
exit(1);
}
@@ -42,10 +42,10 @@ define('LINKBACKPLUGIN_VERSION', '0.1');
* are URLs, we test each URL to see if it supports any
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Event
*/
@@ -75,6 +75,8 @@ class LinkbackPlugin extends Plugin
function linkbackUrl($url)
{
+ common_log(LOG_DEBUG,"Attempting linkback for " . $url);
+
$orig = $url;
$url = htmlspecialchars_decode($orig);
$scheme = parse_url($url, PHP_URL_SCHEME);
@@ -134,15 +136,20 @@ class LinkbackPlugin extends Plugin
"User-Agent: " . $this->userAgent(),
'content' => $request)));
$file = file_get_contents($endpoint, false, $context);
- $response = xmlrpc_decode($file);
- if (xmlrpc_is_fault($response)) {
+ if (!$file) {
common_log(LOG_WARNING,
+ "Pingback request failed for '$url' ($endpoint)");
+ } else {
+ $response = xmlrpc_decode($file);
+ if (xmlrpc_is_fault($response)) {
+ common_log(LOG_WARNING,
"Pingback error for '$url' ($endpoint): ".
"$response[faultString] ($response[faultCode])");
- } else {
- common_log(LOG_INFO,
+ } else {
+ common_log(LOG_INFO,
"Pingback success for '$url' ($endpoint): ".
"'$response'");
+ }
}
}
@@ -225,6 +232,6 @@ class LinkbackPlugin extends Plugin
function userAgent()
{
return 'LinkbackPlugin/'.LINKBACKPLUGIN_VERSION .
- ' Laconica/' . LACONICA_VERSION;
+ ' StatusNet/' . STATUSNET_VERSION;
}
}
diff --git a/plugins/Meteor/MeteorPlugin.php b/plugins/Meteor/MeteorPlugin.php
index d54d565bd..5b345d7c2 100644
--- a/plugins/Meteor/MeteorPlugin.php
+++ b/plugins/Meteor/MeteorPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to do "real time" updates using Comet/Bayeux
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -37,10 +37,10 @@ require_once INSTALLDIR.'/plugins/Realtime/RealtimePlugin.php';
* Plugin to do realtime updates using Meteor
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class MeteorPlugin extends RealtimePlugin
diff --git a/plugins/Meteor/meteorupdater.js b/plugins/Meteor/meteorupdater.js
index 2e688336f..9ce68775b 100644
--- a/plugins/Meteor/meteorupdater.js
+++ b/plugins/Meteor/meteorupdater.js
@@ -1,5 +1,6 @@
-// update the local timeline from a Meteor server
-//
+// Update the local timeline from a Meteor server
+// XXX: If @a is subscribed to @b, @a should get @b's notices in @a's Personal timeline.
+// Do Replies timeline.
var MeteorUpdater = function()
{
diff --git a/plugins/PiwikAnalyticsPlugin.php b/plugins/PiwikAnalyticsPlugin.php
index dc3c7c37f..54faa0bdb 100644
--- a/plugins/PiwikAnalyticsPlugin.php
+++ b/plugins/PiwikAnalyticsPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to use Piwik Analytics
*
@@ -20,15 +20,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @author Tobias Diekershoff <tobias.diekershoff@gmx.net>
- * @copyright 2008 Control Yourself, Inc.
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET')) {
exit(1);
}
@@ -38,30 +38,24 @@ if (!defined('LACONICA')) {
* This plugin will spoot out the correct JavaScript spell to invoke
* Piwik Analytics on a page.
*
- * To use this plugin please add the following three lines to your config.php
+ * To use this plugin add the following to your config.php
*
- * require_once('plugins/PiwikAnalyticsPlugin.php');
- * $pa = new PiwikAnalyticsPlugin("example.com/piwik/","id");
+ * addPlugin('PiwikAnalytics', array('piwikroot' => 'example.com/piwik/',
+ * 'piwikId' => 'id'));
*
- * exchange example.com/piwik/ with the url to your piwik installation and
- * make sure you don't forget the final /
- * exchange id with the ID your laconica installation has in your Piwik analytics
+ * Replace 'example.com/piwik/' with the URL to your Piwik installation and
+ * make sure you don't forget the final /.
+ * Replace 'id' with the ID your statusnet installation has in your Piwik
+ * analytics setup - for example '8'.
*
- * @category Plugin
- * @package Laconica
- * @author Tobias Diekershoff <tobias.diekershoff@gmx.net>
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
- *
- * @see Event
*/
class PiwikAnalyticsPlugin extends Plugin
{
/** the base of your Piwik installation */
- var $piwikroot = null;
- /** the Piwik Id of your laconica installation */
- var $piwikId = null;
+ public $piwikroot = null;
+ /** the Piwik Id of your statusnet installation */
+ public $piwikId = null;
/**
* constructor
@@ -73,7 +67,7 @@ class PiwikAnalyticsPlugin extends Plugin
function __construct($root=null, $id=null)
{
$this->piwikroot = $root;
- $this->piwikid = $id;
+ $this->piwikId = $id;
parent::__construct();
}
@@ -96,7 +90,7 @@ document.write(unescape("%3Cscript src='" + pkBaseURL + "piwik.js' type='text/ja
</script>
<script type="text/javascript">
try {
- var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", 4);
+ var piwikTracker = Piwik.getTracker(pkBaseURL + "piwik.php", {$this->piwikId});
piwikTracker.trackPageView();
piwikTracker.enableLinkTracking();
} catch( err ) {}
@@ -108,4 +102,4 @@ ENDOFPIWIK;
$action->raw($piwikCode);
return true;
}
-} \ No newline at end of file
+}
diff --git a/plugins/Realtime/RealtimePlugin.php b/plugins/Realtime/RealtimePlugin.php
index 507f0194d..0f0d0f9f4 100644
--- a/plugins/Realtime/RealtimePlugin.php
+++ b/plugins/Realtime/RealtimePlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Superclass for plugins that do "real time" updates of timelines using Ajax
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET') && !defined('LACONICA')) {
exit(1);
}
@@ -38,10 +38,10 @@ if (!defined('LACONICA')) {
* this superclass extracts out some of the common functionality
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class RealtimePlugin extends Plugin
@@ -50,6 +50,11 @@ class RealtimePlugin extends Plugin
protected $favorurl = null;
protected $deleteurl = null;
+ /**
+ * When it's time to initialize the plugin, calculate and
+ * pass the URLs we need.
+ */
+
function onInitializePlugin()
{
$this->replyurl = common_local_url('newnotice');
@@ -57,36 +62,31 @@ class RealtimePlugin extends Plugin
// FIXME: need to find a better way to pass this pattern in
$this->deleteurl = common_local_url('deletenotice',
array('notice' => '0000000000'));
+ return true;
}
function onEndShowScripts($action)
{
- $path = null;
+ $timeline = $this->_getTimeline($action);
- switch ($action->trimmed('action')) {
- case 'public':
- $path = array('public');
- break;
- case 'tag':
- $tag = $action->trimmed('tag');
- if (!empty($tag)) {
- $path = array('tag', $tag);
- } else {
- return true;
- }
- break;
- default:
+ // If there's not a timeline on this page,
+ // just return true
+
+ if (empty($timeline)) {
return true;
}
- $timeline = $this->_pathToChannel($path);
+ $base = $action->selfUrl();
+ if (mb_strstr($base, '?')) {
+ $url = $base . '&realtime=1';
+ } else {
+ $url = $base . '?realtime=1';
+ }
$scripts = $this->_getScripts();
foreach ($scripts as $script) {
- $action->element('script', array('type' => 'text/javascript',
- 'src' => $script),
- ' ');
+ $action->script($script);
}
$user = common_current_user();
@@ -97,10 +97,22 @@ class RealtimePlugin extends Plugin
$user_id = 0;
}
+ if ($action->boolean('realtime')) {
+ $realtimeUI = ' RealtimeUpdate.initPopupWindow();';
+ }
+ else {
+ $iconurl = common_path('plugins/Realtime/icon_external.gif');
+ $realtimeUI = ' RealtimeUpdate.addPopup("'.$url.'", "'.$timeline.'", "'. $iconurl .'");';
+ }
+
$action->elementStart('script', array('type' => 'text/javascript'));
- $action->raw("$(document).ready(function() { ");
- $action->raw($this->_updateInitialize($timeline, $user_id));
- $action->raw(" });");
+
+ $script = ' $(document).ready(function() { '.
+ $realtimeUI.
+ $this->_updateInitialize($timeline, $user_id).
+ '}); ';
+ $action->raw($script);
+
$action->elementEnd('script');
return true;
@@ -110,13 +122,23 @@ class RealtimePlugin extends Plugin
{
$paths = array();
- // XXX: Add other timelines; this is just for the public one
+ // Add to the author's timeline
+
+ $user = User::staticGet('id', $notice->profile_id);
+
+ if (!empty($user)) {
+ $paths[] = array('showstream', $user->nickname);
+ }
+
+ // Add to the public timeline
if ($notice->is_local ||
($notice->is_local == 0 && !common_config('public', 'localonly'))) {
$paths[] = array('public');
}
+ // Add to the tags timeline
+
$tags = $this->getNoticeTags($notice);
if (!empty($tags)) {
@@ -125,6 +147,46 @@ class RealtimePlugin extends Plugin
}
}
+ // Add to inbox timelines
+ // XXX: do a join
+
+ $inbox = new Notice_inbox();
+ $inbox->notice_id = $notice->id;
+
+ if ($inbox->find()) {
+ while ($inbox->fetch()) {
+ $user = User::staticGet('id', $inbox->user_id);
+ $paths[] = array('all', $user->nickname);
+ }
+ }
+
+ // Add to the replies timeline
+
+ $reply = new Reply();
+ $reply->notice_id = $notice->id;
+
+ if ($reply->find()) {
+ while ($reply->fetch()) {
+ $user = User::staticGet('id', $reply->profile_id);
+ if (!empty($user)) {
+ $paths[] = array('replies', $user->nickname);
+ }
+ }
+ }
+
+ // Add to the group timeline
+ // XXX: join
+
+ $gi = new Group_inbox();
+ $gi->notice_id = $notice->id;
+
+ if ($gi->find()) {
+ while ($gi->fetch()) {
+ $ug = User_group::staticGet('id', $gi->group_id);
+ $paths[] = array('showgroup', $ug->nickname);
+ }
+ }
+
if (count($paths) > 0) {
$json = $this->noticeAsJson($notice);
@@ -142,6 +204,36 @@ class RealtimePlugin extends Plugin
return true;
}
+ function onStartShowBody($action)
+ {
+ $realtime = $action->boolean('realtime');
+ if (!$realtime) {
+ return true;
+ }
+
+ $action->elementStart('body',
+ (common_current_user()) ? array('id' => $action->trimmed('action'),
+ 'class' => 'user_in')
+ : array('id' => $action->trimmed('action')));
+
+ // XXX hack to deal with JS that tries to get the
+ // root url from page output
+
+ $action->elementStart('address');
+ $action->element('a', array('class' => 'url',
+ 'href' => common_local_url('public')),
+ '');
+ $action->elementEnd('address');
+
+ if (common_logged_in()) {
+ $action->showNoticeForm();
+ }
+
+ $action->showContentBlock();
+ $action->elementEnd('body');
+ return false; // No default processing
+ }
+
function noticeAsJson($notice)
{
// FIXME: this code should be abstracted to a neutral third
@@ -201,8 +293,8 @@ class RealtimePlugin extends Plugin
function _getScripts()
{
- return array(common_path('plugins/Realtime/realtimeupdate.js'),
- common_path('plugins/Realtime/json2.js'));
+ return array('plugins/Realtime/realtimeupdate.js',
+ 'plugins/Realtime/json2.js');
}
function _updateInitialize($timeline, $user_id)
@@ -226,4 +318,41 @@ class RealtimePlugin extends Plugin
{
return '';
}
+
+ function _getTimeline($action)
+ {
+ $path = null;
+ $timeline = null;
+
+ $action_name = $action->trimmed('action');
+
+ switch ($action_name) {
+ case 'public':
+ $path = array('public');
+ break;
+ case 'tag':
+ $tag = $action->trimmed('tag');
+ if (!empty($tag)) {
+ $path = array('tag', $tag);
+ }
+ break;
+ case 'showstream':
+ case 'all':
+ case 'replies':
+ case 'showgroup':
+ $nickname = common_canonical_nickname($action->trimmed('nickname'));
+ if (!empty($nickname)) {
+ $path = array($action_name, $nickname);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!empty($path)) {
+ $timeline = $this->_pathToChannel($path);
+ }
+
+ return $timeline;
+ }
}
diff --git a/plugins/Realtime/icon_external.gif b/plugins/Realtime/icon_external.gif
new file mode 100644
index 000000000..c4118d53b
--- /dev/null
+++ b/plugins/Realtime/icon_external.gif
Binary files differ
diff --git a/plugins/Realtime/jquery.getUrlParam.js b/plugins/Realtime/jquery.getUrlParam.js
new file mode 100644
index 000000000..e8f73eb47
--- /dev/null
+++ b/plugins/Realtime/jquery.getUrlParam.js
@@ -0,0 +1,72 @@
+/* Copyright (c) 2006-2007 Mathias Bank (http://www.mathias-bank.de)
+ * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
+ * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
+ *
+ * Version 2.1
+ *
+ * Thanks to
+ * Hinnerk Ruemenapf - http://hinnerk.ruemenapf.de/ for bug reporting and fixing.
+ * Tom Leonard for some improvements
+ *
+ */
+jQuery.fn.extend({
+/**
+* Returns get parameters.
+*
+* If the desired param does not exist, null will be returned
+*
+* To get the document params:
+* @example value = $(document).getUrlParam("paramName");
+*
+* To get the params of a html-attribut (uses src attribute)
+* @example value = $('#imgLink').getUrlParam("paramName");
+*/
+ getUrlParam: function(strParamName){
+ strParamName = escape(unescape(strParamName));
+
+ var returnVal = new Array();
+ var qString = null;
+
+ if ($(this).attr("nodeName")=="#document") {
+ //document-handler
+
+ if (window.location.search.search(strParamName) > -1 ){
+
+ qString = window.location.search.substr(1,window.location.search.length).split("&");
+ }
+
+ } else if ($(this).attr("src")!="undefined") {
+
+ var strHref = $(this).attr("src")
+ if ( strHref.indexOf("?") > -1 ){
+ var strQueryString = strHref.substr(strHref.indexOf("?")+1);
+ qString = strQueryString.split("&");
+ }
+ } else if ($(this).attr("href")!="undefined") {
+
+ var strHref = $(this).attr("href")
+ if ( strHref.indexOf("?") > -1 ){
+ var strQueryString = strHref.substr(strHref.indexOf("?")+1);
+ qString = strQueryString.split("&");
+ }
+ } else {
+ return null;
+ }
+
+
+ if (qString==null) return null;
+
+
+ for (var i=0;i<qString.length; i++){
+ if (escape(unescape(qString[i].split("=")[0])) == strParamName){
+ returnVal.push(qString[i].split("=")[1]);
+ }
+
+ }
+
+
+ if (returnVal.length==0) return null;
+ else if (returnVal.length==1) return returnVal[0];
+ else return returnVal;
+ }
+}); \ No newline at end of file
diff --git a/plugins/Realtime/realtimeupdate.js b/plugins/Realtime/realtimeupdate.js
index d55db5859..4cd68a816 100644
--- a/plugins/Realtime/realtimeupdate.js
+++ b/plugins/Realtime/realtimeupdate.js
@@ -1,8 +1,8 @@
// add a notice encoded as JSON into the current timeline
//
+// TODO: i18n
RealtimeUpdate = {
-
_userid: 0,
_replyurl: '',
_favorurl: '',
@@ -10,10 +10,22 @@ RealtimeUpdate = {
init: function(userid, replyurl, favorurl, deleteurl)
{
- RealtimeUpdate._userid = userid;
- RealtimeUpdate._replyurl = replyurl;
- RealtimeUpdate._favorurl = favorurl;
- RealtimeUpdate._deleteurl = deleteurl;
+ RealtimeUpdate._userid = userid;
+ RealtimeUpdate._replyurl = replyurl;
+ RealtimeUpdate._favorurl = favorurl;
+ RealtimeUpdate._deleteurl = deleteurl;
+
+ $(window).blur(function() {
+ $('#notices_primary .notice').css({
+ 'border-top-color':$('#notices_primary .notice:last').css('border-top-color'),
+ 'border-top-style':'dotted'
+ });
+
+ $('#notices_primary .notice:first').css({
+ 'border-top-color':'#AAAAAA',
+ 'border-top-style':'solid'
+ });
+ });
},
receive: function(data)
@@ -21,13 +33,13 @@ RealtimeUpdate = {
id = data.id;
// Don't add it if it already exists
-
+ //
if ($("#notice-"+id).length > 0) {
return;
}
var noticeItem = RealtimeUpdate.makeNoticeItem(data);
- $("#notices_primary .notices").prepend(noticeItem, true);
+ $("#notices_primary .notices").prepend(noticeItem);
$("#notices_primary .notice:first").css({display:"none"});
$("#notices_primary .notice:first").fadeIn(1000);
NoticeReply();
@@ -50,30 +62,19 @@ RealtimeUpdate = {
"<p class=\"entry-content\">"+html+"</p>"+
"</div>"+
"<div class=\"entry-content\">"+
- "<dl class=\"timestamp\">"+
- "<dt>Published</dt>"+
- "<dd>"+
- "<a rel=\"bookmark\" href=\""+data['url']+"\" >"+
+ "<a class=\"timestamp\" rel=\"bookmark\" href=\""+data['url']+"\" >"+
"<abbr class=\"published\" title=\""+data['created_at']+"\">a few seconds ago</abbr>"+
"</a> "+
- "</dd>"+
- "</dl>"+
- "<dl class=\"device\">"+
- "<dt>From</dt> "+
- "<dd>"+source+"</dd>"+ // may have a link, I think
- "</dl>";
-
+ "<span class=\"source\">"+
+ "from "+
+ "<span class=\"device\">"+source+"</span>"+ // may have a link
+ "</span>";
if (data['in_reply_to_status_id']) {
- ni = ni+" <dl class=\"response\">"+
- "<dt>To</dt>"+
- "<dd>"+
- "<a href=\""+data['in_reply_to_status_url']+"\" rel=\"in-reply-to\">in reply to</a>"+
- "</dd>"+
- "</dl>";
+ ni = ni+" <a class=\"response\" href=\""+data['in_reply_to_status_url']+"\">in context</a>";
}
ni = ni+"</div>"+
- "<div class=\"notice-options\">";
+ "<div class=\"notice-options\">";
if (RealtimeUpdate._userid != 0) {
var input = $("form#form_notice fieldset input#token");
@@ -95,12 +96,12 @@ RealtimeUpdate = {
var ff;
ff = "<form id=\"favor-"+id+"\" class=\"form_favor\" method=\"post\" action=\""+RealtimeUpdate._favorurl+"\">"+
- "<fieldset>"+
- "<legend>Favor this notice</legend>"+ // XXX: i18n
+ "<fieldset>"+
+ "<legend>Favor this notice</legend>"+
"<input name=\"token-"+id+"\" type=\"hidden\" id=\"token-"+id+"\" value=\""+session_key+"\"/>"+
"<input name=\"notice\" type=\"hidden\" id=\"notice-n"+id+"\" value=\""+id+"\"/>"+
"<input type=\"submit\" id=\"favor-submit-"+id+"\" name=\"favor-submit-"+id+"\" class=\"submit\" value=\"Favor\" title=\"Favor this notice\"/>"+
- "</fieldset>"+
+ "</fieldset>"+
"</form>";
return ff;
},
@@ -108,28 +109,68 @@ RealtimeUpdate = {
makeReplyLink: function(id, nickname)
{
var rl;
- rl = "<dl class=\"notice_reply\">"+
- "<dt>Reply to this notice</dt>"+
- "<dd>"+
- "<a href=\""+RealtimeUpdate._replyurl+"?replyto="+nickname+"\" title=\"Reply to this notice\">Reply <span class=\"notice_id\">"+id+"</span>"+
- "</a>"+
- "</dd>"+
- "</dl>";
+ rl = "<a class=\"notice_reply\" href=\""+RealtimeUpdate._replyurl+"?replyto="+nickname+"\" title=\"Reply to this notice\">Reply <span class=\"notice_id\">"+id+"</span></a>";
return rl;
- },
+ },
makeDeleteLink: function(id)
{
var dl, delurl;
delurl = RealtimeUpdate._deleteurl.replace("0000000000", id);
- dl = "<dl class=\"notice_delete\">"+
- "<dt>Delete this notice</dt>"+
- "<dd>"+
- "<a href=\""+delurl+"\" title=\"Delete this notice\">Delete</a>"+
- "</dd>"+
- "</dl>";
+ dl = "<a class=\"notice_delete\" href=\""+delurl+"\" title=\"Delete this notice\">Delete</a>";
return dl;
},
+
+ addPopup: function(url, timeline, iconurl)
+ {
+ $('#content').prepend('<button id="realtime_timeline" title="Pop up in a window">Pop up</button>');
+
+ $('#realtime_timeline').css({
+ 'margin':'0 0 18px 0',
+ 'background':'transparent url('+ iconurl + ') no-repeat 0% 30%',
+ 'padding':'0 0 0 20px',
+ 'display':'block',
+ 'float':'right',
+ 'border':'none',
+ 'cursor':'pointer',
+ 'color':$("a").css("color"),
+ 'font-weight':'bold',
+ 'font-size':'1em'
+ });
+
+ $('#realtime_timeline').click(function() {
+ window.open(url,
+ timeline,
+ 'toolbar=no,resizable=yes,scrollbars=yes,status=yes');
+
+ return false;
+ });
+ },
+
+ initPopupWindow: function()
+ {
+ window.resizeTo(500, 550);
+ $('address').hide();
+ $('#content').css({'width':'93.5%'});
+
+ $('#form_notice').css({
+ 'margin':'18px 0 18px 1.795%',
+ 'width':'93%',
+ 'max-width':'451px'
+ });
+
+ $('#form_notice label[for=notice_data-text], h1').css({'display': 'none'});
+
+ $('.notices li:first-child').css({'border-top-color':'transparent'});
+
+ $('#form_notice label[for="notice_data-attach"], #form_notice #notice_data-attach').css({'top':'0'});
+
+ $('#form_notice #notice_data-attach').css({
+ 'left':'auto',
+ 'right':'0'
+ });
+ }
}
+
diff --git a/plugins/TemplatePlugin.php b/plugins/TemplatePlugin.php
index 03daf6219..cfa051162 100644
--- a/plugins/TemplatePlugin.php
+++ b/plugins/TemplatePlugin.php
@@ -8,14 +8,14 @@
* The method is disabled unless the user is #1, the first user of the system
*
* @category Plugin
- * @package Laconica
+ * @package StatusNet
* @author Brian Hendrickson <brian@megapump.com>
* @copyright 2009 Megapump, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://megapump.com/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET')) {
exit(1);
}
@@ -195,16 +195,16 @@ class TemplatePlugin extends Plugin {
);
// use the PHP template
- // unless laconica config:
+ // unless statusnet config:
// $config['template']['mode'] = 'html';
if (!(common_config('template', 'mode') == 'html')) {
- $tpl_file = 'tpl/index.php';
+ $tpl_file = $this->templateFolder() . '/index.php';
$tags = array_merge($vars,$this->blocks);
include $tpl_file;
return;
}
- $tpl_file = 'tpl/index.html';
+ $tpl_file = $this->templateFolder() . '/index.html';
// read the static template
$output = file_get_contents( $tpl_file );
@@ -236,6 +236,9 @@ class TemplatePlugin extends Plugin {
return true;
}
+ function templateFolder() {
+ return 'tpl';
+ }
// catching the StartShowHTML event to halt the rendering
function onStartShowHTML( &$act ) {
@@ -258,7 +261,7 @@ class TemplatePlugin extends Plugin {
* parameter "template", containing the new template code
*
* @category Plugin
- * @package Laconica
+ * @package StatusNet
* @author Brian Hendrickson <brian@megapump.com>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://megapump.com/
@@ -280,7 +283,7 @@ class TemplateAction extends Action
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// not authenticated, show login form
- header('WWW-Authenticate: Basic realm="Laconica API"');
+ header('WWW-Authenticate: Basic realm="StatusNet API"');
// cancelled the browser login form
$this->clientError(_('Authentication error!'), $code = 401);
@@ -300,7 +303,7 @@ class TemplateAction extends Action
$this->clientError(_('only User #1 can update the template'), $code = 401);
// open the old template
- $tpl_file = 'tpl/index.html';
+ $tpl_file = $this->templateFolder() . '/index.html';
$fp = fopen( $tpl_file, 'w+' );
// overwrite with the new template
@@ -323,13 +326,13 @@ class TemplateAction extends Action
}
/**
- * Function for retrieving a laconica display section
+ * Function for retrieving a statusnet display section
*
* requires one parameter, the name of the section
* section names are listed in the comments of the TemplatePlugin class
*
* @category Plugin
- * @package Laconica
+ * @package StatusNet
* @author Brian Hendrickson <brian@megapump.com>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://megapump.com/
diff --git a/plugins/WikiHashtagsPlugin.php b/plugins/WikiHashtagsPlugin.php
index 6d186a5fe..0c5649aa4 100644
--- a/plugins/WikiHashtagsPlugin.php
+++ b/plugins/WikiHashtagsPlugin.php
@@ -1,6 +1,6 @@
<?php
/**
- * Laconica, the distributed open-source microblogging tool
+ * StatusNet, the distributed open-source microblogging tool
*
* Plugin to show WikiHashtags content in the sidebar
*
@@ -20,14 +20,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2008 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
-if (!defined('LACONICA')) {
+if (!defined('STATUSNET')) {
exit(1);
}
@@ -37,10 +37,10 @@ define('WIKIHASHTAGSPLUGIN_VERSION', '0.1');
* Plugin to use WikiHashtags
*
* @category Plugin
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*
* @see Event
*/
@@ -104,6 +104,6 @@ class WikiHashtagsPlugin extends Plugin
function userAgent()
{
return 'WikiHashtagsPlugin/'.WIKIHASHTAGSPLUGIN_VERSION .
- ' Laconica/' . LACONICA_VERSION;
+ ' StatusNet/' . STATUSNET_VERSION;
}
}
diff --git a/plugins/recaptcha/LICENSE b/plugins/recaptcha/LICENSE
new file mode 100644
index 000000000..b612f71f0
--- /dev/null
+++ b/plugins/recaptcha/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
+AUTHORS:
+ Mike Crawford
+ Ben Maurer
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/plugins/recaptcha/README b/plugins/recaptcha/README
new file mode 100644
index 000000000..b996f96cc
--- /dev/null
+++ b/plugins/recaptcha/README
@@ -0,0 +1,23 @@
+StatusNet reCAPTCHA plugin 0.2 8/3/09
+====================================
+Adds a captcha to your registration page to reduce automated spam bots registering.
+
+Use:
+1. Get an API key from http://recaptcha.net
+
+2. In config.php add:
+include_once('plugins/recaptcha/recaptcha.php');
+$captcha = new recaptcha(publickey, privatekey, showErrors);
+
+Changelog
+=========
+0.1 initial release
+0.2 Work around for webkit browsers
+
+reCAPTCHA README
+================
+
+The reCAPTCHA PHP Lirary helps you use the reCAPTCHA API. Documentation
+for this library can be found at
+
+ http://recaptcha.net/plugins/php
diff --git a/plugins/recaptcha/recaptcha.php b/plugins/recaptcha/recaptcha.php
new file mode 100644
index 000000000..94cf0ccd1
--- /dev/null
+++ b/plugins/recaptcha/recaptcha.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Plugin to show reCaptcha when a user registers
+ *
+ * PHP version 5
+ *
+ * LICENCE: 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 <http://www.gnu.org/licenses/>.
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Eric Helgeson <erichelgeson@gmail.com>
+ * @copyright 2009
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+define('RECAPTCHA', '0.2');
+
+class recaptcha extends Plugin
+{
+ var $private_key;
+ var $public_key;
+ var $display_errors;
+ var $failed;
+ var $ssl;
+
+ function __construct($public_key, $private_key, $display_errors=false)
+ {
+ parent::__construct();
+ require_once(INSTALLDIR.'/plugins/recaptcha/recaptchalib.php');
+ $this->public_key = $public_key;
+ $this->private_key = $private_key;
+ $this->display_errors = $display_errors;
+ }
+
+ function checkssl(){
+ if(common_config('site', 'ssl') === 'sometimes' || common_config('site', 'ssl') === 'always') {
+ return true;
+ }
+ return false;
+ }
+
+ function onStartShowHTML($action)
+ {
+ //XXX: Horrible hack to make Safari, FF2, and Chrome work with
+ //reChapcha. reChapcha beaks xhtml strict
+ header('Content-Type: text/html');
+
+ $action->extraHeaders();
+
+ $action->startXML('html');
+
+ $action->raw('<style type="text/css">#recaptcha_area{float:left;}</style>');
+ return false;
+ }
+
+ function onEndRegistrationFormData($action)
+ {
+ $action->elementStart('li');
+ $action->raw('<label for="recaptcha_area">Captcha</label>');
+ if($this->checkssl() === true){
+ $action->raw(recaptcha_get_html($this->public_key), null, true);
+ } else {
+ $action->raw(recaptcha_get_html($this->public_key));
+ }
+ $action->elementEnd('li');
+ return true;
+ }
+
+ function onStartRegistrationTry($action)
+ {
+ $resp = recaptcha_check_answer ($this->private_key,
+ $_SERVER["REMOTE_ADDR"],
+ $action->trimmed('recaptcha_challenge_field'),
+ $action->trimmed('recaptcha_response_field'));
+
+ if (!$resp->is_valid)
+ {
+ if($this->display_errors)
+ {
+ $action->showForm ("(reCAPTCHA said: " . $resp->error . ")");
+ }
+ $action->showForm("Captcha does not match!");
+ return false;
+ }
+ }
+}
diff --git a/plugins/recaptcha/recaptchalib.php b/plugins/recaptcha/recaptchalib.php
new file mode 100644
index 000000000..897c50981
--- /dev/null
+++ b/plugins/recaptcha/recaptchalib.php
@@ -0,0 +1,277 @@
+<?php
+/*
+ * This is a PHP library that handles calling reCAPTCHA.
+ * - Documentation and latest version
+ * http://recaptcha.net/plugins/php/
+ * - Get a reCAPTCHA API Key
+ * http://recaptcha.net/api/getkey
+ * - Discussion group
+ * http://groups.google.com/group/recaptcha
+ *
+ * Copyright (c) 2007 reCAPTCHA -- http://recaptcha.net
+ * AUTHORS:
+ * Mike Crawford
+ * Ben Maurer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * The reCAPTCHA server URL's
+ */
+define("RECAPTCHA_API_SERVER", "http://api.recaptcha.net");
+define("RECAPTCHA_API_SECURE_SERVER", "https://api-secure.recaptcha.net");
+define("RECAPTCHA_VERIFY_SERVER", "api-verify.recaptcha.net");
+
+/**
+ * Encodes the given data into a query string format
+ * @param $data - array of string elements to be encoded
+ * @return string - encoded request
+ */
+function _recaptcha_qsencode ($data) {
+ $req = "";
+ foreach ( $data as $key => $value )
+ $req .= $key . '=' . urlencode( stripslashes($value) ) . '&';
+
+ // Cut the last '&'
+ $req=substr($req,0,strlen($req)-1);
+ return $req;
+}
+
+
+
+/**
+ * Submits an HTTP POST to a reCAPTCHA server
+ * @param string $host
+ * @param string $path
+ * @param array $data
+ * @param int port
+ * @return array response
+ */
+function _recaptcha_http_post($host, $path, $data, $port = 80) {
+
+ $req = _recaptcha_qsencode ($data);
+
+ $http_request = "POST $path HTTP/1.0\r\n";
+ $http_request .= "Host: $host\r\n";
+ $http_request .= "Content-Type: application/x-www-form-urlencoded;\r\n";
+ $http_request .= "Content-Length: " . strlen($req) . "\r\n";
+ $http_request .= "User-Agent: reCAPTCHA/PHP\r\n";
+ $http_request .= "\r\n";
+ $http_request .= $req;
+
+ $response = '';
+ if( false == ( $fs = @fsockopen($host, $port, $errno, $errstr, 10) ) ) {
+ die ('Could not open socket');
+ }
+
+ fwrite($fs, $http_request);
+
+ while ( !feof($fs) )
+ $response .= fgets($fs, 1160); // One TCP-IP packet
+ fclose($fs);
+ $response = explode("\r\n\r\n", $response, 2);
+
+ return $response;
+}
+
+
+
+/**
+ * Gets the challenge HTML (javascript and non-javascript version).
+ * This is called from the browser, and the resulting reCAPTCHA HTML widget
+ * is embedded within the HTML form it was called from.
+ * @param string $pubkey A public key for reCAPTCHA
+ * @param string $error The error given by reCAPTCHA (optional, default is null)
+ * @param boolean $use_ssl Should the request be made over ssl? (optional, default is false)
+
+ * @return string - The HTML to be embedded in the user's form.
+ */
+function recaptcha_get_html ($pubkey, $error = null, $use_ssl = false)
+{
+ if ($pubkey == null || $pubkey == '') {
+ die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>");
+ }
+
+ if ($use_ssl) {
+ $server = RECAPTCHA_API_SECURE_SERVER;
+ } else {
+ $server = RECAPTCHA_API_SERVER;
+ }
+
+ $errorpart = "";
+ if ($error) {
+ $errorpart = "&amp;error=" . $error;
+ }
+ return '<script type="text/javascript" src="'. $server . '/challenge?k=' . $pubkey . $errorpart . '"></script>
+
+ <noscript>
+ <iframe src="'. $server . '/noscript?k=' . $pubkey . $errorpart . '" height="300" width="500" frameborder="0"></iframe><br/>
+ <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
+ <input type="hidden" name="recaptcha_response_field" value="manual_challenge"/>
+ </noscript>';
+}
+
+
+
+
+/**
+ * A ReCaptchaResponse is returned from recaptcha_check_answer()
+ */
+class ReCaptchaResponse {
+ var $is_valid;
+ var $error;
+}
+
+
+/**
+ * Calls an HTTP POST function to verify if the user's guess was correct
+ * @param string $privkey
+ * @param string $remoteip
+ * @param string $challenge
+ * @param string $response
+ * @param array $extra_params an array of extra variables to post to the server
+ * @return ReCaptchaResponse
+ */
+function recaptcha_check_answer ($privkey, $remoteip, $challenge, $response, $extra_params = array())
+{
+ if ($privkey == null || $privkey == '') {
+ die ("To use reCAPTCHA you must get an API key from <a href='http://recaptcha.net/api/getkey'>http://recaptcha.net/api/getkey</a>");
+ }
+
+ if ($remoteip == null || $remoteip == '') {
+ die ("For security reasons, you must pass the remote ip to reCAPTCHA");
+ }
+
+
+
+ //discard spam submissions
+ if ($challenge == null || strlen($challenge) == 0 || $response == null || strlen($response) == 0) {
+ $recaptcha_response = new ReCaptchaResponse();
+ $recaptcha_response->is_valid = false;
+ $recaptcha_response->error = 'incorrect-captcha-sol';
+ return $recaptcha_response;
+ }
+
+ $response = _recaptcha_http_post (RECAPTCHA_VERIFY_SERVER, "/verify",
+ array (
+ 'privatekey' => $privkey,
+ 'remoteip' => $remoteip,
+ 'challenge' => $challenge,
+ 'response' => $response
+ ) + $extra_params
+ );
+
+ $answers = explode ("\n", $response [1]);
+ $recaptcha_response = new ReCaptchaResponse();
+
+ if (trim ($answers [0]) == 'true') {
+ $recaptcha_response->is_valid = true;
+ }
+ else {
+ $recaptcha_response->is_valid = false;
+ $recaptcha_response->error = $answers [1];
+ }
+ return $recaptcha_response;
+
+}
+
+/**
+ * gets a URL where the user can sign up for reCAPTCHA. If your application
+ * has a configuration page where you enter a key, you should provide a link
+ * using this function.
+ * @param string $domain The domain where the page is hosted
+ * @param string $appname The name of your application
+ */
+function recaptcha_get_signup_url ($domain = null, $appname = null) {
+ return "http://recaptcha.net/api/getkey?" . _recaptcha_qsencode (array ('domain' => $domain, 'app' => $appname));
+}
+
+function _recaptcha_aes_pad($val) {
+ $block_size = 16;
+ $numpad = $block_size - (strlen ($val) % $block_size);
+ return str_pad($val, strlen ($val) + $numpad, chr($numpad));
+}
+
+/* Mailhide related code */
+
+function _recaptcha_aes_encrypt($val,$ky) {
+ if (! function_exists ("mcrypt_encrypt")) {
+ die ("To use reCAPTCHA Mailhide, you need to have the mcrypt php module installed.");
+ }
+ $mode=MCRYPT_MODE_CBC;
+ $enc=MCRYPT_RIJNDAEL_128;
+ $val=_recaptcha_aes_pad($val);
+ return mcrypt_encrypt($enc, $ky, $val, $mode, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
+}
+
+
+function _recaptcha_mailhide_urlbase64 ($x) {
+ return strtr(base64_encode ($x), '+/', '-_');
+}
+
+/* gets the reCAPTCHA Mailhide url for a given email, public key and private key */
+function recaptcha_mailhide_url($pubkey, $privkey, $email) {
+ if ($pubkey == '' || $pubkey == null || $privkey == "" || $privkey == null) {
+ die ("To use reCAPTCHA Mailhide, you have to sign up for a public and private key, " .
+ "you can do so at <a href='http://mailhide.recaptcha.net/apikey'>http://mailhide.recaptcha.net/apikey</a>");
+ }
+
+
+ $ky = pack('H*', $privkey);
+ $cryptmail = _recaptcha_aes_encrypt ($email, $ky);
+
+ return "http://mailhide.recaptcha.net/d?k=" . $pubkey . "&c=" . _recaptcha_mailhide_urlbase64 ($cryptmail);
+}
+
+/**
+ * gets the parts of the email to expose to the user.
+ * eg, given johndoe@example,com return ["john", "example.com"].
+ * the email is then displayed as john...@example.com
+ */
+function _recaptcha_mailhide_email_parts ($email) {
+ $arr = preg_split("/@/", $email );
+
+ if (strlen ($arr[0]) <= 4) {
+ $arr[0] = substr ($arr[0], 0, 1);
+ } else if (strlen ($arr[0]) <= 6) {
+ $arr[0] = substr ($arr[0], 0, 3);
+ } else {
+ $arr[0] = substr ($arr[0], 0, 4);
+ }
+ return $arr;
+}
+
+/**
+ * Gets html to display an email address given a public an private key.
+ * to get a key, go to:
+ *
+ * http://mailhide.recaptcha.net/apikey
+ */
+function recaptcha_mailhide_html($pubkey, $privkey, $email) {
+ $emailparts = _recaptcha_mailhide_email_parts ($email);
+ $url = recaptcha_mailhide_url ($pubkey, $privkey, $email);
+
+ return htmlentities($emailparts[0]) . "<a href='" . htmlentities ($url) .
+ "' onclick=\"window.open('" . htmlentities ($url) . "', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;\" title=\"Reveal this e-mail address\">...</a>@" . htmlentities ($emailparts [1]);
+
+}
+
+
+?>
diff --git a/scripts/allsites.php b/scripts/allsites.php
index d6768c278..cf1419e55 100755
--- a/scripts/allsites.php
+++ b/scripts/allsites.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/commandline.inc b/scripts/commandline.inc
index 3b6ef6098..1573b569d 100644
--- a/scripts/commandline.inc
+++ b/scripts/commandline.inc
@@ -1,7 +1,7 @@
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - a distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -26,7 +26,7 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
exit();
}
-define('LACONICA', true);
+define('STATUSNET', true);
// Set various flags so we don't time out on long-running processes
diff --git a/scripts/createsim.php b/scripts/createsim.php
new file mode 100644
index 000000000..71ed3bf72
--- /dev/null
+++ b/scripts/createsim.php
@@ -0,0 +1,142 @@
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$shortoptions = 'u:n:b:t:x:';
+$longoptions = array('users=', 'notices=', 'subscriptions=', 'tags=', 'prefix=');
+
+$helptext = <<<END_OF_CREATESIM_HELP
+Creates a lot of test users and notices to (loosely) simulate a real server.
+
+ -u --users Number of users (default 100)
+ -n --notices Average notices per user (default 100)
+ -b --subscriptions Average subscriptions per user (default no. users/20)
+ -t --tags Number of distinct hash tags (default 10000)
+ -x --prefix User name prefix (default 'testuser')
+
+END_OF_CREATESIM_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+// XXX: make these command-line options
+
+function newUser($i)
+{
+ global $userprefix;
+ User::register(array('nickname' => sprintf('%s%d', $userprefix, $i),
+ 'password' => sprintf('password%d', $i),
+ 'fullname' => sprintf('Test User %d', $i)));
+}
+
+function newNotice($i, $tagmax)
+{
+ global $userprefix;
+
+ $n = rand(0, $i - 1);
+ $user = User::staticGet('nickname', sprintf('%s%d', $userprefix, $n));
+
+ $is_reply = rand(0, 4);
+
+ $content = 'Test notice content';
+
+ if ($is_reply == 0) {
+ $n = rand(0, $i - 1);
+ $content = "@$userprefix$n " . $content;
+ }
+
+ $has_hash = rand(0, 2);
+
+ if ($has_hash == 0) {
+ $hashcount = rand(0, 2);
+ for ($j = 0; $j < $hashcount; $j++) {
+ $h = rand(0, $tagmax);
+ $content .= " #tag{$h}";
+ }
+ }
+
+ $notice = Notice::saveNew($user->id, $content, 'system');
+}
+
+function newSub($i)
+{
+ global $userprefix;
+ $f = rand(0, $i - 1);
+
+ $fromnick = sprintf('%s%d', $userprefix, $f);
+
+ $from = User::staticGet('nickname', $fromnick);
+
+ if (empty($from)) {
+ throw new Exception("Can't find user '$fromnick'.");
+ }
+
+ $t = rand(0, $i - 1);
+
+ if ($t == $f) {
+ $t++;
+ if ($t > $i - 1) {
+ $t = 0;
+ }
+ }
+
+ $tunic = sprintf('%s%d', $userprefix, $t);
+
+ $to = User::staticGet('nickname', $tunic);
+
+ if (empty($from)) {
+ throw new Exception("Can't find user '$tunic'.");
+ }
+
+ subs_subscribe_to($from, $to);
+}
+
+function main($usercount, $noticeavg, $subsavg, $tagmax)
+{
+ $n = 1;
+
+ newUser(0);
+
+ // # registrations + # notices + # subs
+
+ $events = $usercount + ($usercount * ($noticeavg + $subsavg));
+
+ for ($i = 0; $i < $events; $i++)
+ {
+ $e = rand(0, 1 + $noticeavg + $subsavg);
+
+ if ($e == 0) {
+ newUser($n);
+ $n++;
+ } else if ($e < $noticeavg + 1) {
+ newNotice($n, $tagmax);
+ } else {
+ newSub($n);
+ }
+ }
+}
+
+$usercount = (have_option('u', 'users')) ? get_option_value('u', 'users') : 100;
+$noticeavg = (have_option('n', 'notices')) ? get_option_value('n', 'notices') : 100;
+$subsavg = (have_option('b', 'subscriptions')) ? get_option_value('b', 'subscriptions') : max($usercount/20, 10);
+$tagmax = (have_option('t', 'tags')) ? get_option_value('t', 'tags') : 10000;
+$userprefix = (have_option('x', 'prefix')) ? get_option_value('x', 'prefix') : 'testuser';
+
+main($usercount, $noticeavg, $subsavg, $tagmax);
diff --git a/scripts/decache.php b/scripts/decache.php
index 90e1ec63c..7cabd78ad 100644
--- a/scripts/decache.php
+++ b/scripts/decache.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/delete_status_network.sh b/scripts/delete_status_network.sh
index 32187382c..f55f1486b 100755
--- a/scripts/delete_status_network.sh
+++ b/scripts/delete_status_network.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-source /etc/laconica/setup.cfg
+source /etc/statusnet/setup.cfg
export nickname=$1
diff --git a/scripts/enjitqueuehandler.php b/scripts/enjitqueuehandler.php
index 05e1d9366..08f733b07 100755
--- a/scripts/enjitqueuehandler.php
+++ b/scripts/enjitqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/facebookqueuehandler.php b/scripts/facebookqueuehandler.php
index 05a35577f..e13ac4e85 100755
--- a/scripts/facebookqueuehandler.php
+++ b/scripts/facebookqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/fixup_conversations.php b/scripts/fixup_conversations.php
index 0be0b4bac..8a9f7bb57 100755
--- a/scripts/fixup_conversations.php
+++ b/scripts/fixup_conversations.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/fixup_hashtags.php b/scripts/fixup_hashtags.php
index bd38e3105..5cfebd8ee 100755
--- a/scripts/fixup_hashtags.php
+++ b/scripts/fixup_hashtags.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -25,7 +25,8 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
}
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('LACONICA', true);
+define('STATUSNET', true);
+define('LACONICA', true); // compatibility
require_once(INSTALLDIR . '/lib/common.php');
diff --git a/scripts/fixup_inboxes.php b/scripts/fixup_inboxes.php
index 3e55edef1..d55a53885 100755
--- a/scripts/fixup_inboxes.php
+++ b/scripts/fixup_inboxes.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -30,7 +30,8 @@ set_time_limit(0);
mb_internal_encoding('UTF-8');
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('LACONICA', true);
+define('STATUSNET', true);
+define('LACONICA', true); // compatibility
require_once(INSTALLDIR . '/lib/common.php');
diff --git a/scripts/fixup_notices_rendered.php b/scripts/fixup_notices_rendered.php
index 3e7eb7acb..359cd6cce 100755
--- a/scripts/fixup_notices_rendered.php
+++ b/scripts/fixup_notices_rendered.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -25,7 +25,8 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
}
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('LACONICA', true);
+define('STATUSNET', true);
+define('LACONICA', true); // compatibility
require_once(INSTALLDIR . '/lib/common.php');
diff --git a/scripts/fixup_replies.php b/scripts/fixup_replies.php
index 9d8cfda08..7328635d3 100755
--- a/scripts/fixup_replies.php
+++ b/scripts/fixup_replies.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -25,7 +25,8 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
}
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('LACONICA', true);
+define('STATUSNET', true);
+define('LACONICA', true); // compatibility
require_once(INSTALLDIR . '/lib/common.php');
diff --git a/scripts/fixup_utf8.php b/scripts/fixup_utf8.php
index 8c9a9127f..5a9fba7c3 100644..100755
--- a/scripts/fixup_utf8.php
+++ b/scripts/fixup_utf8.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
@@ -25,7 +25,7 @@ define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$helptext = <<<ENDOFHELP
fixup_utf8.php <maxdate> <maxid> <minid>
-Fixup records in a database that stored the data incorrectly (pre-0.7.4 for Laconica).
+Fixup records in a database that stored the data incorrectly (pre-0.7.4 for StatusNet).
ENDOFHELP;
@@ -42,7 +42,7 @@ class UTF8FixerUpper
{
$this->args = $args;
- if (array_key_exists('max_date', $args)) {
+ if (!empty($args['max_date'])) {
$this->max_date = strftime('%Y-%m-%d %H:%M:%S', strtotime($args['max_date']));
} else {
$this->max_date = strftime('%Y-%m-%d %H:%M:%S', time());
diff --git a/scripts/getpiddir.php b/scripts/getpiddir.php
index 9927cc6d9..8274c37c0 100755
--- a/scripts/getpiddir.php
+++ b/scripts/getpiddir.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/getvaliddaemons.php b/scripts/getvaliddaemons.php
index 1e4546dff..8f48e8e6f 100755
--- a/scripts/getvaliddaemons.php
+++ b/scripts/getvaliddaemons.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -43,7 +43,12 @@ if(common_config('twitterbridge','enabled')) {
echo "twitterstatusfetcher.php ";
}
echo "ombqueuehandler.php ";
-echo "twitterqueuehandler.php ";
+if (common_config('twitter', 'enabled')) {
+ echo "twitterqueuehandler.php ";
+ echo "synctwitterfriends.php ";
+}
echo "facebookqueuehandler.php ";
echo "pingqueuehandler.php ";
-echo "smsqueuehandler.php ";
+if (common_config('sms', 'enabled')) {
+ echo "smsqueuehandler.php ";
+}
diff --git a/scripts/inbox_users.php b/scripts/inbox_users.php
index 4883fea20..32adcea21 100755
--- a/scripts/inbox_users.php
+++ b/scripts/inbox_users.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/jabberqueuehandler.php b/scripts/jabberqueuehandler.php
index 5b581629d..8f3a56944 100755
--- a/scripts/jabberqueuehandler.php
+++ b/scripts/jabberqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php
index a4003b6b2..11911dcbd 100755
--- a/scripts/maildaemon.php
+++ b/scripts/maildaemon.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -317,6 +317,9 @@ class MailerDaemon
} else if ($parsed->ctype_primary == 'text'
&& $parsed->ctype_secondary=='plain') {
$msg = $parsed->body;
+ if(strtolower($parsed->ctype_parameters['charset']) != "utf-8"){
+ $msg = utf8_encode($msg);
+ }
}else if(!empty($parsed->body)){
if(common_config('attachments', 'uploads')){
//only save attachments if uploads are enabled
@@ -382,5 +385,7 @@ class MailerDaemon
}
}
-$md = new MailerDaemon();
-$md->handle_message('php://stdin');
+if (common_config('emailpost', 'enabled')) {
+ $md = new MailerDaemon();
+ $md->handle_message('php://stdin');
+}
diff --git a/scripts/ombqueuehandler.php b/scripts/ombqueuehandler.php
index 1587192b6..8e685f1c8 100755
--- a/scripts/ombqueuehandler.php
+++ b/scripts/ombqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/pingqueuehandler.php b/scripts/pingqueuehandler.php
index 23678ea4b..c92337e36 100644
--- a/scripts/pingqueuehandler.php
+++ b/scripts/pingqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/publicqueuehandler.php b/scripts/publicqueuehandler.php
index 701d50e01..50a11bcba 100755
--- a/scripts/publicqueuehandler.php
+++ b/scripts/publicqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/rebuilddb_psql.sh b/scripts/rebuilddb_psql.sh
index ac169c205..6b15b9212 100755
--- a/scripts/rebuilddb_psql.sh
+++ b/scripts/rebuilddb_psql.sh
@@ -5,7 +5,7 @@
# below, AND backed up your database. Failure to observe these instructions
# may result in losing all the data in your database.
#
-# This script is used to upgrade Laconica's PostgreSQL database to the
+# This script is used to upgrade StatusNet's PostgreSQL database to the
# latest version. It does the following:
#
# 1. Dumps the existing data to /tmp/rebuilddb_psql.sql
@@ -15,7 +15,7 @@
#
# You MUST run this script as the 'postgres' user.
# You MUST be able to write to /tmp/rebuilddb_psql.sql
-# You MUST specify the laconica database user and database name on the
+# You MUST specify the statusnet database user and database name on the
# command line, e.g. ./rebuilddb_psql.sh myuser mydbname
#
@@ -27,7 +27,7 @@ cd `dirname $0`
pg_dump -a -D --disable-trigger $DB > /tmp/rebuilddb_psql.sql
psql -c "drop schema public cascade; create schema public;" $DB
psql -c "grant all privileges on schema public to $user;" $DB
-psql $DB < ../db/laconica_pg.sql
+psql $DB < ../db/statusnet_pg.sql
psql $DB < /tmp/rebuilddb_psql.sql
for tab in `psql -c '\dts' $DB -tA | cut -d\| -f2`; do
psql -c "ALTER TABLE \"$tab\" OWNER TO $user;" $DB
diff --git a/scripts/reportsnapshot.php b/scripts/reportsnapshot.php
index c644b557f..71f1019ee 100644
--- a/scripts/reportsnapshot.php
+++ b/scripts/reportsnapshot.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/sessiongc.php b/scripts/sessiongc.php
new file mode 100644
index 000000000..af55ddf3f
--- /dev/null
+++ b/scripts/sessiongc.php
@@ -0,0 +1,36 @@
+#!/usr/bin/env php
+<?php
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+
+$helptext = <<<END_OF_GC_HELP
+sessiongc.php
+
+Delete old sessions from the server
+
+END_OF_GC_HELP;
+
+require_once INSTALLDIR.'/scripts/commandline.inc';
+
+$maxlifetime = ini_get('session.gc_maxlifetime');
+
+print "Deleting sessions older than $maxlifetime seconds.\n";
+
+Session::gc($maxlifetime);
diff --git a/scripts/setpassword.php b/scripts/setpassword.php
index b70689f03..50d49d7db 100755
--- a/scripts/setpassword.php
+++ b/scripts/setpassword.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/setup_status_network.sh b/scripts/setup_status_network.sh
index 17440640e..d40d4724f 100755
--- a/scripts/setup_status_network.sh
+++ b/scripts/setup_status_network.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-source /etc/laconica/setup.cfg
+source /etc/statusnet/setup.cfg
export nickname=$1
export sitename=$2
@@ -13,7 +13,7 @@ export username=$nickname$USERBASE
mysqladmin -h $DBHOST -u $ADMIN --password=$ADMINPASS create $database
-for f in laconica.sql innodb.sql sms_carrier.sql foreign_services.sql notice_source.sql; do
+for f in statusnet.sql innodb.sql sms_carrier.sql foreign_services.sql notice_source.sql; do
mysql -h $DBHOST -u $ADMIN --password=$ADMINPASS $database < ../db/$f;
done
diff --git a/scripts/showcache.php b/scripts/showcache.php
index 7a88fdbbb..f17979572 100644
--- a/scripts/showcache.php
+++ b/scripts/showcache.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/sitemap.php b/scripts/sitemap.php
index 88ca2ba7a..f8c392146 100755
--- a/scripts/sitemap.php
+++ b/scripts/sitemap.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/smsqueuehandler.php b/scripts/smsqueuehandler.php
index 94b846d98..6583a77da 100755
--- a/scripts/smsqueuehandler.php
+++ b/scripts/smsqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/sphinx-cron.sh b/scripts/sphinx-cron.sh
index c16af3c4b..bc537af1a 100755
--- a/scripts/sphinx-cron.sh
+++ b/scripts/sphinx-cron.sh
@@ -1,8 +1,8 @@
#!/bin/sh
-# Laconica - a distributed open-source microblogging tool
+# StatusNet - a distributed open-source microblogging tool
-# Copyright (C) 2008, 2009, Control Yourself, Inc.
+# Copyright (C) 2008, 2009, StatusNet, Inc.
#
# 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
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# This program tries to start the daemons for Laconica.
+# This program tries to start the daemons for StatusNet.
# Note that the 'maildaemon' needs to run as a mail filter.
/usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all --rotate
diff --git a/scripts/sphinx-indexer.sh b/scripts/sphinx-indexer.sh
index fe7c16bea..1ec0826be 100755
--- a/scripts/sphinx-indexer.sh
+++ b/scripts/sphinx-indexer.sh
@@ -1,8 +1,8 @@
#!/bin/sh
-# Laconica - a distributed open-source microblogging tool
+# StatusNet - a distributed open-source microblogging tool
-# Copyright (C) 2008, 2009, Control Yourself, Inc.
+# Copyright (C) 2008, 2009, StatusNet, Inc.
#
# 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
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# This program tries to start the daemons for Laconica.
+# This program tries to start the daemons for StatusNet.
# Note that the 'maildaemon' needs to run as a mail filter.
/usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all
diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh
index 9ead20acd..298162673 100755
--- a/scripts/startdaemons.sh
+++ b/scripts/startdaemons.sh
@@ -1,8 +1,8 @@
#!/bin/sh
-# Laconica - a distributed open-source microblogging tool
+# StatusNet - a distributed open-source microblogging tool
-# Copyright (C) 2008, 2009, Control Yourself, Inc.
+# Copyright (C) 2008, 2009, StatusNet, Inc.
#
# 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
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# This program tries to start the daemons for Laconica.
+# This program tries to start the daemons for StatusNet.
# Note that the 'maildaemon' needs to run as a mail filter.
ARGSG=
diff --git a/scripts/laconica.spec b/scripts/statusnet.spec
index 331e10671..ca2e483a7 100644
--- a/scripts/laconica.spec
+++ b/scripts/statusnet.spec
@@ -4,13 +4,13 @@
BuildRequires: php-pear
BuildRequires: httpd-devel
-Name: laconica
+Name: statusnet
Version: %{LACVER}
Release: 1%{?dist}
License: GAGPL v3 or later
-Source: laconica-%{version}.tar.gz
+Source: statusnet-%{version}.tar.gz
Group: Applications/Internet
-Summary: Laconica, the Open Source microblogging platform
+Summary: StatusNet, the Open Source microblogging platform
BuildArch: noarch
Requires: httpd
@@ -31,7 +31,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build
%define confpath %{_sysconfdir}/%{name}
%description
-From the ABOUT file: Laconica (pronounced "luh-KAWN-ih-kuh") is a Free
+From the ABOUT file: StatusNet (pronounced "luh-KAWN-ih-kuh") is a Free
and Open Source microblogging platform. It helps people in a
community, company or group to exchange short (140 character) messages
over the Web. Users can choose which people to "follow" and receive
@@ -49,16 +49,16 @@ similar service to sites like Twitter, Jaiku, and Plurk.
mkdir -p %{buildroot}%{wwwpath}
cp -a * %{buildroot}%{wwwpath}
-mkdir -p %{buildroot}%{_datadir}/laconica
-cp -a db %{buildroot}%{_datadir}/laconica/db
+mkdir -p %{buildroot}%{_datadir}/statusnet
+cp -a db %{buildroot}%{_datadir}/statusnet/db
-mkdir -p %{buildroot}%{_datadir}/laconica/avatar
+mkdir -p %{buildroot}%{_datadir}/statusnet/avatar
mkdir -p %{buildroot}%{_sysconfdir}/httpd/conf.d
-cat > %{buildroot}%{_sysconfdir}/httpd/conf.d/laconica.conf <<"EOF"
-Alias /laconica/ "/var/www/laconica/"
+cat > %{buildroot}%{_sysconfdir}/httpd/conf.d/statusnet.conf <<"EOF"
+Alias /statusnet/ "/var/www/statusnet/"
-<Directory "/var/www/laconica">
+<Directory "/var/www/statusnet">
Options Indexes FollowSymLinks
AllowOverride All
Order allow,deny
@@ -73,26 +73,26 @@ rm -rf %buildroot
%defattr(-,root,root)
%dir %{wwwpath}
%{wwwpath}/*
-%{_datadir}/laconica/*
-%attr(-,apache,apache) %dir %{_datadir}/laconica/avatar
+%{_datadir}/statusnet/*
+%attr(-,apache,apache) %dir %{_datadir}/statusnet/avatar
%doc COPYING README doc-src/*
-%config(noreplace) %{_sysconfdir}/httpd/conf.d/laconica.conf
+%config(noreplace) %{_sysconfdir}/httpd/conf.d/statusnet.conf
%changelog
-* Wed Apr 03 2009 Zach Copley <zach@controlyourself.ca> - 0.7.3
+* Wed Apr 03 2009 Zach Copley <zach@status.net> - 0.7.3
- Changed version number to 0.7.3.
* Fri Mar 13 2009 Ken Sedgwick <ksedgwic@bonsai.com> - 0.7.2.1-1
-- Factored laconica version to the first line of the file.
+- Factored statusnet version to the first line of the file.
-* Wed Mar 03 2009 Zach Copley <zach@controlyourself.ca> - 0.7.2
+* Wed Mar 03 2009 Zach Copley <zach@status.net> - 0.7.2
- Changed version number to 0.7.2.
* Sat Feb 28 2009 Ken Sedgwick <ken@bonsai.com> - 0.7.1-1
- Modified RPM for Fedora.
* Thu Feb 13 2009 tuukka.pasanen@ilmi.fi
-- packaged laconica version 0.7.1
+- packaged statusnet version 0.7.1
* Wed Feb 04 2009 tuukka.pasanen@ilmi.fi
-- packaged laconica version 0.7.0 using the buildservice spec file wizard
+- packaged statusnet version 0.7.0 using the buildservice spec file wizard
diff --git a/scripts/stopdaemons.sh b/scripts/stopdaemons.sh
index 60ffd83ad..55b404c1a 100755
--- a/scripts/stopdaemons.sh
+++ b/scripts/stopdaemons.sh
@@ -1,8 +1,8 @@
#!/bin/bash
-# Laconica - a distributed open-source microblogging tool
+# StatusNet - a distributed open-source microblogging tool
-# Copyright (C) 2008, 2009, Control Yourself, Inc.
+# Copyright (C) 2008, 2009, StatusNet, Inc.
#
# 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
@@ -17,7 +17,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-# This program tries to stop the daemons for Laconica that were
+# This program tries to stop the daemons for StatusNet that were
# previously started by startdaemons.sh
SDIR=`dirname $0`
@@ -25,7 +25,7 @@ DIR=`php $SDIR/getpiddir.php`
for f in jabberhandler ombhandler publichandler smshandler pinghandler \
xmppconfirmhandler xmppdaemon twitterhandler facebookhandler \
- twitterstatusfetcher; do
+ twitterstatusfetcher synctwitterfriends; do
FILES="$DIR/$f.*.pid"
for ff in "$FILES" ; do
diff --git a/scripts/synctwitterfriends.php b/scripts/synctwitterfriends.php
index fe53ff44d..b30e700a1 100755
--- a/scripts/synctwitterfriends.php
+++ b/scripts/synctwitterfriends.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -20,85 +20,267 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-// Uncomment this to get useful console output
+$shortoptions = 'di::';
+$longoptions = array('id::', 'debug');
+
+$helptext = <<<END_OF_TRIM_HELP
+Batch script for synching local friends with Twitter friends.
+ -i --id Identity (default 'generic')
+ -d --debug Debug (lots of log output)
+
+END_OF_TRIM_HELP;
+
+require_once INSTALLDIR . '/scripts/commandline.inc';
+require_once INSTALLDIR . '/lib/parallelizingdaemon.php';
+
+/**
+ * Daemon to sync local friends with Twitter friends
+ *
+ * @category Twitter
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://status.net/
+ */
$helptext = <<<END_OF_TWITTER_HELP
Batch script for synching local friends with Twitter friends.
END_OF_TWITTER_HELP;
-require_once INSTALLDIR.'/scripts/commandline.inc';
+require_once INSTALLDIR . '/scripts/commandline.inc';
+require_once INSTALLDIR . '/lib/parallelizingdaemon.php';
-// Make a lockfile
-$lockfilename = lockFilename();
-if (!($lockfile = @fopen($lockfilename, "w"))) {
- print "Already running... exiting.\n";
- exit(1);
-}
+class SyncTwitterFriendsDaemon extends ParallelizingDaemon
+{
+ /**
+ * Constructor
+ *
+ * @param string $id the name/id of this daemon
+ * @param int $interval sleep this long before doing everything again
+ * @param int $max_children maximum number of child processes at a time
+ * @param boolean $debug debug output flag
+ *
+ * @return void
+ *
+ **/
-// Obtain an exlcusive lock on file (will fail if script is already going)
-if (!@flock( $lockfile, LOCK_EX | LOCK_NB, &$wouldblock) || $wouldblock) {
- // Script already running - abort
- @fclose($lockfile);
- print "Already running... exiting.\n";
- exit(1);
-}
+ function __construct($id = null, $interval = 60,
+ $max_children = 2, $debug = null)
+ {
+ parent::__construct($id, $interval, $max_children, $debug);
+ }
-$flink = new Foreign_link();
-$flink->service = 1; // Twitter
-$flink->orderBy('last_friendsync');
-$flink->limit(25); // sync this many users during this run
-$cnt = $flink->find();
+ /**
+ * Name of this daemon
+ *
+ * @return string Name of the daemon.
+ */
-print "Updating Twitter friends subscriptions for $cnt users.\n";
+ function name()
+ {
+ return ('synctwitterfriends.' . $this->_id);
+ }
-while ($flink->fetch()) {
+ /**
+ * Find all the Twitter foreign links for users who have requested
+ * automatically subscribing to their Twitter friends locally.
+ *
+ * @return array flinks an array of Foreign_link objects
+ */
+ function getObjects()
+ {
+ $flinks = array();
+ $flink = new Foreign_link();
- if (($flink->friendsync & FOREIGN_FRIEND_RECV) == FOREIGN_FRIEND_RECV) {
+ $conn = &$flink->getDatabaseConnection();
- $user = User::staticGet($flink->user_id);
+ $flink->service = TWITTER_SERVICE;
+ $flink->orderBy('last_friendsync');
+ $flink->limit(25); // sync this many users during this run
+ $flink->find();
- if (empty($user)) {
- common_log(LOG_WARNING, "Unmatched user for ID " . $flink->user_id);
- print "Unmatched user for ID $flink->user_id\n";
- continue;
+ while ($flink->fetch()) {
+ if (($flink->friendsync & FOREIGN_FRIEND_RECV) == FOREIGN_FRIEND_RECV) {
+ $flinks[] = clone($flink);
+ }
}
- print "Updating Twitter friends for $user->nickname (Laconica ID: $user->id)... ";
+ $conn->disconnect();
- $fuser = $flink->getForeignUser();
+ global $_DB_DATAOBJECT;
+ unset($_DB_DATAOBJECT['CONNECTIONS']);
- if (empty($fuser)) {
- common_log(LOG_WARNING, "Unmatched user for ID " . $flink->user_id);
- print "Unmatched user for ID $flink->user_id\n";
- continue;
- }
+ return $flinks;
+ }
+
+ function childTask($flink) {
+
+ // Each child ps needs its own DB connection
- save_twitter_friends($user, $fuser->id, $fuser->nickname, $flink->credentials);
+ // Note: DataObject::getDatabaseConnection() creates
+ // a new connection if there isn't one already
+
+ $conn = &$flink->getDatabaseConnection();
+
+ $this->subscribeTwitterFriends($flink);
$flink->last_friendsync = common_sql_now();
$flink->update();
- if (defined('SCRIPT_DEBUG')) {
- print "\nDONE\n";
+ $conn->disconnect();
+
+ // XXX: Couldn't find a less brutal way to blow
+ // away a cached connection
+
+ global $_DB_DATAOBJECT;
+ unset($_DB_DATAOBJECT['CONNECTIONS']);
+ }
+
+ function fetchTwitterFriends($flink)
+ {
+ $friends = array();
+
+ $client = null;
+
+ if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
+ $token = TwitterOAuthClient::unpackToken($flink->credentials);
+ $client = new TwitterOAuthClient($token->key, $token->secret);
+ common_debug($this->name() . '- Grabbing friends IDs with OAuth.');
} else {
- print "DONE\n";
+ $client = new TwitterBasicAuthClient($flink);
+ common_debug($this->name() . '- Grabbing friends IDs with basic auth.');
}
+
+ try {
+ $friends_ids = $client->friendsIds();
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $this->name() .
+ ' - cURL error getting friend ids ' .
+ $e->getCode() . ' - ' . $e->getMessage());
+ return $friends;
+ }
+
+ if (empty($friends_ids)) {
+ common_debug($this->name() .
+ " - Twitter user $flink->foreign_id " .
+ 'doesn\'t have any friends!');
+ return $friends;
+ }
+
+ common_debug($this->name() . ' - Twitter\'s API says Twitter user id ' .
+ "$flink->foreign_id has " .
+ count($friends_ids) . ' friends.');
+
+ // Calculate how many pages to get...
+ $pages = ceil(count($friends_ids) / 100);
+
+ if ($pages == 0) {
+ common_debug($this->name() . " - $user seems to have no friends.");
+ }
+
+ for ($i = 1; $i <= $pages; $i++) {
+
+ try {
+ $more_friends = $client->statusesFriends(null, null, null, $i);
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $this->name() .
+ ' - cURL error getting Twitter statuses/friends ' .
+ "page $i - " . $e->getCode() . ' - ' .
+ $e->getMessage());
+ }
+
+ if (empty($more_friends)) {
+ common_log(LOG_WARNING, $this->name() .
+ " - Couldn't retrieve page $i " .
+ "of Twitter user $flink->foreign_id friends.");
+ continue;
+ } else {
+ $friends = array_merge($friends, $more_friends);
+ }
+ }
+
+ return $friends;
}
-}
-function lockFilename()
-{
- $piddir = common_config('daemon', 'piddir');
- if (!$piddir) {
- $piddir = '/var/run';
+ function subscribeTwitterFriends($flink)
+ {
+ $friends = $this->fetchTwitterFriends($flink);
+
+ if (empty($friends)) {
+ common_debug($this->name() .
+ ' - Couldn\'t get friends from Twitter for ' .
+ "Twitter user $flink->foreign_id.");
+ return false;
+ }
+
+ $user = $flink->getUser();
+
+ foreach ($friends as $friend) {
+
+ $friend_name = $friend->screen_name;
+ $friend_id = (int) $friend->id;
+
+ // Update or create the Foreign_user record for each
+ // Twitter friend
+
+ if (!save_twitter_user($friend_id, $friend_name)) {
+ common_log(LOG_WARNING, $this-name() .
+ " - Couldn't save $screen_name's friend, $friend_name.");
+ continue;
+ }
+
+ // Check to see if there's a related local user
+
+ $friend_flink = Foreign_link::getByForeignID($friend_id,
+ TWITTER_SERVICE);
+
+ if (!empty($friend_flink)) {
+
+ // Get associated user and subscribe her
+
+ $friend_user = User::staticGet('id', $friend_flink->user_id);
+
+ if (!empty($friend_user)) {
+ $result = subs_subscribe_to($user, $friend_user);
+
+ if ($result === true) {
+ common_log(LOG_INFO,
+ $this->name() . ' - Subscribed ' .
+ "$friend_user->nickname to $user->nickname.");
+ } else {
+ common_debug($this->name() .
+ ' - Tried subscribing ' .
+ "$friend_user->nickname to $user->nickname - " .
+ $result);
+ }
+ }
+ }
+ }
+
+ return true;
}
- return $piddir . '/synctwitterfriends.lock';
}
-// Cleanup
-fclose($lockfile);
-unlink($lockfilename);
+$id = null;
+$debug = null;
+
+if (have_option('i')) {
+ $id = get_option_value('i');
+} else if (have_option('--id')) {
+ $id = get_option_value('--id');
+} else if (count($args) > 0) {
+ $id = $args[0];
+} else {
+ $id = null;
+}
+
+if (have_option('d') || have_option('debug')) {
+ $debug = true;
+}
+
+$syncer = new SyncTwitterFriendsDaemon($id, 60, 2, $debug);
+$syncer->runOnce();
-exit(0);
diff --git a/scripts/triminboxes.php b/scripts/triminboxes.php
index 27e200fef..da09817e5 100644
--- a/scripts/triminboxes.php
+++ b/scripts/triminboxes.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/twitterqueuehandler.php b/scripts/twitterqueuehandler.php
index 00e735d98..ce4d824d0 100755
--- a/scripts/twitterqueuehandler.php
+++ b/scripts/twitterqueuehandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php
index e1745cfc0..3cdf1867a 100755
--- a/scripts/twitterstatusfetcher.php
+++ b/scripts/twitterstatusfetcher.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/**
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -46,27 +46,33 @@ require_once INSTALLDIR . '/lib/daemon.php';
* system.
*
* @category Twitter
- * @package Laconica
- * @author Zach Copley <zach@controlyourself.ca>
- * @author Evan Prodromou <evan@controlyourself.ca>
+ * @package StatusNet
+ * @author Zach Copley <zach@status.net>
+ * @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
// NOTE: an Avatar path MUST be set in config.php for this
-// script to work: e.g.: $config['avatar']['path'] = '/laconica/avatar';
+// script to work: e.g.: $config['avatar']['path'] = '/statusnet/avatar';
-class TwitterStatusFetcher extends Daemon
+class TwitterStatusFetcher extends ParallelizingDaemon
{
- private $_children = array();
-
- function __construct($id=null, $daemonize=true)
+ /**
+ * Constructor
+ *
+ * @param string $id the name/id of this daemon
+ * @param int $interval sleep this long before doing everything again
+ * @param int $max_children maximum number of child processes at a time
+ * @param boolean $debug debug output flag
+ *
+ * @return void
+ *
+ **/
+ function __construct($id = null, $interval = 60,
+ $max_children = 2, $debug = null)
{
- parent::__construct($daemonize);
-
- if ($id) {
- $this->set_id($id);
- }
+ parent::__construct($id, $interval, $max_children, $debug);
}
/**
@@ -81,126 +87,22 @@ class TwitterStatusFetcher extends Daemon
}
/**
- * Run the daemon
+ * Find all the Twitter foreign links for users who have requested
+ * importing of their friends' timelines
*
- * @return void
+ * @return array flinks an array of Foreign_link objects
*/
- function run()
+ function getObjects()
{
- if (defined('SCRIPT_DEBUG')) {
- common_debug($this->name() .
- ': debugging log output enabled.');
- }
-
- do {
-
- $flinks = $this->refreshFlinks();
-
- foreach ($flinks as $f) {
-
- // We have to disconnect from the DB before forking so
- // each sub-process will open its own connection and
- // avoid stomping on the others
-
- $conn = &$f->getDatabaseConnection();
- $conn->disconnect();
-
- $pid = pcntl_fork();
-
- if ($pid == -1) {
- die ("Couldn't fork!");
- }
-
- if ($pid) {
-
- // Parent
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Parent: forked new status ".
- " fetcher process " . $pid);
- }
-
- $this->_children[] = $pid;
-
- } else {
-
- // Child
- $this->getTimeline($f);
- exit();
- }
-
- // Remove child from ps list as it finishes
- while (($c = pcntl_wait($status, WNOHANG OR WUNTRACED)) > 0) {
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Child $c finished.");
- }
-
- $this->removePs($this->_children, $c);
- }
-
- // Wait! We have too many damn kids.
- if (sizeof($this->_children) > MAXCHILDREN) {
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Too many children. Waiting...');
- }
-
- if (($c = pcntl_wait($status, WUNTRACED)) > 0) {
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Finished waiting for $c");
- }
-
- $this->removePs($this->_children, $c);
- }
- }
- }
-
- // Remove all children from the process list before restarting
- while (($c = pcntl_wait($status, WUNTRACED)) > 0) {
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Child $c finished.");
- }
-
- $this->removePs($this->_children, $c);
- }
-
- // Rest for a bit before we fetch more statuses
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Waiting ' . POLL_INTERVAL .
- ' secs before hitting Twitter again.');
- }
-
- if (POLL_INTERVAL > 0) {
- sleep(POLL_INTERVAL);
- }
-
- } while (true);
- }
-
- /**
- * Refresh the foreign links for this user
- *
- * @return void
- */
+ global $_DB_DATAOBJECT;
- function refreshFlinks()
- {
$flink = new Foreign_link();
+ $conn = &$flink->getDatabaseConnection();
- $flink->service = 1; // Twitter
-
+ $flink->service = TWITTER_SERVICE;
$flink->orderBy('last_noticesync');
-
- $cnt = $flink->find();
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Updating Twitter friends subscriptions' .
- " for $cnt users.");
- }
+ $flink->find();
$flinks = array();
@@ -215,78 +117,88 @@ class TwitterStatusFetcher extends Daemon
$flink->free();
unset($flink);
+ $conn->disconnect();
+ unset($_DB_DATAOBJECT['CONNECTIONS']);
+
return $flinks;
}
- /**
- * Unknown
- *
- * @param array &$plist unknown.
- * @param string $ps unknown.
- *
- * @return unknown
- * @todo document
- */
+ function childTask($flink) {
- function removePs(&$plist, $ps)
- {
- for ($i = 0; $i < sizeof($plist); $i++) {
- if ($plist[$i] == $ps) {
- unset($plist[$i]);
- $plist = array_values($plist);
- break;
- }
- }
+ // Each child ps needs its own DB connection
+
+ // Note: DataObject::getDatabaseConnection() creates
+ // a new connection if there isn't one already
+
+ $conn = &$flink->getDatabaseConnection();
+
+ $this->getTimeline($flink);
+
+ $flink->last_friendsync = common_sql_now();
+ $flink->update();
+
+ $conn->disconnect();
+
+ // XXX: Couldn't find a less brutal way to blow
+ // away a cached connection
+
+ global $_DB_DATAOBJECT;
+ unset($_DB_DATAOBJECT['CONNECTIONS']);
}
function getTimeline($flink)
{
if (empty($flink)) {
- common_log(LOG_WARNING,
- "Can't retrieve Foreign_link for foreign ID $fid");
+ common_log(LOG_WARNING, $this->name() .
+ " - Can't retrieve Foreign_link for foreign ID $fid");
return;
}
- $fuser = $flink->getForeignUser();
-
- if (empty($fuser)) {
- common_log(LOG_WARNING, "Unmatched user for ID " .
- $flink->user_id);
- return;
- }
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Trying to get timeline for Twitter user ' .
- "$fuser->nickname ($flink->foreign_id).");
- }
+ common_debug($this->name() . ' - Trying to get timeline for Twitter user ' .
+ $flink->foreign_id);
// XXX: Biggest remaining issue - How do we know at which status
// to start importing? How many statuses? Right now I'm going
// with the default last 20.
- $url = 'http://twitter.com/statuses/friends_timeline.json';
+ $client = null;
- $timeline_json = get_twitter_data($url, $fuser->nickname,
- $flink->credentials);
+ if (TwitterOAuthClient::isPackedToken($flink->credentials)) {
+ $token = TwitterOAuthClient::unpackToken($flink->credentials);
+ $client = new TwitterOAuthClient($token->key, $token->secret);
+ common_debug($this->name() . ' - Grabbing friends timeline with OAuth.');
+ } else {
+ $client = new TwitterBasicAuthClient($flink);
+ common_debug($this->name() . ' - Grabbing friends timeline with basic auth.');
+ }
+
+ $timeline = null;
- $timeline = json_decode($timeline_json);
+ try {
+ $timeline = $client->statusesFriendsTimeline();
+ } catch (Exception $e) {
+ common_log(LOG_WARNING, $this->name() .
+ ' - Twitter client unable to get friends timeline for user ' .
+ $flink->user_id . ' - code: ' .
+ $e->getCode() . 'msg: ' . $e->getMessage());
+ }
if (empty($timeline)) {
- common_log(LOG_WARNING, "Empty timeline.");
+ common_log(LOG_WARNING, $this->name() . " - Empty timeline.");
return;
}
// Reverse to preserve order
+
foreach (array_reverse($timeline) as $status) {
- // Hacktastic: filter out stuff coming from this Laconica
+ // Hacktastic: filter out stuff coming from this StatusNet
+
$source = mb_strtolower(common_config('integration', 'source'));
if (preg_match("/$source/", mb_strtolower($status->source))) {
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Skipping import of status ' . $status->id .
- ' with source ' . $source);
- }
+ common_debug($this->name() . ' - Skipping import of status ' .
+ $status->id . ' with source ' . $source);
continue;
}
@@ -294,6 +206,7 @@ class TwitterStatusFetcher extends Daemon
}
// Okay, record the time we synced with Twitter for posterity
+
$flink->last_noticesync = common_sql_now();
$flink->update();
}
@@ -301,11 +214,12 @@ class TwitterStatusFetcher extends Daemon
function saveStatus($status, $flink)
{
$id = $this->ensureProfile($status->user);
+
$profile = Profile::staticGet($id);
- if (!$profile) {
- common_log(LOG_ERR,
- 'Problem saving notice. No associated Profile.');
+ if (empty($profile)) {
+ common_log(LOG_ERR, $this->name() .
+ ' - Problem saving notice. No associated Profile.');
return null;
}
@@ -318,7 +232,7 @@ class TwitterStatusFetcher extends Daemon
// check to see if we've already imported the status
- if (!$notice) {
+ if (empty($notice)) {
$notice = new Notice();
@@ -329,7 +243,7 @@ class TwitterStatusFetcher extends Daemon
$notice->content = common_shorten_links($status->text); // XXX
$notice->rendered = common_render_content($notice->content, $notice);
$notice->source = 'twitter';
- $notice->reply_to = null; // XXX lookup reply
+ $notice->reply_to = null; // XXX: lookup reply
$notice->is_local = Notice::GATEWAY;
if (Event::handle('StartNoticeSave', array(&$notice))) {
@@ -355,24 +269,22 @@ class TwitterStatusFetcher extends Daemon
function ensureProfile($user)
{
// check to see if there's already a profile for this user
+
$profileurl = 'http://twitter.com/' . $user->screen_name;
$profile = Profile::staticGet('profileurl', $profileurl);
- if ($profile) {
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Profile for $profile->nickname found.");
- }
+ if (!empty($profile)) {
+ common_debug($this->name() .
+ " - Profile for $profile->nickname found.");
// Check to see if the user's Avatar has changed
- $this->checkAvatar($user, $profile);
+ $this->checkAvatar($user, $profile);
return $profile->id;
} else {
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Adding profile and remote profile ' .
- "for Twitter user: $profileurl");
- }
+ common_debug($this->name() . ' - Adding profile and remote profile ' .
+ "for Twitter user: $profileurl.");
$profile = new Profile();
$profile->query("BEGIN");
@@ -394,9 +306,10 @@ class TwitterStatusFetcher extends Daemon
}
// check for remote profile
+
$remote_pro = Remote_profile::staticGet('uri', $profileurl);
- if (!$remote_pro) {
+ if (empty($remote_pro)) {
$remote_pro = new Remote_profile();
@@ -433,23 +346,18 @@ class TwitterStatusFetcher extends Daemon
$oldname = $profile->getAvatar(48)->filename;
if ($newname != $oldname) {
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Avatar for Twitter user ' .
- "$profile->nickname has changed.");
- common_debug("old: $oldname new: $newname");
- }
+ common_debug($this->name() . ' - Avatar for Twitter user ' .
+ "$profile->nickname has changed.");
+ common_debug($this->name() . " - old: $oldname new: $newname");
$this->updateAvatars($twitter_user, $profile);
}
if ($this->missingAvatarFile($profile)) {
-
- if (defined('SCRIPT_DEBUG')) {
- common_debug('Twitter user ' . $profile->nickname .
- ' is missing one or more local avatars.');
- common_debug("old: $oldname new: $newname");
- }
+ common_debug($this->name() . ' - Twitter user ' .
+ $profile->nickname .
+ ' is missing one or more local avatars.');
+ common_debug($this->name() ." - old: $oldname new: $newname");
$this->updateAvatars($twitter_user, $profile);
}
@@ -529,23 +437,20 @@ class TwitterStatusFetcher extends Daemon
if ($this->fetchAvatar($url, $filename)) {
$this->newAvatar($id, $size, $mediatype, $filename);
} else {
- common_log(LOG_WARNING, "Problem fetching Avatar: $url", __FILE__);
+ common_log(LOG_WARNING, $this->id() .
+ " - Problem fetching Avatar: $url");
}
}
}
function updateAvatar($profile_id, $size, $mediatype, $filename) {
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Updating avatar: $size");
- }
+ common_debug($this->name() . " - Updating avatar: $size");
$profile = Profile::staticGet($profile_id);
if (empty($profile)) {
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Couldn't get profile: $profile_id!");
- }
+ common_debug($this->name() . " - Couldn't get profile: $profile_id!");
return;
}
@@ -553,6 +458,7 @@ class TwitterStatusFetcher extends Daemon
$avatar = $profile->getAvatar($sizes[$size]);
// Delete the avatar, if present
+
if ($avatar) {
$avatar->delete();
}
@@ -579,7 +485,7 @@ class TwitterStatusFetcher extends Daemon
default:
// Note: Twitter's big avatars are a different size than
- // Laconica's (Laconica's = 96)
+ // StatusNet's (StatusNet's = 96)
$avatar->width = 73;
$avatar->height = 73;
@@ -590,9 +496,7 @@ class TwitterStatusFetcher extends Daemon
$avatar->filename = $filename;
$avatar->url = Avatar::url($filename);
- if (defined('SCRIPT_DEBUG')) {
- common_debug("new filename: $avatar->url");
- }
+ common_debug($this->name() . " - New filename: $avatar->url");
$avatar->created = common_sql_now();
@@ -603,9 +507,8 @@ class TwitterStatusFetcher extends Daemon
return null;
}
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Saved new $size avatar for $profile_id.");
- }
+ common_debug($this->name() .
+ " - Saved new $size avatar for $profile_id.");
return $id;
}
@@ -618,13 +521,12 @@ class TwitterStatusFetcher extends Daemon
$out = fopen($avatarfile, 'wb');
if (!$out) {
- common_log(LOG_WARNING, "Couldn't open file $filename", __FILE__);
+ common_log(LOG_WARNING, $this->name() .
+ " - Couldn't open file $filename");
return false;
}
- if (defined('SCRIPT_DEBUG')) {
- common_debug("Fetching avatar: $url");
- }
+ common_debug($this->name() . " - Fetching Twitter avatar: $url");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
@@ -641,7 +543,8 @@ class TwitterStatusFetcher extends Daemon
}
}
-declare(ticks = 1);
+$id = null;
+$debug = null;
if (have_option('i')) {
$id = get_option_value('i');
@@ -654,9 +557,9 @@ if (have_option('i')) {
}
if (have_option('d') || have_option('debug')) {
- define('SCRIPT_DEBUG', true);
+ $debug = true;
}
-$fetcher = new TwitterStatusFetcher($id);
+$fetcher = new TwitterStatusFetcher($id, 60, 2, $debug);
$fetcher->runOnce();
diff --git a/scripts/uncache_users.php b/scripts/uncache_users.php
index b0b576eb4..5a1d33030 100644
--- a/scripts/uncache_users.php
+++ b/scripts/uncache_users.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/update_pot.sh b/scripts/update_pot.sh
index a7f5e4d3a..9419e4337 100755
--- a/scripts/update_pot.sh
+++ b/scripts/update_pot.sh
@@ -1,3 +1,3 @@
cd `dirname $0`
cd ..
-xgettext --from-code=UTF-8 --default-domain=laconica --output=locale/laconica.po --language=PHP --join-existing actions/*.php classes/*.php lib/*.php scripts/*.php
+xgettext --from-code=UTF-8 --default-domain=statusnet --output=locale/statusnet.po --language=PHP --join-existing actions/*.php classes/*.php lib/*.php scripts/*.php
diff --git a/scripts/update_translations.php b/scripts/update_translations.php
index 2f4ca8720..f145c1f0b 100755
--- a/scripts/update_translations.php
+++ b/scripts/update_translations.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
@@ -25,12 +25,13 @@ if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
}
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
-define('LACONICA', true);
+define('STATUSNET', true);
+define('LACONICA', true); // compatibility
require_once(INSTALLDIR . '/lib/common.php');
-// Master Laconica .pot file location (created by update_pot.sh)
-$laconica_pot = INSTALLDIR . '/locale/laconica.po';
+// Master StatusNet .pot file location (created by update_pot.sh)
+$statusnet_pot = INSTALLDIR . '/locale/statusnet.po';
set_time_limit(60);
@@ -42,12 +43,12 @@ $languages = get_all_languages();
foreach ($languages as $language) {
$code = $language['lang'];
- $file_url = 'http://laconi.ca/pootle/' . $code .
- '/laconica/LC_MESSAGES/laconica.po';
+ $file_url = 'http://status.net/pootle/' . $code .
+ '/statusnet/LC_MESSAGES/statusnet.po';
$lcdir = INSTALLDIR . '/locale/' . $code;
$msgdir = "$lcdir/LC_MESSAGES";
- $pofile = "$msgdir/laconica.po";
- $mofile = "$msgdir/laconica.mo";
+ $pofile = "$msgdir/statusnet.po";
+ $mofile = "$msgdir/statusnet.mo";
/* Check for an existing */
if (!is_dir($msgdir)) {
@@ -71,7 +72,7 @@ foreach ($languages as $language) {
if (sha1($new_file) != $existingSHA1 || !file_exists($mofile)) {
echo "Updating ".$code."\n";
file_put_contents($pofile, $new_file);
- system(sprintf('msgmerge -U %s %s', $pofile, $laconica_pot));
+ system(sprintf('msgmerge -U %s %s', $pofile, $statusnet_pot));
system(sprintf('msgfmt -f -o %s %s', $mofile, $pofile));
} else {
echo "Unchanged - ".$code."\n";
diff --git a/scripts/xmppconfirmhandler.php b/scripts/xmppconfirmhandler.php
index d6821ddef..c7ed15e49 100755
--- a/scripts/xmppconfirmhandler.php
+++ b/scripts/xmppconfirmhandler.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php
index 69512f243..9e621e725 100755
--- a/scripts/xmppdaemon.php
+++ b/scripts/xmppdaemon.php
@@ -1,8 +1,8 @@
#!/usr/bin/env php
<?php
/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* 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
diff --git a/sphinx.conf.sample b/sphinx.conf.sample
index 8204b9db6..3de62f637 100644
--- a/sphinx.conf.sample
+++ b/sphinx.conf.sample
@@ -1,5 +1,5 @@
#
-# Minimal Sphinx configuration sample for laconica
+# Minimal Sphinx configuration sample for statusnet
#
source src1
diff --git a/tests/HashTagDetectionTests.php b/tests/HashTagDetectionTests.php
new file mode 100644
index 000000000..aeac4a5e3
--- /dev/null
+++ b/tests/HashTagDetectionTests.php
@@ -0,0 +1,47 @@
+<?php
+
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+ print "This script must be run from the command line\n";
+ exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('STATUSNET', true);
+
+require_once INSTALLDIR . '/lib/common.php';
+
+class HashTagDetectionTests extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ *
+ */
+ public function testProduction($content, $expected)
+ {
+ $rendered = common_render_text($content);
+ $this->assertEquals($expected, $rendered);
+ }
+
+ static public function provider()
+ {
+ return array(
+ array('hello',
+ 'hello'),
+ array('#hello people',
+ '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span> people'),
+ array('"#hello" people',
+ '&quot;#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>&quot; people'),
+ array('say "#hello" people',
+ 'say &quot;#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>&quot; people'),
+ array('say (#hello) people',
+ 'say (#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>) people'),
+ array('say [#hello] people',
+ 'say [#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>] people'),
+ array('say {#hello} people',
+ 'say {#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>} people'),
+ array('say \'#hello\' people',
+ 'say \'#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('hello'))) . '" rel="tag">hello</a></span>\' people'),
+ );
+ }
+}
+
diff --git a/tests/URLDetectionTest.php b/tests/URLDetectionTest.php
new file mode 100644
index 000000000..1c3f7cd96
--- /dev/null
+++ b/tests/URLDetectionTest.php
@@ -0,0 +1,269 @@
+<?php
+
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+ print "This script must be run from the command line\n";
+ exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('STATUSNET', true);
+
+require_once INSTALLDIR . '/lib/common.php';
+
+class URLDetectionTest extends PHPUnit_Framework_TestCase
+{
+ /**
+ * @dataProvider provider
+ *
+ */
+ public function testProduction($content, $expected)
+ {
+ $rendered = common_render_text($content);
+ $this->assertEquals($expected, $rendered);
+ }
+
+ static public function provider()
+ {
+ return array(
+ array('not a link :: no way',
+ 'not a link :: no way'),
+ array('link http://www.somesite.com/xyz/35637563@N00/52803365/ link',
+ 'link <a href="http://www.somesite.com/xyz/35637563@N00/52803365/" rel="external">http://www.somesite.com/xyz/35637563@N00/52803365/</a> link'),
+ array('http://127.0.0.1',
+ '<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
+ array('127.0.0.1',
+ '<a href="http://127.0.0.1/" rel="external">127.0.0.1</a>'),
+ array('127.0.0.1:99',
+ '<a href="http://127.0.0.1:99/" rel="external">127.0.0.1:99</a>'),
+ array('127.0.0.1/Name:test.php',
+ '<a href="http://127.0.0.1/Name:test.php" rel="external">127.0.0.1/Name:test.php</a>'),
+ array('127.0.0.1/~test',
+ '<a href="http://127.0.0.1/~test" rel="external">127.0.0.1/~test</a>'),
+ array('127.0.0.1/+test',
+ '<a href="http://127.0.0.1/+test" rel="external">127.0.0.1/+test</a>'),
+ array('127.0.0.1/$test',
+ '<a href="http://127.0.0.1/$test" rel="external">127.0.0.1/$test</a>'),
+ array('127.0.0.1/\'test',
+ '<a href="http://127.0.0.1/\'test" rel="external">127.0.0.1/\'test</a>'),
+ array('127.0.0.1/"test',
+ '<a href="http://127.0.0.1/&quot;test" rel="external">127.0.0.1/&quot;test</a>'),
+ array('127.0.0.1/-test',
+ '<a href="http://127.0.0.1/-test" rel="external">127.0.0.1/-test</a>'),
+ array('127.0.0.1/_test',
+ '<a href="http://127.0.0.1/_test" rel="external">127.0.0.1/_test</a>'),
+ array('127.0.0.1/!test',
+ '<a href="http://127.0.0.1/!test" rel="external">127.0.0.1/!test</a>'),
+ array('127.0.0.1/*test',
+ '<a href="http://127.0.0.1/*test" rel="external">127.0.0.1/*test</a>'),
+ array('127.0.0.1/test%20stuff',
+ '<a href="http://127.0.0.1/test%20stuff" rel="external">127.0.0.1/test%20stuff</a>'),
+ array('http://[::1]:99/test.php',
+ '<a href="http://[::1]:99/test.php" rel="external">http://[::1]:99/test.php</a>'),
+ array('http://::1/test.php',
+ '<a href="http://::1/test.php" rel="external">http://::1/test.php</a>'),
+ array('http://::1',
+ '<a href="http://::1/" rel="external">http://::1</a>'),
+ array('2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php',
+ '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab/test.php</a>'),
+ array('[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php',
+ '<a href="http://[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php" rel="external">[2001:4978:1b5:0:21d:e0ff:fe66:59ab]:99/test.php</a>'),
+ array('2001:4978:1b5:0:21d:e0ff:fe66:59ab',
+ '<a href="http://2001:4978:1b5:0:21d:e0ff:fe66:59ab/" rel="external">2001:4978:1b5:0:21d:e0ff:fe66:59ab</a>'),
+ array('http://127.0.0.1',
+ '<a href="http://127.0.0.1/" rel="external">http://127.0.0.1</a>'),
+ array('example.com',
+ '<a href="http://example.com/" rel="external">example.com</a>'),
+ array('example.com',
+ '<a href="http://example.com/" rel="external">example.com</a>'),
+ array('http://example.com',
+ '<a href="http://example.com/" rel="external">http://example.com</a>'),
+ array('http://example.com.',
+ '<a href="http://example.com/" rel="external">http://example.com</a>.'),
+ array('/var/lib/example.so',
+ '/var/lib/example.so'),
+ array('example',
+ 'example'),
+ array('user@example.com',
+ '<a href="mailto:user@example.com" rel="external">user@example.com</a>'),
+ array('user_name+other@example.com',
+ '<a href="mailto:user_name+other@example.com" rel="external">user_name+other@example.com</a>'),
+ array('mailto:user@example.com',
+ '<a href="mailto:user@example.com" rel="external">mailto:user@example.com</a>'),
+ array('mailto:user@example.com?subject=test',
+ '<a href="mailto:user@example.com?subject=test" rel="external">mailto:user@example.com?subject=test</a>'),
+ array('#example',
+ '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example'))) . '" rel="tag">example</a></span>'),
+ array('#example.com',
+ '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('example.com'))) . '" rel="tag">example.com</a></span>'),
+ array('#.net',
+ '#<span class="tag"><a href="' . common_local_url('tag', array('tag' => common_canonical_tag('.net'))) . '" rel="tag">.net</a></span>'),
+ array('http://example',
+ '<a href="http://example/" rel="external">http://example</a>'),
+ array('http://3xampl3',
+ '<a href="http://3xampl3/" rel="external">http://3xampl3</a>'),
+ array('http://example/',
+ '<a href="http://example/" rel="external">http://example/</a>'),
+ array('http://example/path',
+ '<a href="http://example/path" rel="external">http://example/path</a>'),
+ array('http://example.com',
+ '<a href="http://example.com/" rel="external">http://example.com</a>'),
+ array('https://example.com',
+ '<a href="https://example.com/" rel="external">https://example.com</a>'),
+ array('ftp://example.com',
+ '<a href="ftp://example.com/" rel="external">ftp://example.com</a>'),
+ array('ftps://example.com',
+ '<a href="ftps://example.com/" rel="external">ftps://example.com</a>'),
+ array('http://user@example.com',
+ '<a href="http://user@example.com/" rel="external">http://user@example.com</a>'),
+ array('http://user:pass@example.com',
+ '<a href="http://user:pass@example.com/" rel="external">http://user:pass@example.com</a>'),
+ array('http://example.com:8080',
+ '<a href="http://example.com:8080/" rel="external">http://example.com:8080</a>'),
+ array('http://example.com:8080/test.php',
+ '<a href="http://example.com:8080/test.php" rel="external">http://example.com:8080/test.php</a>'),
+ array('example.com:8080/test.php',
+ '<a href="http://example.com:8080/test.php" rel="external">example.com:8080/test.php</a>'),
+ array('http://www.example.com',
+ '<a href="http://www.example.com/" rel="external">http://www.example.com</a>'),
+ array('http://example.com/',
+ '<a href="http://example.com/" rel="external">http://example.com/</a>'),
+ array('http://example.com/path',
+ '<a href="http://example.com/path" rel="external">http://example.com/path</a>'),
+ array('http://example.com/path.html',
+ '<a href="http://example.com/path.html" rel="external">http://example.com/path.html</a>'),
+ array('http://example.com/path.html#fragment',
+ '<a href="http://example.com/path.html#fragment" rel="external">http://example.com/path.html#fragment</a>'),
+ array('http://example.com/path.php?foo=bar&bar=foo',
+ '<a href="http://example.com/path.php?foo=bar&amp;bar=foo" rel="external">http://example.com/path.php?foo=bar&amp;bar=foo</a>'),
+ array('http://example.com.',
+ '<a href="http://example.com/" rel="external">http://example.com</a>.'),
+ array('http://müllärör.de',
+ '<a href="http://m&#xFC;ll&#xE4;r&#xF6;r.de/" rel="external">http://müllärör.de</a>'),
+ array('http://ﺱﺲﺷ.com',
+ '<a href="http://&#xFEB1;&#xFEB2;&#xFEB7;.com/" rel="external">http://ﺱﺲﺷ.com</a>'),
+ array('http://Ñделаткартинки.com',
+ '<a href="http://&#x441;&#x434;&#x435;&#x43B;&#x430;&#x442;&#x43A;&#x430;&#x440;&#x442;&#x438;&#x43D;&#x43A;&#x438;.com/" rel="external">http://Ñделаткартинки.com</a>'),
+ array('http://tūdaliņ.lv',
+ '<a href="http://t&#x16B;dali&#x146;.lv/" rel="external">http://tūdaliņ.lv</a>'),
+ array('http://brændendekærlighed.com',
+ '<a href="http://br&#xE6;ndendek&#xE6;rlighed.com/" rel="external">http://brændendekærlighed.com</a>'),
+ array('http://ã‚ーるã„ã‚“.com',
+ '<a href="http://&#x3042;&#x30FC;&#x308B;&#x3044;&#x3093;.com/" rel="external">http://ã‚ーるã„ã‚“.com</a>'),
+ array('http://예비êµì‚¬.com',
+ '<a href="http://&#xC608;&#xBE44;&#xAD50;&#xC0AC;.com/" rel="external">http://예비êµì‚¬.com</a>'),
+ array('http://example.com.',
+ '<a href="http://example.com/" rel="external">http://example.com</a>.'),
+ array('http://example.com?',
+ '<a href="http://example.com/" rel="external">http://example.com</a>?'),
+ array('http://example.com!',
+ '<a href="http://example.com/" rel="external">http://example.com</a>!'),
+ array('http://example.com,',
+ '<a href="http://example.com/" rel="external">http://example.com</a>,'),
+ array('http://example.com;',
+ '<a href="http://example.com/" rel="external">http://example.com</a>;'),
+ array('http://example.com:',
+ '<a href="http://example.com/" rel="external">http://example.com</a>:'),
+ array('\'http://example.com\'',
+ '\'<a href="http://example.com/" rel="external">http://example.com</a>\''),
+ array('"http://example.com"',
+ '&quot;<a href="http://example.com/" rel="external">http://example.com</a>&quot;'),
+ array('http://example.com',
+ '<a href="http://example.com/" rel="external">http://example.com</a>'),
+ array('(http://example.com)',
+ '(<a href="http://example.com/" rel="external">http://example.com</a>)'),
+ array('[http://example.com]',
+ '[<a href="http://example.com/" rel="external">http://example.com</a>]'),
+ array('<http://example.com>',
+ '&lt;<a href="http://example.com/" rel="external">http://example.com</a>&gt;'),
+ array('http://example.com/path/(foo)/bar',
+ '<a href="http://example.com/path/(foo)/bar" rel="external">http://example.com/path/(foo)/bar</a>'),
+ array('http://example.com/path/[foo]/bar',
+ '<a href="http://example.com/path/[foo]/bar" rel="external">http://example.com/path/[foo]/bar</a>'),
+ array('http://example.com/path/foo/(bar)',
+ '<a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>'),
+ //Not a valid url - urls cannot contain unencoded square brackets
+ array('http://example.com/path/foo/[bar]',
+ '<a href="http://example.com/path/foo/[bar]" rel="external">http://example.com/path/foo/[bar]</a>'),
+ array('Hey, check out my cool site http://example.com okay?',
+ 'Hey, check out my cool site <a href="http://example.com/" rel="external">http://example.com</a> okay?'),
+ array('What about parens (e.g. http://example.com/path/foo/(bar))?',
+ 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)?'),
+ array('What about parens (e.g. http://example.com/path/foo/(bar)?',
+ 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>?'),
+ array('What about parens (e.g. http://example.com/path/foo/(bar).)?',
+ 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>.)?'),
+ //Not a valid url - urls cannot contain unencoded commas
+ array('What about parens (e.g. http://example.com/path/(foo,bar)?',
+ 'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" rel="external">http://example.com/path/(foo,bar)</a>?'),
+ array('Unbalanced too (e.g. http://example.com/path/((((foo)/bar)?',
+ 'Unbalanced too (e.g. <a href="http://example.com/path/((((foo)/bar)" rel="external">http://example.com/path/((((foo)/bar)</a>?'),
+ array('Unbalanced too (e.g. http://example.com/path/(foo))))/bar)?',
+ 'Unbalanced too (e.g. <a href="http://example.com/path/(foo))))/bar" rel="external">http://example.com/path/(foo))))/bar</a>)?'),
+ array('Unbalanced too (e.g. http://example.com/path/foo/((((bar)?',
+ 'Unbalanced too (e.g. <a href="http://example.com/path/foo/((((bar)" rel="external">http://example.com/path/foo/((((bar)</a>?'),
+ array('Unbalanced too (e.g. http://example.com/path/foo/(bar))))?',
+ 'Unbalanced too (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">http://example.com/path/foo/(bar)</a>)))?'),
+ array('example.com',
+ '<a href="http://example.com/" rel="external">example.com</a>'),
+ array('example.org',
+ '<a href="http://example.org/" rel="external">example.org</a>'),
+ array('example.co.uk',
+ '<a href="http://example.co.uk/" rel="external">example.co.uk</a>'),
+ array('www.example.co.uk',
+ '<a href="http://www.example.co.uk/" rel="external">www.example.co.uk</a>'),
+ array('farm1.images.example.co.uk',
+ '<a href="http://farm1.images.example.co.uk/" rel="external">farm1.images.example.co.uk</a>'),
+ array('example.museum',
+ '<a href="http://example.museum/" rel="external">example.museum</a>'),
+ array('example.travel',
+ '<a href="http://example.travel/" rel="external">example.travel</a>'),
+ array('example.com.',
+ '<a href="http://example.com/" rel="external">example.com</a>.'),
+ array('example.com?',
+ '<a href="http://example.com/" rel="external">example.com</a>?'),
+ array('example.com!',
+ '<a href="http://example.com/" rel="external">example.com</a>!'),
+ array('example.com,',
+ '<a href="http://example.com/" rel="external">example.com</a>,'),
+ array('example.com;',
+ '<a href="http://example.com/" rel="external">example.com</a>;'),
+ array('example.com:',
+ '<a href="http://example.com/" rel="external">example.com</a>:'),
+ array('\'example.com\'',
+ '\'<a href="http://example.com/" rel="external">example.com</a>\''),
+ array('"example.com"',
+ '&quot;<a href="http://example.com/" rel="external">example.com</a>&quot;'),
+ array('example.com',
+ '<a href="http://example.com/" rel="external">example.com</a>'),
+ array('(example.com)',
+ '(<a href="http://example.com/" rel="external">example.com</a>)'),
+ array('[example.com]',
+ '[<a href="http://example.com/" rel="external">example.com</a>]'),
+ array('<example.com>',
+ '&lt;<a href="http://example.com/" rel="external">example.com</a>&gt;'),
+ array('Hey, check out my cool site example.com okay?',
+ 'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a> okay?'),
+ array('Hey, check out my cool site example.com.I made it.',
+ 'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.I made it.'),
+ array('Hey, check out my cool site example.com.Funny thing...',
+ 'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.Funny thing...'),
+ array('Hey, check out my cool site example.com.You will love it.',
+ 'Hey, check out my cool site <a href="http://example.com/" rel="external">example.com</a>.You will love it.'),
+ array('What about parens (e.g. example.com/path/foo/(bar))?',
+ 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>)?'),
+ array('What about parens (e.g. example.com/path/foo/(bar)?',
+ 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>?'),
+ array('What about parens (e.g. example.com/path/foo/(bar).)?',
+ 'What about parens (e.g. <a href="http://example.com/path/foo/(bar)" rel="external">example.com/path/foo/(bar)</a>.)?'),
+ array('What about parens (e.g. example.com/path/(foo,bar)?',
+ 'What about parens (e.g. <a href="http://example.com/path/(foo,bar)" rel="external">example.com/path/(foo,bar)</a>?'),
+ array('file.ext',
+ 'file.ext'),
+ array('file.html',
+ 'file.html'),
+ array('file.php',
+ 'file.php')
+ );
+ }
+}
+
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index 867dc0ef7..7706fba48 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -1,10 +1,10 @@
/** theme: base
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
* { margin:0; padding:0; }
@@ -156,7 +156,8 @@ font-weight:bold;
#form_notice_delete legend,
#form_password_recover legend,
#form_password_change legend,
-.form_entity_block legend {
+.form_entity_block legend,
+#form_filter_bytag legend {
display:none;
}
@@ -483,7 +484,7 @@ height:16px;
#form_notice .form_note {
position:absolute;
bottom:2px;
-right:98px;
+right:21.715%;
z-index:9;
}
#form_notice .form_note dt {
@@ -510,6 +511,7 @@ margin-top:7px;
margin-bottom:7px;
margin-left:18px;
float:left;
+max-width:322px;
}
#form_notice .error,
#form_notice .success {
@@ -876,22 +878,9 @@ float:left;
font-size:1.025em;
}
-.notice div.entry-content dl,
-.notice div.entry-content dt,
-.notice div.entry-content dd {
-display:inline;
-}
-
-.notice div.entry-content .timestamp dt,
-.notice div.entry-content .response dt {
-display:none;
-}
-.notice div.entry-content .timestamp a {
+.notice div.entry-content .timestamp {
display:inline-block;
}
-.notice div.entry-content .device dt {
-text-transform:lowercase;
-}
.notice-options {
position:relative;
@@ -921,38 +910,28 @@ left:29px;
.notice-options .notice_delete {
right:0;
}
-.notice-options .notice_reply dt {
-display:none;
-}
-
.notice-options input,
.notice-options a {
text-indent:-9999px;
outline:none;
}
-
-.notice-options .notice_reply a,
.notice-options input.submit {
display:block;
border:0;
}
-.notice-options .notice_reply a,
-.notice-options .notice_delete a {
+.notice-options .notice_reply,
+.notice-options .notice_delete {
text-decoration:none;
padding-left:16px;
}
-
.notice-options form input.submit {
width:16px;
padding:2px 0;
}
-
-.notice-options .notice_delete dt,
.notice-options .form_favor legend,
.notice-options .form_disfavor legend {
display:none;
}
-.notice-options .notice_delete fieldset,
.notice-options .form_favor fieldset,
.notice-options .form_disfavor fieldset {
border:0;
@@ -1072,36 +1051,37 @@ display:none;
#filter_tags ul {
list-style-type:none;
}
-#filter_tags ul li {
+#filter_tags li {
float:left;
margin-left:7px;
padding-left:7px;
border-left-width:1px;
border-left-style:solid;
}
-#filter_tags ul li.child_1 {
+#filter_tags #filter_tags_all {
margin-left:0;
border-left:0;
padding-left:0;
}
-#filter_tags ul li#filter_tags_all a {
+#filter_tags_all a {
font-weight:bold;
margin-top:7px;
float:left;
}
-#filter_tags ul li#filter_tags_item label {
+#filter_tags_item label {
margin-right:7px;
}
-#filter_tags ul li#filter_tags_item label,
-#filter_tags ul li#filter_tags_item select {
-display:inline;
+#filter_tags_item label,
+#filter_tags_item select {
+float:left;
}
-#filter_tags ul li#filter_tags_item p {
+#filter_tags_item p {
float:left;
+clear:both;
margin-left:38px;
}
-#filter_tags ul li#filter_tags_item input {
+#filter_tags_item .submit {
position:relative;
top:3px;
left:3px;
diff --git a/theme/base/css/ie6.css b/theme/base/css/ie6.css
index eca240faa..edc49478f 100644
--- a/theme/base/css/ie6.css
+++ b/theme/base/css/ie6.css
@@ -35,3 +35,6 @@ width:20%;
width:50%;
margin-left:30px;
}
+.notice-options a {
+width:16px;
+} \ No newline at end of file
diff --git a/theme/base/css/jquery.Jcrop.css b/theme/base/css/jquery.Jcrop.css
index 6c6dfb503..b35f332aa 100644
--- a/theme/base/css/jquery.Jcrop.css
+++ b/theme/base/css/jquery.Jcrop.css
@@ -1,18 +1,11 @@
/* Fixes issue here http://code.google.com/p/jcrop/issues/detail?id=1 */
-.jcrop-holder
-{
- text-align: left;
-}
+.jcrop-holder { text-align: left; }
.jcrop-vline, .jcrop-hline
{
font-size: 0;
position: absolute;
- background: #fff url(../images/illustrations/illu_jcrop.gif) top left repeat;
- /*
- opacity: .5;
- *filter:alpha(opacity=50);
- */
+ background: white url(../images/illustrations/illu_jcrop.gif) top left repeat;
}
.jcrop-vline { height: 100%; width: 1px !important; }
.jcrop-hline { width: 100%; height: 1px !important; }
@@ -22,14 +15,11 @@
height: 7px !important;
border: 1px #eee solid;
background-color: #333;
- /*width: 9px;
- height: 9px;*/
+ *width: 9px;
+ *height: 9px;
}
-.jcrop-tracker {
- /*background-color: gray;*/
- width: 100%; height: 100%;
-}
+.jcrop-tracker { width: 100%; height: 100%; }
.custom .jcrop-vline,
.custom .jcrop-hline
diff --git a/theme/base/css/mobile.css b/theme/base/css/mobile.css
index eee98317c..f6c53ea8d 100644
--- a/theme/base/css/mobile.css
+++ b/theme/base/css/mobile.css
@@ -1,10 +1,10 @@
/** theme: base
*
- * @package Laconica
+ * @package StatusNet
* @author Meitar Moscovitz <meitar@maymay.net>
- * @author Sarven Capadisli <csarven@controlyourself.ca>
+ * @author Sarven Capadisli <csarven@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
body {
diff --git a/theme/base/css/print.css b/theme/base/css/print.css
index d76dd608c..094d07fed 100644
--- a/theme/base/css/print.css
+++ b/theme/base/css/print.css
@@ -1,10 +1,10 @@
/** theme: base
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
a:after { background-color:#fff; }
diff --git a/theme/base/images/icons/icon_atom.png b/theme/base/images/icons/icon_atom.png
index 6a001f11a..de63f1577 100644
--- a/theme/base/images/icons/icon_atom.png
+++ b/theme/base/images/icons/icon_atom.png
Binary files differ
diff --git a/theme/base/images/icons/icon_rss.png b/theme/base/images/icons/icon_rss.png
index 0ccd1ce25..e75778a9e 100644
--- a/theme/base/images/icons/icon_rss.png
+++ b/theme/base/images/icons/icon_rss.png
Binary files differ
diff --git a/theme/biz/css/base.css b/theme/biz/css/base.css
index 696fd0645..6357e55b4 100644
--- a/theme/biz/css/base.css
+++ b/theme/biz/css/base.css
@@ -1,10 +1,10 @@
/** theme: biz base
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
* { margin:0; padding:0; }
@@ -849,6 +849,10 @@ float:left;
font-size:1.025em;
}
+.notice div.entry-content .timestamp {
+display:inline-block;
+}
+
.notice div.entry-content dl,
.notice div.entry-content dt,
.notice div.entry-content dd {
@@ -866,15 +870,12 @@ display:inline-block;
text-transform:lowercase;
}
-
.notice-options {
-padding-left:2%;
-float:left;
-width:50%;
position:relative;
font-size:0.95em;
-width:12.5%;
+width:90px;
float:right;
+margin-right:11px;
}
.notice-options a {
@@ -897,38 +898,28 @@ left:29px;
.notice-options .notice_delete {
right:0;
}
-.notice-options .notice_reply dt {
-display:none;
-}
-
.notice-options input,
.notice-options a {
text-indent:-9999px;
outline:none;
}
-
-.notice-options .notice_reply a,
.notice-options input.submit {
display:block;
border:0;
}
-.notice-options .notice_reply a,
-.notice-options .notice_delete a {
+.notice-options .notice_reply,
+.notice-options .notice_delete {
text-decoration:none;
padding-left:16px;
}
-
.notice-options form input.submit {
width:16px;
padding:2px 0;
}
-
-.notice-options .notice_delete dt,
.notice-options .form_favor legend,
.notice-options .form_disfavor legend {
display:none;
}
-.notice-options .notice_delete fieldset,
.notice-options .form_favor fieldset,
.notice-options .form_disfavor fieldset {
border:0;
diff --git a/theme/biz/css/display.css b/theme/biz/css/display.css
index 3af4c06b9..7ea451576 100644
--- a/theme/biz/css/display.css
+++ b/theme/biz/css/display.css
@@ -1,10 +1,10 @@
/** theme: biz
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
@import url(base.css);
@@ -30,10 +30,10 @@ font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif;
}
input, textarea, select,
.entity_remote_subscribe {
-border-color:#aaa;
+border-color:#AAAAAA;
}
#filter_tags ul li {
-border-color:#ddd;
+border-color:#DDDDDD;
}
.form_settings input.form_action-primary {
@@ -50,11 +50,14 @@ background-color:#9BB43E;
input:focus, textarea:focus, select:focus,
#form_notice.warning #notice_data-text {
border-color:#9BB43E;
+box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
+-moz-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
+-webkit-box-shadow:3px 3px 3px rgba(194, 194, 194, 0.3);
}
input.submit,
.entity_remote_subscribe,
#site_nav_local_views a {
-color:#fff;
+color:#FFFFFF;
}
a,
@@ -62,10 +65,13 @@ a,
div.notice-options input,
.form_user_block input.submit,
.form_user_unblock input.submit,
+.form_group_block input.submit,
+.form_group_unblock input.submit,
.entity_send-a-message a,
.form_user_nudge input.submit,
.entity_nudge p,
-.form_settings input.form_action-primary {
+.form_settings input.form_action-primary,
+.form_make_admin input.submit {
color:#002E6E;
}
@@ -82,13 +88,6 @@ border-top-color:#CEE1E9;
border-top-color:#87B4C8;
}
-#content .notice p.entry-content a:visited {
-background-color:#fcfcfc;
-}
-#content .notice p.entry-content .vcard a {
-background-color:#fcfffc;
-}
-
.aside .section {
background-color:#F1F5F8;
background-position:100% 0;
@@ -97,10 +96,10 @@ background-repeat:no-repeat;
}
#notice_text-count {
-color:#333;
+color:#333333;
}
#form_notice.warning #notice_text-count {
-color:#000;
+color:#000000;
}
#form_notice label[for=notice_data-attach] {
background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no-repeat 0 45%;
@@ -109,28 +108,43 @@ background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no
opacity:0;
}
-#form_notice.processing #notice_action-submit {
-background:#fff url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
+#wrap form.processing input.submit {
+background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait;
text-indent:-9999px;
+outline:none;
}
+#content {
+box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3);
+-moz-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3);
+-webkit-box-shadow:5px 7px 7px rgba(194, 194, 194, 0.3);
+}
#content,
#site_nav_local_views a,
.aside .section {
-border-color:#fff;
+border-color:#FFFFFF;
}
#content,
#site_nav_local_views .current a {
-background-color:#fff;
+background-color:#FFFFFF;
}
+#site_nav_local_views li {
+box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5);
+-moz-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5);
+-webkit-box-shadow:3px 7px 5px rgba(194, 194, 194, 0.5);
+}
#site_nav_local_views a {
-background-color:rgba(135, 180, 200, 0.3);
+background-color:rgba(194, 194, 194, 0.5);
}
#site_nav_local_views a:hover {
background-color:rgba(255, 255, 255, 0.7);
}
+#site_nav_local_views .current a {
+text-shadow: rgba(194,194,194,0.5) 1px 1px 1px;
+}
+
.error {
background-color:#F7E8E8;
@@ -140,10 +154,7 @@ background-color:#EFF3DC;
}
#anon_notice {
-color:#fff;
-}
-
-#showstream #anon_notice {
+color:#FFFFFF;
}
#export_data li a {
@@ -165,7 +176,10 @@ background-image:url(../../base/images/icons/icon_foaf.gif);
.form_user_nudge input.submit,
.form_user_block input.submit,
.form_user_unblock input.submit,
-.entity_nudge p {
+.form_group_block input.submit,
+.form_group_unblock input.submit,
+.entity_nudge p,
+.form_make_admin input.submit {
background-position: 0 40%;
background-repeat: no-repeat;
background-color:transparent;
@@ -175,7 +189,7 @@ background-color:transparent;
.form_user_subscribe input.submit,
.form_user_unsubscribe input.submit {
background-color:#9BB43E;
-color:#fff;
+color:#FFFFFF;
}
.form_user_unsubscribe input.submit,
.form_group_leave input.submit,
@@ -194,20 +208,23 @@ background-image:url(../../base/images/icons/twotone/green/quote.gif);
background-image:url(../../base/images/icons/twotone/green/mail.gif);
}
.form_user_block input.submit,
-.form_user_unblock input.submit {
+.form_user_unblock input.submit,
+.form_group_block input.submit,
+.form_group_unblock input.submit {
background-image:url(../../base/images/icons/twotone/green/shield.gif);
}
+.form_make_admin input.submit {
+background-image:url(../../base/images/icons/twotone/green/admin.gif);
+}
/* NOTICES */
-.notices li.over {
-background-color:#fcfcfc;
+.notice .attachment {
+background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no-repeat 0 45%;
}
-
-.notice-options .notice_reply a,
-.notice-options form input.submit {
-background-color:transparent;
+#attachments .attachment {
+background:none;
}
-.notice-options .notice_reply a {
+.notice-options .notice_reply {
background:transparent url(../../base/images/icons/twotone/green/reply.gif) no-repeat 0 45%;
}
.notice-options form.form_favor input.submit {
@@ -216,7 +233,7 @@ background:transparent url(../../base/images/icons/twotone/green/favourite.gif)
.notice-options form.form_disfavor input.submit {
background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%;
}
-.notice-options .notice_delete a {
+.notice-options .notice_delete {
background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%;
}
@@ -224,19 +241,32 @@ background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-r
.notices div.notice-options {
opacity:0.4;
}
-.notices li.hover div.entry-content,
-.notices li.hover div.notice-options {
+.notices li:hover div.entry-content,
+.notices li:hover div.notice-options {
opacity:1;
}
-div.entry-content {
-color:#333;
-}
div.notice-options a,
div.notice-options input {
font-family:sans-serif;
}
-.notices li.hover {
-background-color:#fcfcfc;
+#content .notices li:hover {
+background-color:rgba(240, 240, 240, 0.2);
+}
+#conversation .notices li:hover {
+background-color:transparent;
+}
+
+.notices .notices {
+background-color:rgba(200, 200, 200, 0.050);
+}
+.notices .notices .notices {
+background-color:rgba(200, 200, 200, 0.100);
+}
+.notices .notices .notices .notices {
+background-color:rgba(200, 200, 200, 0.150);
+}
+.notices .notices .notices .notices .notices {
+background-color:rgba(200, 200, 200, 0.300);
}
/*END: NOTICES */
diff --git a/theme/biz/logo.png b/theme/biz/logo.png
index fdead6c4a..550d373fe 100644
--- a/theme/biz/logo.png
+++ b/theme/biz/logo.png
Binary files differ
diff --git a/theme/cloudy/css/display.css b/theme/cloudy/css/display.css
index 82a1a1e4e..3fe05eb3d 100644
--- a/theme/cloudy/css/display.css
+++ b/theme/cloudy/css/display.css
@@ -1,10 +1,10 @@
/** theme: cloudy
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
* { margin:0; padding:0; }
@@ -120,6 +120,10 @@ float:left;
margin-left:11px;
float:left;
}
+.form_settings .form_data textarea {
+width:325px;
+}
+
.form_settings .form_data input.submit {
margin-left:0;
}
@@ -414,9 +418,12 @@ width:518px;
min-height:322px;
padding:20px;
float:left;
-border-radius-topleft:4px;
--moz-border-radius-topleft:4px;
--webkit-border-top-left-radius:4px;
+border-radius:4px;
+-moz-border-radius:4px;
+-webkit-border-radius:4px;
+border-radius-topright:0;
+-moz-border-radius-topright:0;
+-webkit-border-top-right-radius:0;
border-style:solid;
border-width:1px;
}
@@ -484,7 +491,7 @@ width:16px;
height:16px;
}
#form_notice #notice_data-attach {
-left:34.6%;
+left:40%;
padding:0;
height:16px;
}
@@ -528,9 +535,12 @@ float:left;
#form_notice .success {
float:left;
clear:both;
-width:81.5%;
+width:83.5%;
margin-bottom:0;
line-height:1.618;
+position:absolute;
+top:87px;
+left:0;
}
#form_notice #notice_data-attach_selected code {
float:left;
@@ -934,7 +944,6 @@ float:left;
font-size:0.95em;
width:16px;
float:right;
-display:none;
}
.notices li:hover div.notice-options {
display:block;
@@ -963,9 +972,6 @@ right:7px;
top:47px;
right:7px;
}
-.notice-options .notice_reply dt {
-display:none;
-}
.notice-options input,
.notice-options a {
@@ -973,17 +979,21 @@ text-indent:-9999px;
outline:none;
}
-.notice-options .notice_reply a,
+.notice-options .notice_reply,
.notice-options input.submit {
display:block;
border:0;
}
-.notice-options .notice_reply a,
-.notice-options .notice_delete a {
+.notice-options .notice_reply,
+.notice-options .notice_delete {
text-decoration:none;
padding-left:16px;
}
+.notice-options .notice_reply .notice_id {
+display:none;
+}
+
.notice-options form input.submit {
width:16px;
padding:2px 0;
@@ -1366,6 +1376,12 @@ padding-top:160px;
#smssettings #form_notice,
#twittersettings #form_notice,
#imsettings #form_notice,
+#userdesignsettings #form_notice,
+#groupdesignsettings #form_notice,
+#grouplogo #form_notice,
+#editgroup #form_notice,
+#blockedfromgroup #form_notice,
+#groupmembers #form_notice,
#doc #form_notice,
#usergroups #form_notice,
#invite #form_notice,
@@ -1575,11 +1591,11 @@ background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no
background:none;
}
-.notice-options .notice_reply a,
+.notice-options .notice_reply,
.notice-options form input.submit {
background-color:transparent;
}
-.notice-options .notice_reply a {
+.notice-options .notice_reply {
background:transparent url(../images/icons/icon_reply.gif) no-repeat 0 45%;
}
.notice-options form.form_favor input.submit {
@@ -1588,7 +1604,7 @@ background:transparent url(../images/icons/icon_favourite.gif) no-repeat 0 45%;
.notice-options form.form_disfavor input.submit {
background:transparent url(../images/icons/icon_disfavourite.gif) no-repeat 0 45%;
}
-.notice-options .notice_delete a {
+.notice-options .notice_delete {
background:transparent url(../images/icons/icon_trash.gif) no-repeat 0 45%;
}
diff --git a/theme/cloudy/css/ie.css b/theme/cloudy/css/ie.css
index 94c2093b1..a698676fb 100644
--- a/theme/cloudy/css/ie.css
+++ b/theme/cloudy/css/ie.css
@@ -8,15 +8,33 @@ color:#fff;
background-color:#ddffcc;
}
+#form_notice {
+width:525px;
+}
+#form_notice .form_note {
+top:-5px;
+right:0;
+}
+#form_notice textarea {
+width:97.75%;
+}
#form_notice .form_note + label {
position:absolute;
-top:25px;
-left:83%;
+top:87px;
+left:77%;
text-indent:-9999px;
height:16px;
width:16px;
display:block;
}
+#form_notice #notice_data-attach {
+filter: alpha(opacity = 0);
+left:33.5%;
+}
+
+#form_notice #notice_action-submit {
+right:0;
+}
#aside_primary {
width:181px;
@@ -24,7 +42,7 @@ width:181px;
#form_notice,
#anon_notice {
-top:158px;
+top:190px;
}
#public #content,
diff --git a/theme/cloudy/logo.png b/theme/cloudy/logo.png
index fdead6c4a..550d373fe 100644
--- a/theme/cloudy/logo.png
+++ b/theme/cloudy/logo.png
Binary files differ
diff --git a/theme/default/css/display.css b/theme/default/css/display.css
index 251d6706b..86369cb99 100644
--- a/theme/default/css/display.css
+++ b/theme/default/css/display.css
@@ -1,10 +1,10 @@
/** theme: default
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
@import url(../../base/css/display.css);
@@ -66,7 +66,7 @@ div.notice-options input,
.entity_nudge p,
.form_settings input.form_action-primary,
.form_make_admin input.submit {
-color:#002E6E;
+color:#002FA7;
}
.notice,
@@ -94,10 +94,11 @@ background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no
opacity:0;
}
-#form_notice.processing #notice_action-submit {
+#wrap form.processing input.submit {
background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait;
text-indent:-9999px;
+outline:none;
}
#content {
@@ -214,11 +215,7 @@ background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no
#attachments .attachment {
background:none;
}
-.notice-options .notice_reply a,
-.notice-options form input.submit {
-background-color:transparent;
-}
-.notice-options .notice_reply a {
+.notice-options .notice_reply {
background:transparent url(../../base/images/icons/twotone/green/reply.gif) no-repeat 0 45%;
}
.notice-options form.form_favor input.submit {
@@ -227,7 +224,7 @@ background:transparent url(../../base/images/icons/twotone/green/favourite.gif)
.notice-options form.form_disfavor input.submit {
background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%;
}
-.notice-options .notice_delete a {
+.notice-options .notice_delete {
background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%;
}
@@ -239,9 +236,6 @@ opacity:0.4;
.notices li:hover div.notice-options {
opacity:1;
}
-div.entry-content {
-color:#333333;
-}
div.notice-options a,
div.notice-options input {
font-family:sans-serif;
diff --git a/theme/default/default-avatar-mini.png b/theme/default/default-avatar-mini.png
index 38b8692b4..6c7808616 100644
--- a/theme/default/default-avatar-mini.png
+++ b/theme/default/default-avatar-mini.png
Binary files differ
diff --git a/theme/default/default-avatar-profile.png b/theme/default/default-avatar-profile.png
index f8357d4fc..08ce4e48e 100644
--- a/theme/default/default-avatar-profile.png
+++ b/theme/default/default-avatar-profile.png
Binary files differ
diff --git a/theme/default/default-avatar-stream.png b/theme/default/default-avatar-stream.png
index 6b63baa70..f18994d75 100644
--- a/theme/default/default-avatar-stream.png
+++ b/theme/default/default-avatar-stream.png
Binary files differ
diff --git a/theme/default/logo.png b/theme/default/logo.png
index fdead6c4a..550d373fe 100644
--- a/theme/default/logo.png
+++ b/theme/default/logo.png
Binary files differ
diff --git a/theme/h4ck3r/css/base.css b/theme/h4ck3r/css/base.css
index 41b3a77e6..18ea742a5 100644
--- a/theme/h4ck3r/css/base.css
+++ b/theme/h4ck3r/css/base.css
@@ -1,10 +1,10 @@
/** theme: h4ck3r base
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
* { margin:0; padding:0; }
diff --git a/theme/h4ck3r/css/display.css b/theme/h4ck3r/css/display.css
index 31d49a58e..58b3f242a 100644
--- a/theme/h4ck3r/css/display.css
+++ b/theme/h4ck3r/css/display.css
@@ -1,10 +1,10 @@
/** theme: h4ck3r
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
@import url(base.css);
diff --git a/theme/h4ck3r/logo.png b/theme/h4ck3r/logo.png
index fdead6c4a..550d373fe 100644
--- a/theme/h4ck3r/logo.png
+++ b/theme/h4ck3r/logo.png
Binary files differ
diff --git a/theme/identica/css/display.css b/theme/identica/css/display.css
index 42a4573a7..9fc97180d 100644
--- a/theme/identica/css/display.css
+++ b/theme/identica/css/display.css
@@ -1,10 +1,10 @@
/** theme: identica
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
@import url(../../base/css/display.css);
@@ -66,7 +66,7 @@ div.notice-options input,
.entity_nudge p,
.form_settings input.form_action-primary,
.form_make_admin input.submit {
-color:#002E6E;
+color:#002FA7;
}
.notice,
@@ -94,10 +94,11 @@ background:transparent url(../../base/images/icons/twotone/green/clip-01.gif) no
opacity:0;
}
-#form_notice.processing #notice_action-submit {
+#wrap form.processing input.submit {
background:#FFFFFF url(../../base/images/icons/icon_processing.gif) no-repeat 47% 47%;
cursor:wait;
text-indent:-9999px;
+outline:none;
}
#content {
@@ -214,11 +215,7 @@ background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no
#attachments .attachment {
background:none;
}
-.notice-options .notice_reply a,
-.notice-options form input.submit {
-background-color:transparent;
-}
-.notice-options .notice_reply a {
+.notice-options .notice_reply {
background:transparent url(../../base/images/icons/twotone/green/reply.gif) no-repeat 0 45%;
}
.notice-options form.form_favor input.submit {
@@ -227,7 +224,7 @@ background:transparent url(../../base/images/icons/twotone/green/favourite.gif)
.notice-options form.form_disfavor input.submit {
background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%;
}
-.notice-options .notice_delete a {
+.notice-options .notice_delete {
background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%;
}
@@ -239,9 +236,6 @@ opacity:0.4;
.notices li:hover div.notice-options {
opacity:1;
}
-div.entry-content {
-color:#333333;
-}
div.notice-options a,
div.notice-options input {
font-family:sans-serif;
diff --git a/theme/identica/default-avatar-mini.png b/theme/identica/default-avatar-mini.png
index 38b8692b4..6c7808616 100644
--- a/theme/identica/default-avatar-mini.png
+++ b/theme/identica/default-avatar-mini.png
Binary files differ
diff --git a/theme/identica/default-avatar-profile.png b/theme/identica/default-avatar-profile.png
index f8357d4fc..08ce4e48e 100644
--- a/theme/identica/default-avatar-profile.png
+++ b/theme/identica/default-avatar-profile.png
Binary files differ
diff --git a/theme/identica/default-avatar-stream.png b/theme/identica/default-avatar-stream.png
index 6b63baa70..f18994d75 100644
--- a/theme/identica/default-avatar-stream.png
+++ b/theme/identica/default-avatar-stream.png
Binary files differ
diff --git a/theme/identica/logo.png b/theme/identica/logo.png
index 7c68b34f6..b32c6f951 100644
--- a/theme/identica/logo.png
+++ b/theme/identica/logo.png
Binary files differ
diff --git a/theme/otalk/css/base.css b/theme/otalk/css/base.css
index b39992570..8af86f9db 100644
--- a/theme/otalk/css/base.css
+++ b/theme/otalk/css/base.css
@@ -1,10 +1,10 @@
/** theme: otalk base
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
* { margin:0; padding:0; }
diff --git a/theme/otalk/css/display.css b/theme/otalk/css/display.css
index d2a4719a8..bdfaea749 100644
--- a/theme/otalk/css/display.css
+++ b/theme/otalk/css/display.css
@@ -1,10 +1,10 @@
/** theme: otalk
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
@import url(base.css);
diff --git a/theme/pigeonthoughts/css/base.css b/theme/pigeonthoughts/css/base.css
index 5d5eb9896..4b30710fb 100644
--- a/theme/pigeonthoughts/css/base.css
+++ b/theme/pigeonthoughts/css/base.css
@@ -1,10 +1,10 @@
/** theme: pigeonthoughts base
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
* { margin:0; padding:0; }
@@ -847,23 +847,9 @@ margin-left:0;
float:left;
font-size:1.025em;
}
-
-.notice div.entry-content dl,
-.notice div.entry-content dt,
-.notice div.entry-content dd {
-display:inline;
-}
-
-.notice div.entry-content .timestamp dt,
-.notice div.entry-content .response dt {
-display:none;
-}
-.notice div.entry-content .timestamp a {
+.notice div.entry-content .timestamp {
display:inline-block;
}
-.notice div.entry-content .device dt {
-text-transform:lowercase;
-}
.notice-options {
position:relative;
@@ -893,38 +879,28 @@ left:29px;
.notice-options .notice_delete {
right:0;
}
-.notice-options .notice_reply dt {
-display:none;
-}
-
.notice-options input,
.notice-options a {
text-indent:-9999px;
outline:none;
}
-
-.notice-options .notice_reply a,
.notice-options input.submit {
display:block;
border:0;
}
-.notice-options .notice_reply a,
-.notice-options .notice_delete a {
+.notice-options .notice_reply,
+.notice-options .notice_delete {
text-decoration:none;
padding-left:16px;
}
-
.notice-options form input.submit {
width:16px;
padding:2px 0;
}
-
-.notice-options .notice_delete dt,
.notice-options .form_favor legend,
.notice-options .form_disfavor legend {
display:none;
}
-.notice-options .notice_delete fieldset,
.notice-options .form_favor fieldset,
.notice-options .form_disfavor fieldset {
border:0;
diff --git a/theme/pigeonthoughts/css/display.css b/theme/pigeonthoughts/css/display.css
index f113225fb..2b9174182 100644
--- a/theme/pigeonthoughts/css/display.css
+++ b/theme/pigeonthoughts/css/display.css
@@ -1,10 +1,10 @@
/** theme: pigeonthoughts
*
- * @package Laconica
- * @author Sarven Capadisli <csarven@controlyourself.ca>
- * @copyright 2009 Control Yourself, Inc.
+ * @package StatusNet
+ * @author Sarven Capadisli <csarven@status.net>
+ * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
@import url(base.css);
@@ -269,11 +269,7 @@ background:transparent url(../../base/images/icons/twotone/green/clip-02.gif) no
#attachments .attachment {
background:none;
}
-.notice-options .notice_reply a,
-.notice-options form input.submit {
-background-color:transparent;
-}
-.notice-options .notice_reply a {
+.notice-options .notice_reply {
background:transparent url(../../base/images/icons/twotone/green/reply.gif) no-repeat 0 45%;
}
.notice-options form.form_favor input.submit {
@@ -282,7 +278,7 @@ background:transparent url(../../base/images/icons/twotone/green/favourite.gif)
.notice-options form.form_disfavor input.submit {
background:transparent url(../../base/images/icons/twotone/green/disfavourite.gif) no-repeat 0 45%;
}
-.notice-options .notice_delete a {
+.notice-options .notice_delete {
background:transparent url(../../base/images/icons/twotone/green/trash.gif) no-repeat 0 45%;
}
diff --git a/theme/pigeonthoughts/logo.png b/theme/pigeonthoughts/logo.png
index fdead6c4a..550d373fe 100644
--- a/theme/pigeonthoughts/logo.png
+++ b/theme/pigeonthoughts/logo.png
Binary files differ
diff --git a/theme/readme.txt b/theme/readme.txt
index 83b5a61d0..151b1fb71 100644
--- a/theme/readme.txt
+++ b/theme/readme.txt
@@ -1,6 +1,6 @@
-/** Howto: create a laconica theme
+/** Howto: create a statusnet theme
*
- * @package Laconica
+ * @package StatusNet
* @author Sarven Capadisli <csarven@controlyourself.ca>
* @copyright 2009 Control Yourself, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
@@ -18,7 +18,7 @@ Location of key paths and files under theme/:
./default/images/
./base/display.css contains layout, typography rules:
-Only alter this file if you want to change the layout of the site. Please note that, any updates to this in future laconica releases may not be compatible with your version.
+Only alter this file if you want to change the layout of the site. Please note that, any updates to this in future statusnet releases may not be compatible with your version.
./default/css/display.css contains only the background images and colour rules:
This file is a good basis for creating your own theme.
diff --git a/tpl/index.php b/tpl/index.php
index 5f1ed8439..36a161144 100644
--- a/tpl/index.php
+++ b/tpl/index.php
@@ -1,6 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html
-PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<?php echo '<?';?>xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><?php echo section('title'); ?></title>
@@ -44,4 +42,4 @@ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
</div>
</div>
</body>
- </html> \ No newline at end of file
+ </html>