From 7b9e69eb8923ef3018f0ce3e6042d9901ed16abd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 10 Feb 2009 22:32:38 -0500 Subject: [PATCH] integrate URL routing into core code --- htaccess.sample | 162 +---------------------- index.php | 148 +++++++++++++-------- lib/router.php | 340 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 435 insertions(+), 215 deletions(-) create mode 100644 lib/router.php diff --git a/htaccess.sample b/htaccess.sample index 5f9827f963..634900dbf6 100644 --- a/htaccess.sample +++ b/htaccess.sample @@ -4,165 +4,9 @@ RewriteEngine On RewriteBase /mublog/ -RewriteRule ^$ index.php?action=public [L,QSA] -RewriteRule ^rss$ index.php?action=publicrss [L,QSA] -RewriteRule ^xrds$ index.php?action=publicxrds [L,QSA] -RewriteRule ^featuredrss$ index.php?action=featuredrss [L,QSA] -RewriteRule ^favoritedrss$ index.php?action=favoritedrss [L,QSA] -RewriteRule ^opensearch/people$ index.php?action=opensearch&type=people [L,QSA] -RewriteRule ^opensearch/notice$ index.php?action=opensearch&type=notice [L,QSA] - -RewriteRule ^doc/about$ index.php?action=doc&title=about [L,QSA] -RewriteRule ^doc/contact$ index.php?action=doc&title=contact [L,QSA] -RewriteRule ^doc/faq$ index.php?action=doc&title=faq [L,QSA] -RewriteRule ^doc/help$ index.php?action=doc&title=help [L,QSA] -RewriteRule ^doc/im$ index.php?action=doc&title=im [L,QSA] -RewriteRule ^doc/openid$ index.php?action=doc&title=openid [L,QSA] -RewriteRule ^doc/openmublog$ index.php?action=doc&title=openmublog [L,QSA] -RewriteRule ^doc/privacy$ index.php?action=doc&title=privacy [L,QSA] -RewriteRule ^doc/source$ index.php?action=doc&title=source [L,QSA] -RewriteRule ^doc/tags$ index.php?action=doc&title=tags [L,QSA] -RewriteRule ^doc/groups$ index.php?action=doc&title=groups [L,QSA] -RewriteRule ^doc/sms$ index.php?action=doc&title=sms [L,QSA] - -RewriteRule ^facebook/$ index.php?action=facebookhome [L,QSA] -RewriteRule ^facebook/index.php$ index.php?action=facebookhome [L,QSA] -RewriteRule ^facebook/settings.php$ index.php?action=facebooksettings [L,QSA] -RewriteRule ^facebook/invite.php$ index.php?action=facebookinvite [L,QSA] -RewriteRule ^facebook/remove$ index.php?action=facebookremove [L,QSA] - -RewriteRule ^main/login$ index.php?action=login [L,QSA] -RewriteRule ^main/logout$ index.php?action=logout [L,QSA] -RewriteRule ^main/register/(.*)$ index.php?action=register&code=$1 [L,QSA] -RewriteRule ^main/register$ index.php?action=register [L,QSA] -RewriteRule ^main/openid$ index.php?action=openidlogin [L,QSA] -RewriteRule ^main/remote$ index.php?action=remotesubscribe [L,QSA] - -RewriteRule ^main/subscribe$ index.php?action=subscribe [L,QSA] -RewriteRule ^main/unsubscribe$ index.php?action=unsubscribe [L,QSA] -RewriteRule ^main/confirmaddress$ index.php?action=confirmaddress [L,QSA] -RewriteRule ^main/confirmaddress/(.*)$ index.php?action=confirmaddress&code=$1 [L,QSA] -RewriteRule ^main/recoverpassword$ index.php?action=recoverpassword [L,QSA] -RewriteRule ^main/recoverpassword/(.*)$ index.php?action=recoverpassword&code=$1 [L,QSA] -RewriteRule ^main/invite$ index.php?action=invite [L,QSA] - -RewriteRule ^main/favor$ index.php?action=favor [L,QSA] -RewriteRule ^main/disfavor$ index.php?action=disfavor [L,QSA] - -RewriteRule ^main/sup$ index.php?action=sup [L,QSA] - -RewriteRule ^main/tagother$ index.php?action=tagother [L,QSA] - -RewriteRule ^main/block$ index.php?action=block [L,QSA] - -RewriteRule ^settings/profile$ index.php?action=profilesettings [L,QSA] -RewriteRule ^settings/avatar$ index.php?action=avatarsettings [L,QSA] -RewriteRule ^settings/password$ index.php?action=passwordsettings [L,QSA] -RewriteRule ^settings/openid$ index.php?action=openidsettings [L,QSA] -RewriteRule ^settings/im$ index.php?action=imsettings [L,QSA] -RewriteRule ^settings/email$ index.php?action=emailsettings [L,QSA] -RewriteRule ^settings/sms$ index.php?action=smssettings [L,QSA] -RewriteRule ^settings/twitter$ index.php?action=twittersettings [L,QSA] -RewriteRule ^settings/other$ index.php?action=othersettings [L,QSA] - -RewriteRule ^search/group$ index.php?action=groupsearch [L,QSA] -RewriteRule ^search/people$ index.php?action=peoplesearch [L,QSA] -RewriteRule ^search/notice$ index.php?action=noticesearch [L,QSA] -RewriteRule ^search/notice/rss$ index.php?action=noticesearchrss [L,QSA] - -RewriteRule ^notice/new$ index.php?action=newnotice [L,QSA] -RewriteRule ^notice/(\d+)$ index.php?action=shownotice¬ice=$1 [L,QSA] -RewriteRule ^notice/delete/((\d+))?$ index.php?action=deletenotice¬ice=$2 [L,QSA] -RewriteRule ^notice/delete$ index.php?action=deletenotice [L,QSA] - -RewriteRule ^message/new$ index.php?action=newmessage [L,QSA] -RewriteRule ^message/(\d+)$ index.php?action=showmessage&message=$1 [L,QSA] - -RewriteRule ^user/(\d+)$ index.php?action=userbyid&id=$1 [L,QSA] - -RewriteRule ^tags/?$ index.php?action=publictagcloud [L,QSA] -RewriteRule ^tag/([a-zA-Z0-9]+)/rss$ index.php?action=tagrss&tag=$1 [L,QSA] -RewriteRule ^tag(/(.*))?$ index.php?action=tag&tag=$2 [L,QSA] - -RewriteRule ^peopletag/([a-zA-Z0-9]+)$ index.php?action=peopletag&tag=$1 [L,QSA] - -RewriteRule ^featured/?$ index.php?action=featured [L,QSA] -RewriteRule ^favorited/?$ index.php?action=favorited [L,QSA] - -RewriteRule ^group/new$ index.php?action=newgroup [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/edit$ index.php?action=editgroup&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/join$ index.php?action=joingroup&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/leave$ index.php?action=leavegroup&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/members$ index.php?action=groupmembers&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/logo$ index.php?action=grouplogo&nickname=$1 [L,QSA] -RewriteRule ^group/([0-9]+)/id$ index.php?action=groupbyid&id=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/rss$ index.php?action=grouprss&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)$ index.php?action=showgroup&nickname=$1 [L,QSA] -RewriteRule ^group$ index.php?action=groups [L,QSA] - -# Twitter-compatible API rewrites -# XXX: Surely these can be refactored a little -- Zach -RewriteRule ^api/statuses/public_timeline(.*)$ index.php?action=api&apiaction=statuses&method=public_timeline$1 [L,QSA] -RewriteRule ^api/statuses/friends_timeline(.*)$ index.php?action=api&apiaction=statuses&method=friends_timeline$1 [L,QSA] -RewriteRule ^api/statuses/user_timeline/(.*)$ index.php?action=api&apiaction=statuses&method=user_timeline&argument=$1 [L,QSA] -RewriteRule ^api/statuses/user_timeline(.*)$ index.php?action=api&apiaction=statuses&method=user_timeline$1 [L,QSA] -RewriteRule ^api/statuses/show/(.*)$ index.php?action=api&apiaction=statuses&method=show&argument=$1 [L,QSA] -RewriteRule ^api/statuses/update(.*)$ index.php?action=api&apiaction=statuses&method=update$1 [L,QSA] -RewriteRule ^api/statuses/replies(.*)$ index.php?action=api&apiaction=statuses&method=replies&argument=$1 [L,QSA] -RewriteRule ^api/statuses/destroy/(.*)$ index.php?action=api&apiaction=statuses&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/statuses/friends/(.*)$ index.php?action=api&apiaction=statuses&method=friends&argument=$1 [L,QSA] -RewriteRule ^api/statuses/friends(.*)$ index.php?action=api&apiaction=statuses&method=friends$1 [L,QSA] -RewriteRule ^api/statuses/followers/(.*)$ index.php?action=api&apiaction=statuses&method=followers&argument=$1 [L,QSA] -RewriteRule ^api/statuses/followers(.*)$ index.php?action=api&apiaction=statuses&method=followers$1 [L,QSA] -RewriteRule ^api/statuses/featured(.*)$ index.php?action=api&apiaction=statuses&method=featured$1 [L,QSA] -RewriteRule ^api/users/show/(.*)$ index.php?action=api&apiaction=users&method=show&argument=$1 [L,QSA] -RewriteRule ^api/users/show(.*)$ index.php?action=api&apiaction=users&method=show$1 [L,QSA] -RewriteRule ^api/direct_messages/sent(.*)$ index.php?action=api&apiaction=direct_messages&method=sent$1 [L,QSA] -RewriteRule ^api/direct_messages/destroy/(.*)$ index.php?action=api&apiaction=direct_messages&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/direct_messages/new(.*)$ index.php?action=api&apiaction=direct_messages&method=create$1 [L,QSA] -RewriteRule ^api/direct_messages(.*)$ index.php?action=api&apiaction=direct_messages&method=direct_messages$1 [L,QSA] -RewriteRule ^api/friendships/create/(.*)$ index.php?action=api&apiaction=friendships&method=create&argument=$1 [L,QSA] -RewriteRule ^api/friendships/destroy/(.*)$ index.php?action=api&apiaction=friendships&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/friendships/exists(.*)$ index.php?action=api&apiaction=friendships&method=exists$1 [L,QSA] -RewriteRule ^api/account/verify_credentials(.*)$ index.php?action=api&apiaction=account&method=verify_credentials$1 [L,QSA] -RewriteRule ^api/account/end_session$ index.php?action=api&apiaction=account&method=end_session$1 [L,QSA] -RewriteRule ^api/account/update_location(.*)$ index.php?action=api&apiaction=account&method=update_location$1 [L,QSA] -RewriteRule ^api/account/update_delivery_device(.*)$ index.php?action=api&apiaction=account&method=update_delivery_device$1 [L,QSA] -RewriteRule ^api/account/rate_limit_status(.*)$ index.php?action=api&apiaction=account&method=rate_limit_status$1 [L,QSA] -RewriteRule ^api/favorites/create/(.*)$ index.php?action=api&apiaction=favorites&method=create&argument=$1 [L,QSA] -RewriteRule ^api/favorites/destroy/(.*)$ index.php?action=api&apiaction=favorites&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/favorites/(.*)$ index.php?action=api&apiaction=favorites&method=favorites&argument=$1 [L,QSA] -RewriteRule ^api/favorites(.*)$ index.php?action=api&apiaction=favorites&method=favorites$1 [L,QSA] -RewriteRule ^api/notifications/follow/(.*)$ index.php?action=api&apiaction=notifications&method=follow&argument=$1 [L,QSA] -RewriteRule ^api/notifications/leave/(.*)$ index.php?action=api&apiaction=notifications&method=leave&argument=$1 [L,QSA] -RewriteRule ^api/blocks/create/(.*)$ index.php?action=api&apiaction=blocks&method=create&argument=$1 [L,QSA] -RewriteRule ^api/blocks/destroy/(.*)$ index.php?action=api&apiaction=blocks&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/help/(.*)$ index.php?action=api&apiaction=help&method=$1 [L,QSA] -RewriteRule ^api/laconica/version(.*)$ index.php?action=api&apiaction=laconica&method=version$1 [L,QSA] -RewriteRule ^api/laconica/config(.*)$ index.php?action=api&apiaction=laconica&method=config$1 [L,QSA] -RewriteRule ^api/laconica/wadl\.xml$ index.php?action=api&apiaction=laconica&method=wadl.xml [L,QSA] - -RewriteRule ^(\w+)/subscriptions$ index.php?action=subscriptions&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/subscriptions/([a-zA-Z0-9]+)$ index.php?action=subscriptions&nickname=$1&tag=$2 [L,QSA] -RewriteRule ^(\w+)/subscribers/([a-zA-Z0-9]+)$ index.php?action=subscribers&nickname=$1&tag=$2 [L,QSA] -RewriteRule ^(\w+)/subscribers$ index.php?action=subscribers&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/nudge$ index.php?action=nudge&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/xrds$ index.php?action=xrds&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/rss$ index.php?action=userrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/all$ index.php?action=all&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/all/rss$ index.php?action=allrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/foaf$ index.php?action=foaf&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/replies$ index.php?action=replies&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/replies/rss$ index.php?action=repliesrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/avatar/(original|96|48|24)$ index.php?action=avatarbynickname&nickname=$1&size=$2 [L,QSA] -RewriteRule ^(\w+)/favorites$ index.php?action=showfavorites&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/favorites/rss$ index.php?action=favoritesrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/inbox$ index.php?action=inbox&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/outbox$ index.php?action=outbox&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/microsummary$ index.php?action=microsummary&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/groups$ index.php?action=usergroups&nickname=$1 [L,QSA] - -RewriteRule ^(\w+)$ index.php?action=showstream&nickname=$1 [L,QSA] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule (.*) index.php?p=$1 [L,QSA] Order allow,deny diff --git a/index.php b/index.php index e62d9469ab..f334e2c345 100644 --- a/index.php +++ b/index.php @@ -22,69 +22,105 @@ define('LACONICA', true); require_once INSTALLDIR . '/lib/common.php'; -// XXX: we need a little more structure in this script +$user = null; +$action = null; -// get and cache current user - -$user = common_current_user(); - -// initialize language env - -common_init_language(); - -$action = $_REQUEST['action']; - -if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) { - common_redirect(common_local_url('public')); -} - -// 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'))) { - common_redirect(common_local_url('login')); -} - -$action_class = ucfirst($action).'Action'; - -if (!class_exists($action_class)) { - $cac = new ClientErrorAction(_('Unknown action'), 404); - $cac->showPage(); -} else { - $action_obj = new $action_class(); - - // XXX: find somewhere for this little block to live - - if ($config['db']['mirror'] && $action_obj->isReadOnly()) { - if (is_array($config['db']['mirror'])) { - // "load balancing", ha ha - $k = array_rand($config['db']['mirror']); - - $mirror = $config['db']['mirror'][$k]; - } else { - $mirror = $config['db']['mirror']; - } - $config['db']['database'] = $mirror; +function getPath($req) { + if (common_config('site', 'fancy')) { + return $req['p']; + } else if ($_SERVER['PATH_INFO']) { + return $_SERVER['PATH_INFO']; + } else { + return $req['p']; } +} - try { - if ($action_obj->prepare($_REQUEST)) { - $action_obj->handle($_REQUEST); - } - } catch (ClientException $cex) { - $cac = new ClientErrorAction($cex->getMessage(), $cex->getCode()); +function main() { + + global $user, $action; + + // XXX: we need a little more structure in this script + + // get and cache current user + + $user = common_current_user(); + + // initialize language env + + common_init_language(); + + $path = getPath($_REQUEST); + + $r = new Router(); + + $args = $r->map($path); + + if (!$args) { + $cac = new ClientErrorAction(_('Unknown page'), 404); $cac->showPage(); - } catch (ServerException $sex) { // snort snort guffaw - $sac = new ServerErrorAction($sex->getMessage(), $sex->getCode()); - $sac->showPage(); - } catch (Exception $ex) { - $sac = new ServerErrorAction($ex->getMessage()); - $sac->showPage(); + return; + } + + $args = array_merge($args, $_REQUEST); + + $action = $args['action']; + + if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) { + common_redirect(common_local_url('public')); + return; + } + + // 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'))) { + common_redirect(common_local_url('login')); + return; + } + + $action_class = ucfirst($action).'Action'; + + if (!class_exists($action_class)) { + $cac = new ClientErrorAction(_('Unknown action'), 404); + $cac->showPage(); + } else { + $action_obj = new $action_class(); + + // XXX: find somewhere for this little block to live + + if ($config['db']['mirror'] && $action_obj->isReadOnly()) { + if (is_array($config['db']['mirror'])) { + // "load balancing", ha ha + $k = array_rand($config['db']['mirror']); + + $mirror = $config['db']['mirror'][$k]; + } else { + $mirror = $config['db']['mirror']; + } + $config['db']['database'] = $mirror; + } + + try { + if ($action_obj->prepare($args)) { + $action_obj->handle($args); + } + } catch (ClientException $cex) { + $cac = new ClientErrorAction($cex->getMessage(), $cex->getCode()); + $cac->showPage(); + } catch (ServerException $sex) { // snort snort guffaw + $sac = new ServerErrorAction($sex->getMessage(), $sex->getCode()); + $sac->showPage(); + } catch (Exception $ex) { + $sac = new ServerErrorAction($ex->getMessage()); + $sac->showPage(); + } } } +main(); + // XXX: cleanup exit() calls or add an exit handler so // this always gets called diff --git a/lib/router.php b/lib/router.php new file mode 100644 index 0000000000..6781322a29 --- /dev/null +++ b/lib/router.php @@ -0,0 +1,340 @@ +. + * + * @category URL + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once 'Net/URL/Mapper.php'; + +/** + * URL Router + * + * Cheap wrapper around Net_URL_Mapper + * + * @category URL + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class Router +{ + var $m = null; + + function __construct() + { + $m = Net_URL_Mapper::getInstance(); + + // In the "root" + + $m->connect('', array('action' => 'public')); + $m->connect('rss', array('action' => 'publicrss')); + $m->connect('xrds', array('action' => 'publicxrds')); + $m->connect('featuredrss', array('action' => 'featuredrss')); + $m->connect('favoritedrss', array('action' => 'favoritedrss')); + $m->connect('opensearch/people', array('action' => 'opensearch', + 'type' => 'people')); + $m->connect('opensearch/notice', array('action' => 'opensearch', + 'type' => 'notice')); + + // docs + + $m->connect('doc/:title', array('action' => 'doc')); + + // facebook + + $m->connect('facebook', array('action' => 'facebookhome')); + $m->connect('facebook/index.php', array('action' => 'facebookhome')); + $m->connect('facebook/settings.php', array('action' => 'facebooksettings')); + $m->connect('facebook/invite.php', array('action' => 'facebookinvite')); + $m->connect('facebook/remove', array('action' => 'facebookremove')); + + // main stuff is repetitive + + $main = array('login', 'logout', 'register', 'subscribe', + 'unsubscribe', 'confirmaddress', 'recoverpassword', + 'invite', 'favor', 'disfavor', 'sup', + 'tagother', 'block'); + + foreach ($main as $a) { + $m->connect('main/'.$a, array('action' => $a)); + } + + // these take a code + + foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) { + $m->connect('main/'.$c.'/:code', array('action' => $c)); + } + + // exceptional + + $m->connect('main/openid', array('action' => 'openidlogin')); + $m->connect('main/remote', array('action' => 'remotesubscribe')); + + // settings + + foreach (array('profile', 'avatar', 'password', 'openid', 'im', + 'email', 'sms', 'twitter', 'other') as $s) { + $m->connect('settings/'.$s, array('action' => $s.'settings')); + } + + // search + + foreach (array('group', 'people', 'notice') as $s) { + $m->connect('search/'.$s, array('action' => $s.'search')); + } + + $m->connect('search/notice/rss', array('action' => 'noticesearchrss')); + + // notice + + $m->connect('notice/new', array('action' => 'newnotice')); + $m->connect('notice/:notice', + array('action' => 'shownotice'), + array('notice' => '[0-9]+')); + $m->connect('notice/delete', array('action' => 'deletenotice')); + $m->connect('notice/delete/:notice', + array('action' => 'deletenotice'), + array('notice' => '[0-9]+')); + + $m->connect('message/new', array('action' => 'newmessage')); + $m->connect('message/:message', + array('action' => 'showmessage'), + array('message' => '[0-9]+')); + + $m->connect('user/:id', + array('action' => 'userbyid'), + array('id' => '[0-9]+')); + + $m->connect('tags/?', array('action' => 'publictagcloud')); + $m->connect('tag/?', array('action' => 'publictagcloud')); + $m->connect('tag/:tag/rss', + array('action' => 'tagrss'), + array('tag' => '[a-zA-Z0-9]+')); + $m->connect('tag/:tag', + array('action' => 'tag'), + array('tag' => '[a-zA-Z0-9]+')); + + $m->connect('peopletag/:tag', + array('action' => 'peopletag'), + array('tag' => '[a-zA-Z0-9]+')); + + $m->connect('featured/?', array('action' => 'featured')); + $m->connect('favorited/?', array('action' => 'favorited')); + + // groups + + $m->connect('group/new', array('action' => 'newgroup')); + + foreach (array('edit', 'join', 'leave') as $v) { + $m->connect('group/:nickname/'.$v, + array('action' => $v.'group'), + array('nickname' => '[a-zA-Z0-9]+')); + } + + foreach (array('members', 'logo', 'rss') as $n) { + $m->connect('group/:nickname/'.$n, + array('action' => 'group'.$n), + array('nickname' => '[a-zA-Z0-9]+')); + } + + $m->connect('group/:id/id', + array('action' => 'groupbyid'), + array('id' => '[0-9]+')); + + $m->connect('group/:nickname', + array('action' => 'showgroup'), + array('nickname' => '[a-zA-Z0-9]+')); + + $m->connect('group/?', array('action' => 'groups')); + + // Twitter-compatible API + + // statuses API + + $m->connect('api/statuses/:method', + array('action' => 'api', + 'apiaction' => 'statuses'), + array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|friends|followers|featured)(\.(atom|rss|xml|json))?')); + + $m->connect('api/statuses/:method/:argument', + array('action' => 'api', + 'apiaction' => 'statuses'), + array('method' => '(user_timeline|show|destroy|friends|followers)')); + + // users + + $m->connect('api/users/show/:argument', + array('action' => 'api', + 'apiaction' => 'users')); + + $m->connect('api/users/:method', + array('action' => 'api', + 'apiaction' => 'users'), + array('method' => 'show(\.(xml|json|atom|rss))?')); + + // direct messages + + $m->connect('api/direct_messages/:method', + array('action' => 'api', + 'apiaction' => 'direct_messages'), + array('method' => '(sent|new)(\.(xml|json|atom|rss))?')); + + $m->connect('api/direct_messages/destroy/:argument', + array('action' => 'api', + 'apiaction' => 'direct_messages')); + + $m->connect('api/:method', + array('action' => 'api', + 'apiaction' => 'direct_messages'), + array('method' => 'direct_messages(\.(xml|json|atom|rss))?')); + + // friendships + + $m->connect('api/friendships/:method/:argument', + array('action' => 'api', + 'apiaction' => 'friendships'), + array('method' => '(create|destroy)')); + + $m->connect('api/friendships/:method', + array('action' => 'api', + 'apiaction' => 'friendships'), + array('method' => 'exists(\.(xml|json|rss|atom))')); + + // account + + $m->connect('api/account/:method', + array('action' => 'api', + 'apiaction' => 'account')); + + // favorites + + $m->connect('api/favorites/:method/:argument', + array('action' => 'api', + 'apiaction' => 'favorites')); + + $m->connect('api/favorites/:argument', + array('action' => 'api', + 'apiaction' => 'favorites', + 'method' => 'favorites')); + + $m->connect('api/:method', + array('action' => 'api', + 'apiaction' => 'favorites'), + array('method' => 'favorites(\.(xml|json|rss|atom))?')); + + // notifications + + $m->connect('api/notifications/:method/:argument', + array('action' => 'api', + 'apiaction' => 'favorites')); + + // blocks + + $m->connect('api/blocks/:method/:argument', + array('action' => 'api', + 'apiaction' => 'blocks')); + + // help + + $m->connect('api/help/:method', + array('action' => 'api', + 'apiaction' => 'help')); + + // laconica + + $m->connect('api/laconica/:method', + array('action' => 'api', + 'apiaction' => 'laconica')); + + // user stuff + + foreach (array('subscriptions', 'subscribers', + 'nudge', 'xrds', 'all', 'foaf', + 'replies', 'inbox', 'outbox', 'microsummary') as $a) { + $m->connect(':nickname/'.$a, + array('action' => $a), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('subscriptions', 'subscribers') as $a) { + $m->connect(':nickname/'.$a.'/:tag', + array('action' => $a), + array('tag' => '[a-zA-Z0-9]+', + 'nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('rss', 'groups') as $a) { + $m->connect(':nickname/'.$a, + array('action' => 'user'.$a), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('all', 'replies', 'favorites') as $a) { + $m->connect(':nickname/'.$a.'/rss', + array('action' => $a.'rss'), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + $m->connect(':nickname/favorites', + array('action' => 'showfavorites'), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + + $m->connect(':nickname/avatar/:size', + array('action' => 'avatarbynickname'), + array('size' => '(original|96|48|24)', + 'nickname' => '[a-zA-Z0-9]{1,64}')); + + $m->connect(':nickname', + array('action' => 'showstream'), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + + $this->m = $m; + } + + function map($path) + { + return $this->m->match($path); + } + + function build($action, $args=null, $fragment=null) + { + $action_arg = array('action' => $action); + + if ($args) { + $args = array_merge($args, $action_arg); + } else { + $args = $action_arg; + } + + return $this->m->generate($args, null, $fragment); + } +} \ No newline at end of file