summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/char/Makefile4
-rw-r--r--src/char_sql/GNUmakefile20
-rw-r--r--src/char_sql/Makefile2
-rw-r--r--src/common/Makefile1
-rw-r--r--src/ladmin/GNUmakefile14
-rw-r--r--src/ladmin/Makefile2
-rw-r--r--src/login/Makefile4
-rw-r--r--src/login_sql/GNUmakefile17
-rw-r--r--src/login_sql/Makefile2
-rw-r--r--src/map/Makefile3
-rw-r--r--src/tool/Makefile18
-rw-r--r--src/tool/eathena-monitor.c288
-rwxr-xr-xsrc/tool/ipcheck.rb82
-rw-r--r--src/tool/marriage-info.c486
-rwxr-xr-xsrc/tool/marriage-info.sh20
-rwxr-xr-xsrc/tool/stats.sh44
-rw-r--r--src/txt-converter/char/GNUmakefile13
-rw-r--r--src/txt-converter/char/Makefile2
-rw-r--r--src/txt-converter/login/GNUmakefile11
-rw-r--r--src/txt-converter/login/Makefile1
-rw-r--r--src/webserver/Makefile18
21 files changed, 957 insertions, 95 deletions
diff --git a/src/char/Makefile b/src/char/Makefile
index 841edfd..271aafd 100644
--- a/src/char/Makefile
+++ b/src/char/Makefile
@@ -1,10 +1,12 @@
+include ../../make.defs
+
all: char-server
txt: char-server
COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/db.o ../common/lock.o ../common/malloc.o ../common/mt_rand.o
COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/lock.h ../common/timer.h ../common/malloc.h ../common/mt_rand.h
char-server: char.o inter.o int_party.o int_guild.o int_storage.o $(COMMON_OBJ)
- $(CC) -o ../../$@ $>
+ $(CC) $(CFLAGS) -o ../../$@ $>
char.o: char.c char.h inter.h $(COMMON_H) ../common/version.h
inter.o: inter.c inter.h int_party.h int_guild.h int_storage.h char.h $(COMMON_H)
diff --git a/src/char_sql/GNUmakefile b/src/char_sql/GNUmakefile
deleted file mode 100644
index 9c7b5e5..0000000
--- a/src/char_sql/GNUmakefile
+++ /dev/null
@@ -1,20 +0,0 @@
-all: char-server_sql
-sql: char-server_sql
-
-COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/db.o ../common/malloc.o
-COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/db.h ../common/malloc.h
-
-char-server_sql: char.o inter.o int_party.o int_guild.o int_storage.o int_pet.o strlib.o itemdb.o $(COMMON_OBJ)
- $(CC) -o ../../$@ $^ $(LIB_S)
-
-char.o: char.c char.h strlib.h itemdb.h
-inter.o: inter.c inter.h int_party.h int_guild.h int_storage.h int_pet.h ../common/mmo.h char.h ../common/socket.h
-int_party.o: int_party.c int_party.h inter.h ../common/mmo.h char.h ../common/socket.h ../common/timer.h ../common/db.h
-int_guild.o: int_guild.c int_guild.h inter.h ../common/mmo.h char.h ../common/socket.h ../common/db.h
-int_storage.o: int_storage.c int_storage.h char.h itemdb.h
-int_pet.o: int_pet.c int_pet.h inter.h char.h ../common/mmo.h ../common/socket.h ../common/db.h
-strlib.o: strlib.c strlib.h
-itemdb.o: itemdb.c itemdb.h ../common/db.h ../common/mmo.h
-
-clean:
- rm -f *.o ../../char-server_sql
diff --git a/src/char_sql/Makefile b/src/char_sql/Makefile
index 9c7b5e5..8f21f0b 100644
--- a/src/char_sql/Makefile
+++ b/src/char_sql/Makefile
@@ -1,3 +1,5 @@
+include ../../make.defs
+
all: char-server_sql
sql: char-server_sql
diff --git a/src/common/Makefile b/src/common/Makefile
index 9218a55..9eac7b4 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -1,3 +1,4 @@
+include ../../make.defs
txt sql all: core.o socket.o timer.o grfio.o db.o lock.o nullpo.o malloc.o mt_rand.o
core.o: core.c core.h
diff --git a/src/ladmin/GNUmakefile b/src/ladmin/GNUmakefile
deleted file mode 100644
index bed7b6b..0000000
--- a/src/ladmin/GNUmakefile
+++ /dev/null
@@ -1,14 +0,0 @@
-all: ladmin
-txt: ladmin
-sql: ladmin
-
-COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/db.o ../common/malloc.o ../common/mt_rand.o
-COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/db.h ../common/malloc.h ../common/mt_rand.h
-
-ladmin: ladmin.o md5calc.o $(COMMON_OBJ)
- $(CC) -o ../../$@ ladmin.o md5calc.o $(COMMON_OBJ)
-ladmin.o: ladmin.c ladmin.h md5calc.h $(COMMON_H)
-md5calc.o: md5calc.c md5calc.h
-
-clean:
- rm -f *.o ../../ladmin
diff --git a/src/ladmin/Makefile b/src/ladmin/Makefile
index bed7b6b..3221901 100644
--- a/src/ladmin/Makefile
+++ b/src/ladmin/Makefile
@@ -1,3 +1,5 @@
+include ../../make.defs
+
all: ladmin
txt: ladmin
sql: ladmin
diff --git a/src/login/Makefile b/src/login/Makefile
index 0411129..4b65c33 100644
--- a/src/login/Makefile
+++ b/src/login/Makefile
@@ -1,3 +1,5 @@
+include ../../make.defs
+
all: login-server
txt: login-server
@@ -5,7 +7,7 @@ COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/db.
COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/db.h ../common/lock.h ../common/malloc.h ../common/mt_rand.h
login-server: login.o md5calc.o $(COMMON_OBJ)
- $(CC) -o ../../$@ login.o md5calc.o $(COMMON_OBJ)
+ $(CC) $(CFLAGS) -o ../../$@ login.o md5calc.o $(COMMON_OBJ)
login.o: login.c login.h md5calc.h $(COMMON_H)
md5calc.o: md5calc.c md5calc.h
diff --git a/src/login_sql/GNUmakefile b/src/login_sql/GNUmakefile
deleted file mode 100644
index c245b79..0000000
--- a/src/login_sql/GNUmakefile
+++ /dev/null
@@ -1,17 +0,0 @@
-all: login-server_sql
-sql: login-server_sql
-
-shared_libs=all
-COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/db.o ../common/malloc.o
-COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h ../common/version.h ../common/db.h ../common/malloc.h
-
-login-server_sql: login.o md5calc.o strlib.o $(COMMON_OBJ)
- $(CC) -o ../../$@ $^ $(LIB_S)
-
-login.o: login.c login.h md5calc.h strlib.h $(COMMON_H)
-md5calc.o: md5calc.c md5calc.h
-strlib.o: strlib.c strlib.h
-
-clean:
- rm -f *.o ../../login-server_sql
-
diff --git a/src/login_sql/Makefile b/src/login_sql/Makefile
index c245b79..12fd7f3 100644
--- a/src/login_sql/Makefile
+++ b/src/login_sql/Makefile
@@ -1,3 +1,5 @@
+include ../../make.defs
+
all: login-server_sql
sql: login-server_sql
diff --git a/src/map/Makefile b/src/map/Makefile
index 5e80410..730e72f 100644
--- a/src/map/Makefile
+++ b/src/map/Makefile
@@ -1,5 +1,4 @@
-LEX=flex
-BISON=bison
+include ../../make.defs
all: txt
diff --git a/src/tool/Makefile b/src/tool/Makefile
index d2616a7..5d37183 100644
--- a/src/tool/Makefile
+++ b/src/tool/Makefile
@@ -1,12 +1,16 @@
-CC=gcc -m32 -O0 -g
+include ../../make.defs
+
BDIR=..
-COBJS=${BDIR}/common/timer.o ${BDIR}/common/malloc.o ${BDIR}/common/socket.o ${BDIR}/common/lock.o ${BDIR}/common/db.o ${BDIR}/char/int_pet.o ${BDIR}/char/int_storage.o ${BDIR}/char/inter.o ${BDIR}/char/int_party.o ${BDIR}/char/int_guild.o
+COBJS=${BDIR}/common/timer.o ${BDIR}/common/malloc.o ${BDIR}/common/socket.o ${BDIR}/common/lock.o ${BDIR}/common/db.o ${BDIR}/char/int_storage.o ${BDIR}/char/inter.o ${BDIR}/char/int_party.o ${BDIR}/char/int_guild.o
+MOBJS=${BDIR}/common/socket.o ${BDIR}/common/timer.o ${BDIR}/common/db.o ${BDIR}/common/lock.o ${BDIR}/common/malloc.o ${BDIR}/char/int_guild.o ${BDIR}/char/int_party.o ${BDIR}/char/int_storage.o ${BDIR}/char/inter.o
-all:
- $(CC) -o adduser adduser.c
- $(CC) -I ${BDIR}/char -I ${BDIR}/common itemfrob.c -o itemfrob ${COBJS}
- $(CC) -I ${BDIR}/char -I ${BDIR}/common mapfrob.c -o mapfrob ${COBJS}
+all: ${COBJS} ${MOBJS}
+ $(CC) $(CFLAGS) -o adduser adduser.c $(BDIR)/common/socket.o
+ $(CC) $(CFLAGS) -I ${BDIR}/char -I ${BDIR}/common itemfrob.c -o itemfrob ${COBJS}
+ $(CC) $(CFLAGS) -I ${BDIR}/char -I ${BDIR}/common mapfrob.c -o mapfrob ${COBJS}
+ $(CC) $(CFLAGS) -I ${BDIR}/char -I ${BDIR}/common -I ${BDIR}/map -I ${BDIR}/login marriage-info.c -o marriage-info ${MOBJS}
+ $(CC) $(CFLAGS) -o ${BDIR}/../eathena-monitor eathena-monitor.c
clean:
- rm -f adduser itemfrob mapfrop
+ rm -f adduser itemfrob mapfrob marriage-info ${BDIR}/../eathena-monitor
rm -f *.exe
diff --git a/src/tool/eathena-monitor.c b/src/tool/eathena-monitor.c
new file mode 100644
index 0000000..d0b3995
--- /dev/null
+++ b/src/tool/eathena-monitor.c
@@ -0,0 +1,288 @@
+/**
+ * Name: eAthena processes monitor
+ * Author: Bartosz Waszak <waszi@evil.org.pl>
+ * License: GPL
+ * Compilation:
+ * gcc -o eathena-monitor eathena-monitor.c
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !defined(linux) && (defined(__sgi) || defined(__sun__) || defined(__sun) || defined(__sparc) || defined(__sparc__))
+#include <sys/statfs.h>
+#endif
+
+#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) || defined (__APPLE__)
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#if defined(linux) || defined(__CYGWIN32__) || defined(__hpux)
+#include <sys/vfs.h>
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#define HOME getenv("HOME")
+#define LOGIN_SERVER "login-server"
+#define MAP_SERVER "map-server"
+#define CHAR_SERVER "char-server"
+#define CONFIG "conf/eathena-monitor.conf"
+#define LOGFILE "log/eathena-monitor.log"
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#define IS_BLANK(ptr) \
+ (((*(ptr)) == ' ') || ((*(ptr)) == '\b') || \
+ ((*(ptr)) == '\n') || ((*(ptr)) == '\r'))
+
+#define SKIP_BLANK(ptr) \
+ { while (((*(ptr)) == ' ') || ((*(ptr)) == '\b') || \
+ ((*(ptr)) == '\n') || ((*(ptr)) == '\r')) ptr++; }
+
+#define GOTO_EQL(ptr) \
+ { while (((*(ptr)) != '\0') && ((*(ptr)) != '=') && \
+ ((*(ptr)) != '\n') && ((*(ptr)) != '\r')) ptr++; }
+
+#define GOTO_EOL(ptr) \
+ { while (((*(ptr)) != '\0') && \
+ ((*(ptr)) != '\n') && ((*(ptr)) != '\r')) ptr++; }
+
+char *workdir;
+char *login_server;
+char *map_server;
+char *char_server;
+char *config;
+char *logfile;
+unsigned int interval = 5;
+unsigned int pid_login, pid_map, pid_char;
+char use_login = 1;
+
+void parse_option (char *name, char *value) {
+ if (!strcasecmp(name, "login_server")) {
+ login_server = strdup(value);
+ } else if (!strcasecmp(name, "map_server")) {
+ map_server = strdup(value);
+ } else if (!strcasecmp(name, "char_server")) {
+ char_server = strdup(value);
+ } else if (!strcasecmp(name, "workdir")) {
+ workdir = strdup(value);
+ } else if (!strcasecmp(name, "logfile")) {
+ logfile = strdup(value);
+ } else if (!strcasecmp(name, "interval")) {
+ interval = atoi(strdup(value));
+ } else {
+ printf("WARNING: ingnoring invalid options '%s'\n", name);
+ }
+}
+
+int read_config(char *filename) {
+ FILE *input;
+ char *str, *base;
+ char string[1000];
+ char *name;
+ char *value;
+ int errors = 0;
+
+ if (!(input = fopen(filename,"r")) && !(input = fopen (config, "r"))) {
+ fprintf (stderr, "ERROR: Config file doesn't exist (%s and %s), using builtin defaults\n", filename, config);
+ return -1;
+ }
+
+ while (1) {
+ if (fgets (&string[0], sizeof (string) - 1, input) == NULL)
+ break;
+ str = &string[0];
+ SKIP_BLANK(str);
+ string[sizeof (string) - 1] = '\0';
+ if (*str == '#')
+ continue;
+ if (*str == '\0')
+ continue;
+ name = str;
+
+ GOTO_EQL (str);
+
+ if (*str != '=') {
+ continue;
+ }
+
+ *str++ = '\0';
+ SKIP_BLANK(str);
+ value = str;
+ GOTO_EOL(str);
+ *str = '\0';
+ parse_option(name, value);
+ }
+
+ fclose (input);
+ return(0);
+}
+
+void start_process(char *exec) {
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) {
+ if (!fork()) {
+ execl(exec,exec,NULL);
+ exit(0);
+ }
+ exit(0);
+ }
+ wait(0);
+}
+
+void stop_process(int sig) {
+ system("killall map-server");
+ system("killall login-server");
+ system("killall char-server");
+ exit(0);
+}
+
+int main(int argc, char *argv[]) {
+ DIR *procdir;
+ FILE *log;
+
+ int fd;
+
+ char pathbuf[PATH_MAX];
+ char link[PATH_MAX];
+ char timestamp[256];
+
+ struct tm *tmp;
+ struct dirent *procdirp;
+ struct statfs sfs;
+
+ unsigned int proc_login, proc_map, proc_char;
+
+ time_t t;
+ size_t l_size;
+
+ if ( statfs("/proc", &sfs) == -1 ) {
+ fprintf(stderr,"ERROR: /proc filesystem is unaccessible\n");
+ return(255);
+ }
+
+ signal(SIGTERM, stop_process);
+ signal(SIGINT, stop_process);
+
+ workdir = (char *) malloc(sizeof(char) * 1024);
+ login_server = (char *) malloc(sizeof(char) * 1024);
+ char_server = (char *) malloc(sizeof(char) * 1024);
+ map_server = (char *) malloc(sizeof(char) * 1024);
+ logfile = (char *) malloc(sizeof(char) * 1024);
+ config = (char *) malloc(sizeof(char) * 1024);
+
+ sprintf(workdir,"%s/tmwserver",HOME);
+ sprintf(login_server,"%s/%s", workdir, LOGIN_SERVER);
+ sprintf(map_server,"%s/%s", workdir, MAP_SERVER);
+ sprintf(char_server,"%s/%s", workdir, CHAR_SERVER);
+ sprintf(logfile,"%s/%s", workdir,LOGFILE);
+ sprintf(config,"%s/%s", workdir, CONFIG);
+
+ read_config(argv[1]);
+
+ chdir(workdir);
+
+ if (strlen(login_server) == 0) use_login = 0;
+
+ printf ("Starting:\n");
+ printf ("* interval: %d s\n", interval);
+ printf ("* workdir: %s\n", workdir);
+ if (use_login)
+ printf ("* login_server: %s\n", login_server);
+ else
+ printf ("* login_server: (none)\n");
+ printf ("* map_server: %s\n", map_server);
+ printf ("* char_server: %s\n", char_server);
+
+ if (fork()) {
+ exit(0);
+ }
+
+ if ((fd = open("/dev/null", O_RDONLY)) != 0) {
+ dup2(fd, 0);
+ close(fd);
+ }
+
+ if ((fd = open("/dev/null", O_WRONLY)) != 1) {
+ dup2(fd, 1);
+ close(fd);
+ }
+ dup2(1, 2);
+
+ while (1) {
+ if (use_login) proc_login = 0;
+ proc_map = 0;
+ proc_char = 0;
+
+ if ((procdir = opendir("/proc")) == NULL) {
+ fprintf(stderr,"ERROR: Cannot open /proc filesystem\n");
+ return(255);
+ }
+
+ while ((procdirp = readdir(procdir)) != NULL) {
+ if (strtok(procdirp->d_name, "0123456789") == NULL) {
+ sprintf(pathbuf, "%s%s%s", "/proc/", procdirp->d_name, "/exe");
+ l_size = readlink(pathbuf, link, PATH_MAX);
+
+ if (l_size != -1) {
+ link[l_size] = '\0';
+ if (use_login && !strcmp(link, login_server)) {
+ proc_login = 1;
+ pid_login = (unsigned int) procdirp->d_name;
+ }
+
+ if (!strcmp(link, char_server)) {
+ proc_char = 1;
+ pid_char = (unsigned int) procdirp->d_name;
+ }
+
+ if (!strcmp(link, map_server)) {
+ proc_map = 1;
+ pid_map = (unsigned int) procdirp->d_name;
+ }
+ }
+ }
+ }
+ closedir(procdir);
+
+ if (!(log = fopen (logfile,"a"))) {
+ log = fopen("/tmp/monitor.log","a");
+ }
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ strftime(timestamp, sizeof(timestamp), "%F %X", tmp);
+
+ if (use_login && proc_login == 0) {
+ fprintf (log,"[%d][%s] NOTICE: Login server is dead - restarting\n", getpid(), timestamp);
+ start_process(login_server);
+ sleep(2);
+ }
+ if (proc_char == 0) {
+ fprintf (log,"[%d][%s] NOTICE: Char server is dead - restarting\n", getpid(), timestamp);
+ start_process(char_server);
+ sleep(2);
+ }
+ if (proc_map == 0) {
+ fprintf (log,"[%d][%s] NOTICE: Map server is dead - restarting\n", getpid(), timestamp);
+ start_process(map_server);
+ sleep(2);
+ }
+
+ fclose(log);
+ sleep(interval);
+ }
+}
diff --git a/src/tool/ipcheck.rb b/src/tool/ipcheck.rb
new file mode 100755
index 0000000..7c2e22a
--- /dev/null
+++ b/src/tool/ipcheck.rb
@@ -0,0 +1,82 @@
+#!/usr/bin/env ruby
+# A script to check which characters play from the same IP address
+# (c) 2009 Bjorn Lindeijer
+#
+# Summary of how it works:
+#
+# Character -> Account
+# Account -> IP
+# IP -> Accounts
+# Accounts -> Characters
+#
+
+if ARGV.length != 1
+ puts "Usage: ipcheck.rb character_name"
+ exit 1
+else
+ $search_character = ARGV[0]
+ puts "Searching for character #{$search_character}"
+end
+
+class Character
+ attr_reader :name, :account_id
+
+ def initialize(name, account_id)
+ @name = name
+ @account_id = account_id
+ end
+end
+
+class Account
+ attr_reader :id, :ip, :last_login
+
+ def initialize(id, ip, last_login)
+ @id = id
+ @ip = ip
+ @last_login = last_login
+ end
+end
+
+accounts = Array.new
+characters = Array.new
+
+File.open("save/athena.txt", "r") do |f|
+ f.each_line do |line|
+ split = line.split("\t")
+ if split.length >= 3
+ account_id, char_index = split[1].split(',')
+ character_name = split[2]
+ characters.push(Character.new(character_name, account_id))
+ if $search_character.casecmp(character_name) == 0
+ puts "Searching for account #{account_id}"
+ $search_account_id = account_id
+ end
+ end
+ end
+end
+
+if not $search_account_id
+ puts "Error: character #{$search_character} not found!"
+ exit 1
+end
+
+File.open("save/account.txt", "r") do |f|
+ f.each_line do |line|
+ split = line.split("\t")
+ if split.length >= 11
+ account_id, last_login, ip = split[0], split[3], split[10]
+ accounts.push(Account.new(account_id, ip, last_login))
+ if $search_account_id == account_id
+ puts "Searching for IP #{ip}"
+ $search_ip = ip
+ end
+ end
+ end
+end
+
+accounts.find_all { |a| a.ip == $search_ip }.each do |a|
+ puts "Characters for account #{a.id} (last login #{a.last_login}):"
+ characters.find_all { |c| c.account_id == a.id }.each do |c|
+ puts " #{c.name}"
+ end
+end
diff --git a/src/tool/marriage-info.c b/src/tool/marriage-info.c
new file mode 100644
index 0000000..cd13843
--- /dev/null
+++ b/src/tool/marriage-info.c
@@ -0,0 +1,486 @@
+/* To build:
+gcc -O2 -m32 -Isrc/common -Isrc/char -Isrc/map -Isrc/login -o marriage-info \
+marriage-info.c src/common/socket.o src/common/timer.o src/common/db.o \
+src/common/lock.o src/common/malloc.o src/char/int_guild.o \
+src/char/int_party.o src/char/int_storage.o src/char/inter.o
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "login.h"
+#include "mmo.h"
+#include "char.c"
+
+int mode;
+#define MODE_MARRIED 0
+#define MODE_SINGLES_F 1
+#define MODE_SINGLES_M 2
+#define MODE_SINGLES_A 3
+
+#define CHUNK_SIZE 1024
+
+/* chunked list to represent leaves */
+typedef struct {
+ int char_id;
+ int exp;
+ char name[24];
+ unsigned char level;
+ unsigned char sex;
+} char_leaf_t;
+
+/* Chunks are in descending order, but chars are in ascending order */
+typedef struct chunklist_node {
+ int size;
+ char_leaf_t chars[CHUNK_SIZE];
+ struct chunklist_node *next;
+} chunklist_node_t;
+
+chunklist_node_t *list = NULL;
+
+static void
+insert(chunklist_node_t **listp, struct mmo_charstatus *p)
+{
+ chunklist_node_t *chunk = *listp;
+ char_leaf_t *l;
+
+ if ((chunk && chunk->size == CHUNK_SIZE)
+ || (!chunk)) {
+ chunk = malloc(sizeof(chunklist_node_t));
+ chunk->size = 0;
+ chunk->next = *listp;
+ *listp = chunk;
+ }
+
+ l = &chunk->chars[chunk->size++];
+
+ l->char_id = p->char_id;
+ l->level = p->base_level;
+ l->exp = p->base_exp;
+ l->sex = p->sex;
+ strcpy(l->name, p->name);
+}
+
+static int
+compare_leaf(const void *l, const void *r)
+{
+ return ((char_leaf_t *)l)->char_id - ((char_leaf_t *)r)->char_id;
+}
+
+static char_leaf_t *
+find(chunklist_node_t *list, int char_id)
+{
+ if (!list)
+ return NULL; /* fatal error */
+ else {
+ int start = list->chars[0].char_id;
+ int stop = list->chars[list->size - 1].char_id;
+
+ if (char_id >= start && char_id <= stop) { /* in this chunk */
+ char_leaf_t key;
+ key.char_id = char_id;
+ return (char_leaf_t *)
+ bsearch(&key, &list->chars, list->size, sizeof(char_leaf_t),
+ compare_leaf);
+ }
+ else find(list->next, char_id);
+ }
+}
+
+
+void /* replace blanks with percent signs */
+namefrob(char *n)
+{
+ while (*n++) /* can't start with a blank */
+ if (*n == ' ')
+ *n = '%';
+}
+
+/*
+--------------------------------------------------------------------------------
+ Copied and pasted due to lacking modularity
+*/
+
+char account_filename[1024] = "save/account.txt";
+int account_id_count = START_ACCOUNT_NUM;
+
+struct auth_dat {
+ int account_id, sex;
+ char userid[24], pass[24], lastlogin[24];
+ int logincount;
+ int state;
+ char email[40];
+ char error_message[20];
+ time_t ban_until_time;
+ time_t connect_until_time;
+ char last_ip[16];
+ char memo[255];
+ int account_reg2_num;
+ struct global_reg account_reg2[ACCOUNT_REG2_NUM];
+} *auth_dat;
+
+int auth_num = 0, auth_max = 0;
+
+
+/*
+ Reading of the accounts database
+*/
+int mmo_auth_init(void) {
+ FILE *fp;
+ int account_id, logincount, state, n, i, j, v;
+ char line[2048], *p, userid[2048], pass[2048], lastlogin[2048], sex, email[2048], error_message[2048], last_ip[2048], memo[2048];
+ time_t ban_until_time;
+ time_t connect_until_time;
+ char str[2048];
+ int GM_count = 0;
+ int server_count = 0;
+
+ auth_dat = calloc(sizeof(struct auth_dat) * 256, 1);
+ auth_max = 256;
+
+ fp = fopen(account_filename, "r");
+ if (fp == NULL) {
+ printf("\033[1;31mmmo_auth_init: Accounts file [%s] not found.\033[0m\n", account_filename);
+ return 0;
+ }
+
+ while(fgets(line, sizeof(line)-1, fp) != NULL) {
+ if (line[0] == '/' && line[1] == '/')
+ continue;
+ line[sizeof(line)-1] = '\0';
+ p = line;
+
+ if (((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t"
+ "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]\t%ld%n",
+ &account_id, userid, pass, lastlogin, &sex, &logincount, &state,
+ email, error_message, &connect_until_time, last_ip, memo, &ban_until_time, &n)) == 13 && line[n] == '\t') ||
+ ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t"
+ "%[^\t]\t%[^\t]\t%ld\t%[^\t]\t%[^\t]%n",
+ &account_id, userid, pass, lastlogin, &sex, &logincount, &state,
+ email, error_message, &connect_until_time, last_ip, memo, &n)) == 12 && line[n] == '\t')) {
+ n = n + 1;
+
+ if (account_id > END_ACCOUNT_NUM) {
+ continue;
+ }
+ userid[23] = '\0';
+ remove_control_chars(userid);
+ for(j = 0; j < auth_num; j++) {
+ if (auth_dat[j].account_id == account_id) {
+ break;
+ } else if (strcmp(auth_dat[j].userid, userid) == 0) {
+ break;
+ }
+ }
+ if (j != auth_num)
+ continue;
+
+ if (auth_num >= auth_max) {
+ auth_max += 256;
+ auth_dat = realloc(auth_dat, sizeof(struct auth_dat) * auth_max);
+ }
+
+ memset(&auth_dat[auth_num], '\0', sizeof(struct auth_dat));
+
+ auth_dat[auth_num].account_id = account_id;
+
+ strncpy(auth_dat[auth_num].userid, userid, 24);
+
+ pass[23] = '\0';
+ remove_control_chars(pass);
+ strncpy(auth_dat[auth_num].pass, pass, 24);
+
+ lastlogin[23] = '\0';
+ remove_control_chars(lastlogin);
+ strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24);
+
+ auth_dat[auth_num].sex = (sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm');
+
+ if (logincount >= 0)
+ auth_dat[auth_num].logincount = logincount;
+ else
+ auth_dat[auth_num].logincount = 0;
+
+ if (state > 255)
+ auth_dat[auth_num].state = 100;
+ else if (state < 0)
+ auth_dat[auth_num].state = 0;
+ else
+ auth_dat[auth_num].state = state;
+
+ if (e_mail_check(email) == 0) {
+ strncpy(auth_dat[auth_num].email, "a@a.com", 40);
+ } else {
+ remove_control_chars(email);
+ strncpy(auth_dat[auth_num].email, email, 40);
+ }
+
+ error_message[19] = '\0';
+ remove_control_chars(error_message);
+ if (error_message[0] == '\0' || state != 7) {
+ strncpy(auth_dat[auth_num].error_message, "-", 20);
+ } else {
+ strncpy(auth_dat[auth_num].error_message, error_message, 20);
+ }
+
+ if (i == 13)
+ auth_dat[auth_num].ban_until_time = ban_until_time;
+ else
+ auth_dat[auth_num].ban_until_time = 0;
+
+ auth_dat[auth_num].connect_until_time = connect_until_time;
+
+ last_ip[15] = '\0';
+ remove_control_chars(last_ip);
+ strncpy(auth_dat[auth_num].last_ip, last_ip, 16);
+
+ memo[254] = '\0';
+ remove_control_chars(memo);
+ strncpy(auth_dat[auth_num].memo, memo, 255);
+
+ for(j = 0; j < ACCOUNT_REG2_NUM; j++) {
+ p += n;
+ if (sscanf(p, "%[^\t,],%d %n", str, &v, &n) != 2) {
+ if (p[0] == ',' && sscanf(p, ",%d %n", &v, &n) == 1) {
+ j--;
+ continue;
+ } else
+ break;
+ }
+ str[31] = '\0';
+ remove_control_chars(str);
+ strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32);
+ auth_dat[auth_num].account_reg2[j].value = v;
+ }
+ auth_dat[auth_num].account_reg2_num = j;
+
+ if (isGM(account_id) > 0)
+ GM_count++;
+ if (auth_dat[auth_num].sex == 2)
+ server_count++;
+
+ auth_num++;
+ if (account_id >= account_id_count)
+ account_id_count = account_id + 1;
+
+ } else if ((i = sscanf(line, "%d\t%[^\t]\t%[^\t]\t%[^\t]\t%c\t%d\t%d\t%n",
+ &account_id, userid, pass, lastlogin, &sex, &logincount, &state, &n)) >= 5) {
+ if (account_id > END_ACCOUNT_NUM) {
+ continue;
+ }
+ userid[23] = '\0';
+ remove_control_chars(userid);
+ for(j = 0; j < auth_num; j++) {
+ if (auth_dat[j].account_id == account_id) {
+ break;
+ } else if (strcmp(auth_dat[j].userid, userid) == 0) {
+ break;
+ }
+ }
+ if (j != auth_num)
+ continue;
+
+ if (auth_num >= auth_max) {
+ auth_max += 256;
+ auth_dat = realloc(auth_dat, sizeof(struct auth_dat) * auth_max);
+ }
+
+ memset(&auth_dat[auth_num], '\0', sizeof(struct auth_dat));
+
+ auth_dat[auth_num].account_id = account_id;
+
+ strncpy(auth_dat[auth_num].userid, userid, 24);
+
+ pass[23] = '\0';
+ remove_control_chars(pass);
+ strncpy(auth_dat[auth_num].pass, pass, 24);
+
+ lastlogin[23] = '\0';
+ remove_control_chars(lastlogin);
+ strncpy(auth_dat[auth_num].lastlogin, lastlogin, 24);
+
+ auth_dat[auth_num].sex = (sex == 'S' || sex == 's') ? 2 : (sex == 'M' || sex == 'm');
+
+ if (i >= 6) {
+ if (logincount >= 0)
+ auth_dat[auth_num].logincount = logincount;
+ else
+ auth_dat[auth_num].logincount = 0;
+ } else
+ auth_dat[auth_num].logincount = 0;
+
+ if (i >= 7) {
+ if (state > 255)
+ auth_dat[auth_num].state = 100;
+ else if (state < 0)
+ auth_dat[auth_num].state = 0;
+ else
+ auth_dat[auth_num].state = state;
+ } else
+ auth_dat[auth_num].state = 0;
+
+ strncpy(auth_dat[auth_num].email, "a@a.com", 40);
+ strncpy(auth_dat[auth_num].error_message, "-", 20);
+ auth_dat[auth_num].ban_until_time = 0;
+ auth_dat[auth_num].connect_until_time = 0;
+ strncpy(auth_dat[auth_num].last_ip, "-", 16);
+ strncpy(auth_dat[auth_num].memo, "-", 255);
+
+ for(j = 0; j < ACCOUNT_REG2_NUM; j++) {
+ p += n;
+ if (sscanf(p, "%[^\t,],%d %n", str, &v, &n) != 2) {
+ if (p[0] == ',' && sscanf(p, ",%d %n", &v, &n) == 1) {
+ j--;
+ continue;
+ } else
+ break;
+ }
+ str[31] = '\0';
+ remove_control_chars(str);
+ strncpy(auth_dat[auth_num].account_reg2[j].str, str, 32);
+ auth_dat[auth_num].account_reg2[j].value = v;
+ }
+ auth_dat[auth_num].account_reg2_num = j;
+
+ if (isGM(account_id) > 0)
+ GM_count++;
+ if (auth_dat[auth_num].sex == 2)
+ server_count++;
+
+ auth_num++;
+ if (account_id >= account_id_count)
+ account_id_count = account_id + 1;
+
+ } else {
+ i = 0;
+ if (sscanf(line, "%d\t%%newid%%\n%n", &account_id, &i) == 1 &&
+ i > 0 && account_id > account_id_count)
+ account_id_count = account_id;
+ }
+ }
+ fclose(fp);
+
+ if (auth_num == 0) {
+ sprintf(line, "No account found in %s.", account_filename);
+ } else {
+ if (auth_num == 1) {
+ sprintf(line, "1 account read in %s,", account_filename);
+ } else {
+ sprintf(line, "%d accounts read in %s,", auth_num, account_filename);
+ }
+ if (GM_count == 0) {
+ sprintf(str, "%s of which is no GM account and", line);
+ } else if (GM_count == 1) {
+ sprintf(str, "%s of which is 1 GM account and", line);
+ } else {
+ sprintf(str, "%s of which is %d GM accounts and", line, GM_count);
+ }
+ if (server_count == 0) {
+ sprintf(line, "%s no server account ('S').", str);
+ } else if (server_count == 1) {
+ sprintf(line, "%s 1 server account ('S').", str);
+ } else {
+ sprintf(line, "%s %d server accounts ('S').", str, server_count);
+ }
+ }
+
+ return 0;
+}
+
+/*--------------------------------------------------------------------------------*/
+
+
+void
+mmo_check_dumpworthy(struct mmo_charstatus *p)
+{
+ int i;
+ namefrob(p->name);
+
+ for (i = 0; i < auth_num; i++)
+ if (auth_dat[i].account_id == p->account_id) {
+ p->sex = auth_dat[i].sex;
+ break;
+ }
+
+ if (p->partner_id) {
+ if (mode != MODE_MARRIED)
+ return;
+
+ if (p->partner_id < p->char_id) {
+ char_leaf_t *partner = find(list, p->partner_id);
+ if (!partner)
+ fprintf(stderr, "Char %d (%s)'s partner (%d) no longer available\n",
+ p->char_id,
+ p->name,
+ p->partner_id);
+ else
+ printf ("%d\t%d\t%s\t%s\t%d\t%s\t%s\t%d--%d,%d\n",
+ p->base_level + partner->level,
+ p->base_exp + partner->exp,
+ p->name, p->sex? "M" : "F", p->base_level,
+ partner->name, partner->sex? "M" : "F", partner->level);
+ } else {
+ insert(&list, p);
+ }
+ } else if (p->sex == (mode - 1))
+ printf("%d\t%d\t%s\n", p->base_level, p->base_exp, p->name);
+ else if (mode == MODE_SINGLES_A)
+ printf("%d\t%d\t%s\t%s\n", p->base_level, p->base_exp, p->name, p->sex? "M" : "F");
+}
+
+int mmo_char_dump()
+{
+ char line[965536];
+ int ret;
+ struct mmo_charstatus char_dat;
+ FILE *ifp,*ofp;
+
+ ifp=stdin;
+ while(fgets(line,65535,ifp)){
+ memset(&char_dat,0,sizeof(struct mmo_charstatus));
+ ret=mmo_char_fromstr(line,&char_dat);
+ if(ret){
+ mmo_check_dumpworthy(&char_dat);
+ }
+ }
+ fcloseall();
+ return 0;
+}
+
+
+int init(char *mode_s)
+{
+ if (!strcmp(mode_s, "-c"))
+ mode = MODE_MARRIED;
+ else if (!strcmp(mode_s, "-f"))
+ mode = MODE_SINGLES_F;
+ else if (!strcmp(mode_s, "-m"))
+ mode = MODE_SINGLES_M;
+ else if (!strcmp(mode_s, "-s"))
+ mode = MODE_SINGLES_A;
+ else {
+ fprintf(stderr, "Unknown mode `%s'\n", mode_s);
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc,char *argv[])
+{
+ mmo_auth_init();
+
+ if(argc < 2) {
+ printf("Usage: %s <mode>\n", argv[0]);
+ printf("Where <mode> is one of -c (couples), -s (singles), -f (female singles), -m (male singles)\n", argv[0]);
+ exit(0);
+ }
+ if (init(argv[1]))
+ return 1;
+
+ mmo_char_dump();
+
+ return 0;
+}
+
+
+/* satisfy linker */
+void set_termfunc(void (*termfunc)(void)) {};
diff --git a/src/tool/marriage-info.sh b/src/tool/marriage-info.sh
new file mode 100755
index 0000000..2389d7f
--- /dev/null
+++ b/src/tool/marriage-info.sh
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+cd ~/tmwserver
+
+cat save/athena.txt | sort -n > athena-sorted.txt
+
+printf "Top married couples\n===================\n" > ~/public_html/stats/married.txt
+cat athena-sorted.txt | ./marriage-info -c | sort -rn | awk '{printf "%d %s oo %s (%s (%s, %d), %s(%s, %d))\n", ++rank, $3, $6, $3, $4, $5, $6, $7, $8}' | tr '%' ' ' >> ~/public_html/stats/married.txt
+
+printf "Top female singles\n==================\n" > ~/public_html/stats/female-singles.txt
+cat athena-sorted.txt | ./marriage-info -f | sort -rn | awk '{printf "%d %s(%d)\n", ++rank, $3, $1}' | tr '%' ' ' | head -50 >> ~/public_html/stats/female-singles.txt
+
+printf "Top male singles\n===============\n" > ~/public_html/stats/male-singles.txt
+cat athena-sorted.txt | ./marriage-info -m | sort -rn | awk '{printf "%d %s(%d)\n", ++rank, $3, $1}' | tr '%' ' ' | head -50 >> ~/public_html/stats/male-singles.txt
+
+printf "Top singles\n===============\n" > ~/public_html/stats/singles.txt
+cat athena-sorted.txt | ./marriage-info -s | sort -rn | awk '{printf "%d %s(%s, %d)\n", ++rank, $3, $4, $1}' | tr '%' ' ' | head -50 >> ~/public_html/stats/singles.txt
+
+rm athena-sorted.txt
+
diff --git a/src/tool/stats.sh b/src/tool/stats.sh
new file mode 100755
index 0000000..9ea021b
--- /dev/null
+++ b/src/tool/stats.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+ATHENATXT="save/athena.txt"
+DEST="$HOME/public_html/stats"
+
+:> ${DEST}/top-money.txt
+(echo "TOP 50 RICHEST PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); sub(/ *[0-9]+$/,"",$6);print $6,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-money.txt
+
+:> ${DEST}/top-highest-level.txt
+(echo "TOP 50 HIGHEST LEVEL PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); print $3,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-highest-level.txt
+
+:> ${DEST}/top-highest-str.txt
+(echo "TOP 50 HIGHEST LEVEL PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); sub(/^[0-9]+[[:space:]]*/,"",$9);print $9,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-highest-str.txt
+
+:> ${DEST}/top-highest-agi.txt
+(echo "TOP 50 HIGHEST LEVEL PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); print $10,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-highest-agi.txt
+
+:> ${DEST}/top-highest-vit.txt
+(echo "TOP 50 HIGHEST LEVEL PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); print $11,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-highest-vit.txt
+
+:> ${DEST}/top-highest-int.txt
+(echo "TOP 50 HIGHEST LEVEL PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); print $12,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-highest-int.txt
+
+:> ${DEST}/top-highest-dex.txt
+(echo "TOP 50 HIGHEST LEVEL PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); print $13,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-highest-dex.txt
+
+:> ${DEST}/top-highest-luk.txt
+(echo "TOP 50 HIGHEST LEVEL PLAYERS"; echo ""; cat ${ATHENATXT} \
+| awk -F , '{sub(/^[0-9] */,"",$2);sub(/ *[0-9]$/,"",$2); sub(/[[:space:]]*[0-9]+$/,"",$14);print $14,$2}' \
+| sort -nr | head -n 50 | awk '{first=$1;$1="";print $0, "("first")"}' | nl -s ". "; echo ""; echo "Generated at `date`") >> ${DEST}/top-highest-luk.txt
diff --git a/src/txt-converter/char/GNUmakefile b/src/txt-converter/char/GNUmakefile
deleted file mode 100644
index 56723ca..0000000
--- a/src/txt-converter/char/GNUmakefile
+++ /dev/null
@@ -1,13 +0,0 @@
-all: char-converter
-sql: char-converter
-
-COMMON_OBJ = ../../common/core.o ../../common/socket.o ../../common/timer.o ../../common/db.o ../../common/malloc.o
-
-char-converter: char-converter.o strlib.o $(COMMON_OBJ)
- $(CC) -o ../../../$@ $^ $(LIB_S)
-
-char-converter.o: char-converter.c char.h strlib.h
-strlib.o: strlib.c strlib.h
-clean:
- rm -f *.o ../../../char-converter
-
diff --git a/src/txt-converter/char/Makefile b/src/txt-converter/char/Makefile
index 56723ca..47d97d3 100644
--- a/src/txt-converter/char/Makefile
+++ b/src/txt-converter/char/Makefile
@@ -1,3 +1,5 @@
+include ../../../make.defs
+
all: char-converter
sql: char-converter
diff --git a/src/txt-converter/login/GNUmakefile b/src/txt-converter/login/GNUmakefile
deleted file mode 100644
index 9f34e14..0000000
--- a/src/txt-converter/login/GNUmakefile
+++ /dev/null
@@ -1,11 +0,0 @@
-all: login-converter
-sql: login-converter
-
-COMMON_OBJ = ../../common/core.o ../../common/socket.o ../../common/timer.o ../../common/db.o ../../common/malloc.o
-COMMON_H = ../../common/core.h ../../common/socket.h ../../common/timer.h ../../common/mmo.h ../../common/version.h ../../common/db.h ../../common/malloc.h
-
-login-converter: login-converter.o ../../login_sql/md5calc.o ../../login_sql/strlib.o $(COMMON_OBJ)
- $(CC) -o ../../../$@ $^ $(LIB_S)
-login-converter.o: login-converter.c ../../login_sql/login.h ../../login_sql/md5calc.h ../../login_sql/strlib.h $(COMMON_H)
-clean:
- rm -f *.o ../../../login-converter
diff --git a/src/txt-converter/login/Makefile b/src/txt-converter/login/Makefile
index 9f34e14..832a21a 100644
--- a/src/txt-converter/login/Makefile
+++ b/src/txt-converter/login/Makefile
@@ -1,3 +1,4 @@
+include ../../../make.defs
all: login-converter
sql: login-converter
diff --git a/src/webserver/Makefile b/src/webserver/Makefile
index 065c1ff..417fa7c 100644
--- a/src/webserver/Makefile
+++ b/src/webserver/Makefile
@@ -1,19 +1,19 @@
-cc = gcc
+include ../../make.defs
all:
#Generate framework...
- $(cc) -c parse.c
- $(cc) -c generate.c
- $(cc) -c htmlstyle.c
- $(cc) -c logs.c
+ $(CC) $(CFLAGS) -c parse.c
+ $(CC) $(CFLAGS) -c generate.c
+ $(CC) $(CFLAGS) -c htmlstyle.c
+ $(CC) $(CFLAGS) -c logs.c
#Generate "pages"...
- cd pages && $(cc) -c about.c && cd ..
- cd pages && $(cc) -c sample.c && cd ..
- cd pages && $(cc) -c notdone.c && cd ..
+ cd pages && $(CC) $(CFLAGS) -c about.c && cd ..
+ cd pages && $(CC) $(CFLAGS) -c sample.c && cd ..
+ cd pages && $(CC) $(CFLAGS) -c notdone.c && cd ..
#Building the server...
- $(cc) -o webserver main.c parse.o generate.o htmlstyle.o \
+ $(CC) $(CFLAGS) -o webserver main.c parse.o generate.o htmlstyle.o \
logs.o pages/about.o pages/sample.o pages/notdone.o