/*******************************************************************************
        static2.c
        Z-World, 2000

        Similar to static.c, this program serves up basic statis
        web pages, but integrates the ftp server to allow you to
        change the pages at runtime.
*******************************************************************************/

/*
 *   Sample HTTP + FTP daemon.
 *
 *   To use:
 *      Edit IP/netmask/etc as normal at the top.
 *      Compile/Run it.
 *      Browse to it with netscape, and note the default index.html page.
 *      FTP to it, and upload a file called 'index.html'
 *      Browse to it again with netscape, and your file will have
 *         replaced the default index.html
 */
 
/***********************************
 * Configuration                   *
 * -------------                   *
 * All fields in this section must *
 * be altered to match your local  *
 * network settings.               *
 ***********************************/

/*
 * You must change the following values to whatever
 * your local IP address and netmask are. Contact your
 * network administrator for these numbers.
 */
#define MY_IP_ADDRESS   "10.10.6.100"
#define MY_NETMASK      "255.255.255.0"

/*
 * TCP/IP modification - reduce TCP socket buffer
 * size, to allow more connections. This can be increased,
 * with increased performance, if the number of sockets
 * are reduced.  Note that this buffer size is split in
 * two for TCP sockets--1024 bytes for send and 1024 bytes
 * for receive.
 */
#define TCP_BUF_SIZE 2048

/*
 * Web server configuration
 */

/*
 * Only one server is needed when using a reserved port
 */
#define HTTP_MAXSERVERS 1

/*
 * Define this if you do not need to use the http_flashspec array.
 * Since this program uses only the ZSERVER.LIB functionality,
 * then it does not need the http_flashspec array.
 */
#define HTTP_NO_FLASHSPEC

/*
 * Set the maximum number of sockets to use.  We have set the HTTP
 * server to use 1 sockets, and the FTP server uses 2 sockets.
 */
#define MAX_TCP_SOCKET_BUFFERS 3

/********************************
 * End of configuration section *
 ********************************/

/*
 * FTP configuration - you shouldn't have to change this
 */
/* maximum size of a file we can receive for 'index.html' */
#define MAX_NEWFILESIZE	0x4000

/* we will use our own handler */
#define FTP_NODEFAULTHANDLER

#memmap xmem
#use "dcrtcp.lib"
#use "http.lib"
#use "ftp_server.lib"

#ximport "samples/tcpip/http/pages/rabbit1.gif"    rabbit1_gif
#ximport "samples/tcpip/http/pages/static.html"  index_html

/* the default mime type for '/' must be first */
const HttpType http_types[] =
{
   { ".html", "text/html", NULL},
   { ".gif", "image/gif", NULL}
};

/* storage for the new file */
long newfile;
long newfilesize;
int newuser;

/* handlers for ftp */
int ftp_handlers_open(char *name, int options, int uid);
long ftp_handlers_getfilesize(int fd);
int ftp_handlers_read(int fd, char *buf, long offset, int len);
int ftp_handlers_write(int fd, char *buf, long offset, int len);
int ftp_handlers_close(int fd);
int ftp_handlers_list(int item, char *line, int listing);


const FTPhandlers ftp_file_handlers = {
	ftp_handlers_open,
	ftp_handlers_read,
	ftp_handlers_write,
	ftp_handlers_close,
	ftp_handlers_getfilesize,
	ftp_handlers_list
};

main()
{
	int file;
	int user;

	// Set up the anonymous user
	user = sauth_adduser("anonymous", "", SERVER_FTP);
	sauth_setwriteaccess(user, 1);

	// Add index.html
	file = sspec_addxmemfile("index.html", index_html, SERVER_HTTP | SERVER_FTP);
	sspec_setuser(file, user);

	// Add this entry, so that index_html is the default page
	sspec_addxmemfile("/", index_html, SERVER_HTTP);

	// Add rabbit1.gif
	file = sspec_addxmemfile("rabbit1.gif", rabbit1_gif, SERVER_HTTP | SERVER_FTP);
	sspec_setuser(file, user);

	// Set up the foo user
	user = sauth_adduser("foo", "bar", SERVER_FTP);
	sauth_setwriteaccess(user, 1);
	
	newfile = xalloc(MAX_NEWFILESIZE + 4);
	if(0 == newfile) {
		exit(0);
	}
	
	sock_init();
	http_init();
	ftp_init(&ftp_file_handlers);
	tcp_reserveport(80); //reserve port for HTTP server

	while(1) {
		http_handler();
		ftp_tick();
	}
}


/*******************************
 * The FTP read/write handlers *
 *******************************/

int ftp_handlers_open(char *name, int options, int uid)
{
	if( options != O_WRONLY ) {
		/* unsupported mode at this time */
		return -1;
	}

	if(strncmp(name,"index.html", 10)) {
		/* not index.html */
		return -1;
	}
	
	sspec_remove(sspec_findname("/", SERVER_HTTP));
	sspec_remove(sspec_findname("index.html", SERVER_HTTP));
	newuser = uid;

	newfilesize = 4;
	
	return 0;
}

long ftp_handlers_getfilesize(int fd)
{
	/* should never come here - we don't
	support reading in this handler */
	return 0;
}

int ftp_handlers_read(int fd, char *buf, long offset, int len)
{
	/* should never come here - we don't
	support reading in this handler */
	return 0;
}

int ftp_handlers_write(int fd, char *buf, long offset, int len)
{
	auto int wlen, i;

	if(0 != fd) {
		/* bad fd */
		return -1;
	}
	
	/* find write length */
	wlen = (MAX_NEWFILESIZE + 4) - (int)offset;
	if(wlen > len) wlen = len;

	root2xmem(newfile + offset + 4, buf, wlen);
	newfilesize += wlen;

	return wlen;
}

int ftp_handlers_close(int fd)
{
	int file;

	newfilesize -= 4;

	root2xmem(newfile, &newfilesize, 4);

	file = sspec_addxmemfile("index.html", newfile, SERVER_HTTP | SERVER_FTP);
	sspec_setuser(file, newuser);

	sspec_addxmemfile("/", newfile, SERVER_HTTP);

	return 0;
}

int ftp_handlers_list(int item, char *line, int listing)
{
	auto int spec;
	auto char *username;
	auto char *filename;
	auto long length;
	
	spec = sspec_findnextfile(item, SERVER_FTP);
	if (spec != -1) {
		username = sspec_getusername(spec);
		filename = sspec_getname(spec);
		length = sspec_getlength(spec);
		if(listing) {
			sprintf(line, "%s\r\n", filename);
		} else {
			sprintf(line, "-rw-rw-rw-   1 %s %s\t\t%ld Jan  1 12:00 %s\r\n",
				username, username,
				length,
				filename);
		}
		return spec;
	} else {
		return -1;
	}
}
