# # 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 . define('NO_GUI', 1); // blank page, please global $db; global $_USER; //So we load the $start variable, for the pages. if (!$_GET['page']) $start = getStart(1); else $start = getStart($_GET['page']); $params = PARAMS; $module = MODULE; $extra = EXTRA; /* Structure: http://myserver.com/$module[0].$module[1]/$params[0].$params[1]/$extra[0].$extra[1] $XXXXX[0] = the name , $XXXXX[1] = the extension */ $params = explode('.', $params); $module = explode('.', $module); $extra = explode('.', $extra); // If we find a cookie, then we set $_USER checkUserAPI(); // Because not all the applications can handle HTTP Errors, we allow them to overpass this limit if (isset($_GET['suppress_response_codes'])) $no401 = true; else $no401 = false; // If an application wants more than 25 notes, we allow it to load more than 25 notes. if (isset($_GET['count']) && (!empty($_GET['count']) && (is_numeric($_GET['count'])))) $count = $_GET['count']; else $count = NOTES_PER_PAGE; // Array containing the actions that an non-authentificated user can do $public_actions = array('/statuses/public_timeline', '/statuses/show', '/help/test', '/users/show'); if (!empty($params[0])) { if (!empty($extra[0])) { $action = '/'.$module[0].'/'.$params[0].'/'.$extra[0].'.'.$extra[1]; if (empty($extra[1])) $extension = 'basic'; else $extension = $extra[1]; } else { $action = '/'.$module[0].'/'.$params[0].'.'.$params[1]; if (empty($params[1])) $extension = 'basic'; else $extension = $params[1]; } } else { $action = '/'.$module[0].'.'.$module[1]; if (empty($module[1])) $extension = 'basic'; else $extension = $module[1]; } //We split $action in 2 strings, the action and the extension $explode = explode('.', $action); if (!in_array($explode[0], $public_actions)) { if ($_USER) { //Because the user is banned, it shouldn't have access to the API if ($_USER['status'] == 'banned') die(apiError($extension, $action, 'User not allowed.', $no401)); else extract($_USER); } else { if ($_SERVER['PHP_AUTH_USER'] && $_SERVER['PHP_AUTH_PW']) { if (filter_var($_SERVER['PHP_AUTH_USER'], FILTER_VALIDATE_EMAIL)) $_USER = $db->getUserInfoAPI(false, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); else $_USER = $db->getUserInfoAPI($_SERVER['PHP_AUTH_USER'], false, $_SERVER['PHP_AUTH_PW']); if (!empty($_USER)) { $SID = md5($_USER['password'].$_USER['salt'].$_USER['api'].time()); $db->newSession($_USER['ID'], $SID, 'api'); setcookie('JSESSIONID', $SID, time()+(86400*60)); } else header('WWW-Authenticate: Basic realm="'.NAME.'"'); } else header('WWW-Authenticate: Basic realm="'.NAME.'"'); } //The user is not logged, so we return a 401 Error. if (!$_USER) { die(apiError($extension, $action, 'This method requires authentication.', $no401)); } else { $db->updateLastSeen($_USER['ID'], time()); } } // OK, party starts here! if ($module[0] == 'statuses') { if ($params[0] == 'public_timeline') { $result = $db->getNotes('public', $start, $count, false, false, $_USER['ignored']); switch ($params[1]) { case 'xml': createXML('notes', $result); break; case 'json': createJSON('notes', $result); break; case 'rss': createRSS($result, __('Public notes from all the users'), __('Public notes from all the users'), 'statuses/public_timeline.rss'); break; } } elseif ($params[0] == 'friends_timeline') { $result = $db->getNotes('friends', $start, $count, $_USER['ID'], false, $_USER['ignored']); switch ($params[1]) { case 'xml': createXML('notes', $result); break; case 'json': createJSON('notes', $result); break; } } elseif ($params[0] == 'user_timeline') { $result = $db->getNotes('archive', $start, $count, $_USER['ID'], false); switch ($params[1]) { case 'xml': createXML('notes', $result); break; case 'json': createJSON('notes', $result); break; case 'rss': createRSS($result, __('Notes of ').$_USER['username'], __('Notes of ').$_USER['username'], 'statuses/user_timeline.rss'); break; } } elseif ($params[0] == 'replies') { $result = $db->getNotes('replies', $start, $count, $_USER['ID'], $_USER['username'], $_USER['ignored']); switch ($params[1]) { case 'xml': createXML('notes', $result); break; case 'json': createJSON('notes', $result); break; case 'rss': createRSS($result, __('Replies for ').$_USER['username'], __('Related replies to ').$_USER['username'], 'statuses/replies.rss'); break; } } elseif ($params[0] == 'followers') { if (!$extra[0]) $result = $db->getFollowers($_USER['ID'], $start, $count); else { if (!is_numeric($extra[0])) $extra[0] = $db->getIdByUser($extra[0]); $result = $db->getFollowers($extra[0], $start, $count); } switch ($extension) { case 'xml': createXML('users', $result); break; case 'json': createJSON('users', $result); break; } } elseif ($params[0] == 'friends') { if (!$extra[0]) $result = $db->getFollowing($_USER['ID'], $start, $count); else { if (!is_numeric($extra[0])) $extra[0] = $db->getIdByUser($extra[0]); $result = $db->getFollowing($extra[0], $start, $count); } switch ($extension) { case 'xml': createXML('users', $result); break; case 'json': createJSON('users', $result); break; } } elseif ($params[0] == 'show') { if (!$extra[0]) die(apiError($extension, $action, 'No status found with that ID.', $no401)); else { $result = $db->getNoteCombined($extra[0]); if (!$result) die(apiError($extension, $action, 'No status found with that ID.', $no401)); else { if ($type == 'private') { if (!$_USER['ID']) die(apiError($extension, $action, 'This method requires authentication.', $no401)); else { if ($db->checkFollowing($result['user_id'], $_USER['ID'])) { switch ($extra[1]) { case 'xml': createXML('notess', array('id'=>$extra[0])); break; case 'json': createJSON('notess', array('id'=>$extra[0])); break; } } else die(apiError($extension, $action, 'This method requires authentication.', $no401)); } } else { switch ($extra[1]) { case 'xml': createXML('notess', array('id'=>$extra[0])); break; case 'json': createJSON('notess', array('id'=>$extra[0])); break; } } } } } elseif ($params[0] == 'update') { if (!$_POST) die(apiError($extension, $action, 'This method requires a POST.', $no401)); else { if (!$_POST['status']) die(apiError($extension, $action, "Client must provide a 'status' parameter with a value.", $no401)); else { if ((time() - $_USER['last_note']) < WAIT_UNTIL_REPOST) die(apiError($extension, $action, 'Relax...', $no401)); global $skipauth; $skipauth = 1; if (empty($_POST['source'])) $source = 'api'; else $source = $_POST['source']; if ($_USER['twitter_username'] && ($_USER['twitter_username'] && ($_USER['post_tweets']))) $twitter = true; else $twitter = false; $result = postNote($_POST['status'], $_USER, $source, false, false, false, $twitter); switch ($params[1]) { case 'xml': createXML('notess', array('id'=>$result)); break; case 'json': createJSON('notess', array('id'=>$result)); break; } } } } elseif ($params[0] == 'destroy') { if (!$_POST || (!$_DELETE)) die(apiError($extension, $action, 'This method requires a POST or DELETE.')); else { if (!$extra[0]) die(apiError($extension, $action, 'No status found with that ID.')); else { $result = getNoteCombined($extra[0]); if (!$result) die(apiError($extension, $action, 'No status found with that ID.')); else { if ($result['username'] != $_SERVER['PHP_AUTH_USER']) die(apiError($extension, $action, "You may not delete another user's status.", $no401)); switch ($extra[1]) { case 'xml': createXML('notess', $extra[0]); break; case 'json': createJSON('notess', $extra[0]); break; } $result = $db->deleteNote($extra[0], false, $_SERVER['PHP_AUTH_USER']); } } } } } elseif ($module[0] == 'direct_messages') { if (!$params[0]) { $result = $db->getNotes('private', $start, $count, $_USER['ID'], $_USER['username']); switch ($module[1]) { case 'xml': createXML('direct_messages', $result); break; case 'json': createJSON('direct_messages', $result); break; case 'rss': createRSS($result, __('Private notes to ').$_USER['username'], __('Private notes to ').$_USER['username'], 'direct_messages.rss'); break; } } elseif ($params[0] == 'sent') { $result = $db->getNotes('private_sent', $start, $count, $_USER['ID'], $_USER['username']); switch ($params[1]) { case 'xml': createXML('direct_messages', $result); break; case 'json': createJSON('direct_messages', $result); break; case 'rss': createRSS($result, __('Private notes sent by ').$_USER['username'], __('Private notes sent by ').$_USER['username'], 'direct_messages/sent.rss'); break; } } } elseif ($module[0] == 'users') { if ($params[0] == 'show') { if (!$extra[0]) die(apiError($extension, $action, 'Not found', $no401)); else { if (!is_numeric($extra[0])) $userInfo = $db->getUserInfo(false, $extra[0]); else $userInfo = $db->getUserInfo($extra[0]); if (!$userInfo) die(apiError($extension, $action, 'Not found', $no401)); else { if ($userInfo['private'] == 1) { if (!$_USER['ID']) die(apiError($extension, $action, 'This method requires authentication.', $mo401)); else { if ($db->checkFollowing($userInfo['user_id'], $_USER['ID'])) { switch ($extra[1]) { case 'xml': createXML('users', $userInfo['ID']); break; case 'json': createJSON('users', array('id'=>$userInfo['ID'])); break; } } else die(apiError($extension, $action, 'This method requires authentication.', $no401)); } } else { switch ($extra[1]) { case 'xml': createXML('users', array('id'=>$userInfo['ID'])); break; case 'json': createJSON('users', array('id'=>$userInfo['ID'])); break; } } } } } } elseif ($module[0] == 'favorites') { if ($params[0] == 'create') { if (!$_POST) die(apiError($extension, $action, 'This method requires a POST.', $no401)); else { if ($extra[0]) { $result = $db->getNoteCombined($extra[0]); if (!$result) die(apiError($extension, $action, 'Not found', $no401)); else { $favorited = $db->checkFavorite($_USER['ID'], $extra[0]); if (!$favorited) { $db->newFavorite($_USER['ID'], $extra[0]); switch ($extra[1]) { case 'xml': createXML('notess', array('id'=>$extra[0])); break; case 'json': createJSON('notess', array('id'=>$extra[0])); break; } } else die(apiError($extension, $action, 'You have already favorited this status.', $no401)); } } } } elseif ($params[0] == 'destroy') { if ($_POST) die(apiError($extension, $action, 'This method requires a POST.', $no401)); else { if ($extra[0]) { $result = $db->getNoteCombined($extra[0]); if (!$result) die(apiError($extension, $action, 'Not found', $no401)); else { $favorited = $db->checkFavorite($_USER['ID'], $extra[0]); if ($favorited) { $db->deleteFavorite($_USER['ID'], $extra[0]); switch ($extra[1]) { case 'xml': createXML('notess', array('id'=>$extra[0])); break; case 'json': createJSON('notess', array('id'=>$extra[0])); break; } } else die(apiError($extension, $action, 'Not found.', $no401)); } } } } else { if (!$params[0]) $result = $db->getNotes('favorites', $start, $count, $_USER['ID'], false); else { if (!is_numeric($params[0])) $params[0] = $db->getIdByUser($params[0]); $result = $db->getNotes('favorites', $start, $count, $params[0], false); } switch ($params[1]) { case 'xml': createXML('notes', $result); break; case 'json': createJSON('notes', $result); break; case 'rss': if (!$params[0]) $title = __('Favorite notes of ').$_USER['username']; else $title = __('Favorite notes of ').$params[0]; createRSS($result, $title, $title, substr($action, 1)); break; } } } elseif ($module[0] == 'followers') { if ($params[0] == 'ids') { $result = $db->getFollowers($_USER['ID'], $start, $count); switch ($params[1]) { case 'xml': createXML('ids', $result); break; case 'json': createJSON('ids', $result); break; } } } elseif ($module[0] == 'friends') { if ($params[0] == 'ids') { $result = $db->getFollowing($_USER['ID'], $start, $count); switch ($params[1]) { case 'xml': createXML('ids', $result); break; case 'json': createJSON('ids', $result); break; } } } elseif ($module[0] == 'account') { if ($params[0] == 'verify_credentials') { switch ($params[1]) { case 'xml': createXML('users', array('id'=>$_USER['ID'])); break; case 'json': createJSON('acc_verif', array('id'=>$_USER['ID'])); break; default: echo 'Authorized'; break; } } elseif ($params[0] == 'rate_limit_status') { if ($params[1] == 'xml') { header('HTTP/1.0 200 OK'); header('Content-Type: text/xml charset=UTF-8'); $XMLWriter = new XMLWriter(); $XMLWriter->openURI('php://output'); $XMLWriter->startDocument('1.0', 'UTF-8'); $XMLWriter->startElement('hash'); $XMLWriter->startElement('reset-time'); $XMLWriter->writeAttribute('type','datetime'); $XMLWriter->text('2020-01-01T00:00:00+00:00'); $XMLWriter->endElement(); $XMLWriter->startElement('remaining-hits'); $XMLWriter->writeAttribute('type','integer'); $XMLWriter->text('10000'); $XMLWriter->endElement(); $XMLWriter->startElement('hourly-limit'); $XMLWriter->writeAttribute('type','integer'); $XMLWriter->text('10000'); $XMLWriter->endElement(); $XMLWriter->startElement('reset-time-in-seconds'); $XMLWriter->writeAttribute('type','integer'); $XMLWriter->text('1577836800'); $XMLWriter->endElement(); $XMLWriter->endElement(); $XMLWriter->flush(); } elseif ($params[1] == 'json') { header('Content-Type: text/javascript; charset=utf-8'); echo json_encode(array( 'hourly_limit' => 10000, 'reset_time_in_seconds' => 1577836800, 'reset_time' => 'Mon Jan 1 00:00:00 +0000 2012', 'remaining_hits' => 10000 )); } } elseif ($params[0] == 'end_session') { setcookie(NAME, '', time()-3600); } } elseif ($module[0] == 'help') { if ($params[0] == 'test') { switch ($params[1]) { case 'xml': echo 'true'; break; case 'json': echo '"ok"'; break; default: echo 'ok'; break; } } } ?>