From 86672771393d552ac6d9c742fa1d80c34cc1cf74 Mon Sep 17 00:00:00 2001
From: ptt <ptt@63ad8ddf-47c3-0310-b6dd-a9e9d9715204>
Date: Fri, 18 Oct 2002 14:43:58 +0000
Subject: *** empty log message ***

git-svn-id: http://opensvn.csie.org/pttbbs/pttbbs/trunk/pttbbs@539 63ad8ddf-47c3-0310-b6dd-a9e9d9715204
---
 web/Makefile.old      | 120 ++++++++++++
 web/Makefile.tmpl     |  16 ++
 web/Makefile.tmpl.bak |  17 ++
 web/args.c            | 228 ++++++++++++++++++++++
 web/board.c           |  39 ++++
 web/chmod             |   1 +
 web/libptt.a          | Bin 0 -> 107932 bytes
 web/mail.c            |   6 +
 web/post.c            |   6 +
 web/stuff.c           | 269 ++++++++++++++++++++++++++
 web/user.c            |   6 +
 web/util_cache.c      | 516 ++++++++++++++++++++++++++++++++++++++++++++++++++
 web/util_passwd.c     | 141 ++++++++++++++
 web/util_record.c     | 245 ++++++++++++++++++++++++
 14 files changed, 1610 insertions(+)
 create mode 100644 web/Makefile.old
 create mode 100644 web/Makefile.tmpl
 create mode 100644 web/Makefile.tmpl.bak
 create mode 100755 web/args.c
 create mode 100644 web/board.c
 create mode 100644 web/chmod
 create mode 100644 web/libptt.a
 create mode 100644 web/mail.c
 create mode 100644 web/post.c
 create mode 100755 web/stuff.c
 create mode 100644 web/user.c
 create mode 100755 web/util_cache.c
 create mode 100755 web/util_passwd.c
 create mode 100755 web/util_record.c

diff --git a/web/Makefile.old b/web/Makefile.old
new file mode 100644
index 00000000..db2735bf
--- /dev/null
+++ b/web/Makefile.old
@@ -0,0 +1,120 @@
+##
+##  Apache Makefile, automatically generated by Configure script.
+##  Hand-edited changes will be lost if the Configure script is re-run.
+##  Sources: - ../../Makefile.config (via Configuration)
+##           - ./Makefile.tmpl
+##
+
+##
+##  Inherited Makefile options from Configure script
+##  (Begin of automatically generated section)
+##
+SRCDIR=../..
+EXTRA_CFLAGS=
+EXTRA_LDFLAGS=
+EXTRA_LIBS=
+EXTRA_INCLUDES=
+EXTRA_DEPS=
+OSDIR=$(SRCDIR)/os/unix
+INCDIR=$(SRCDIR)/include
+INCLUDES0=-I$(OSDIR) -I$(INCDIR) -I../$(INCDIR)
+SHELL=/bin/sh
+OS=FreeBSD 4.6
+CC=gcc
+CPP=gcc -E
+TARGET=httpd
+OPTIM=
+CFLAGS1= -funsigned-char -DUSE_EXPAT -I$(SRCDIR)/lib/expat-lite -DNO_DL_NEEDED
+INCLUDES1=
+LIBS_SHLIB=
+LDFLAGS1=
+MFLAGS_STATIC=
+REGLIB=
+EXPATLIB=lib/expat-lite/libexpat.a
+RANLIB=ranlib
+LIBS1=  -lcrypt
+##
+##  (End of automatically generated section)
+##
+
+##
+##  Default Makefile options from Configure script
+##  (Begin of automatically generated section)
+##
+CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS)
+LIBS=$(EXTRA_LIBS) $(LIBS1)
+INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES)
+LDFLAGS=$(LDFLAGS1) $(EXTRA_LDFLAGS)
+INCDIR=$(SRCDIR)/include
+OBJS=mod_ptt.o parse_html.o
+BBSLIBS=util_cache.o util_passwd.o util_record.o
+LIB=libptt.a
+SHLIBS=
+OBJS_PIC=
+
+all: lib shlib
+
+lib:	$(LIB) 
+
+shlib:	$(SHLIBS)
+
+dummy $(LIB): $(OBJS)
+	rm -f $@
+	ar cr $@ $(OBJS) $(BBSLIBS)
+	$(RANLIB) $@
+
+.SUFFIXES: .o .so .dll
+
+.c.o:
+	$(CC) -c $(INCLUDES) $(CFLAGS) $<
+
+.c.so:
+	$(CC) -c $(INCLUDES) $(CFLAGS) $(CFLAGS_SHLIB) $< && mv $*.o $*.lo
+	$(LD_SHLIB) $(LDFLAGS_SHLIB) -o $@ $*.lo $(LIBS_SHLIB)
+
+clean:
+	rm -f $(LIB) $(OBJS) $(SHLIBS) $(OBJS_PIC)
+
+distclean: clean
+	rm -f Makefile
+
+#   NOT FOR END USERS!
+depend:
+	cp Makefile.tmpl Makefile.tmpl.bak \
+	    && sed -ne '1,/^# DO NOT REMOVE/p' Makefile.tmpl > Makefile.new \
+	    && gcc -MM $(INCLUDES) $(CFLAGS) *.c >> Makefile.new \
+	    && sed -e '1,$$s: $(INCDIR)/: $$(INCDIR)/:g' \
+		   -e '1,$$s: $(OSDIR)/: $$(OSDIR)/:g' Makefile.new \
+		> Makefile.tmpl \
+	    && rm Makefile.new
+
+##
+##  (End of automatically generated section)
+##
+
+#Dependencies
+
+$(OBJS) $(OBJS_PIC): Makefile
+
+# DO NOT REMOVE
+mod_ptt.o: mod_ptt.c $(INCDIR)/httpd.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(INCDIR)/ap_ctype.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/ap_alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
+ $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
+ $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_protocol.h \
+ $(INCDIR)/util_script.h \
+ /home/bbs/pttbbs/include/bbs.h
+
+parse_html.o: parse_html.c $(INCDIR)/httpd.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(INCDIR)/ap_ctype.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/ap_alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
+ $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
+ $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_protocol.h \
+ $(INCDIR)/util_script.h \
+ /home/bbs/pttbbs/include/bbs.h
diff --git a/web/Makefile.tmpl b/web/Makefile.tmpl
new file mode 100644
index 00000000..83ed1e84
--- /dev/null
+++ b/web/Makefile.tmpl
@@ -0,0 +1,16 @@
+
+#Dependencies
+
+$(OBJS) $(OBJS_PIC): Makefile
+
+BBSLIBS=   util_cache.o util_record.o util_passwd.o
+
+# DO NOT REMOVE
+mod_ptt.o: mod_ptt.c $(INCDIR)/httpd.h $(INCDIR)/ap_config.h \
+ $(INCDIR)/ap_mmn.h $(INCDIR)/ap_config_auto.h \
+ $(OSDIR)/os.h $(OSDIR)/os-inline.c $(INCDIR)/ap_ctype.h \
+ $(INCDIR)/ap_alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
+ $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
+ $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_protocol.h \
+ $(INCDIR)/util_script.h
diff --git a/web/Makefile.tmpl.bak b/web/Makefile.tmpl.bak
new file mode 100644
index 00000000..e686b7a9
--- /dev/null
+++ b/web/Makefile.tmpl.bak
@@ -0,0 +1,17 @@
+
+#Dependencies
+
+$(OBJS) $(OBJS_PIC): Makefile
+
+BBSLIBS=   util_cache.o util_record.o util_passwd.o
+
+# DO NOT REMOVE
+mod_ptt.o: mod_ptt.c $(INCDIR)/httpd.h \
+ $(INCDIR)/ap_config.h $(INCDIR)/ap_mmn.h \
+ $(INCDIR)/ap_config_auto.h $(OSDIR)/os.h \
+ $(INCDIR)/ap_ctype.h $(INCDIR)/hsregex.h \
+ $(INCDIR)/ap_alloc.h $(INCDIR)/buff.h $(INCDIR)/ap.h \
+ $(INCDIR)/util_uri.h $(INCDIR)/http_config.h \
+ $(INCDIR)/http_core.h $(INCDIR)/http_log.h \
+ $(INCDIR)/http_main.h $(INCDIR)/http_protocol.h \
+ $(INCDIR)/util_script.h
diff --git a/web/args.c b/web/args.c
new file mode 100755
index 00000000..02e0fad0
--- /dev/null
+++ b/web/args.c
@@ -0,0 +1,228 @@
+/*  �ϥΤ�k: �ۤv���� r->method_number �P�_�O M_GET �� M_POST
+ */
+#include "mod_ptt.h"
+
+unsigned char xtoc(char ch1, char ch2) {
+  unsigned char d, up1, up2;
+
+  if (!isxdigit(ch1) || !isxdigit(ch2)) return ' ';
+
+  up1 = toupper(ch1);
+  up2 = toupper(ch2);
+
+  if (up1>='0' && up1<='9') d = up1-'0';
+  else d = up1-'A'+10;
+  d <<= 4;
+  if (up2>='0' && up2<='9') d += up2-'0';
+  else d += up2-'A'+10;
+
+  return d;
+}
+
+char * cstoxs(pool *p, char *str)
+{
+  char * newstr = pstrdup(p,""), *po = str;
+
+  for(po = str; *po; po++)
+    {
+	if(isprint(*po) && *po!=' ') newstr=psprintf(p, "%s%c", newstr,*po);
+	else newstr=psprintf(p, "%s%%%X", newstr, *po& 0xFF);
+    }
+  return newstr;
+}
+
+int  // Ptt: �ڭ��g����mygetchar �å[�Wfileupload���\�� 
+inital_postdata(request_rec *r, int *fileupload, char *boundary, 
+        char **data)
+{ 
+  char *buf, *mb;
+  int  size, off = 0, len_read; 
+  void (*handler)();
+ 
+  buf = table_get(r->subprocess_env,"CONTENT_TYPE"); 
+  if(!buf || 
+     (strncasecmp(buf,"application/x-www-form-urlencoded",33) && 
+             strncasecmp(buf,"multipart/form-data",19)))
+                return -1; 
+
+  if(!strncasecmp(buf,"multipart/form-data",19)) { 
+		if(!fileupload) return -1;
+                *fileupload=1; 
+                mb = strchr(buf,'='); 
+                if(mb) {
+			strcpy(boundary,mb+1);  
+			strtok(boundary, " ;\n");
+		       }
+                else return -1; 
+        } 
+ 
+  buf = table_get(r->subprocess_env,"CONTENT_LENGTH"); 
+  if(buf==NULL) return -1; 
+ 
+  size = atoi(buf); 
+  mb = (char *)palloc(r->pool,(size+1)*sizeof(char)); 
+ 
+  if(!mb || 
+     (setup_client_block(r ,REQUEST_CHUNKED_ERROR) != 0) ||               
+     (should_client_block(r) == 0)) 
+     return -1; 
+                 
+  hard_timeout("args.c copy script args", r);              
+  handler = signal(SIGPIPE, SIG_IGN);
+
+  while(size-off > 0 && (len_read = get_client_block 
+                (r, mb + off, size - off)) > 0) { 
+                        off += len_read; 
+        } 
+
+  signal(SIGPIPE, handler);
+  kill_timeout(r);
+
+  if(len_read < 0) return -1; // Ū�����~�����_
+  mb[size]=0; // Ptt:�I�����ݭn�a �]�����O�Φr��B�z�覡
+ (*data) = mb; 
+  return size; 
+} 
+
+#define ENCODED_NAME     " name=\""
+#define ENCODED_FILENAME " filename=\"" 
+#define ENCODED_CONTENT  "Content-Type: "
+
+//#define FILEDATAFILE DATABASEDIR "/" FDATA
+
+int 
+unescape(request_rec *r, char** name, char** value) {
+  static char *sp=NULL,  boundary[150]; 
+  static int fileupload,  boundarylen, dsize; 
+  pool *p = r->pool;
+  char   ch, ch1, *dp, *p0, *p1, *temp_sp, *ftype;
+  int type;
+
+  if (sp==NULL) {
+    fileupload=0;
+    switch (r->method_number) { 
+	    case M_GET: 
+	       if (r->args) sp = pstrdup(p, r->args);
+	       else {sp=NULL; return -1;}
+	       break;
+	    case M_POST:
+	       if ((dsize = 
+		 inital_postdata(r, &fileupload, boundary,&sp))<0) 
+	           {sp=NULL; return -1; }
+	       if(fileupload) boundarylen = strlen(boundary);
+	       break;
+	    default: 
+	       sp=NULL;
+ 	       return -1; 
+	}
+   }
+
+  if(fileupload) 
+   {	
+	if(dsize >0 && (temp_sp = memstr(sp, boundary, dsize)))
+         { 
+	   temp_sp += boundarylen; 
+           p0 = strstr(temp_sp, "\r\n\r\n"); 
+           p1 = strstr(temp_sp, "\n\n"); 
+
+           if(!((*name) = strstr(temp_sp, ENCODED_NAME))) 
+		        {sp=NULL; return -1; }
+	   (*name) += strlen(ENCODED_NAME);
+	   strtok((*name) + 1 , "\"");
+	   if( (!p0 && p1) || (p0 && p1 && p1<p0)) 
+		{
+			(*value) = sp = p1 + 2;
+			type = 2;
+		}
+	   else if(p0)  
+		{
+                        (*value) = sp = p0 + 4; 
+			type = 4;
+		}
+	   else 
+		{
+	          sp=NULL; 
+ 	 	  return -1;
+	        }
+
+          if((p1 = memstr(temp_sp, boundary, dsize - boundarylen))) 
+		  temp_sp = p1;
+	  else
+		  temp_sp = sp + dsize;
+
+	  *(temp_sp - type) = 0;
+
+          // �ˬd�O���Ofile �Y�O�N��fileinfo
+          if((dp=memstr(
+  	      (*name) + strlen(*name) +1, ENCODED_FILENAME, dsize)) && 
+	      dp < *value)
+            {
+		dp += strlen(ENCODED_FILENAME);
+		p0 = strchr(dp,'"');
+                *p0 = 0;
+                if(p0 - dp>3)
+		{
+                 fileheader_t *file=(fileheader_t *)pcalloc(p, sizeof(fileheader_t));
+                 if((ftype = strstr(p0 + 1, ENCODED_CONTENT)))
+		  {
+ 		   ftype +=  strlen(ENCODED_CONTENT);
+		   strtok(ftype, "\r\n");
+		  }
+                 while(p0 > dp && *p0 !='/' && *p0 !='\\') p0--;
+                 strcpy(file->name, p0+1);    
+		 strcpy(file->content_type, ftype);
+		 file->icontent_type = filetype(ftype);
+	//	 if(file->icontent_type & (FILE_TXT | FILE_HTML))
+         //          file->size = strlen(sp);
+          //       else
+		   file->size = temp_sp - sp - type;
+		 file->uploadtime = time(NULL); 
+		 file->data = (*value);
+                 (*value) = (char *)file;
+		}
+               else
+                {
+                 (*value) = NULL;
+                }      
+            }     
+
+	  dsize -= (temp_sp - sp);
+	  sp = temp_sp;
+	  return 1;
+         } 
+        else 
+         { 
+          sp=NULL; 
+          return -1; 
+         }   
+  }
+
+  dp = (*name) = sp;  
+  while(1) {
+    ch = *sp++;
+    switch(ch) {
+      case '+':
+        *dp++ = ' ';
+        break;
+      case '=':
+        *dp++ = '\0';
+	(*value) = dp;
+	break;
+      case '&': case '|':
+        *dp++ = '\0';
+        return 1;
+      case '\0': case EOF:
+        *dp = '\0'; 
+	sp=NULL;
+        return 0;
+      case '%':
+        ch = *sp++; ch1 = *sp++;
+        *dp++ = xtoc(ch, ch1);
+        break;
+      default:
+	*dp++=ch;
+        break;
+    }
+  }
+}
+
diff --git a/web/board.c b/web/board.c
new file mode 100644
index 00000000..43347912
--- /dev/null
+++ b/web/board.c
@@ -0,0 +1,39 @@
+#include "mod_ptt.h"
+
+extern int numboards;
+extern boardheader_t *bcache;
+extern int ptt_handler(request_rec *r, void *args);
+
+int bbs_board(request_rec *r, void *args)
+{
+    int i;
+    r->content_type = "text/xml";
+    ap_send_http_header(r);
+    ap_rputs("<hr> Ptt \n", r);
+return ptt_handler (r,args);
+
+    ap_rprintf(r,"r->filename : %s <br>",r->filename);
+    ap_rprintf(r,"r->request_time : %s <br>",ctime(&r->request_time));
+    ap_rprintf(r,"r->method : %s <br>",r->method);
+    ap_rprintf(r,"r->method_number : %d <br>",r->method_number);
+    ap_rprintf(r,"r->path_info : %s <br>",r->path_info);
+    ap_rprintf(r,"r->args : %s <br>",r->args);
+    ap_rprintf(r,"r->unparsed_uri : %s <br>",r->unparsed_uri);
+    ap_rprintf(r,"r->uri : %s <br>",r->uri);
+    ap_rprintf(r,"r->handler : %s <br>",r->handler);
+    ap_rprintf(r,"r->content_type : %s <br>",r->content_type);
+    ap_rprintf(r, "Server built: \"%s\"\n", ap_get_server_built());
+
+    ap_rputs("<hr> Ptt \n", r);
+
+    ap_rputs("<XML>",r);
+/*
+    for(i = 0; i++ < numboards; i++)
+      {
+         ap_rputs("<board>",r);
+         ap_rputs("</board>",r);
+      }
+*/
+ 
+   return OK;
+}
diff --git a/web/chmod b/web/chmod
new file mode 100644
index 00000000..a91df6d5
--- /dev/null
+++ b/web/chmod
@@ -0,0 +1 @@
+ftasfdsf
diff --git a/web/libptt.a b/web/libptt.a
new file mode 100644
index 00000000..26c2f527
Binary files /dev/null and b/web/libptt.a differ
diff --git a/web/mail.c b/web/mail.c
new file mode 100644
index 00000000..9f226afe
--- /dev/null
+++ b/web/mail.c
@@ -0,0 +1,6 @@
+#include "mod_ptt.h"
+
+int bbs_mail(request_rec *r, void *args)
+{
+   return OK;
+}
diff --git a/web/post.c b/web/post.c
new file mode 100644
index 00000000..3e67937e
--- /dev/null
+++ b/web/post.c
@@ -0,0 +1,6 @@
+#include "mod_ptt.h"
+
+int bbs_post(request_rec *r, void *args)
+{
+   return OK;
+}
diff --git a/web/stuff.c b/web/stuff.c
new file mode 100755
index 00000000..b02dbb0d
--- /dev/null
+++ b/web/stuff.c
@@ -0,0 +1,269 @@
+/* Ptt : �`�Φr��禡��z */            
+#include "mod_ptt.h"
+
+// �ʤ� escape_url���F��
+
+/*
+ * �ɮקP�O
+ */      
+
+ /* �Ǧ^:���|�j�p */
+
+off_t
+dashs(fname)
+  char *fname;
+{
+  struct stat st;
+
+  if (!stat(fname, &st))
+        return (st.st_size);
+  else
+        return 0; /* �L���ɬO size 0 */
+}   
+
+ /* �Ǧ^:���|�ɶ� */
+long
+dasht(char *fname)
+{
+  struct stat st;
+
+  if (!stat(fname, &st))
+        return (st.st_mtime);
+  else
+        return -1;
+}
+
+ /* �Ǧ^:���|�O�_��link�� */
+int
+dashl(char *fname)
+{
+  struct stat st;   
+  return (lstat(fname, &st) == 0 && S_ISLNK(st.st_mode));
+}
+
+ /* �Ǧ^:���|�O�_���ɮ� */
+dashf(char *fname)
+{
+  struct stat st;
+
+  return (stat(fname, &st) == 0 && S_ISREG(st.st_mode));
+}
+
+/* �r�ꪺ�p�g */
+#define char_lower(c)  ((c >= 'A' && c <= 'Z') ? c|32 : c)                   
+
+void
+str_lower(t, s)
+  char *t, *s;
+{
+  register char ch;
+  do
+  {
+    ch = *s++;
+    *t++ = char_lower(ch);
+  } while (ch);
+}                
+
+int
+str_ncmp(s1, s2, n)
+  char *s1, *s2;
+  int n;
+{
+  int c1, c2;
+
+  while (n--)
+  {
+    c1 = *s1++;
+    if (c1 >= 'A' && c1 <= 'Z')
+      c1 |= 32;
+
+    c2 = *s2++;
+    if (c2 >= 'A' && c2 <= 'Z')
+      c2 |= 32;
+
+    if (c1 -= c2)
+      return (c1);
+
+    if (!c2)  
+      break;
+  }
+  return 0;
+}  
+char *
+memstr(char *mem, char *str, int size)
+{                        
+  char *loc, *ptr=mem, *end=mem+size;
+  int  len = strlen(str);
+  while((loc = memchr(ptr, *str, size)))
+   {
+     if(!strncmp(loc, str, len))
+	return loc;
+     ptr = loc +1;
+     size = (end - ptr);
+     if(size <=0 ) return NULL;
+   }
+  return NULL;
+}
+
+/* �Ǧ^: strstr����������p�j�p�g�����G */
+/*
+char *
+strcasestr(str, tag)
+  char *str, *tag;             
+{
+  char buf[BUFLEN];
+
+  str_lower(buf, str);
+  return  strstr(buf, tag);
+}
+*/
+                      
+/* �Ǧ^: �@��checksum ���r������ */
+
+int str_checksum(char *str)
+{
+  int n=1;
+  if(strlen(str) < 6) return 0;
+  while(*str)
+        n += *str++ ^ n;
+  return n;
+}
+                    
+int
+not_alpha(ch)
+  register char ch;
+{
+  return (ch < 'A' || (ch > 'Z' && ch < 'a') || ch > 'z');
+}  
+
+int
+not_alnum(ch)
+  register char ch;
+{
+  return (ch < '0' || (ch > '9' && ch < 'A') ||
+    (ch > 'Z' && ch < 'a') || ch > 'z');
+}           
+
+char
+ch2ph(char ch)
+{
+  static const
+  //             a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
+  char table[]={'2','2','2','3','3','3','4','4','4','5','5','5','6','6','6',
+  //      p   q   r   s   t   u   v   w   x   y   z
+         '7','1','7','7','8','8','8','9','9','9','1'};
+  static char d;
+  d = char_lower(ch);
+  if(d>='a' && d<='z') d=table[d-'a'];
+  return d;
+}
+
+void
+archiv32(chrono, fname)
+  time_t chrono;        /* 32 bits */
+  char *fname;          /* 7 chars */
+{
+  char *str;
+  char radix32[32] = {
+  '0', '1', '2', '3', '4', '5', '6', '7',
+  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
+  'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+  'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+  };
+
+  str = fname + 7;
+  *str = '\0';
+  for (;;)
+  {
+    *(--str) = radix32[chrono & 31];
+    if (str == fname)
+      return;
+    chrono >>= 5;
+  }
+}
+
+/* ARPANET�ɶ��榡 */
+char *
+Atime(clock) 
+  time_t *clock;
+{
+  static char datemsg[40];
+  /* ARPANET format: Thu, 11 Feb 1999 06:00:37 +0800 (CST) */
+  /* strftime(datemsg, 40, "%a, %d %b %Y %T %Z", localtime(clock)); */
+  /* time zone���Ǧ^�Ȥ����MARPANET�榡�O�_�@��,���w��,�Psendmail*/
+  strftime(datemsg, 40, "%a, %d %b %Y %T +0800 (CST)", localtime(clock));
+  return (datemsg);
+}
+
+
+/* userid�O�_�X�k */
+int
+bad_user_id(userid)
+  char *userid;
+{
+  register char ch;
+  if (strlen(userid) < 2)
+    return 1;
+  if (not_alpha(*userid))
+    return 1;
+  if (!strcasecmp(userid, "new") || !strcasecmp(userid, "guest") ||
+      !strcasecmp(userid, "root") || !strcasecmp(userid, "webadm") ||
+      !strncasecmp(userid,"yam",3)
+     )
+    return 1;
+
+  while (ch = *(++userid))             
+  {
+    if (not_alnum(ch) || ch == '0')
+      return 1;
+  }
+  return 0;
+}    
+
+
+int
+logfile(pool *p, char *filename,char *buf)
+{
+    FILE *fp;
+    time_t now;
+    if( (fp = ap_pfopen(p, filename, "a" )) ) {
+   
+        fputs( buf, fp );
+        if(!strchr(buf,'\n')) 
+	  { 
+	    now = time(NULL);
+	    fputs(ctime(&now), fp);
+	  }
+        ap_pfclose(p, fp );
+        return 0;
+    }
+    else{ 
+        printf("error open file");
+        return -1; 
+    }
+}
+
+/* �ˬd�����_�r���D */
+char *strexam(char *s)
+{
+  int i;
+  int odd;
+  for (i = 0, odd = 0; s[i]; i++)
+    if (odd) odd = 0;
+    else if (s[i] & 128) odd = 1;
+  if (odd) s[--i] = 0;
+  return s;
+}
+
+int
+maxline(char *data,char *newline, int max)
+{
+  register int n, nlen=strlen(newline);
+  register char *po;
+
+  for(n=0, po = data; (po = strstr(po, newline)); po+=nlen)
+   {
+      if(++n>=max) {*po=0; return -1;}
+   }
+  return n;
+}
diff --git a/web/user.c b/web/user.c
new file mode 100644
index 00000000..fe5d0696
--- /dev/null
+++ b/web/user.c
@@ -0,0 +1,6 @@
+#include "mod_ptt.h"
+
+int bbs_user(request_rec *r, void *args)
+{
+   return OK;
+}
diff --git a/web/util_cache.c b/web/util_cache.c
new file mode 100755
index 00000000..5178dad5
--- /dev/null
+++ b/web/util_cache.c
@@ -0,0 +1,516 @@
+/* $Id: util_cache.c,v 1.1 2002/10/18 14:43:58 ptt Exp $ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
+
+#ifdef __FreeBSD__
+#include <machine/param.h>
+#endif
+
+#include "config.h"
+#include "pttstruct.h"
+#include "common.h"
+#include "perm.h"
+#include "modes.h"
+#include "proto.h"
+
+/* the reason for "safe_sleep" is that we may call sleep during
+   SIGALRM handler routine, while SIGALRM is blocked.
+   if we use the original sleep, we'll never wake up. */
+unsigned int safe_sleep(unsigned int seconds) {
+    /* jochang  sleep�����D�ɥ�*/
+    sigset_t set,oldset;
+    
+    sigemptyset(&set);
+    sigprocmask(SIG_BLOCK, &set, &oldset);
+    if(sigismember(&oldset, SIGALRM)) {
+	unsigned long retv;
+	sigemptyset(&set);
+	sigaddset(&set,SIGALRM);
+	sigprocmask(SIG_UNBLOCK,&set,NULL);
+	retv=sleep(seconds);
+	sigprocmask(SIG_BLOCK,&set,NULL);
+	return retv;
+    }
+    return sleep(seconds);
+}
+
+void setapath(char *buf, char *boardname) {
+    sprintf(buf, "man/boards/%c/%s", boardname[0], boardname);
+}
+
+static char *str_dotdir = ".DIR";
+
+void setadir(char *buf, char *path) {
+    sprintf(buf, "%s/%s", path, str_dotdir);
+}
+
+static void attach_err(int shmkey, char *name) {
+    fprintf(stderr, "[%s error] key = %x\n", name, shmkey);
+    fprintf(stderr, "errno = %d: %s\n", errno, strerror(errno));
+    exit(1);
+}
+
+void *attach_shm(int shmkey, int shmsize) {
+    void *shmptr;
+    int shmid;
+
+    char *empty_addr;
+    /* set up one page in-accessible -- jochang */
+    {
+	int fd = open("/dev/zero",O_RDONLY);
+	int size = ((shmsize + 4095) / 4096) * 4096;
+	
+	munmap(
+	    (empty_addr=mmap(0,4096+size,PROT_NONE,MAP_PRIVATE,fd,0))+4096
+	    ,size);
+	
+	close(fd);
+    }
+    
+    shmid = shmget(shmkey, shmsize, 0);
+    if(shmid < 0) {
+	shmid = shmget(shmkey, shmsize, IPC_CREAT | 0600);
+	if(shmid < 0)
+	    attach_err(shmkey, "shmget");
+	shmptr = (void *)shmat(shmid, NULL, 0);
+	if(shmptr == (void *)-1)
+	    attach_err(shmkey, "shmat");
+    } else {
+	shmptr = (void *)shmat(shmid, NULL, 0);
+	if(shmptr == (void *)-1)
+	    attach_err(shmkey, "shmat");
+    }
+    
+    /* unmap the page -- jochang */
+    {
+	munmap(empty_addr,4096);		
+    }
+    return shmptr;
+}
+
+#ifndef __FreeBSD__
+/* according to X/OPEN we have to define it ourselves */
+union semun {
+    int val;                    /* value for SETVAL */
+    struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
+    unsigned short int *array;  /* array for GETALL, SETALL */
+    struct seminfo *__buf;      /* buffer for IPC_INFO */
+};
+#endif
+
+#define SEM_FLG        0600    /* semaphore mode */
+
+/* ----------------------------------------------------- */
+/* semaphore : for critical section                      */
+/* ----------------------------------------------------- */
+void sem_init(int semkey,int *semid) {
+    union semun s;
+
+    s.val=1;
+    *semid = semget(semkey, 1, 0);
+    if(*semid == -1) {
+	*semid = semget(semkey, 1, IPC_CREAT | SEM_FLG);
+	if(*semid == -1)
+	    attach_err(semkey, "semget");
+	semctl(*semid, 0, SETVAL, s);
+    }
+}
+
+void sem_lock(int op,int semid) {
+    struct sembuf sops;
+
+    sops.sem_num = 0;
+    sops.sem_flg = SEM_UNDO;
+    sops.sem_op = op;
+    semop(semid, &sops, 1);
+}
+
+SHM_t   *SHM;
+int     *GLOBALVAR;
+boardheader_t   *bcache;
+int     numboards = -1;
+
+void attach_SHM(void)
+{
+    SHM = attach_shm(SHM_KEY, sizeof(SHM_t));
+    if( !SHM->loaded ) /* (uhash) assume fresh shared memory is zeroed */
+	exit(1);
+    if( SHM->Btouchtime == 0 )
+	SHM->Btouchtime = 1;
+    bcache = SHM->bcache;
+    
+    GLOBALVAR = SHM->GLOBALVAR;
+    if( SHM->Ptouchtime == 0 )
+	SHM->Ptouchtime = 1;
+
+    if( SHM->Ftouchtime == 0 )
+	SHM->Ftouchtime = 1;
+
+    bcache = SHM->bcache;
+    numboards = SHM->Bnumber;
+}
+
+int setumoney(int uid, int money) {
+   SHM->money[uid-1]=money;
+   passwd_update_money(uid);
+   return SHM->money[uid-1];
+}
+
+int deumoney(int uid, int money) {
+   if(money<0 && SHM->money[uid-1]<-money)
+       return setumoney(uid,0);
+   else
+       return setumoney(uid,SHM->money[uid-1]+money);
+}
+int moneyof(int uid){   /* ptt ��i�����B�z�IJv */
+   return SHM->money[uid-1];
+}
+
+static unsigned string_hash(unsigned char *s) {
+    unsigned int v=0;
+    while(*s) {
+	v = (v << 8) | (v >> 24);
+	v ^= toupper(*s++);	/* note this is case insensitive */
+    }
+    return (v * 2654435769UL) >> (32 - HASH_BITS);
+}
+
+void add_to_uhash(int n, char *id) {
+    int *p, h = string_hash(id);
+    strcpy(SHM->userid[n], id);
+    
+    p = &(SHM->hash_head[h]);
+			
+    while(*p != -1)
+	p = &(SHM->next_in_hash[*p]);
+				
+    SHM->next_in_hash[*p = n] = -1;
+}
+
+/* note: after remove_from_uhash(), you should add_to_uhash()
+   (likely with a different name) */
+void remove_from_uhash(int n) {
+    int h = string_hash(SHM->userid[n]);
+    int *p = &(SHM->hash_head[h]);
+    
+    while(*p != -1 && *p != n)
+	p = &(SHM->next_in_hash[*p]);
+    if(*p == n)
+	*p = SHM->next_in_hash[n];
+}
+
+int searchuser(char *userid) {
+    int h,p;
+    
+    if(SHM == NULL)
+	attach_SHM();	/* for sloopy util programs */
+    
+    h = string_hash(userid);
+    p = SHM->hash_head[h];
+	
+    while(p != -1) {
+	if(strcasecmp(SHM->userid[p],userid) == 0) {
+	    strcpy(userid,SHM->userid[p]);
+	    return p + 1;
+	}
+	p = SHM->next_in_hash[p];
+    }
+    return 0;
+}
+userec_t xuser;
+
+int getuser(char *userid) {
+    int uid;
+    if((uid = searchuser(userid)))
+        passwd_query(uid, &xuser);
+    return uid;
+}   
+
+void setuserid(int num, char *userid) {
+    if(num > 0 && num <= MAX_USERS) {
+	if(num > SHM->number)
+	    SHM->number = num;
+	else
+	    remove_from_uhash(num-1);
+	add_to_uhash(num-1,userid);
+    }
+}
+
+/*-------------------------------------------------------*/
+/* .UTMP cache                                           */
+/*-------------------------------------------------------*/
+void resolve_utmp() {
+    if(SHM == NULL) {
+	attach_SHM();
+	if(SHM->UTMPuptime == 0)
+	    SHM->UTMPuptime = SHM->UTMPnumber = 1;
+    }
+}
+
+userinfo_t *currutmp = NULL;
+
+void getnewutmpent(userinfo_t *up) {
+    extern int errno;
+    register int i;
+    register userinfo_t *uentp;
+
+    resolve_utmp();
+    
+    for(i = 0; i < USHM_SIZE; i++) {
+	uentp = &(SHM->uinfo[i]);
+	if(!(uentp->pid)) {
+	    memcpy(uentp, up, sizeof(userinfo_t));
+	    currutmp = uentp;
+	    SHM->number++;
+	    return;
+	}
+    }
+    exit(1);
+}
+
+int apply_ulist(int (*fptr)(userinfo_t *)) {
+    register userinfo_t *uentp;
+    register int i, state;
+
+    resolve_utmp();
+    for(i = 0; i < USHM_SIZE; i++) {
+	uentp = &(SHM->uinfo[i]);
+	if(uentp->pid && (PERM_HIDE(currutmp) || !PERM_HIDE(uentp)))
+	    if((state = (*fptr) (uentp)))
+		return state;
+    }
+    return 0;
+}
+
+userinfo_t *search_ulist(int uid) {
+    register int i;
+    register userinfo_t *uentp;
+    
+    resolve_utmp();
+    for(i = 0; i < USHM_SIZE; i++) {
+	uentp = &(SHM->uinfo[i]);
+	if(uid==uentp->uid)
+	    return uentp;
+    }
+    return 0;
+}
+
+/*-------------------------------------------------------*/
+/* .BOARDS cache                                         */
+/*-------------------------------------------------------*/
+char *fn_board=BBSHOME"/"FN_BOARD;
+static void reload_bcache() {
+    if(SHM->Bbusystate) {
+	safe_sleep(1);
+    }
+}
+
+void resolve_boards() {
+    if(SHM == NULL) {
+	attach_SHM();
+	if(SHM->Btouchtime == 0)
+	    SHM->Btouchtime = 1;
+    }
+
+    while(SHM->Buptime < SHM->Btouchtime)
+	reload_bcache();
+    numboards = SHM->Bnumber;
+}
+
+void touch_boards() {
+    time(&(SHM->Btouchtime));
+    numboards = -1;
+    resolve_boards();  
+}
+void reset_board(int bid)
+{
+  int fd;
+  boardheader_t bh;
+  if(--bid<0)return;
+  if(SHM->Bbusystate==0)
+   {
+    SHM->Bbusystate = 1;
+    if((fd = open(fn_board, O_RDONLY)) > 0) {
+      lseek(fd, (off_t)(bid *  sizeof(boardheader_t)), SEEK_SET);
+      read(fd, &bh , sizeof(boardheader_t));
+      close(fd);
+      if(bh.brdname[0] && !strcmp(bh.brdname,bcache[bid].brdname))
+         memcpy(&bcache[bid],&bh, sizeof(boardheader_t));
+    }
+    SHM->Bbusystate = 0;
+   }
+}
+boardheader_t *getbcache(int bid) { /* Ptt��g */
+    return bcache + bid - 1;
+}
+
+void touchbtotal(int bid) {
+    SHM->total[bid - 1] = 0;
+    SHM->lastposttime[bid - 1] = 0;
+}
+
+
+int getbnum(char *bname) {
+    register int i;
+    register boardheader_t *bhdr;
+    
+    for(i = 0, bhdr = bcache; i++ < numboards; bhdr++)
+	if(
+	    !strcasecmp(bname, bhdr->brdname))
+	    return i;
+    return 0;
+}
+
+/*-------------------------------------------------------*/
+/* PTT  cache                                            */
+/*-------------------------------------------------------*/
+/* cachefor �ʺA�ݪ� */
+void reload_pttcache(void)
+{
+    if(SHM->Pbusystate)
+	safe_sleep(1);
+    else {				/* jochang: temporary workaround */
+	fileheader_t item, subitem;
+	char pbuf[256], buf[256], *chr;
+	FILE *fp, *fp1, *fp2;
+	int id, section = 0;
+
+	SHM->Pbusystate = 1;
+	SHM->max_film = 0;
+	bzero(SHM->notes, sizeof SHM->notes);
+	setapath(pbuf, "Note");
+	setadir(buf, pbuf);
+	id = 0;
+	if((fp = fopen(buf, "r"))) {
+	    while(fread(&item, sizeof(item), 1, fp)) {
+		if(item.title[3]=='<' && item.title[8]=='>') {
+		    sprintf(buf,"%s/%s", pbuf, item.filename);
+		    setadir(buf, buf);
+		    if(!(fp1 = fopen(buf, "r")))
+			continue;
+		    SHM->next_refresh[section] = SHM->n_notes[section] = id;
+		    section ++;
+		    while(fread(&subitem, sizeof(subitem), 1, fp1)) {
+			sprintf(buf,"%s/%s/%s", pbuf, item.filename ,
+				subitem.filename);
+			if(!(fp2=fopen(buf,"r")))
+			    continue;
+			fread(SHM->notes[id],sizeof(char), 200*11, fp2);
+			SHM->notes[id][200*11 - 1]=0;
+			id++;
+			fclose(fp2);
+			if(id >= MAX_MOVIE)
+			    break;  
+		    }
+		    fclose(fp1);	   
+		    if(id >= MAX_MOVIE || section >= MAX_MOVIE_SECTION)
+			break;	  
+		}
+	    }
+	    fclose(fp);
+	}
+	SHM->next_refresh[section] = -1;
+	SHM->n_notes[section] = SHM->max_film = id-1;
+	SHM->max_history = SHM->max_film - 2;
+	if(SHM->max_history > MAX_HISTORY - 1)
+	    SHM->max_history = MAX_HISTORY - 1;
+	if(SHM->max_history <0) SHM->max_history=0;
+
+	fp = fopen("etc/today_is","r");
+	if(fp) {
+	    fgets(SHM->today_is,15,fp);
+	    if((chr = strchr(SHM->today_is,'\n')))
+		*chr = 0;
+	    SHM->today_is[15] = 0;
+	    fclose(fp);
+	}
+     
+	/* ���Ҧ���Ƨ�s��A�]�w uptime */
+
+	SHM->Puptime = SHM->Ptouchtime ;
+	SHM->Pbusystate = 0;
+    }
+}
+
+void resolve_garbage() {
+    int count=0;
+    
+    if(SHM == NULL) {
+	attach_SHM();
+	if(SHM->Ptouchtime == 0)
+	    SHM->Ptouchtime = 1;
+    }
+    while(SHM->Puptime < SHM->Ptouchtime) { /* ����while�� */
+	reload_pttcache();
+	if(count ++ > 10 && SHM->Pbusystate) {
+/* Ptt: �o��|�����D  load�W�L10 ���|�Ҧ��iloop��process���� busystate = 0
+   �o�˷|�Ҧ�prcosee���|�bload �ʺA�ݪO �|�y��load�j�W
+   ���S���γo��function���� �U�@load passwd�ɪ�process���F �S�S���H��L
+   �Ѷ}  �P�˪����D�o�ͦbreload passwd
+*/    
+	    SHM->Pbusystate = 0;
+	}
+    }
+}
+
+/*-------------------------------------------------------*/
+/* PTT's cache                                           */
+/*-------------------------------------------------------*/
+/* cachefor from host �P�̦h�W�u�H�� */
+static void reload_fcache() {
+    if(SHM->Fbusystate)
+	safe_sleep(1);
+    else {
+	FILE *fp;
+
+	SHM->Fbusystate = 1;
+	bzero(SHM->domain, sizeof SHM->domain);
+	if((fp = fopen("etc/domain_name_query","r"))) {
+	    char buf[101],*po;
+
+	    SHM->top=0;
+	    while(fgets(buf,100,fp)) {
+		if(buf[0] && buf[0] != '#' && buf[0] != ' ' &&
+		   buf[0] != '\n') {
+		    sscanf(buf,"%s",SHM->domain[SHM->top]);
+		    po = buf + strlen(SHM->domain[SHM->top]);
+		    while(*po == ' ')
+			po++;
+		    strncpy(SHM->replace[SHM->top],po,49);
+		    SHM->replace[SHM->top]
+			[strlen(SHM->replace[SHM->top])-1] = 0;
+		    (SHM->top)++;
+		}	
+	    }
+	}
+
+	SHM->max_user=0;
+
+	/* ���Ҧ���Ƨ�s��A�]�w uptime */
+	SHM->Fuptime = SHM->Ftouchtime;
+	SHM->Fbusystate = 0;
+    }
+}
+
+void resolve_fcache() {
+    if(SHM == NULL) {
+	attach_SHM();
+	if(SHM->Ftouchtime == 0)
+	    SHM->Ftouchtime = 1;
+    }
+    while(SHM->Fuptime < SHM->Ftouchtime)
+	reload_fcache();
+}
diff --git a/web/util_passwd.c b/web/util_passwd.c
new file mode 100755
index 00000000..03e90f6c
--- /dev/null
+++ b/web/util_passwd.c
@@ -0,0 +1,141 @@
+/* $Id: util_passwd.c,v 1.1 2002/10/18 14:43:58 ptt Exp $ */
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "common.h"
+#include "proto.h"
+
+#ifndef SEM_R
+#define SEM_R 0400
+#endif
+
+#ifndef SEM_A
+#define SEM_A 0200
+#endif
+
+#ifndef __FreeBSD__
+union semun {
+        int     val;            /* value for SETVAL */
+        struct  semid_ds *buf;  /* buffer for IPC_STAT & IPC_SET */
+        u_short *array;         /* array for GETALL & SETALL */
+        struct seminfo *__buf;  /* buffer for IPC_INFO */
+};
+#endif
+
+static userec_t *passwd_image = NULL;
+static int passwd_image_size;
+static int semid = -1;
+
+int passwd_mmap() {
+    int fd;
+    
+    if(passwd_image!=NULL) return 0;
+    fd = open(FN_PASSWD, O_RDWR);
+    if(fd > 0) {
+	struct stat st;
+	
+	fstat(fd, &st);
+	passwd_image_size = st.st_size;
+	passwd_image = mmap(NULL, passwd_image_size,
+			    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+	if(passwd_image == (userec_t *)-1) {
+	    perror("mmap");
+	    return -1;
+	}
+        close(fd);	
+	semid = semget(PASSWDSEM_KEY, 1, SEM_R | SEM_A | IPC_CREAT | IPC_EXCL);
+	if(semid == -1) {
+	    if(errno == EEXIST) {
+		semid = semget(PASSWDSEM_KEY, 1, SEM_R | SEM_A);
+		if(semid == -1) {
+		    perror("semget");
+		    exit(1);
+		}
+	    } else {
+		perror("semget");
+		exit(1);
+	    }
+	} else {
+	    union semun s;
+	    
+	    s.val = 1;
+	    if(semctl(semid, 0, SETVAL, s) == -1) {
+		perror("semctl");
+		exit(1);
+	    }
+	}
+    } else {
+	perror(FN_PASSWD);
+	return -1;
+    }
+    return 0;
+}
+int passwd_update_money(int num) {
+    int money;
+    if(num < 1 || num > MAX_USERS)
+        return -1;
+    money = moneyof(num);
+    memcpy(&passwd_image[num - 1].money, &money, sizeof(int));
+    return 0;
+}
+
+int passwd_update(int num, userec_t *buf) {
+    if(num < 1 || num > MAX_USERS)
+        return -1;
+    buf->money = moneyof(num);
+    memcpy(&passwd_image[num - 1], buf, sizeof(userec_t));
+    return 0;
+}
+
+int passwd_query(int num, userec_t *buf) {
+    if(num < 1 || num > MAX_USERS)
+	return -1;
+    memcpy(buf, &passwd_image[num - 1], sizeof(userec_t));
+    return 0;
+}
+
+int passwd_apply(int (*fptr)(userec_t *)) {
+    int i;
+
+    for(i = 0; i < MAX_USERS; i++)
+	if((*fptr)(&passwd_image[i]) == QUIT)
+	    return QUIT;
+    return 0;
+}
+
+int passwd_apply2(int (*fptr)(int, userec_t *)) {
+    int i;
+
+    for(i = 0; i < MAX_USERS; i++)
+	if((*fptr)(i, &passwd_image[i]) == QUIT)
+	    return QUIT;
+    return 0;
+}
+
+void passwd_lock() {
+    struct sembuf buf = { 0, -1, SEM_UNDO };
+    
+    if(semop(semid, &buf, 1)) {
+	perror("semop");
+	exit(1);
+    }
+}
+
+void passwd_unlock() {
+    struct sembuf buf = { 0, 1, SEM_UNDO };
+    
+    if(semop(semid, &buf, 1)) {
+	perror("semop");
+	exit(1);
+    }
+}
diff --git a/web/util_record.c b/web/util_record.c
new file mode 100755
index 00000000..bc74d575
--- /dev/null
+++ b/web/util_record.c
@@ -0,0 +1,245 @@
+/* $Id: util_record.c,v 1.1 2002/10/18 14:43:58 ptt Exp $ */
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include "config.h"
+#include "pttstruct.h"
+#include "modes.h"
+#include "proto.h"
+
+#undef  HAVE_MMAP
+#define BUFSIZE 512
+
+extern char *str_reply;
+
+static void PttLock(int fd, int size, int mode) {
+    static struct flock lock_it;
+    int ret;
+
+    lock_it.l_whence = SEEK_CUR;        /* from current point */
+    lock_it.l_start = 0;                /* -"- */
+    lock_it.l_len = size;               /* length of data */
+    lock_it.l_type = mode;              /* set exclusive/write lock */
+    lock_it.l_pid = 0;                  /* pid not actually interesting */
+    while((ret = fcntl(fd, F_SETLKW, &lock_it)) < 0 && errno == EINTR);
+}
+
+#define safewrite       write
+
+int get_num_records(char *fpath, int size) {
+    struct stat st;
+    if(stat(fpath, &st) == -1)
+	return 0;
+    return st.st_size / size;
+}
+
+int get_sum_records(char* fpath, int size) {
+    struct stat st;
+    long ans = 0;
+    FILE* fp;
+    fileheader_t fhdr;
+    char buf[200], *p;
+
+    if(!(fp = fopen(fpath, "r")))
+	return -1;
+    
+    strcpy(buf, fpath);
+    p = strrchr(buf, '/') + 1;
+    
+    while(fread(&fhdr, size, 1, fp) == 1) {
+	strcpy(p, fhdr.filename);
+	if(stat(buf, &st) == 0 && S_ISREG(st.st_mode) && st.st_nlink == 1)
+	    ans += st.st_size;
+    }
+    fclose(fp);
+    return ans / 1024;
+}
+
+int get_record(char *fpath, void *rptr, int size, int id) {
+    int fd = -1;
+    
+    if(id < 1 || (fd = open(fpath, O_RDONLY, 0)) != -1) {
+	if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) != -1) {
+	    if(read(fd, rptr, size) == size) {
+		close(fd);
+		return 0;
+	    }
+	}
+	close(fd);
+    }
+    return -1;
+}
+
+int get_records(char *fpath, void *rptr, int size, int id, int number) {
+    int fd;
+    
+    if(id < 1 || (fd = open(fpath, O_RDONLY, 0)) == -1)
+	return -1;
+
+    if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) == -1) {
+	close(fd);
+	return 0;
+    }
+    if((id = read(fd, rptr, size * number)) == -1) {
+	close(fd);
+	return -1;
+    }
+    close(fd);
+    return id / size;
+}
+
+int substitute_record(char *fpath, void *rptr, int size, int id) {
+    int fd;
+
+#ifdef POSTBUG
+    if(size == sizeof(fileheader) && (id > 1) && ((id - 1) % 4 == 0))
+	saverecords(fpath, size, id);
+#endif
+    
+    if(id < 1 || (fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1)
+	return -1;
+    
+#ifdef HAVE_REPORT
+    if(lseek(fd, (off_t)(size * (id - 1)), SEEK_SET) == -1)
+	report("substitute_record failed!!! (lseek)");
+    PttLock(fd, size, F_WRLCK);
+    if(safewrite(fd, rptr, size) != size)
+	report("substitute_record failed!!! (safewrite)");
+    PttLock(fd, size, F_UNLCK);
+#else
+    lseek(fd, (off_t) (size * (id - 1)), SEEK_SET);
+    PttLock(fd, size, F_WRLCK);
+    safewrite(fd, rptr, size);
+    PttLock(fd, size, F_UNLCK);
+#endif
+    close(fd);
+    
+#ifdef POSTBUG
+    if(size == sizeof(fileheader) && (id > 1) && ((id - 1) % 4 == 0))
+	restorerecords(fpath, size, id);
+#endif
+    
+    return 0;
+}
+
+int apply_record(char *fpath, int (*fptr)(), int size) {
+    char abuf[BUFSIZE];
+    FILE* fp;
+    
+    if(!(fp = fopen(fpath, "r")))
+	return -1;
+    
+    while(fread(abuf, 1, size, fp) == size)
+	if((*fptr) (abuf) == QUIT) {
+	    fclose(fp);
+	    return QUIT;
+	}
+    fclose(fp);
+    return 0;
+}
+
+/* mail / post �ɡA�̾ڮɶ��إ��ɮסA�[�W�l�W */
+int stampfile(char *fpath, fileheader_t *fh) {
+    register char *ip = fpath;
+    time_t dtime;
+    struct tm *ptime;
+    int fp = 0;
+
+    if(access(fpath, X_OK | R_OK | W_OK))
+	mkdir(fpath, 0755);
+
+    time(&dtime);
+    while (*(++ip));
+    *ip++ = '/';
+    do {
+	sprintf(ip, "M.%ld.A.%3.3X", ++dtime, rand()&0xfff );
+	if(fp == -1 && errno != EEXIST)
+	    return -1;
+    } while((fp = open(fpath, O_CREAT | O_EXCL | O_WRONLY, 0644)) == -1);
+    close(fp);
+    memset(fh, 0, sizeof(fileheader_t));
+    strcpy(fh->filename, ip);
+    ptime = localtime(&dtime);
+    sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+    return 0;
+}
+
+void stampdir(char *fpath, fileheader_t *fh) {
+    register char *ip = fpath;
+    time_t dtime;
+    struct tm *ptime;
+    
+    if(access(fpath, X_OK | R_OK | W_OK))
+	mkdir(fpath, 0755);
+    
+    time(&dtime);
+    while(*(++ip));
+    *ip++ = '/';
+    do {
+	sprintf(ip, "D%lX", ++dtime & 07777);
+    } while(mkdir(fpath, 0755) == -1);
+    memset(fh, 0, sizeof(fileheader_t));
+    strcpy(fh->filename, ip);
+    ptime = localtime(&dtime);
+    sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+}
+
+void stamplink(char *fpath, fileheader_t *fh) {
+    register char *ip = fpath;
+    time_t dtime;
+    struct tm *ptime;
+
+    if(access(fpath, X_OK | R_OK | W_OK))
+	mkdir(fpath, 0755);
+
+    time(&dtime);
+    while(*(++ip));
+    *ip++ = '/';
+    do {
+	sprintf(ip, "S%lX", ++dtime );
+    } while(symlink("temp", fpath) == -1);
+    memset(fh, 0, sizeof(fileheader_t));
+    strcpy(fh->filename, ip);
+    ptime = localtime(&dtime);
+    sprintf(fh->date, "%2d/%02d", ptime->tm_mon + 1, ptime->tm_mday);
+}
+
+int do_append(char *fpath, fileheader_t *record, int size) {
+    int fd;
+    
+    if((fd = open(fpath, O_WRONLY | O_CREAT, 0644)) == -1) {
+	perror("open");
+	return -1;
+    }
+    flock(fd, LOCK_EX);
+    lseek(fd, 0, SEEK_END);
+    
+    safewrite(fd, record, size);
+    
+    flock(fd, LOCK_UN);
+    close(fd);
+    return 0;
+}
+
+int append_record(char *fpath, fileheader_t *record, int size) {
+#ifdef POSTBUG
+    int numrecs = (int)get_num_records(fpath, size);
+
+    bug_possible = 1;
+    if(size == sizeof(fileheader) && numrecs && (numrecs % 4 == 0))
+	saverecords(fpath, size, numrecs + 1);
+#endif
+    do_append(fpath,record,size);
+    
+#ifdef POSTBUG
+    if(size == sizeof(fileheader) && numrecs && (numrecs % 4 == 0))
+	restorerecords(fpath, size, numrecs + 1);
+    bug_possible = 0;
+#endif
+    return 0;
+}
-- 
cgit v1.2.3