summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorin2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2004-03-15 15:30:22 +0800
committerin2 <in2@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>2004-03-15 15:30:22 +0800
commit0b8de94f2b29a383d6b42260a57d249a3ba88403 (patch)
tree8cb23ec0ab60185274a40bddd987192ddedc59f2
parent2428ed917d4a0c82c956c355de60b6dff1afca23 (diff)
downloadpttbbs-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
-rw-r--r--pttpi/README4
-rw-r--r--pttpi/cgi/Makefile16
-rw-r--r--pttpi/cgi/pttpi.c249
-rw-r--r--pttpi/cgi/t/.cvsignore1
-rw-r--r--pttpi/cgi/t/article.list.pl16
-rw-r--r--pttpi/cgi/t/article.readfn.pl15
-rw-r--r--pttpi/cgi/t/board.getBid.pl12
-rw-r--r--pttpi/cgi/t/board.getBrdInfo.pl15
-rw-r--r--pttpi/cgi/t/board.getNarticle.pl14
-rw-r--r--pttpi/cgi/t/class.list.pl14
-rw-r--r--pttpi/cgi/t/host.pl.sample2
-rw-r--r--pttpi/doc/spec50
-rw-r--r--pttpi/include/pierr.h9
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