diff options
author | in2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2004-03-15 15:30:22 +0800 |
---|---|---|
committer | in2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204> | 2004-03-15 15:30:22 +0800 |
commit | 0b8de94f2b29a383d6b42260a57d249a3ba88403 (patch) | |
tree | 8cb23ec0ab60185274a40bddd987192ddedc59f2 /pttpi | |
parent | 2428ed917d4a0c82c956c355de60b6dff1afca23 (diff) | |
download | pttbbs-0b8de94f2b29a383d6b42260a57d249a3ba88403.tar pttbbs-0b8de94f2b29a383d6b42260a57d249a3ba88403.tar.gz pttbbs-0b8de94f2b29a383d6b42260a57d249a3ba88403.tar.bz2 pttbbs-0b8de94f2b29a383d6b42260a57d249a3ba88403.tar.lz pttbbs-0b8de94f2b29a383d6b42260a57d249a3ba88403.tar.xz pttbbs-0b8de94f2b29a383d6b42260a57d249a3ba88403.tar.zst pttbbs-0b8de94f2b29a383d6b42260a57d249a3ba88403.zip |
no longer maintained
git-svn-id: http://opensvn.csie.org/pttbbs/trunk/not-maintained@1595 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
Diffstat (limited to 'pttpi')
-rw-r--r-- | pttpi/README | 4 | ||||
-rw-r--r-- | pttpi/cgi/Makefile | 16 | ||||
-rw-r--r-- | pttpi/cgi/pttpi.c | 249 | ||||
-rw-r--r-- | pttpi/cgi/t/.cvsignore | 1 | ||||
-rw-r--r-- | pttpi/cgi/t/article.list.pl | 16 | ||||
-rw-r--r-- | pttpi/cgi/t/article.readfn.pl | 15 | ||||
-rw-r--r-- | pttpi/cgi/t/board.getBid.pl | 12 | ||||
-rw-r--r-- | pttpi/cgi/t/board.getBrdInfo.pl | 15 | ||||
-rw-r--r-- | pttpi/cgi/t/board.getNarticle.pl | 14 | ||||
-rw-r--r-- | pttpi/cgi/t/class.list.pl | 14 | ||||
-rw-r--r-- | pttpi/cgi/t/host.pl.sample | 2 | ||||
-rw-r--r-- | pttpi/doc/spec | 50 | ||||
-rw-r--r-- | pttpi/include/pierr.h | 9 |
13 files changed, 417 insertions, 0 deletions
diff --git a/pttpi/README b/pttpi/README new file mode 100644 index 00000000..8f60ff6c --- /dev/null +++ b/pttpi/README @@ -0,0 +1,4 @@ +PTT Programming Interface + +這目前還是一個實驗性的東西, +它還不穩定, 沒有效率, 沒有經過完整測試, 並且 spec 還在編修中. diff --git a/pttpi/cgi/Makefile b/pttpi/cgi/Makefile new file mode 100644 index 00000000..42613de3 --- /dev/null +++ b/pttpi/cgi/Makefile @@ -0,0 +1,16 @@ +# $Id: Makefile,v 1.1 2003/05/19 01:33:00 in2 Exp $ + +.include "../../pttbbs.mk" + +CFLAGS+= -I../../include `xmlrpc-c-config cgi-server --cflags` +LDFLAGS+= `xmlrpc-c-config cgi-server --libs` + +UTIL_OBJS= \ + ../../util/util_cache.o ../../util/util_record.o ../../util/util_passwd.o +all: pttpi.cgi + +pttpi.cgi: pttpi.c + $(CC) $(CFLAGS) $(LDFLAGS) -o pttpi.cgi pttpi.c $(UTIL_OBJS) + +clean: + rm -f *.cgi *~ diff --git a/pttpi/cgi/pttpi.c b/pttpi/cgi/pttpi.c new file mode 100644 index 00000000..1e452f68 --- /dev/null +++ b/pttpi/cgi/pttpi.c @@ -0,0 +1,249 @@ +/* $Id: pttpi.c,v 1.5 2003/05/19 05:15:36 in2 Exp $ */ +#include "bbs.h" +#include "pierr.h" +#include <xmlrpc.h> +#include <xmlrpc_cgi.h> + +extern SHM_t *SHM; +typedef xmlrpc_int32 int32; + +#define errorexit() if( env->fault_occurred ) return NULL +int check_board_and_permission(int bid) +{ + return (bid < 0 || bid > MAX_BOARD || + !bcache[bid].brdname[0] || + (bcache[bid].brdattr & BRD_HIDE) || + (bcache[bid].level && !(bcache[bid].brdattr & BRD_POSTMASK) && + (bcache[bid].level & + ~(PERM_BASIC|PERM_CHAT|PERM_PAGE|PERM_POST|PERM_LOGINOK)))); +} + +#define check_bp_return(bid) \ + if( check_board_and_permission(bid) ) \ + return xmlrpc_build_value(env, "{s:i}", \ + "errno", PIERR_NOBRD); + +#define errorreturn(returncode) \ + return xmlrpc_build_value(env, "{s:i}", \ + "errno", returncode) + +xmlrpc_value * +getBid(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) +{ + /* !!! overwrite util_cache.c !!! */ + char *brdname; + int bid; + + xmlrpc_parse_value(env, param_array, "(s)", &brdname); + errorexit(); + + bid = getbnum(brdname); + return xmlrpc_build_value(env, "{s:i,s:s,s:i}", + "errno", (bid == -1 ? PIERR_NOBRD : PIERR_OK), + "brdname", brdname, + "bid", (int32)bid); +} + +xmlrpc_value * +getBrdInfo(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) +{ + int32 bid; + + xmlrpc_parse_value(env, param_array, "(i)", &bid); + errorexit(); + check_bp_return(bid); + + return xmlrpc_build_value(env, "{s:i,s:s,s:i,s:6,s:6,s:i}", + "errno", PIERR_OK, + "brdname", bcache[bid].brdname, + "bid", (int32)bid, + "title", bcache[bid].title, strlen(bcache[bid].title), + "BM", bcache[bid].BM, strlen(bcache[bid].BM), + "nuser", bcache[bid].nuser); +} + +char *getpath(int bid, char *fn) +{ + static char fpath[MAXPATHLEN]; + if( fn == NULL ) + fn = ""; + snprintf(fpath, sizeof(fpath), "boards/%c/%s/%s", + bcache[bid].brdname[0], bcache[bid].brdname, fn); + return fpath; +} + +int getfilesize(int bid, char *fn, int *fd) +{ + struct stat sb; + if( fd == NULL ){ + if( stat(getpath(bid, fn), &sb) < 0 ) + return -1; + } + else { + if( (*fd = open(getpath(bid, fn), O_RDONLY)) < 0 ) + return -1; + if( fstat(*fd, &sb) < 0 ){ + close(*fd); + return -1; + } + } + return sb.st_size; +} + +xmlrpc_value * +getNarticle(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) +{ + int bid, nas; + + xmlrpc_parse_value(env, param_array, "(i)", &bid); + errorexit(); + check_bp_return(bid); + nas = getfilesize(bid, ".DIR", NULL); + + return xmlrpc_build_value(env, "{s:i,s:i}", + "errno", (nas == -1 ? PIERR_INT : PIERR_OK), + "narticle", nas / sizeof(fileheader_t)); +} + +xmlrpc_value * +class_list(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) +{ + int bid; + boardheader_t *bptr; + xmlrpc_value *ret, *t; + + xmlrpc_parse_value(env, param_array, "(i)", &bid); + errorexit(); + + if( bid != 0 ) + check_bp_return(bid); + + if( bid != 0 && !(bcache[bid].brdattr & BRD_GROUPBOARD) ) + errorreturn(PIERR_NOTCLASS); + + ret = xmlrpc_build_value(env, "()"); + for( bptr = bcache[bid].firstchild[0] ; + bptr != (boardheader_t*)~0 ; + bptr = bptr->next[0] ){ + if( check_board_and_permission(bptr - bcache) ) + continue; + t = xmlrpc_build_value(env, "{s:i,s:s,s:6,s:i,s:6,s:i,s:b}", + "bid", (int32)(bptr - bcache), + "brdname", bptr->brdname, + "title", bptr->title + 5, strlen(bptr->title) - 5, + "gid", bptr->gid, + "BM", bptr->BM, strlen(bptr->BM), + "nuser", (int32)bptr->nuser, + "isclass", (xmlrpc_bool) + (bptr->brdattr & BRD_GROUPBOARD) ? 1 : 0 + ); + xmlrpc_array_append_item(env, ret, t); + } + return ret; +} + +xmlrpc_value * +article_list(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) +{ +#define MAXGETARTICLES 20 + xmlrpc_value *ret, *t; + fileheader_t art[MAXGETARTICLES]; + int32 bid, from, nArticles, fd, nGets, i; + + xmlrpc_parse_value(env, param_array, "(ii)", &bid, &from); + errorexit(); + check_bp_return(bid); + + if( (nArticles = getfilesize(bid, ".DIR", &fd)) < 0 ) + errorreturn(PIERR_INT); + nArticles /= sizeof(fileheader_t); + + if( from < 0 ) + from += nArticles; + if( from < 0 || from > nArticles ){ + close(fd); + errorreturn(PIERR_NOMORE); + } + + nGets = (((from + MAXGETARTICLES) < nArticles) ? + MAXGETARTICLES : (nArticles - from)); + if( (nGets = read(fd, art, nGets * sizeof(fileheader_t))) < 0 ){ + close(fd); + errorreturn(PIERR_INT); + } + close(fd); + nGets /= sizeof(fileheader_t); + + ret = xmlrpc_build_value(env, "()"); + for( i = 0 ; i < nGets ; ++i ){ + t = xmlrpc_build_value(env, "{s:i,s:s,s:i,s:s,s:s,s:6}", + "articleid", (int32)(from + i), + "filename", art[i].filename, + "recommend", (int32)art[i].recommend, + "owner", art[i].owner, + "date", art[i].date, + "title", art[i].title, strlen(art[i].title) + ); + xmlrpc_array_append_item(env, ret, t); + } + return ret; +} + +xmlrpc_value * +_article_readfn(xmlrpc_env *env, int bid, char *fn) +{ + char *content; + int fd, size; + xmlrpc_value *ret; + if( (size = getfilesize(bid, fn, &fd)) < 0 ) + errorreturn(PIERR_INT); + + content = (char *)malloc(sizeof(char) * size); + read(fd, content, size); + close(fd); + ret = xmlrpc_build_value(env, "{s:6}", "content", content, size); + free(content); + + return ret; +} + +xmlrpc_value * +article_readfn(xmlrpc_env *env, xmlrpc_value *param_array, void *user_data) +{ + int bid; + char *fn; + + xmlrpc_parse_value(env, param_array, "(is)", &bid, &fn); + errorexit(); + + if( fn == NULL || (fn[0] != 'M' && fn[0] != 'G') || fn[1] != '.' ) + errorreturn(PIERR_NOBRD); + check_bp_return(bid); + + return _article_readfn(env, bid, fn); +} + +int main(int argc, char **argv) +{ + attach_SHM(); + chdir(BBSHOME); + xmlrpc_cgi_init(XMLRPC_CGI_NO_FLAGS); + xmlrpc_cgi_add_method_w_doc("board.getBid", &getBid, NULL, "?", + "get bid from brdname"); + xmlrpc_cgi_add_method_w_doc("board.getBrdInfo", &getBrdInfo, NULL, "?", + "get board information"); + xmlrpc_cgi_add_method_w_doc("board.getNarticle", &getNarticle, NULL, "?", + "get # articles in the board"); + + xmlrpc_cgi_add_method_w_doc("class.list", &class_list, NULL, "?", + "list (C)lass"); + + xmlrpc_cgi_add_method_w_doc("article.list", &article_list, NULL, "?", + "article list"); + xmlrpc_cgi_add_method_w_doc("article.readfn", &article_readfn, NULL, "?", + "read the article by filename"); + + xmlrpc_cgi_process_call(); + xmlrpc_cgi_cleanup(); + return 0; +} diff --git a/pttpi/cgi/t/.cvsignore b/pttpi/cgi/t/.cvsignore new file mode 100644 index 00000000..9f20a79c --- /dev/null +++ b/pttpi/cgi/t/.cvsignore @@ -0,0 +1 @@ +host.pl diff --git a/pttpi/cgi/t/article.list.pl b/pttpi/cgi/t/article.list.pl new file mode 100644 index 00000000..27370aa1 --- /dev/null +++ b/pttpi/cgi/t/article.list.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl +# $Id: article.list.pl,v 1.1 2003/05/19 02:04:14 in2 Exp $ +use Frontier::Client; +use Frontier::RPC2; +use MIME::Base64; +use Data::Dumper; +do 'host.pl'; + +$bid = $ARGV[0] || 0; + +$server = Frontier::Client->new(url => $server_url); +$result = $server->call('article.list', + $bid, # bid + 0); # from # article + +print Dumper($result); diff --git a/pttpi/cgi/t/article.readfn.pl b/pttpi/cgi/t/article.readfn.pl new file mode 100644 index 00000000..e2d0bc27 --- /dev/null +++ b/pttpi/cgi/t/article.readfn.pl @@ -0,0 +1,15 @@ +#!/usr/bin/perl +# $Id: article.readfn.pl,v 1.1 2003/05/19 02:06:34 in2 Exp $ +use Frontier::Client; +use Frontier::RPC2; +use MIME::Base64; +use Data::Dumper; +do 'host.pl'; + +$bid = $ARGV[0] || 0; +$fn = $ARGV[1] || 'M.1047292518.A.48E'; + +$server = Frontier::Client->new(url => $server_url); +$result = $server->call('article.readfn', $bid, $fn); + +print decode_base64($result->{content}->value()); diff --git a/pttpi/cgi/t/board.getBid.pl b/pttpi/cgi/t/board.getBid.pl new file mode 100644 index 00000000..a628da4e --- /dev/null +++ b/pttpi/cgi/t/board.getBid.pl @@ -0,0 +1,12 @@ +#!/usr/bin/perl +# $Id: board.getBid.pl,v 1.1 2003/05/19 01:57:22 in2 Exp $ +use Frontier::Client; +use Data::Dumper; +do 'host.pl'; + +$brdname = $ARGV[0] || 'SYSOP'; +$server = Frontier::Client->new(url => $server_url); +$result = $server->call('board.getBid', $brdname); + +print "board.getBid($brdname) from $server_url:\n"; +print Dumper($result); diff --git a/pttpi/cgi/t/board.getBrdInfo.pl b/pttpi/cgi/t/board.getBrdInfo.pl new file mode 100644 index 00000000..7870e386 --- /dev/null +++ b/pttpi/cgi/t/board.getBrdInfo.pl @@ -0,0 +1,15 @@ +#!/usr/bin/perl +# $Id: board.getBrdInfo.pl,v 1.1 2003/05/19 01:58:27 in2 Exp $ +use Frontier::Client; +use Frontier::RPC2; +use MIME::Base64; +use Data::Dumper; +do 'host.pl'; + +$bid = $ARGV[0] || 0; + +$server = Frontier::Client->new(url => $server_url); +$result = $server->call('board.getBrdInfo', $bid); + +print Dumper($result); +print decode_base64($result->{title}->value()); diff --git a/pttpi/cgi/t/board.getNarticle.pl b/pttpi/cgi/t/board.getNarticle.pl new file mode 100644 index 00000000..a5fb56a1 --- /dev/null +++ b/pttpi/cgi/t/board.getNarticle.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl +# $Id: board.getNarticle.pl,v 1.1 2003/05/19 02:01:15 in2 Exp $ +use Frontier::Client; +use Frontier::RPC2; +use MIME::Base64; +use Data::Dumper; +do 'host.pl'; + +$bid = $ARGV[0] || 0; + +$server = Frontier::Client->new(url => $server_url); +$result = $server->call('board.getNarticle', $bid); + +print Dumper($result); diff --git a/pttpi/cgi/t/class.list.pl b/pttpi/cgi/t/class.list.pl new file mode 100644 index 00000000..9e10932b --- /dev/null +++ b/pttpi/cgi/t/class.list.pl @@ -0,0 +1,14 @@ +#!/usr/bin/perl +# $Id: class.list.pl,v 1.1 2003/05/19 02:02:52 in2 Exp $ +use Frontier::Client; +use Frontier::RPC2; +use MIME::Base64; +use Data::Dumper; +do 'host.pl'; + +$bid = $ARGV[0] || 0; + +$server = Frontier::Client->new(url => $server_url); +$result = $server->call('class.list', $bid); + +print Dumper($result); diff --git a/pttpi/cgi/t/host.pl.sample b/pttpi/cgi/t/host.pl.sample new file mode 100644 index 00000000..72669230 --- /dev/null +++ b/pttpi/cgi/t/host.pl.sample @@ -0,0 +1,2 @@ +#!/usr/bin/perl +$server_url = 'http://host_to_pttpi/path_to_pttpi/pttpi.cgi' diff --git a/pttpi/doc/spec b/pttpi/doc/spec new file mode 100644 index 00000000..e1460030 --- /dev/null +++ b/pttpi/doc/spec @@ -0,0 +1,50 @@ +board.getBid get bid from board name +input (s) + (board name) +output ({s:i, s:s, s:i}) + {errno => errno, + brdname => boardname, + bid => boardid} (bid = -1 if error) + + +board.getBrdInfo +get board information (by bid) +input (i) + (bid) +output ({s:i,s:s,s:i,s:6,s:6,s:i}) + {errno => errno, + brdname => boardname + bid => bid, + title => title (Base64), + BM => board manager(s) (Base64), + nuser => #users in this board, + } + +board.getNarticle +get # articles in the board +input (i) + (bid) +output ({s:i, s:s, s:i}) + {errno => errno, + narticle => #articles in the board} + +article.list +get article list of bid +input (ii) + (bid, from # article) +output: ({s:i,s:s,s:i,s:s,s:s,s:6}...) + [{articleid => article id, + filename => file name, + recommend => recommend, + owner => owner's userid, + date => date (format: mm/dd), + title => article title (Base64)}, + {...},...] + +article.readfn +read article by bid and filename +input (is) + (bid, filename) +output ({s:6}) + {content => content} + diff --git a/pttpi/include/pierr.h b/pttpi/include/pierr.h new file mode 100644 index 00000000..da462a36 --- /dev/null +++ b/pttpi/include/pierr.h @@ -0,0 +1,9 @@ +#ifndef _PIERR_H_ +#define _PIERR_H_ + +#define PIERR_OK (int32)0 /* no error */ +#define PIERR_INT (int32)1 /* internal error (ex: syscall failure) */ +#define PIERR_NOBRD (int32)2 /* no such board or permission denied */ +#define PIERR_NOMORE (int32)3 /* no more data */ +#define PIERR_NOTCLASS (int32)4 /* this bid is NOT class */ +#endif |