/*
 * Copyright 1990 by Baylor College of Medicine ALL RIGHTS RESERVED. 
 *
 * This program is subject to a license agreement between 
 * Baylor College of Medicine and MIT. Any use inconsistent with
 * said license and any use by persons other than the faculty, 
 * students and staff at MIT or any use on a computer not operated 
 * as part of the Athena Computing Environment (ACE) is expressly 
 * prohibited.
 */
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <time.h>
#include <malloc.h>
#include <dfa.h>

#include "dbsrv.h"
#include "util.h"

/*
 * determine if a page in a notebook is an island or not.
 */
is_island(nb,page)
	dbNotebook nb;
	dbPage page;
{
	page->visited = TRUE;
	if (nb->home_page == page->pid)
	{
		return FALSE;
	}
	else
	{
		LinkList ll = page->link_list;
		while(ll != NULL)
		{
			if (!ll->page->visited)
			{
				if (is_island(ll->note,ll->page))
				{
					return FALSE;
				}
			}
			ll = ll->next;
		}
	}
}

/*
 * construct a dfa by processing "*" as wild cards in the string
 */
static 
Dfa construct_wild_dfa(s,case_sens)
	char *s;
	int case_sens;
{
	Dfa d_return = NULL;
	int first = 0;

	while (*s != '\0')
	{
		if (first == 0)
		{
			first = 1;
			if (*s == '~')
			{
				d_return = dfa_wild_string("dbsrv");
			}
			else
			{
				d_return = dfa_nstring("dbsrv",s,1,case_sens);
			}
		}
		else
		{
			if (*s == '~')
			{
				Dfa d = dfa_wild_string("dbsrv");
				d_return = dfa_concat("dbsrv",d_return,d);
			}
			else
			{
				Dfa d = dfa_nstring("dbsrv",s,1,case_sens);
				d_return = dfa_concat("dbsrv",d_return,d);
			}
		}
		s++;
	}

	return d_return;
}	

/*
 * constructs a dfa from string
 */
static
Dfa construct_dfa(s,case_sens,wild_cards)
	char *s;
	int case_sens;
	int wild_cards;
{

	if (!wild_cards)
	{
		Dfa d1 = dfa_string("dbsrv",s,case_sens);
		return d1;
	}
	else
	{
		Dfa d1 = construct_wild_dfa(s,case_sens);
		return d1;
	}
}

/*
 * get the filename fo a specific notebook in a specific database
 */
get_note_fname(db,note,s)
	dbDatabase db ;
	char *s ;
{
	sprintf(s,"%s/%s/%d",pc.data_dir,db->name,note) ;
}

/*
 * get the filename for a spcific page in a notebook.
 */
get_page_fname(db,note,page,s)
	dbDatabase db ;
	char *s ;
{
	char note_name[256] ;
	get_note_fname(db,note,note_name) ;
	sprintf(s,"%s/%d",note_name,page) ;
}

/*
 * get the filename for a spcific object
 */
get_object_fname(db,note,page,object,s)
	dbDatabase db ;
	char *s ;
{
	char page_name[256] ;
	get_page_fname(db,note,page,page_name) ;
	sprintf(s,"%s/%d",page_name,object) ;
}

/*
 * get the current date
 */
get_cur_date(buf)
	char *buf ;
{
	time_t time() ;
	time_t clock = time((time_t *)0) ;
	struct tm *tm = localtime(&clock) ;
	static char *months[] = 
		{"Jan","Feb","Mar","Apr","May","Jun",
		"Jul","Aug","Sep","Oct","Nov","Dec"} ;
	sprintf(buf,"%s %d %d %02d:%02d%cM",
		months[tm->tm_mon],tm->tm_mday,tm->tm_year + 1900,
			(tm->tm_hour == 0 ? 12 :
			tm->tm_hour < 13 ? tm->tm_hour :
			(tm->tm_hour - 12)),
			tm->tm_min,
			(tm->tm_hour < 12) ? 'A' : 'P') ;
}

/* Returns TRUE if author can read given notebook */
static
can_read(c,note)
	Connection c ;
	dbNotebook note ;
{
	Access_List al = find_access(c->author,note) ;
	return (al != NULL) ;
}

/* Returns TRUE if author can write given notebook */
static
can_write(c,note)
	Connection c ;
	dbNotebook note ;
{
	Access_List al = find_access(c->author,note) ;
	return (al == NULL) ? FALSE : (al->access > 0) ;
}

/* search entire database */
req_search_database(c)
	Connection c ;
{
	dbNotebook nb;
	LongLinkedList ln ;
	LongLinkedList lp ;
	char s[256];
	long case_sens;
	long wild;
	Dfa d;

	if (read_f(c->conn_sock,"lls",&case_sens,&wild,s,sizeof s) < 0)
	{
		return -1 ;
	}

	/* construct the dfa for the string */
	d = construct_dfa(s,(int)case_sens,(int)wild);

	ll_init(&ln);
	ll_init(&lp);
	nb = c->db->notebooks;
	while(nb != NULL)
	{
		if(can_read(c,nb))
		{
			dbPage p = nb->pages;
			while (p != NULL)
			{
				if (dfa_execute(d,p->title))
				{
					ll_add(&ln,nb->nid);
					ll_add(&lp,p->pid);
				}				
				p = p->next;
			}
		}
		nb = nb->next;
	}

	/* Return the notebook ids */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ln) < 0)
	{
		ll_free(&ln) ;
		return -1 ;
	}
	ll_free(&ln) ;

	/* return the page ids */
	if (write_f(c->conn_sock,"la",EVT_DATA,&lp) < 0)
	{
		ll_free(&lp) ;
		return -1 ;
	}
	ll_free(&lp) ;
	return 0 ;
}

/* Sevices request to search for a page name */
req_search_notebook(c)
	Connection c ;
{
	LongLinkedList ll ;
	char s[256];
	long nid ;
	long pid ;
	long case_sens;
	long wild;
	dbNotebook note ;
	dbPage page;
	Dfa d;

	if (read_f(c->conn_sock,"llls",&nid, &case_sens, &wild, s, sizeof s) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	if (!can_read(c,note))
	{
		return -2 ;
	}

	/* construct the dfa for the string */
	d = construct_dfa(s,(int)case_sens,(int)wild);

	/* check the dfa against all page names in notebook */
	ll_init(&ll);
	page = note->pages ;
	while(page != NULL)
	{
		if (dfa_execute(d,page->title))
		{
			ll_add(&ll,(long)page->pid);
		}
		page = page->next;
	}

	/* Return the results */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ll) < 0)
	{
		ll_free(&ll) ;
		return -1 ;
	}
	ll_free(&ll) ;
	return 0;
}

/* Services request to get links on a page */
req_inq_page_links(c)
	Connection c ;
{
	LongLinkedList ln ;
	LongLinkedList lp ;
	long nid ;
	long pid ;
	dbNotebook note ;
	dbPage page ;
	if (read_f(c->conn_sock,"ll",&nid,&pid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return -2 ;
	}
	if (!can_read(c,note))
	{
		return -2 ;
	}

	/* read in the notebook ids for the links */
	ll_init(&ln) ;
	ll_init(&lp) ;
	{
		dbObject ol = page->objects;
		while (ol != NULL)
		{
			if (ol->type == OT_LINK) 
			{
				int lnk_nid = -1;
				int lnk_pid = -1;
				if (ol->data.link.dest_note != (dbNotebook)NULL)
				{
					if (can_read(c,ol->data.link.dest_note))
					{
						lnk_nid = ol->data.link.dest_note->nid;
					}
				}
				if (ol->data.link.dest_page != (dbPage)NULL)
				{
					lnk_pid = ol->data.link.dest_page->pid;
				}
				/* only add valid links */
				if ((lnk_nid != -1) && (lnk_pid != -1))
				{
					ll_add(&ln,(long)lnk_nid) ;
					ll_add(&lp,(long)lnk_pid) ;
				}
			}
			ol = ol->next;
		}
	}

	/* Return the notebook ids */
	if (write_f(c->conn_sock,"laa",EVT_DATA,&ln,&lp) < 0)
	{
		ll_free(&ln) ;
		ll_free(&lp) ;
		return -1 ;
	}
	ll_free(&ln) ;
	ll_free(&lp) ;
	return 0 ;
}

/* Services request to get notebook access list */
req_get_notebook_access_list(c)
	Connection c ;
{
	LongLinkedList ll ;
	dbNotebook note = c->db->notebooks ;

	ll_init(&ll) ;
	while(note != NULL)
	{
		if (c->author == note->author || can_read(c,note))
		{
			ll_add(&ll,(long)note->nid);
		}
		note = note->next ;
	}

	/* Return the results */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ll) < 0)
	{
		ll_free(&ll) ;
		return -1 ;
	}
	ll_free(&ll) ;
	return 0 ;
}

/* Services request to get list of authors */
req_get_active_authors(c)
	Connection c ;
{
	LongLinkedList ll ;
	Connection cp = pc.cl.first;

	ll_init(&ll) ;
	while(cp != NULL)
	{
		if (cp->author)
		{
			ll_add(&ll,(long)cp->author->aid) ;
		}
		cp = cp->next;
	}

	/* Return list of active authors */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ll) < 0)
	{
		ll_free(&ll) ;
		return -1 ;
	}
	ll_free(&ll) ;
	return 0 ;
}

/* Services request to get list of authors */
req_get_author_list(c)
	Connection c ;
{
	LongLinkedList ll ;
	dbAuthor author = c->db->authors ;

	ll_init(&ll) ;
	while(author != NULL)
	{
		ll_add(&ll,(long)author->aid) ;
		author = author->next ;
	}

	/* Return the results */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ll) < 0)
	{
		ll_free(&ll) ;
		return -1 ;
	}
	ll_free(&ll) ;
	return 0 ;
}

req_inq_page_objects(c)
	Connection c ;
{
	LongLinkedList ll ;
	long nid ;
	long pid ;
	dbNotebook note ;
	dbPage page ;
	if (read_f(c->conn_sock,"ll",&nid,&pid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return -2 ;
	}
	if (!can_read(c,note))
	{
		return -2 ;
	}

	/* Read in the results */
	ll_init(&ll) ;
	{
		dbObject o ;
		for(o = page->objects; o != NULL; o = o->next)
		{
			ll_add(&ll,(long)o->oid) ;
		}
	}

	/* Return the results */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ll) < 0)
	{
		ll_free(&ll) ;
		return -1 ;
	}
	ll_free(&ll) ;
	return 0 ;
}

req_find_page_by_name(c)
	Connection c ;
{
	char name[256] ;
	dbNotebook note ;
	long nid ;

	if (read_f(c->conn_sock,"ls",&nid,name,sizeof name) < 0)
	{
		return -1 ;
	}
	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	if (!can_read(c,note))
	{
		return -2 ;
	}

	{
		dbPage page = note->pages ;
		while(page != NULL)
		{
			if (!strcmp(page->title,name))
			{
				if (write_f(c->conn_sock,"ll",EVT_DATA,page->pid) < 0)
				{
					return -1 ;
				}
				return 0 ;
			}
			page = page->next ;
		}
	}
	return -2 ;
}

req_find_notebook_by_name(c)
	Connection c ;
{
	char name[256] ;

	if (read_f(c->conn_sock,"s",name,sizeof name) < 0)
	{
		return -1 ;
	}

	{
		dbNotebook note = c->db->notebooks ;
		while(note != NULL)
		{
			if (!strcmp(note->title,name))
			{
				if (can_read(c,note))
				{
					if (write_f(c->conn_sock,"ll",EVT_DATA,note->nid) < 0)
					{
						return -1 ;
					}
					return 0 ;
				}
				return -2 ;
			}
			note = note->next ;
		}
	}
	return -2 ;
}

/* Services request the orphan pages of selected notebook */
req_inq_notebook_orphans(c)
	Connection c ;
{
	LongLinkedList ll ;
	long nid ;
	dbNotebook note ;
	dbPage page ;
	if (read_f(c->conn_sock,"l",&nid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	if (!can_read(c,note))
	{
		return -2 ;
	}

	/* for each page, search for any links to it */
	ll_init(&ll) ;
	page = note->pages ;
	while(page != NULL)
	{
		if (is_island(note,page))
		{
			ll_add(&ll,(long)page->pid) ;
		}
		page = page->next ;
	}

	/* Return the results */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ll) < 0)
	{
		ll_free(&ll) ;
		return -1 ;
	}
	ll_free(&ll) ;
	return 0 ;
}

/* Services request to get notebook access list */
req_inq_notebook_pages(c)
	Connection c ;
{
	LongLinkedList ll ;
	long nid ;
	dbNotebook note ;
	if (read_f(c->conn_sock,"l",&nid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	if (!can_read(c,note))
	{
		return -2 ;
	}

	/* Read in the results */
	ll_init(&ll) ;
	{
		dbPage page = note->pages ;
		while(page != NULL)
		{
			ll_add(&ll,(long)page->pid) ;
			page = page->next ;
		}
	}

	/* Return the results */
	if (write_f(c->conn_sock,"la",EVT_DATA,&ll) < 0)
	{
		ll_free(&ll) ;
		return -1 ;
	}
	ll_free(&ll) ;
	return 0 ;
}

/* Gets information on a notebook */
req_inq_notebook(c)
	Connection c ;
{
	long nid ;
	dbNotebook note ;
	int access ;

	/* Read in notebook id */
	if (read_f(c->conn_sock,"l",&nid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	{
		Access_List al = find_access(c->author,note) ;
		if (al == NULL)
		{
			if (c->author == note->author)
			{
				access = 0 ;
			}
			else
			{
				return -2 ;
			}
		}
		else
		{
			access =
				(al->access == 1) ?
					2 :
					1 ;
		}
	}

	/* Send it out */
	if (write_f(c->conn_sock,"lslll",EVT_DATA,note->title,access,note->author->aid,note->home_page) < 0)
	{
		return -1 ;
	}

	return 0 ;
}

/* Gets information on an object */
req_inq_object(c)
	Connection c ;
{
	dbNotebook note ;
	dbPage page ;
	dbObject object ;
	long nid ;
	long pid ;
	long oid ;

	/* Read in notebook id */
	if (read_f(c->conn_sock,"lll",&nid,&pid,&oid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return -2 ;
	}
	object = find_object_by_id(page,(int)oid) ;
	if (object == NULL)
	{
		return -2 ;
	}
	/* Make sure he can read the object */
	if (!can_read(c,note))
	{
		return -2 ;
	}

	if (write_f(c->conn_sock,"lllllll",EVT_DATA,
			object->x,object->y,object->width,object->height,object->type,object->author->aid) < 0)
	{
		return -1 ;
	}

	/* Get object specific informations */
	switch(object->type)
	{
		case IMAGE_OBJECT_TYPE :
			if (write_f(c->conn_sock,"ll",
				object->data.image.create_colormap,object->data.image.low_res_sw) < 0)
			{
				return -1 ;
			}
			break ;
		case TEXT_OBJECT_TYPE :
			if (write_f(c->conn_sock,"ss",object->data.text.font,object->data.text.color) < 0)
			{
				return -1 ;
			}
			break ;
		case LINK_OBJECT_TYPE :
			{
				int lnk_nid = -1;
				int lnk_pid = -1;
				if (object->data.link.dest_note != (dbNotebook)NULL)
				{
					lnk_nid = object->data.link.dest_note->nid;
				}
				if (object->data.link.dest_page != (dbPage)NULL)
				{
					lnk_pid = object->data.link.dest_page->pid;
				}
				if (write_f(c->conn_sock,"llsss",lnk_nid,lnk_pid,
					object->data.link.title,
					object->data.link.font,
					object->data.link.color) < 0)
				{
					return -1 ;
				}
			}
			break ;
		case ACTION_LINK_OBJECT_TYPE :
			if (write_f(c->conn_sock,"ssss",object->data.action_link.command,object->data.action_link.title,object->data.action_link.font,object->data.action_link.color) < 0)
			{
				return -1 ;
			}
			break ;
	}

	return 0 ;
}

/* Gets information on a page */
req_inq_page(c)
	Connection c ;
{
	long nid ;
	long pid ;
	dbNotebook note ;
	dbPage page ;

	/* Read in notebook id */
	if (read_f(c->conn_sock,"ll",&nid,&pid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return -2 ;
	}

	/* Make sure he can read the object */
	if (!can_read(c,note))
	{
		return -2 ;
	}

	/* Send it out */
	if (write_f(c->conn_sock,"lsllssl",EVT_DATA,page->title,page->width,page->height,page->color,page->create_date,page->author->aid) < 0)
	{
		return -1 ;
	}

	return 0 ;
}

/*
 * check for a valid page. Reply values are:
 *   1 - if page is valid
 *   2 - if page does not exist
 *   3 - if page exists but not accessible due to access restrictions
 */
req_validate_page(c)
	Connection c ;
{
	long nid ;
	long pid ;
	dbNotebook note ;
	dbPage page ;

	/* Read in notebook id */
	if (read_f(c->conn_sock,"ll",&nid,&pid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		/* if notebook does not exist then page doesn't either */
		if (write_f(c->conn_sock,"ll",EVT_DATA,2) < 0)
		{
			return -1;
		}
		return 0;
	}

	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		/* page does note exist in notebook */
		if (write_f(c->conn_sock,"ll",EVT_DATA,2) < 0)
		{
			return -1;
		}
		return 0;
	}
	else
	{
		/* Make sure he can read the page */
		if (!can_read(c,note))
		{
			/* the page exists but we don't have access */
			if (write_f(c->conn_sock,"ll",EVT_DATA,3) < 0)
			{
				return -1;
			}
			return 0;
		}
		else
		{
			/* the page exists and we have access */
			if (write_f(c->conn_sock,"ll",EVT_DATA,1) < 0)
			{
				return -1;
			}
			return 0;
		}
	}
}

/* Services request to create a notebook */
req_create_notebook(c)
    Connection c ;
{
    char title[256] ;
    long nid ;
    char current_date[256] ;
	long home_page ;

    /* Read in title */
    if (read_f(c->conn_sock,"sl",title,sizeof title,&home_page) < 0)
    {
        return -1 ;
    }

    /* Get new notebook */
    nid = c->db->next_notebook_id ;
    get_cur_date(current_date) ;
    if (sy_call_exec(c->db,"Create_Notebook","ddqqd",nid,c->author->aid,current_date,title,home_page) < 0)
    {
        return -2 ;
    }

	add_notebook(c->db,(int)nid,c->author,title,current_date,current_date,home_page) ;

	/* Make a directory for it */
    {
        char dir_name[256] ;
        get_note_fname(c->db,(int)nid,dir_name) ;
        mkdir(dir_name,0700) ;
    }

    /* Return the notebook id */
    if (write_f(c->conn_sock,"ll",EVT_DATA,nid) < 0)
    {
        return -1 ;
    }

    return 0 ;
}

/* Services request to modify a notebook */
req_modify_notebook(c)
    Connection c ;
{
    char title[256] ;
    long nid ;
    dbNotebook note ;
	long home_page ;

    /* Read in title */
    if (read_f(c->conn_sock,"lsl",&nid,title,sizeof title,&home_page) < 0)
    {
        return -1 ;
    }

    note = find_note_by_id(c->db,(int)nid) ;
    if (note == NULL)
    {
        return 0 ;
    }

    /* Make sure the user is allowed to write to the notebook */
    if (c->author != note->author)
    {
        return 0 ;
    }

    change_notebook(c->db,note,title,home_page) ;

    /* Tell everyone about it */
    {
        Connection cp = pc.cl.first ;
        while(cp != NULL)
        {
            if (c->db == cp->db && can_read(cp,note) && c != cp)
            {
                write_f(cp->conn_sock,"lll",EVT_MODIFY_NOTEBOOK,sizeof(long),nid) ;
            }
            cp = cp->next ;
        }
    }

    return 0 ;
}

/* Services request to create a page */
req_create_page(c)
	Connection c ;
{
	char title[256] ;
	long nid ;
	long pid ;
	long width,height ;
	char color[256] ;
	dbNotebook note ;
	char current_date[256] ;

	/* Read in notebook and title */
	if (read_f(c->conn_sock,"lslls",&nid,title,sizeof title,&width,&height,color,sizeof color) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}

    /* Make sure the user is allowed to write to the notebook */
    if (!can_write(c,note))
    {
        return 0 ;
    }

	pid = note->next_page_id ;

	/* Create the page */
	get_cur_date(current_date) ;
	if (sy_call_exec(c->db,"Create_Page","dddqddqq",pid,c->author->aid,nid,title,width,height,color,current_date) < 0)
	{
		return 0 ;
	}
	add_page(note,(int)pid,c->author,title,current_date,current_date,(int)width,(int)height,color) ;

	/* Make a directory for it */
	{
		char dir_name[256] ;
		get_page_fname(c->db,(int)nid,(int)pid,dir_name) ;
		mkdir(dir_name,0700) ;
	}

	/* Tell everyone about it */
	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c->db == cp->db && can_read(cp,note) && c != cp)
			{
				write_f(cp->conn_sock,"llll",EVT_CREATE_PAGE,2 * sizeof(long),nid,pid) ;
			}
			cp = cp->next ;
		}
	}

	/* Return the page id */
	if (write_f(c->conn_sock,"ll",EVT_DATA,pid) < 0)
	{
		return -1 ;
	}

	return 0 ;
}

/* Services request to create a page */
req_modify_page(c)
	Connection c ;
{
	dbNotebook note ;
	dbPage page ;
	char title[256] ;
	long nid ;
	long pid ;
	long width,height ;
	char color[256] ;

	/* Read in notebook and title */
	if (read_f(c->conn_sock,"llslls",&nid,&pid,title,sizeof title,&width,&height,color,sizeof color) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return 0 ;
	}

    /* Make sure the user is allowed to write to the notebook */
    if (!can_write(c,note))
    {
        return 0 ;
    }

	change_page(c->db,note,page,title,(int)width,(int)height,color) ;

	/* Tell everyone about it */
	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c->db == cp->db && can_read(cp,note) && cp != c)
			{
				write_f(cp->conn_sock,"llll",EVT_MODIFY_PAGE,2 * sizeof(long),nid,pid) ;
			}
			cp = cp->next ;
		}
	}

	return 0 ;
}

/* Services request to create an object */
req_create_object(c)
	Connection c ;
{
	long nid ;
	long pid ;
	long oid ;
	dbPage page ;
	dbNotebook note ;
	char current_date[256] ;
	long x ;
	long y ;
	long width ;
	long height ;
	long type ;
	long create_colormap ;
	long low_res_sw ;
	char font[256] ;
	char color[256] ;
	char title[256] ;
	char command[256] ;
	long dest_note ;
	long dest_page ;

	/* Read in notebook */
	if (read_f(c->conn_sock,"lllllll",&nid,&pid,&x,&y,&width,&height,&type) < 0)
	{
		return -1 ;
	}

	switch(type)
	{
		case IMAGE_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"ll",
					&create_colormap,
			    	&low_res_sw) < 0)
			{
				return -1 ;
			}
			break ;
		}
		case TEXT_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"ss",
				font,sizeof font,
				color,sizeof color) < 0)
			{
				return -1 ;
			}
			break ;
		}
		case ACTION_LINK_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"ssss",
					command,sizeof command,
					title,sizeof title,
					font,sizeof font,
					color,sizeof color) < 0)
			{
				return -1 ;
			}
			break ;
		}
		case LINK_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"llsss",
					&dest_note,
					&dest_page,
					title,sizeof title,
					font,sizeof font,
					color,sizeof color) < 0)
			{
				return -1 ;
			}
			break ;
		}
		default :
			return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return -2 ;
	}

    /* Make sure the user is allowed to write to the notebook */
    if (!can_write(c,note))
    {
        return -2 ;
    }

	oid = page->next_object_id ;
	get_cur_date(current_date) ;

	switch(type)
	{
		case IMAGE_OBJECT_TYPE :
		{
			if (sy_call_exec(c->db,"Create_Image_Object","ddddddddddq",oid,
				c->author->aid,nid,pid,x,y,width,height,
				create_colormap,
				low_res_sw,current_date) < 0)
			{
				return -2 ;
			}
			add_image_object(
				page,(int)oid,c->author,current_date,current_date,
				(int)type,(int)x,(int)y,(int)width,(int)height,
				(int)create_colormap,(int)low_res_sw) ;
			break ;
		}
		case TEXT_OBJECT_TYPE :
		{
			if (sy_call_exec(c->db,"Create_Txt_Object","ddddddddqqq",oid,
				c->author->aid,nid,pid,x,y,width,height,
				font,
				color,current_date) < 0)
			{
				return -2 ;
			}
			add_text_object(
				page,(int)oid,c->author,current_date,current_date,
				(int)type,(int)x,(int)y,(int)width,(int)height,
				color,font,(char *)NULL) ;
			break ;
		}
		case ACTION_LINK_OBJECT_TYPE :
		{
			if (sy_call_exec(c->db,"Create_Action_Link_Object","ddddddddqqqqq",oid,
				c->author->aid,nid,pid,x,y,width,height,
				command,
				title,
				font,
				color,current_date) < 0)
			{
				return -2 ;
			}
			add_action_link_object(
				page,(int)oid,c->author,current_date,current_date,
				(int)type,(int)x,(int)y,(int)width,(int)height,
				color,font,title,command) ;
			break ;
		}
		case LINK_OBJECT_TYPE :
		{
			if (sy_call_exec(c->db,"Create_Link_Object","ddddddddddqqqqq",oid,
				c->author->aid,nid,pid,x,y,width,height,
				dest_note,
				dest_page,
				title,
				font,
				color,current_date,c->db->name) < 0)
			{
				return -2 ;
			}
			add_link_object(c->db,note,page,
				(int)oid,c->author,current_date,current_date,
				(int)type,(int)x,(int)y,(int)width,(int)height,
				color,font,title,(int)dest_note,(int)dest_page) ;
			break ;
		}
	}

	/* Tell everyone about it */
	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c->db == cp->db && can_read(cp,note) && c != cp)
			{
				write_f(cp->conn_sock,"lllll",EVT_CREATE_OBJECT,3 * sizeof(long),nid,pid,oid) ;
			}
			cp = cp->next ;
		}
	}

	/* Return the page id */
	if (write_f(c->conn_sock,"ll",EVT_DATA,oid) < 0)
	{
		return -1 ;
	}

	return 0 ;
}

/* Services request to create an object */
req_modify_object(c)
	Connection c ;
{
	long nid ;
	long pid ;
	long oid ;
	dbNotebook note ;
	dbPage page ;
	dbObject object ;
	long x ;
	long y ;
	long width ;
	long height ;
	long create_colormap ;
	long low_res_sw ;
	char font[256] ;
	char color[256] ;
	char title[256] ;
	char command[256] ;
	long dest_note ;
	long dest_page ;
	long type ;

	/* Read in notebook */
	if (read_f(c->conn_sock,"llllllll",&nid,&pid,&oid,&x,&y,&width,&height,&type) < 0)
	{
		return -1 ;
	}

	switch(type)
	{
		case IMAGE_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"ll",
					&create_colormap,
			    	&low_res_sw) < 0)
			{
				return -1 ;
			}
			break ;
		}
		case TEXT_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"ss",
				font,sizeof font,
				color,sizeof color) < 0)
			{
				return -1 ;
			}
			break ;
		}
		case ACTION_LINK_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"ssss",
					command,sizeof command,
					title,sizeof title,
					font,sizeof font,
					color,sizeof color) < 0)
			{
				return -1 ;
			}
			break ;
		}
		case LINK_OBJECT_TYPE :
		{
			if (read_f(c->conn_sock,"llsss",
					&dest_note,
					&dest_page,
					title,sizeof title,
					font,sizeof font,
					color,sizeof color) < 0)
			{
				return -1 ;
			}
			break ;
		}
		default :
			return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return 0 ;
	}
	object = find_object_by_id(page,(int)oid) ;
	if (object == NULL)
	{
		return 0 ;
	}

	/* Make sure the user is allowed to write to the notebook */
	if (!can_write(c,note))
	{
		return 0 ;
	}

	if (type != object->type)
	{
		return 0 ;
	}

	switch(type)
	{
		case IMAGE_OBJECT_TYPE :
		{
			change_image_object(c->db,note,page,object,
					(int)x,(int)y,(int)width,(int)height,
					(int)create_colormap,
					(int)low_res_sw) ;
			break ;
		}
		case TEXT_OBJECT_TYPE :
		{
			change_text_object(c->db,
					note,page,object,
					(int)x,(int)y,(int)width,(int)height,
					color,
					font) ;
			break ;
		}
		case LINK_OBJECT_TYPE :
		{
			change_link_object(c->db,
					note,page,object,
					(int)x,(int)y,(int)width,(int)height,
					color,
					font,
					title,
					(int)dest_note,
					(int)dest_page) ;
			break ;
		}
		case ACTION_LINK_OBJECT_TYPE :
		{
			change_action_link_object(c->db,
					note,page,object,
					(int)x,(int)y,(int)width,(int)height,
					color,
					font,
					title,
					command) ;
			break ;
		}
	}

	/* Tell everyone about it */
	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c->db == cp->db && can_read(cp,note) && c != cp)
			{
				write_f(cp->conn_sock,"lllll",EVT_MODIFY_OBJECT,3 * sizeof(long),nid,pid,oid) ;
			}
			cp = cp->next ;
		}
	}

	return 0 ;
}

/* Adds a user to the database */
req_add_user(c)
	Connection c ;
{
	long aid ;
	if (read_f(c->conn_sock,"l",&aid) < 0)
	{
		return -1 ;
	}
	if (find_author_by_id(c->db,(int)aid) != NULL)
	{
		return 0 ;
	}
	if (sy_call_exec(c->db,"Add_Author","d",aid) < 0)
	{
		return 0 ;
	}
	add_author(c->db,(int)aid) ;
	return 0 ;
}

/* Write a debugging message from client */
req_debug(c)
	Connection c ;
{
	char buf[256] ;

	/* Read message */
	if (read_f(c->conn_sock,"s",buf,sizeof buf) < 0)
	{
		return -1 ;
	}

	printf("Somebody said '%s'\n",buf) ;
	write_f(c->conn_sock,"ll",EVT_DATA,0) ;
	return 0 ;
}

/* Deletes a page in a notebook */
req_delete_page(c)
	Connection c ;
{
	long nid,pid,del_links ;
	dbNotebook note ;
	dbPage page ;

	/* Read in notebook and page id and delete links flag */
	if (read_f(c->conn_sock,"lll",&nid,&pid,&del_links) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}

	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return 0 ;
	}

	/* Make sure the user is allowed to write to the notebook */
	if (!can_write(c,note))
	{
		return 0 ;
	}

	delete_page(c,note,page,del_links) ;

    {
        Connection cp = pc.cl.first ;

         /* Tell everyone that it was deleted */
         while(cp != NULL)
         {
             if (c->db == cp->db && can_read(cp,note) && c != cp)
             {
                 write_f(cp->conn_sock,"lllll",EVT_DELETE_PAGE,3 * sizeof(long),
					note->nid,page->pid,del_links) ;
             }
             cp = cp->next ;
         }
     }
	return 0 ;
}

/* Deletes a notebook */
req_delete_notebook(c)
	Connection c ;
{
	long nid ;
	dbNotebook note ;

	if (read_f(c->conn_sock,"l",&nid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}

	delete_notebook(c,note) ;
    {
        Connection cp = pc.cl.first ;

        /* Tell everyone that it was deleted */
        while(cp != NULL)
        {
            if (c->db == cp->db && can_read(cp,note) && c != cp)
            {
                write_f(cp->conn_sock,"lll",EVT_DELETE_NOTEBOOK,sizeof(long),note->nid) ;
            }
            cp = cp->next ;
        }
    }

	return 0 ;
}

/* Deletes an object */
req_delete_object(c)
	Connection c ;
{
	long nid ;
	long pid ;
	long oid ;
	dbNotebook note ;
	dbPage page ;
	dbObject object ;

	if (read_f(c->conn_sock,"lll",&nid,&pid,&oid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}

	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return 0 ;
	}

	object = find_object_by_id(page,(int)oid) ;
	if (object == NULL)
	{
		return 0 ;
	}

	delete_object(c,note,page,object) ;
    {
        Connection cp = pc.cl.first ;

        /* Tell everyone that it was deleted */
        while(cp != NULL)
        {
            if (c->db == cp->db && can_read(cp,note) && c != cp)
            {
                write_f(cp->conn_sock,"lllll",EVT_DELETE_OBJECT,3 * sizeof(long),note->nid,page->pid,object->oid) ;
            }
            cp = cp->next ;
        }
    }

	return 0 ;
}

/* kill the server */
req_kill(c)
	Connection c ;
{
	Connection cp = pc.cl.first ;
	while(cp != NULL)
	{
		close(cp->conn_sock) ;
		cp = cp->next ;
	}
	close(pc.listen_sock) ;
	sy_close() ;
	exit(0) ;
	return 0 ;
}

/* shutdown all clients connected to the server */
req_shutdown_clients(c)
	Connection c ;
{
	Connection cp = pc.cl.first ;
	long level = 0;

	/* broadcast the shutdown event to all clients */
	while(cp != NULL)
	{
		if (c != cp)
		{
			write_f(cp->conn_sock,"lll",EVT_SHUTDOWN,sizeof(long),level);
		}
		cp = cp->next ;
	}

	return 0 ;
}

req_allow_author(c)
	Connection c ;
{
	long aid ;
	long nid ;
	long access ;
	dbNotebook note ;
	dbAuthor author ;
	Access_List al ;
	long event ;

	if (read_f(c->conn_sock,"lll",&nid,&aid,&access) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}

	author = find_author_by_id(c->db,(int)aid) ;
	if (author == NULL)
	{
		return 0 ;
	}

    if (c->author != note->author)
	{
		return 0 ;
	}

	al = find_access(author,note) ;

	if (al == NULL)
	{

		/* Put author in access list */
		if (sy_call_exec(c->db,"Add_Access","ddd",nid,aid,access) < 0)
		{
			return 0 ;
		}
		add_access(note,author,(int)access) ;
		event = EVT_ACCESS_ALLOWED ;
	}

	else
	{
		/* Put author in access list */
		if (sy_call_exec(c->db,"Update_Access","ddd",nid,aid,access) < 0)
		{
			return 0 ;
		}
		al->access = access ;
		event = EVT_MODIFY_NOTEBOOK ;
	}

	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c != cp && cp->author == author)
			{
				write_f(cp->conn_sock,"lll",event,sizeof(long),nid) ;
			}
			cp = cp->next ;
		}
	}
	return 0 ;
}

req_disallow_author(c)
	Connection c ;
{
	long aid ;
	long nid ;
	dbNotebook note ;
	dbAuthor author ;

	if (read_f(c->conn_sock,"ll",&nid,&aid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return 0 ;
	}
	author = find_author_by_id(c->db,(int)aid) ;
	if (author == NULL)
	{
		return 0 ;
	}
    if (c->author != note->author)
	{
		return 0 ;
	}

	rmv_access(c->db,note,author) ;

	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c != cp && cp->author == author)
			{
				write_f(cp->conn_sock,"lll",EVT_ACCESS_DISALLOWED,sizeof(long),nid) ;
			}
			cp = cp->next ;
		}
	}

	return 0 ;
}

/* Set file data */
req_set_text(c)
	Connection c ;
{
	long nid ;
	long pid ;
	long oid ;
	long dat_len ;
	char dir_name[256] ;
	int fd ;
	char current_date[256] ;
	dbNotebook note ;
	dbPage page ;
	dbObject object ;

	/* Read in object identifier and data length */
	if (read_f(c->conn_sock,"llll",&nid,&pid,&oid,&dat_len) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -1 ;
	}

	page = find_page_by_id(note,(int)pid) ;
	if (note == NULL)
	{
		return -1 ;
	}

	object = find_object_by_id(page,(int)oid) ;
	if (object == NULL)
	{
		return -1 ;
	}

	if (object->type != TEXT_OBJECT_TYPE)
	{
		return -1 ;
	}

	/* Make sure the user is allowed to write to the notebook */
	if (!can_write(c,note))
	{
		return -1 ;
	}

	if (dat_len < 0)
	{
		return -1 ;
	}

	if (dat_len < 256)
	{
		char contents[256] ;
		get_object_fname(c->db,(int)nid,(int)pid,(int)oid,dir_name) ;
		if (must_read(c->conn_sock,contents,dat_len) != dat_len)
		{
			return -1 ;
		}
		contents[dat_len] = 0 ;
		if (object->data.text.contents == NULL)
		{
			unlink(dir_name) ;
		}
		change_str(&object->data.text.contents,contents) ;
        if (sy_call_exec(c->db,"Update_Txt_Contents","dddq",
                        note->nid,page->pid,object->oid,
                        object->data.text.contents) < 0)
        {
			return -1 ;
        }
	}
	else
	{
		if (object->data.text.contents != NULL)
		{
			rmv_string(object->data.text.contents) ;
			object->data.text.contents = NULL ;
			if (sy_call_exec(c->db,"Update_Txt_Contents","dddq",
				note->nid,page->pid,object->oid,
   	                     NULL) < 0)
			{
				return -1 ;
			}
		}

		/* Open the file */
		get_object_fname(c->db,(int)nid,(int)pid,(int)oid,dir_name) ;
		fd = open(dir_name,O_WRONLY | O_TRUNC | O_CREAT,0600) ;
		if (fd < 0)
		{
			return -1 ;
		}

		/* Read from client in chunks and write in chunks */
		while(dat_len)
		{
			static char buf[512] ;
			int bc = (dat_len > sizeof buf) ? sizeof buf : dat_len ;
	
			/* Read chunk */
			if (must_read(c->conn_sock,buf,bc) != bc)
			{
				close(fd) ;
				return -1 ;
			}

			/* Write chunk */
			if (write(fd,buf,bc) != bc)
			{
				close(fd) ;
				return -1 ;
			}

			dat_len -= bc ;
		}
		close(fd) ;
	}

	/* Update last write date on object */
	get_cur_date(current_date) ;
	if (sy_call_exec(c->db,"Update_Object_LW","dddq",nid,pid,oid,current_date) < 0)
	{
		return -1 ;
	}

	/* Tell everyone about it */
	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c->db == cp->db && can_read(cp,note) && c != cp)
			{
				write_f(cp->conn_sock,"lllll",EVT_OBJECT_CONTENTS_CHANGED,3 * sizeof(long),nid,pid,oid) ;
			}
			cp = cp->next ;
		}
	}

	return 0 ;
}

static
send_text(c,nid,pid,oid)
	Connection c ;
{
	char dir_name[256] ;
	int dat_len ;
	int fd ;

	get_object_fname(c->db,nid,pid,oid,dir_name) ;

	fd = open(dir_name,O_RDONLY) ;
	if (fd < 0)
	{
		if (write_f(c->conn_sock,"l",0) < 0)
		{
			return -1 ;
		}
		return 0 ;
	}

	/* find out how big it is */
	{
		struct stat st ;
		fstat(fd,&st) ;
		dat_len = st.st_size ;
	}

	/* Send back how big data is that is coming over */
	if (write_f(c->conn_sock,"l",dat_len) < 0)
	{
		close(fd) ;
		return -1 ;
	}

	/* Send over in chunks */
	while(dat_len)
	{
		static char buf[512] ;
		int bc = (dat_len > sizeof buf) ? sizeof buf : dat_len ;

		/* Read a chunk */
		if (read(fd,buf,bc) != bc)
		{
			close(fd) ;
			return -1 ;
		}

		/* Write  a chunk */
		if (must_write(c->conn_sock,buf,bc) != bc)
		{
			close(fd) ;
			return -1 ;
		}
		dat_len -= bc ;
	}
	close(fd) ;
	return 0 ;
}

static
send_img(c,nid,pid,oid)
	Connection c ;
{
	char dir_name[256] ;
	int fd ;

	get_object_fname(c->db,nid,pid,oid,dir_name) ;

	fd = open(dir_name,O_RDONLY) ;
	if (fd < 0)
	{
		return -1 ;
	}

	if (read_rast_img_fd(fd,c->conn_sock) < 0)
	{
		close(fd) ;
		return -1 ;
	}

	close(fd) ;

	return 0 ;
}

/* Retreive file data */
req_get_text(c)
	Connection c ;
{
	long nid ;
	long pid ;
	long oid ;
	dbNotebook note ;
	dbPage page ;
	dbObject object ;

	/* Read in object identifier */
	if (read_f(c->conn_sock,"lll",&nid,&pid,&oid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}

	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return -2 ;
	}

	object = find_object_by_id(page,(int)oid) ;
	if (object == NULL)
	{
		return -2 ;
	}

	if (object->type != TEXT_OBJECT_TYPE)
	{
		return -2 ;
	}

	/* Make sure he can read the notebook */
	if (!can_read(c,note))
	{
		return -2 ;
	}

	if (write_f(c->conn_sock,"l",EVT_DATA) < 0)
	{
		return -1 ;
	}

	if (object->data.text.contents == NULL)
	{
		if (send_text(c,(int)nid,(int)pid,(int)oid) < 0)
		{
			return -1 ;
		}
	}
	else
	{
		if (write_f(c->conn_sock,"s",object->data.text.contents) < 0)
		{
			return -1 ;
		}
	}
	return 0 ;
}

req_get_image(c)
	Connection c ;
{
	long nid ;
	long pid ;
	long oid ;
	dbNotebook note ;

	/* Read in object identifier */
	if (read_f(c->conn_sock,"lll",&nid,&pid,&oid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}

	/* Make sure he can read the notebook */
	if (!can_read(c,note))
	{
		return -2 ;
	}

	if (write_f(c->conn_sock,"l",EVT_DATA) < 0)
	{
		return -1 ;
	}

	if (send_img(c,(int)nid,(int)pid,(int)oid) < 0)
	{
		return -1 ;
	}
	return 0 ;
}

req_set_image(c)
	Connection c ;
{
	long nid ;
	long pid ;
	long oid ;
	char dir_name[256] ;
	char current_date[256] ;
	dbNotebook note ;
	int fd ;

	/* Read in object identifier and data length */
	if (read_f(c->conn_sock,"lll",&nid,&pid,&oid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -1 ;
	}

	/* Make sure the user is allowed to write to the notebook */
	if (!can_write(c,note))
	{
		return -1 ;
	}

	/* Open the file */
	get_object_fname(c->db,(int)nid,(int)pid,(int)oid,dir_name) ;
	fd = open(dir_name,O_WRONLY | O_TRUNC | O_CREAT,0600) ;
	if (fd < 0)
	{
		return -1 ;
	}

	if (write_rast_img_fd(fd,c->conn_sock) < 0)
	{
		close(fd) ;
		return -1 ;
	}
	close(fd) ;

	/* Update last write date on object */
	get_cur_date(current_date) ;
	if (sy_call_exec(c->db,"Update_Object_LW","dddq",nid,pid,oid,current_date) < 0)
	{
		return -1 ;
	}

	/* Tell everyone about it */
	{
		Connection cp = pc.cl.first ;
		while(cp != NULL)
		{
			if (c->db == cp->db && can_read(cp,note) && c != cp)
			{
				write_f(cp->conn_sock,"lllll",EVT_OBJECT_CONTENTS_CHANGED,3 * sizeof(long),nid,pid,oid) ;
			}
			cp = cp->next ;
		}
	}

	return 0 ;
}

req_get_author_access(c)
	Connection c ;
{
	long nid ;
	dbNotebook note ;
	dbAuthor authors = c->db->authors ;
	int num_authors = 0 ;

	if (read_f(c->conn_sock,"l",&nid) < 0)
	{
		return -1 ;
	}
	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	while(authors != NULL)
	{
		num_authors++ ;
		authors = authors->next ;
	}
	authors = c->db->authors ;
	if (write_f(c->conn_sock,"ll",EVT_DATA,num_authors) < 0)
	{
		return -1 ;
	}
	while(authors != NULL)
	{
		Access_List al = find_access(authors,note) ;
		int access ;
		if (al == NULL)
		{
			access = 0 ;
		}
		else
		{
			access = al->access + 1 ;
		}
		if (write_f(c->conn_sock,"ll",authors->aid,access) < 0)
		{
			return -1 ;
		}
		authors = authors->next ;
	}
	return 0 ;
}

req_blurt_note(c)
	Connection c ;
{
	dbNotebook note = c->db->notebooks ;
	int count = 0;

	while(note != NULL)
	{
		if (c->author == note->author || can_read(c,note))
		{
			++count;
		}
		note = note->next ;
	}

	/* return the number of notebooks */
	if (write_f(c->conn_sock,"ll",EVT_DATA,count) < 0)
	{
		return -1 ;
	}

	/* send info for each page */
	note = c->db->notebooks;
	while(note != NULL)
	{
		if (c->author == note->author || can_read(c,note))
		{
			Access_List al = find_access(c->author,note) ;
			int access;
			if (al == NULL)
			{
				if (c->author == note->author)
				{
					access = 0 ;
				}
				else
				{
					return -2 ;
				}
			}
			else
			{
				access = (al->access == 1) ? 2 : 1;
			}

			/* Send it out */
			if (write_f(c->conn_sock,"lslll",note->nid,note->title,
				access,note->author->aid,note->home_page) < 0)
			{
				return -1 ;
			}
		}
		note = note->next ;
	}
	return 0;
}

req_blurt_page(c)
	Connection c ;
{
	long nid ;
	long pid ;
	dbNotebook note ;
	dbPage page ;
	int num_objects ;
	if (read_f(c->conn_sock,"ll",&nid,&pid) < 0)
	{
		return -1 ;
	}

	note = find_note_by_id(c->db,(int)nid) ;
	if (note == NULL)
	{
		return -2 ;
	}
	page = find_page_by_id(note,(int)pid) ;
	if (page == NULL)
	{
		return -2 ;
	}
	if (!can_read(c,note))
	{
		return -2 ;
	}

	num_objects = 0 ;

	{
		dbObject o = page->objects ;
		while(o != NULL)
		{
			num_objects++ ;
			o = o->next ;
		}
	}

	/* Send it out */
	if (write_f(c->conn_sock,"lsllssll",EVT_DATA,page->title,page->width,page->height,page->color,page->create_date,num_objects,page->author->aid) < 0)
	{
		return -1 ;
	}

	{
		dbObject object = page->objects ;
		while(object != NULL)
		{
			if (write_f(c->conn_sock,"lllllll",object->oid,
					object->x,object->y,object->width,object->height,object->type,object->author->aid) < 0)
			{
				return -1 ;
			}

			/* Get object specific informations */
			switch(object->type)
			{
				case IMAGE_OBJECT_TYPE :
					if (write_f(c->conn_sock,"ll",
						object->data.image.create_colormap,object->data.image.low_res_sw) < 0)
					{
						return -1 ;
					}
					if (send_img(c,note->nid,page->pid,object->oid) < 0)
					{
						return -1 ;
					}
					break ;
				case TEXT_OBJECT_TYPE :
					if (write_f(c->conn_sock,"ss",object->data.text.font,object->data.text.color) < 0)
					{
						return -1 ;
					}
					if (object->data.text.contents == NULL)
					{
						if (send_text(c,note->nid,page->pid,object->oid) < 0)
						{
							return -1 ;
						}
					}
					else
					{
						if (write_f(c->conn_sock,"s",object->data.text.contents) < 0)
						{
							return -1 ;
						}
					}
					break ;
				case LINK_OBJECT_TYPE :
					{
						int lnk_nid = -1;
						int lnk_pid = -1;
						if (object->data.link.dest_note != (dbNotebook)NULL)
						{
							lnk_nid = object->data.link.dest_note->nid;
						}
						if (object->data.link.dest_page != (dbPage)NULL)
						{
							lnk_pid = object->data.link.dest_page->pid;
						}
						if (write_f(c->conn_sock,"llsss",lnk_nid,lnk_pid,
							object->data.link.title,
							object->data.link.font,
							object->data.link.color) < 0)
						{
							return -1 ;
						}
					}
					break ;
				case ACTION_LINK_OBJECT_TYPE :
					if (write_f(c->conn_sock,"ssss",object->data.action_link.command,object->data.action_link.title,object->data.action_link.font,object->data.action_link.color) < 0)
					{
						return -1 ;
					}
					break ;
			}
			object = object->next ;
		}
	}

	return 0 ;
}
