/*
 * $Source: $
 * $Revision: $
 * $Date: $
 * $State: $
 * $Author: $
 *
 *
 * $Log: $
 * Revision 3.1  3/10/92 wade
 * Added Baylor's changes
 * cmd_read_gif_file()
 * allow creation/modification of image node type
 *
 * Modified 04/28/92 - mec
 * replaced SetPort(&oldPort) with SetPort(oldPort) (oops)
 *
 * Modified 05/12/92 - mec
 * started changes to allow both network and file reading, also monochrome mods
 *
 * Modified 06/9/92 - mec
 * file reading & writing as well as monochrome mods rolled into 3.2 code
 */
/*  
 *	Copyright (c) 1991 by the Massachusetts Institute of Technology,
 *	For copying and distribution information, see the file
 *	"mit-copyright.h".
 *
 * 	commandMgr.c  - WADE 8/31/89
 *	
 *	cmd_show
 *	cmd_new_display
 *	cmd_send_message
 *	cmd_find
 *	cmd_show_parent
 *	cmd_main_menu
 *	cmd_back
 *	cmd_unlink_child
 *	cmd_authorize
 *	cmd_list_window
 *	cmd_text_window
 *	cmd_save_text
 *	cmd_open_document
 *	cmd_select_word
 *	cmd_path
 *	cmd_link_child
 *	cmd_publish_document
 *	cmd_define_item
 *	cmd_modify_item
 *  cmd_phone;
 */
 
#include <Limits.h>
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Events.h>
#include <Controls.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Desk.h>
#include <Scrap.h>
#include <ToolUtils.h>
#include <Memory.h>
#include <SegLoad.h>
#include <Files.h>
#include <OSUtils.h>
#include <Traps.h>
#include <string.h>
#include "pips.h" 
#include "prototype.h"
#include <stdio.h>
#include <resources.h>
#include "mit-copyright.h"
#include "documentRec.h"

static Boolean	first_time = true;	/* 	don't draw the list the very first time we create it as
										the activate event from main() will do this */
extern char			gMessage[];
extern Handle 		gTextStr;
extern int			gListSize;
extern WindowPtr	gListWindow;
extern WindowPtr	gTextWindow;
extern Boolean		gProvider;

enum{find_tr1,below_tr,path_tr,text_tr,add_subj_tr,modify_subj_tr,add_doc_tr,modify_doc_tr,
	link_child_tr,unlink_child_tr,file_tr,authorize_tr,keyword_tr,content_tr,
	version_browser_tr,version_provider_tr,close_provider_tr,remove_tr,
	reorder_above_tr,reorder_below_tr,quit_tr,move_tr,show_tr,servers_tr,
	source_read_info_tr, source_write_info_tr,find_tr2,source_read_info_tr2,gif_tr};

/* global variables */
char	node_id[6];
char	parent_id[6];
char	menu_id[6];
char	type[2];
Str255	dates;
Str255	topic;
Str255	title;
Str255	source;
Str255	locker;
Str255	path;
Str255	username;
Str255	password;
Str255	find_str;
Str255	phone_str;
Str255	meta;
Str255	filename;
char	link_id[6] = {NULL};
int		netseek;
int		netstop;
char	depth[6];
int		document_flag;
long	gif_offset;
						 
void	compose_transaction(int	type );

/*     
 *
 * cmd_new_display:
 * 
 *
 */
Boolean
cmd_new_display( commandStr, sendType, replyType )
char 	*commandStr;
int		 sendType;
int		 replyType;
{	
	int				badRecords;
	int				listSize;
	int				temp_size;
	int				rc;
	Str255			badRecordsStr;
	Str255			title;
	Str255			list_string;
	Str255			banner;
	Str255			node;
	short			cell;
	int				command_length;
	Boolean			owner;
	int				text_size;
	Str255			partial="*** THIS DOCUMENT CONTAINS MULTIPLE SECTIONS ***\n";
	extern Boolean	gDebug;
					
	/* retrieve list/text information */
	command_length = strlen(commandStr);
	
	/* make sure that we have a visible text window */
	if (replyType == text)
		text_show_new_text(gTextWindow);
		
	switch(sendType) {
		case command:  /* send command to the server */
			rc = net_talk( commandStr, command_length, gDebug, sendType, replyType, &listSize, &badRecords);
			break;
		case local:		/* the menu was filled out by the application, not from server */
			rc = 0; 	/* initialize some variables */
			data_local_menu_size(retrieve,&listSize);
			badRecords = 0;
			break;
	}
	
	if ( rc == 0 ) {
		if ( listSize == 0 ) 
			return false;
		else {
			switch ( replyType ) {
				case list:
					/* do we have a menu created from a below,content,main ... transaction? */
					/* ie. excluded menu items formed from an index transaction */
					owner = (*commandStr == 'w' && *(commandStr+2) == '2');

					listSize--;					    /* use cell range [0:n] */
										
					/* if the last command was a "path" w:1: command, then change the indent level */
					if ((!owner) && (*(commandStr+2) == '1'))
						for(cell=0; cell <= listSize; cell++) {
							rc = list_get_buffer(list_string,cell);
							if (rc) {
								list_string[0] = list_string[0] + 1;
								list_Replace( list_string, strlen(list_string), cell);
							}
						}

					if (owner) {
						cell = 0;
						rc = list_get_buffer(list_string,cell);
						if (rc) rc = get_field(list_string,TITLE,title);
						if (rc) {
							sprintf(banner,"%s  (%d items)",title,listSize);
							c2pstr(banner);				/* set window title */
							SetWTitle( gListWindow,banner );	
						}
					
						/* save the nodeid for this menu */
						rc = get_field(list_string,NODE,node);
						if (rc) 
							data_current_nodeid(store,node);
					}
					else {
						temp_size = listSize + 1;
						/* set banner title for path command */
						if (*commandStr == 'w' && *(commandStr+2) == '1')
							sprintf(banner,"Path result (%d items)",temp_size);
						else 
							switch(*commandStr) {
								case 'b':  /* find command */
									/* get the second token of the command string, e.g. b:hello */
									rc = get_field(commandStr,2,find_str);
									sprintf(banner,"Keyword '%s' (%d items)",find_str,temp_size);
									break;
								case 'm':	/* other servers command */
									sprintf(banner,"World Wide TechInfo Systems (%d items)",temp_size);
									break;
								default:
									sprintf(banner,"huh?");
									break;
							}
								
						c2pstr(banner);				/* set window title */
						SetWTitle( gListWindow,banner );
					}
					
					list_unselect();					/* no cells should be highlighted */
		 			list_Configure( listSize,owner );	/* change old list size */
					if ( first_time )			    	/* draw list window     */
		 				InvalRect( &gListWindow -> portRect );  
					else 
						first_time = false;
					
						
					list_vscroll();
													/* list window must be the active window */
					if ( FrontWindow() != gListWindow ) {
						SelectWindow( gListWindow );
						SetPort(gListWindow);
						InvalRect( &gListWindow -> portRect );
						ShowWindow(gListWindow);
					}
					
					if ( badRecords > 0 ) {
						sprintf(badRecordsStr,"%d items are not shown.",badRecords);
						OpenAlertDialog(LIST_TRUNCATED,badRecordsStr);
					}

					break;
					
				case text:
					data_text_size(retrieve,&text_size);
					if ( (netseek > 0 ) || ( text_size > NETWORK_RECEIVE_SIZE) )
						rc = text_bind( partial );
					
					text_draw();								/* draw text window  */
					
					break;
					
				case message:
					break;
					
				case gif:
					/* the view stuff is done in the GIFtoPICT() */
					/* we use this cmd_new_display to talk to the network */
					break;
			}
							
			return true;
		}
	}

}	/* cmd_new_display */

/*     
 *
 * 	cmd_send_message:
 * 
 *	Send a commandStr or text stream and receive a reply in the global message variable.
 *	The reply is used as an acknowledgement and should be evaluated by the calling routine.
 *
 */
Boolean
cmd_send_message( commandStr )
char 	*commandStr;
{	
	int				badRecords;
	int				listSize;
	int				rc;
	int				command_length;

	extern Boolean	gDebug; 
	
	/* send commandStr/text and receive a message reply */
	command_length = strlen(commandStr);
	rc = net_talk( commandStr, command_length, gDebug, command, message, &listSize, &badRecords);
	
	/* if the networking stuff worked, zero return code, then return a true code */
	if ( rc == 0 ) 
		return true;
	else
		return false;

}	/* cmd_send_message */

/*     
 *
 * 	cmd_send_text:
 * 
 */
Boolean
cmd_send_text( text_handle, text_length )
char	*text_handle;
int		text_length;
{	
	int				badRecords;
	int				listSize;
	int				rc;
	
	rc = net_talk( text_handle, text_length, gDebug, text, message, &listSize, &badRecords);
	
	/* if the networking stuff worked, then send a false return code */
	if ( rc == 0 ) 
		return false;
	else
		return true;

}	/* cmd_send_text */

/*     
 *
 * cmd_find:
 * 
 *
 */
void
cmd_find()
{
	Boolean 		find;
	Boolean			rc;
	Boolean			search_from_current_menu;
	Str255			window_title;
	
	find = dlog_keyword( find_str, &search_from_current_menu );	   /* get user's input          */
	if ( find ) {
		if (search_from_current_menu) {
			data_current_nodeid(retrieve,node_id);
			/* if we are at the root node, for efficiency, force find_tr1 */
			if (!strcmp(node_id,"0"))
				compose_transaction(find_tr1);
			else
				compose_transaction(find_tr2);
		}
		else
			compose_transaction(find_tr1);;  /* start search from the root node */

		rc = cmd_new_display( meta, command, list ); 
		if (rc) {
			sprintf(window_title,"Search: %s",find_str);
			util_push_stack(meta,window_title);
		}
		else
			OpenAlertDialog(NO_TOPIC,find_str);
	}
}

/*     
 *
 * cmd_phone:
 * 
 *
 */
void
cmd_phone(alias)
char *alias;
{
	Boolean			action = 0;
	int				listSize;
	Str255			banner;
	char			request[255];
	
	/* use alias if it was passed as an argument */
	if (alias != NULL) {
		// mec - fix for our nameserver, assumes that the alias is indeed that.
		// and prepends "alias=" to the string
		sprintf(request, "alias=%s", alias);
		listSize = do_phone(request);
	} else {
		action = dlog_phone( phone_str );	   /* get user's input          */
		if (!action)
			return;  /* user hit the cancel button */
		listSize = do_phone(phone_str);
	}
					
	switch(listSize) {
		case 0: /* no list; must be for the text window */
			text_draw();
			sprintf(banner,"Directory: %s",alias ? alias : phone_str,listSize);
			c2pstr(banner);				/* set window title */
			SetWTitle( gTextWindow,banner );	
			break;
			
		case -1: /* must have been a network error */
			break;
			
		default: /* must be a list */
			listSize--;					    	/* use cell range [0:n] */
								
			list_unselect();					/* no cells should be highlighted */
			list_Configure( listSize,0);		/* change old list size */
			if ( first_time )			    	/* draw list window     */
				InvalRect( &gListWindow -> portRect );  
			else 
				first_time = false;
				
			list_vscroll();
				
			/* list window must be the active window */
			if ( FrontWindow() != gListWindow ) {
				SelectWindow( gListWindow );
				SetPort(gListWindow);
				InvalRect( &gListWindow -> portRect );
				ShowWindow(gListWindow);
			}
			
			/* increment listSize as range should be [1:n] and not [0:n] */
			sprintf(banner,"%s  (%d items)", alias ? alias : phone_str,++listSize);
			c2pstr(banner);				/* set window title */
			SetWTitle( gListWindow,banner );	

			break;
	}
}

/*     
 *
 * cmd_path:
 * 
 * this does a "w:1:node-id:99" transaction.
 */
void
cmd_path()
{
	Str255	list_buffer;
	Boolean	rc;
	Str255	window_title;
	
	rc = list_last_click_buffer(list_buffer);
	if (rc) rc = get_field(list_buffer,NODE,node_id);
	if (rc) rc = get_field(list_buffer,TITLE,title);
	 
	if ( rc ) {
		compose_transaction(path_tr);
		rc = cmd_new_display( meta, command, list );
		
		/* add to command stack */
		if (rc) {
			sprintf(window_title,"Path: %s",title);
			util_push_stack(meta,window_title);
		}
	}
}

/*     
 *
 * cmd_back:
 * 
 *
 */
void
cmd_back()
{
	int		rc;
	
	rc = util_pop_stack(meta);
	
	if ( rc )
		rc = cmd_new_display( meta, command, list );
}

Boolean
cmd_main_menu()
{
	int		rc;
	Str255	last_command;
	Str255	text_title;
	
	strcpy(node_id,"0");						/* starting node has a value of zero */
	compose_transaction(below_tr);				/* create meta/transaction string */
	rc = cmd_new_display( meta, command, list );
	if (rc) {
		/* we never want the main menu to be on the stack consecutively */
		rc = util_query_stack(last_command);
		if (strcmp(meta,last_command)) {
			compose_transaction(show_tr);
			rc = cmd_send_message(meta);
			if (rc) {
				rc = get_field(gMessage,S_TITLE,text_title);
				compose_transaction(below_tr);  /* store the right transaction */
				util_push_stack(meta,text_title);  
			}
		}
	}
	
	return rc;
}

Boolean
cmd_startup()
{
	int		rc;
	char	startup[255];
	char	startup_node_id[6];
	short	ctr,end;
	
	pref_get_string(STARTUP_ID, startup);		/* get starting nodeid               */
	
	/* this version only supports a maximum of two windows - a menu and a text,
		however, this design should scale to more than two startup windows. 
		the "protocol" for this resource is n:node-id:node-id:...etc, where
		n is the number of node-id's and each field is colon seperated */
	for (end=atoi(startup),ctr=1; ctr <= end; ctr++) {
		rc = get_field(startup,ctr+1,startup_node_id);
		if (rc && strlen(startup_node_id) > 0) 
			rc = cmd_show(startup_node_id);
	}
	
	return rc;
}

/*     
 *
 * cmd_show:
 * 
 *
 * we got here from 
 *	DoContent() - user double clicked on a list item.
 *	menu_do_command() - user selected show from pull down menu
 *	cmd_startup() - called at start of program 
 *  DoKeyDown() - user hit the enter key for a selected list item
 *
 */
Boolean
cmd_show(mystartup)
char	*mystartup;
{
	Str255	list_string;
	Boolean	rc;
	short	zero = 0;
	Str255	title;
	Str255	sections;
	int		text_size;
	Str255	host;
	Str255	port;
	
	/* just to be on the safe side */
	*title = NULL;
	*node_id = NULL;
	
	/* get information from the hilighted list item */
	if (mystartup == NULL) {
		rc = list_last_click_buffer(list_string);
		if (rc) rc = get_field(list_string,NODE,node_id);
		if (rc) rc = get_field(list_string,TYPE,type);
		if (rc) rc = get_field(list_string,TITLE,title);
	}
	else {
		/* get information from the resource file */
		strcpy(node_id,mystartup);
		
		/* determine if startup node id is a list or a document */
		compose_transaction(show_tr);
		rc = cmd_send_message(meta);
		
		/* make sure that the node exists in the web/database */
		/* this is a bit klugie, but .... */
		if (rc) rc = get_field(gMessage,S_TITLE,title);
		if (strncmp(title,"<title>",7)) {
			if (rc) rc = get_field(gMessage,S_TYPE,type);
		}
		else {
			/* we can not find the node in the web/database */
			/* force it to the main menu                    */
			OpenAlertDialog(UNKNOWN_NODEID,node_id);
			strcpy(node_id,"0");
			strcpy(type,"s");
		}
	}
	
	if ( rc ) {
		switch (type[0]) {
			case TEXT_ITEM:  	/* show a text document */
				netseek = 0;
				netstop = NETWORK_RECEIVE_SIZE;
				
				/* set the window title */
				c2pstr(title);				
				SetWTitle( gTextWindow,title );
				
				compose_transaction(text_tr);
				rc = cmd_new_display( meta, command, text );
				if (rc) {
					data_text_nodeid(store,node_id);
					data_text_active(store,&zero);
					
					/* do we have multiple sections? */
					data_text_size(retrieve,&text_size);
					if ( text_size > NETWORK_RECEIVE_SIZE) {
					
						/* change window title to reflect multiple sections */
						title[title[0]+1] = ':';
						title[0] = title[0] + 2;
						title[title[0]] = '1';
						SetWTitle(gTextWindow,title);

						sprintf(sections,
							"This document contains %d sections.",(text_size / NETWORK_RECEIVE_SIZE) + 1);
						OpenAlertDialog(OPEN_WARNING,sections);
					}

				}
				
				break;
				
			case MENU_ITEM:	/* show a subject item, ie. do below one level */
				compose_transaction(below_tr);
				rc = cmd_new_display( meta, command, list );
				if (rc)
					util_push_stack(meta,title);
				break;
				
			case PHONE_ITEM: /* phone record */
				rc = get_field(list_string,SOURCE,source);	/* this is the unique alias field */
				cmd_phone(source);
				break;
				
			case SERVER_ITEM:
				rc = get_field(list_string,TI_HOST_NAME,host);	/* this is the host name field */
				rc = get_field(list_string,TI_PORT,port);		/* this is the port field */
				cmd_change_server(host,port);
				break;
				
			case IMAGE_ITEM:
				/* store the node id that we are working on */
				rc = gif_net_data(gif_init);
				
				/* retrieve and display the gif image */
				if (rc) cmd_read_gif_file(false); 		// not from a file
				
				/* clean up after ourselfs */
				rc = gif_net_data(gif_close);
				break;
				
			/* otherwise don't do anything */
		}
		
	}
	
	return rc;
}

/*     
 *
 * cmd_content:
 * 
 *
 * we got here from DoContent - user double clicked on a list item.
 *
 */
void
cmd_content()
{
	Str255	list_string;
	Boolean	rc;

	rc = list_last_click_buffer(list_string);
	if (rc) rc = get_field(list_string,NODE,node_id);
	if (rc) rc = get_field(list_string,TYPE,type);
	if (rc) rc = get_field(list_string,TITLE,title);
	
	if (rc && *type == 's' ) {
		pref_get_string(OUTLINE_DEPTH, depth);
		compose_transaction(content_tr);
		rc = cmd_new_display( meta, command, list );
		if (rc)
			util_push_stack(meta,title);
	}
}

/*     
 *
 * cmd_send:
 * 
 *
 */
void
cmd_send()
{
	Boolean 		send;
	char			sendStr[80];
	Boolean			rc;
	
	send = SendDialog( sendStr );	   /* get user's input          */
	if ( send ) {
		rc = cmd_new_display( sendStr, command, text ); 
	}
}

/*     
 *
 * cmd_link_child:
 * 
 *
 */
void
cmd_link_child(child_node)
char	*child_node;
{
	Boolean		we_are_ok;
	Boolean		rc;
	Str255		list_buffer;
	Str255		parent_list;
	Str255		message;
	
	/* 	if the parameter (child_node) does not have a node value, then we must
		try to obtain this from the last list item the user clicked on.  We also need
		to obtain the saved parent id.  If the child_node contains a value, then link this
		to the current menu in the list window. */
	we_are_ok = false;
	if ( strlen(child_node) == 0 ) {
		rc = list_last_click_buffer(list_buffer);
		if (rc) {
			rc = get_field(list_buffer,NODE,node_id);
		
			/* get the parent node to link a item to */
			if (rc) rc = data_parent(retrieve,parent_list);
			if (rc) {
				rc = get_field(parent_list,NODE,parent_id);
	
				/* 	the child node must not be equal to the parent node, 
				if this the case, then we should give an error message */
				if ( ( rc ) && (strcmp(node_id,parent_id) != 0 ))
					we_are_ok = true;
			}
		}
	}
	else {
		strcpy( node_id, child_node );
		we_are_ok = true;
	}
	
	/* check to see if we have a parent node set */
	/* this could have been set in the add_subject or add_document function */
	if (parent_id[0] == '\0')
		we_are_ok = false;
		
	/* let's do the link */
	if  ( we_are_ok ) {
		/* create link  */
		compose_transaction(link_child_tr);
		rc = cmd_send_message( meta );
		if (rc) {
			rc = atoi(gMessage);
			if (rc) {
				rc = get_field(gMessage,MSGTEXT,message);
				OpenAlertDialog(BAD_PROVIDER,message);
			}
		}
	}
	
	return;
}	/* cmd_link_child */

/*     
 *
 * cmd_link_child_edit:
 * 
 * this version is called from the edit and may eventually replace the
 * cmd_link_child version.
 */
void
cmd_link_child_edit()
{
	Boolean		rc;
	Str255		list_buffer;
	Str255		message;
	data_edit	undo_flags;
		
	rc = list_last_click_buffer(list_buffer);
	if (rc) {
		/* get last node that was cut or copied */
		data_edits(retrieve,&undo_flags);
		
		/* make sure we have everything correct */
		if ((undo_flags.type == edit_copy || undo_flags.type == edit_cut) &&
			*undo_flags.node_b) {
			strcpy(node_id,undo_flags.node_b); 
			rc = true;
		}
		else
			rc = false;

		if (rc) rc = get_field(list_buffer,NODE,parent_id);
	
		/* create link  */
		if (rc) compose_transaction(link_child_tr);
		if (rc) rc = cmd_send_message( meta );
		if (rc) {
			rc = atoi(gMessage);
			if (rc) {
				rc = get_field(gMessage,MSGTEXT,message);
				OpenAlertDialog(BAD_PROVIDER,message);
			}
			else {
				/* set Undo Edit menu stuff */
				bzero(&undo_flags,sizeof(undo_flags));
				undo_flags.type = edit_paste;
				data_edits(store,&undo_flags);
			}
		}
	}
	
	return;
}	/* cmd_link_child_edit */
/*     
 *
 * cmd_copy_edit:
 * 
 * this version is called from the edit and saves the selected cell nodeid for
 * use in a paste function.
 */
void
cmd_copy_edit()
{
	Boolean		rc;
	Str255		list_buffer;
	data_edit	undo_flags;
	
	rc = list_last_click_buffer(list_buffer);
	if (rc) {
		rc = get_field(list_buffer,NODE,node_id);

		if (rc) {
			/* set Undo Edit menu stuff */
			bzero(&undo_flags,sizeof(undo_flags));
			undo_flags.type = edit_copy;
			strcpy(undo_flags.node_b,node_id);   /* this is node copied   */
			data_edits(store,&undo_flags);
		}
	}
	
	return;
}	/* cmd_copy_edit */

/*     
 *
 * cmd_unlink_child:
 * 
 *
 */
void
cmd_unlink_child()
{
	Boolean		rc;
	Str255		list_buffer;
	Str255		message;
	data_edit	undo_flags;
	short		item;
		
	/* get current menu id - beware of the outline menu display */
	list_get_list_select(&item);  /* get currently selected item */
	do_find_menu_id(parent_id,false,item,true);
	
	rc = list_last_click_buffer(list_buffer);
	if (rc) rc = get_field(list_buffer,NODE,node_id);
	
	if  (rc) {
		compose_transaction(unlink_child_tr);
		rc = cmd_send_message( meta );
	
		if (rc) {
			rc = atoi(gMessage);
			if (rc) {
				rc = get_field(gMessage,MSGTEXT,message);
				OpenAlertDialog(BAD_PROVIDER,message);
			}
			else {
				/* it must have worked as rc is nil, save info for edits */

				/* set Undo Edit menu stuff */
				bzero(&undo_flags,sizeof(undo_flags));
				undo_flags.type = edit_cut;
				strcpy(undo_flags.node_a,parent_id); /* this is working menu  */
				strcpy(undo_flags.node_b,node_id);   /* this is cell unlinked */
				data_edits(store,&undo_flags);
			}
			
			/* redisplay the menu */
			rc = util_query_stack(meta);
			if (rc) rc = cmd_new_display( meta, command, list );
		}
	}
	return;
}	/* cmd_unlink_child */

/*     
 *
 * cmd_unlink_child_edit:
 * 
 *
 */
void
cmd_unlink_child_edit()
{
	Boolean		rc;
	Str255		message;
	data_edit	undo_flags;
		
	/* get information needed to remove a paste */
	data_edits(retrieve,&undo_flags);

	/* get current menu id where node is to be removed*/
	strcpy(parent_id,undo_flags.node_a);
	
	/* get node to remove */
	strcpy(node_id,undo_flags.node_b);
	
	compose_transaction(unlink_child_tr);
	rc = cmd_send_message( meta );
	
	if (rc) {
		rc = atoi(gMessage);
		if (rc) {
			rc = get_field(gMessage,MSGTEXT,message);
			OpenAlertDialog(BAD_PROVIDER,message);
		}
		else {
			/* it must have worked as rc is nil, save info for edits */

			/* set Undo Edit menu stuff */
			bzero(&undo_flags,sizeof(undo_flags));
			undo_flags.type = edit_cut;
			strcpy(undo_flags.node_a,parent_id); /* this is working menu  */
			strcpy(undo_flags.node_b,node_id);   /* this is cell unlinked */
			data_edits(store,&undo_flags);
		}
		
		/* redisplay the menu */
		rc = util_query_stack(meta);
		if (rc) rc = cmd_new_display( meta, command, list );
	}
	
	return;
}	/* cmd_unlink_child_edit */

/*     
 *
 * cmd_publish_document:
 * 
 *
 */
void
cmd_publish_document( add_doc_node_id )
char *add_doc_node_id;
{
	Boolean		rc,good=true;
	Str255		list_buffer;
	int			text_length;
	char		*text_ptr;
	Str255		message;
	short		cleared;
			
	/* get node_id if we don't have it */
	if ( strlen(add_doc_node_id) == 0 ) {
		/* first, confirm that the user has highlighted the correct list item */
		rc = list_last_click_buffer(list_buffer);
		if (rc) rc = get_field(list_buffer,TITLE,title);
		if (rc) good = dlog_replace(title);
		
		if (good && rc) {
			rc = list_last_click_buffer(list_buffer);
			if (rc) rc = get_field(list_buffer,NODE,node_id);
		}
	}
	else
		strcpy(node_id,add_doc_node_id);
	
	/* keep going if we have a valid node id */
	if  (good && strlen(node_id) > 0) {
		/* send file transaction */
		compose_transaction(file_tr);
		rc = cmd_send_message( meta );
		
		if ( rc ) {
			rc = atoi(gMessage);
			if ( rc ) {
				rc = get_field(gMessage,MSGTEXT,message);
				OpenAlertDialog(PUBLISH_ERROR,message);
			}
			else {
		
				/* change soft returns to hard returns, make sure the document ends with a CR */
				text_soft_breaks(gTextWindow);
		
				HLock(gTextStr);

				/* we need to copy the text buffer into a temporary one as netowrkMgr makes changes it */
				text_get_buffer();
	 			text_length = text_get_length(gTextWindow);
			
				/* don't send the first line of text if it is the document status line */
				/* This document was last modified on Tue Jun  5 08:34:49 1990         */
				/* 123456789012345678901234567890123456789012345678901234567890        */

				if (strncmp(*gTextStr,"This document was last modified",31) == 0) {
			   		text_ptr = *gTextStr + 61;
					text_length = text_length - 61;
				}
				else
			   		text_ptr = *gTextStr;
					
				/* replace 8-bit ascii characters */
				cleared = clear_hibit(text_ptr,text_length);
				
				rc = cmd_send_text( text_ptr, text_length );
				HUnlock(gTextStr);
			
				if (rc) {
					rc = atoi(gMessage);
					if (rc) {
						rc = get_field(gMessage,MSGTEXT,message);
						OpenAlertDialog(PUBLISH_ERROR,message);
					}
				}
			}
		}
	}
}

/*     
 *
 * cmd_open_document:
 * 
 *
 */
cmd_open_document()
{
	Boolean 	rc;
	short		vRefNum;
	short		refNum;
	char		name[63];
	OSErr		file_rc;
	long		count;
	char		rc_string[35];
	long		logEOF; 
	int			readLimit = kMaxTELength;
	int			zero = 0;
	short		zeros = 0;
	char		*temp_ptr;
	TEHandle	tehandle;
	
	rc = dlog_get_file(&vRefNum,name);
	
	/* a true return code results when the user tries to open a file vs. the cancel button */
	if ( rc ) {
		
		file_rc = FSOpen(name,vRefNum,&refNum);
		
		/* check for file errors */
		if (file_rc != 0 ) {
			switch(file_rc) {
				case -49:  /* we know what this is */
					OpenAlertDialog(ALREADY_OPEN,"");
					break;
				default:
					sprintf(rc_string,"Return Code: %d",file_rc);
					OpenAlertDialog(FILE_ERROR,rc_string);
			}
		}
		else {
			count = readLimit;/* this is the max number of char. that can be displlayed in the TE */
			
			**gTextStr = '/0';
			file_rc = FSRead( refNum, &count, *gTextStr);
			
			/* if no errors or EOF reached, then display text */
			if ( file_rc == 0 || file_rc == -39) {
				
				/* bind the text in gTextStr to the TE buffer */
				HLock(gTextStr);
				temp_ptr = *gTextStr + count;
				*temp_ptr = '\0';
				text_show_new_text(gTextWindow);
				text_bind(*gTextStr);
				HUnlock(gTextStr);
				
				/* expand all tabs */
				tehandle = ((DocumentPeek) gTextWindow)->docTE;
				untabify(tehandle);
				
				text_draw();
				
				/* how many characters did we loose? */
				if ( file_rc != -39 ) {
					file_rc = GetEOF( refNum, &logEOF );
					if (file_rc != 0 ) {
						sprintf(rc_string,"Return Code: %d",file_rc);
						OpenAlertDialog(FILE_ERROR,rc_string);
					}
					else {
						logEOF = logEOF - readLimit;
						if (logEOF > 0 ) {  	/* make sure the file was not exactly = readLimit */
							sprintf(rc_string,"%u characters are missing.",logEOF);
							OpenAlertDialog(OPEN_WARNING,rc_string);
						}
					}
				}
				file_rc = FSClose( refNum );
				
				SetWTitle(gTextWindow,name);
				
				/* save text size as static data for use in the menuMgr */
				data_text_size(store,&zero);
				data_text_active(store,&zeros);

			}
			else {
				sprintf(rc_string,"Return Code: %d",file_rc);
				OpenAlertDialog(FILE_ERROR,rc_string);
				}
		}
	}
}

/*     
 *
 * 	cmd_authorize:
 *
 * 	Authorization check for user who wants to be a provider of information.
 *	Obtain username and password from dialog box and send string to server.
 */
 Boolean
 cmd_authorize()
 {
 	Boolean	rc;
	Boolean	tr_rc;
	Str255	message;
		
	rc = dlog_login(username,password);
	
	if ( rc ) {
		compose_transaction(authorize_tr);
		rc = cmd_send_message( meta );
		
		/* if no networking errors, then check the return message */
		if ( rc ) {
			tr_rc = atoi(gMessage);
			rc = get_field(gMessage,MSGTEXT,message);
			if (tr_rc) 
				OpenAlertDialog( NOT_AUTHORIZED,message );
			else
				data_source(store,message);
		}
	}
	
	if ((!rc) || (tr_rc))
		return false;
	else
		return true;
 }
 
/*     
 *
 * 	cmd_list_window:
 *
 * 
 */
void
cmd_list_window()
{	
	if (!wind_visible(gListWindow)) {
		SelectWindow(gListWindow);
		ShowWindow(gListWindow);
	}
	else
		if (FrontWindow() != gListWindow)
			SelectWindow(gListWindow);
	
}	/* cmd_list_window */

/*     
 *
 * 	cmd_text_window:
 *
 * 
 */
void
cmd_text_window()
{
	if (!wind_visible(gTextWindow)) {
		SelectWindow(gTextWindow);
		ShowWindow(gTextWindow);
	}
	else
		if (FrontWindow() != gTextWindow)
			SelectWindow(gTextWindow);
		
}	/* cmd_text_window */

/*     
 *
 * 	cmd_select_word:
 *
 * 	find a word in the document and highlight it.
 */
void
cmd_select_word(again)
Boolean	again;
{
	static	Str255	word = {'\0'};
	static	Boolean setting = false;
	
	Boolean			find;
	char			*start_ptr;
	long			start;
	int				end;
	char			*search_ptr;
	short			list_begin;
	short			list_bottom;
	Boolean			selected;
	Str255			list_buffer;
	Str255			title;
	int				rc;
	Boolean			found_it;
	Boolean 		beginning = false;
	
	find = true;
	
	/* "find again" function does not require a dialog box */
	if (!again)
		find = dlog_find_string( word,&setting,&beginning );/* get user's input          */
		
	if ( find ) {
		if (FrontWindow() == gListWindow ) {	/* must be a list window */
												/* get start of selected list item */
			if ( !beginning ) {
				selected = list_get_list_select(&list_begin);
				if (selected)
					list_begin = list_begin + 1;/* increment search past selected list item */
			}
			else
				list_begin = 0;
			
			list_bottom = list_end() - 1;		/* get end of list */
			
			found_it = false;
			for(;list_begin <= list_bottom && found_it == false; list_begin++) {
				list_get_buffer(list_buffer,list_begin); 
				rc = get_field(list_buffer,TITLE,title);
				start_ptr = util_search_str(title,strlen(title),word,strlen(word),setting);
				if ( start_ptr != NULL ) 
					found_it = true;
			}
			
			if (found_it ) {
				list_unselect();				/* unselect any highlighted items */
				list_select(list_begin - 1);	/* select appropriate list item */
			}
			else
				SysBeep(1);						/* could not find word, give the user a beep */
		}
		
		else {									/* must be a text window */
			if ( !beginning )					/* start search from insertion point? */
				end = text_select_end();
			else
				end = 0;
			text_get_buffer();					/* get current text buffer */
			search_ptr = *gTextStr + end;		/* start search here */
			start_ptr = util_search_str(search_ptr,strlen(search_ptr),word,strlen(word),setting);
			if ( start_ptr != NULL ) {
				start = start_ptr - *gTextStr;
				text_select_word(start,start + strlen(word));
			}
			else
				SysBeep(1);						/* could not find word, give the user a beep */
		}
	}
}

/*     
 *
 * 	cmd_save_text:
 *
 * 	save text window to a document.
 */
void
cmd_save_text()
{
	Boolean good;
	short		vRefNum;
	char		fName[63];
	IOParam		pbr;
	FileParam	fparam;
	FILE		*new_file;
	Handle		text_handle;
	int			text_length;
	short		list_begin;
	short		list_bottom;
	Str255		list_buffer;
	Str255		title;
	int			rc;
	
	good = dlog_put_file(&vRefNum,fName);
	
	if (!good)
		return;	/* the user does not want to continue, so let's get out of here */
	
	 /* set the default volumn to the mounted volumn specified by vRefNum */
     pbr.ioNamePtr = nil;
     pbr.ioVRefNum = vRefNum;
     PBSetVol((ParmBlkPtr) &pbr, false);
     if (pbr.ioResult != noErr) {
	 	 OpenAlertDialog(WRITE_ERROR,"Set volumn failed.");
		 return;
	 }

     p2cstr(fName);
     new_file = fopen(fName, "w");
	 if ( new_file == NULL ) {
	 	OpenAlertDialog(WRITE_ERROR,"Could not open the file in write mode.");
		return;
	}

	 /* get current file information into the parameter block */
     c2pstr(fName);
     fparam.ioNamePtr = fName;
     fparam.ioVRefNum = 0;
     fparam.ioFVersNum = 0;
     fparam.ioFDirIndex = 0;
     PBGetFInfo((ParmBlkPtr) &fparam, false);
	 if (pbr.ioResult != noErr) {
	 	 OpenAlertDialog(WRITE_ERROR,"Getting current file information.");
		 return;
	 }

	 /* set information needed by the finder */
     fparam.ioFlFndrInfo.fdType = 'TEXT';
     fparam.ioFlFndrInfo.fdCreator = 'MSWD';
     PBSetFInfo((ParmBlkPtr) &fparam, false);
	 if (pbr.ioResult != noErr) {
	 	 OpenAlertDialog(WRITE_ERROR,"Could not set the file information.");
		 return;
	 }
	
	 if (FrontWindow() != gListWindow ) {				/* handle text window */
	 	text_handle = text_get_handle(gTextWindow);
	 	text_length = text_get_length(gTextWindow);
	 	fwrite(*text_handle, 1, text_length, new_file);
	 }
	 else {												/* handle a list window */
		list_bottom = list_end() - 1;		
		list_begin = 0;
		for(;list_begin <= list_bottom; list_begin++) {
			list_get_buffer(list_buffer,list_begin); 
			rc = get_field(list_buffer,TITLE,title);
			if (rc)
				fwrite(title, 1, strlen(title), new_file);
				fwrite("\n", 1, 1, new_file );
		}
	 }
	
     if (fclose(new_file) == EOF) {
	 	 OpenAlertDialog(WRITE_ERROR,"Closing file.");
		 return;
	 }

	 /* write descriptive information about the volumn, contents ... */
     pbr.ioNamePtr = 0;
     pbr.ioVRefNum = vRefNum;
     PBFlushVol((ParmBlkPtr) &pbr, false);
	 if (pbr.ioResult != noErr) {
	 	 OpenAlertDialog(WRITE_ERROR,"Writting descriptive information.");
		 return;
	 }

     return;
}

void
compose_transaction(type)
int	  type;
{
	switch(type) {
		case find_tr1:		
			sprintf(meta,"%s%s%s","b",DELIM,find_str);
			break;
		case find_tr2:
			sprintf(meta,"%s%s%s%s%s","b",DELIM,find_str,DELIM,node_id);
			break;
		case keyword_tr:		
			/* sprintf(meta,"%s%s%s","k",DELIM,find_str); */
			strcpy(meta,"list\015\012");
			break;
		case below_tr:
			sprintf(meta,"%s%s%d%s%s%s%d","w",DELIM,2,DELIM,node_id,DELIM,1);
			break;
		case content_tr:
			sprintf(meta,"%s%s%d%s%s%s%d","w",DELIM,2,DELIM,node_id,DELIM,atoi(depth));
			break;
		case modify_subj_tr:
			sprintf(meta,"%s%s%s%s%d%s%s%s%s%s%s%s%s%s%s%s",
				"r",DELIM,node_id,DELIM,4,DELIM,dates,DELIM,
				topic,DELIM,title,DELIM,source,DELIM,DELIM,DELIM);
			break;
		case add_subj_tr:
			sprintf(meta,"%s%s%s%d%s%s%s%s%s%s%s%s%s%s%s",
				"a",DELIM,DELIM,4,DELIM,dates,DELIM,
				topic,DELIM,title,DELIM,source,DELIM,DELIM,DELIM);
			break;
		case path_tr:
			sprintf(meta,"%s%s%d%s%s%s%d","w",DELIM,1,DELIM,node_id,DELIM,99);
			break;
		case show_tr:
			sprintf(meta,"%s%s%s","s",DELIM,node_id);
			break;
		case text_tr:
			sprintf(meta,"%s%s%s%s%d%s%d","t",DELIM,node_id,DELIM,netseek,DELIM,netstop);
			break;
		case gif_tr:
			sprintf(meta,"%s%s%s%s%d%s%d","t",DELIM,node_id,DELIM,gif_offset,DELIM,GIF_BUF_SIZE);
			break;
		case add_doc_tr:
			sprintf(meta,"%s%s%s%d%s%s%s%s%s%s%s%s%s%s%s%s",
    			"a",DELIM,DELIM,document_flag,DELIM,dates,DELIM,
				topic,DELIM,title,DELIM,source,DELIM,locker,DELIM,path);
			break;
		case modify_doc_tr:
			sprintf(meta,"%s%s%s%s%d%s%s%s%s%s%s%s%s%s%s%s%s",
				"r",DELIM,node_id,DELIM,document_flag,DELIM,dates,DELIM,
				topic,DELIM,title,DELIM,source,DELIM,locker,DELIM,path);
			break;
		case link_child_tr:
			sprintf(meta,"%s%s%s%s%s","l",DELIM,parent_id,DELIM,node_id);
			break;
		case move_tr:
			sprintf(meta,"%s%s%s%s%s%s%s","l",DELIM,parent_id,DELIM,node_id,DELIM,link_id);
			break;
		case unlink_child_tr:
			sprintf(meta,"%s%s%s%s%s","u",DELIM,parent_id,DELIM,node_id);
			break;
		case file_tr:
			sprintf(meta,"%s%s%s","f",DELIM,node_id);
			break;
		case authorize_tr:
			sprintf(meta,"%s%s%s%s%s","p",DELIM,username,DELIM,password);
			break;
		case version_browser_tr:
			sprintf(meta,"%s%s%s","v",DELIM,"MAC");
			break;
		case version_provider_tr:
			sprintf(meta,"%s%s%s%s%s","v",DELIM,"MPR",DELIM,PROVIDER_VERSION);
			break;
		case close_provider_tr:
			sprintf(meta,"%c",'c');
			break;
		case remove_tr:
			sprintf(meta,"%s%s%s","x",DELIM,node_id);
			break;
		case reorder_above_tr:
			sprintf(meta,"%s%s%s%s%s%s%s","g",DELIM,menu_id,DELIM,parent_id,DELIM,node_id);
			break;
		case reorder_below_tr:
			sprintf(meta,"%s%s%s%s%s%s%s","j",DELIM,menu_id,DELIM,parent_id,DELIM,node_id);
			break;
		case quit_tr:
			sprintf(meta,"%c",'q');
			break;
		case servers_tr:
			sprintf(meta,"%c",'m');
			break;
		case source_read_info_tr:
			sprintf(meta,"%s%s%s","n",DELIM,node_id);
			break;
		case source_read_info_tr2:
			sprintf(meta,"%s%s%s%s","n",DELIM,DELIM,source);
			break;
		case source_write_info_tr:
			break;
	}
}

/*     
 *
 * 	cmd_get_info:
 *
 * 	Bring up Get Info dialog box.
 */
void
cmd_get_info(window)
WindowPtr	window;
{
	Str255		list_string;
	Boolean		rc;
	char    	*sp;
/*  char		*time_string; */
	WindowPtr	new_window;
	Str255		source_long;
	Str255		source_name;
	Str255		source_email;
	Str255		source_phone;
	Str255  	source_topic;
	NODE_INFO 	**select_node;
		
	/* null out global variables */
	title[0] = NULL;
	source[0] = NULL;
	dates[0] = NULL;
	path[0] = NULL;
	type[0] = NULL;
	node_id[0] = NULL;
	
	/* null out local variables */
	source_name[0] = NULL;
	source_email[0] = NULL;
	source_phone[0] = NULL;
	source_long[0] = NULL;
	source_topic[0] = NULL;

	/* do we have a new getinfo display ? */
	if ( window == NULL ) {
		rc = list_last_click_buffer(list_string);
		select_node = (NODE_INFO**) NewHandle(sizeof(NODE_INFO));
		
		/* get information currently in the cell */
		rc = get_field(list_string,TITLE,title);
		if (rc) rc = get_field(list_string,SOURCE,source);
		if (rc) rc = get_field(list_string,DATE,dates);
		if (rc) rc = get_field(list_string,PATH,path);
		if (rc) rc = get_field(list_string,TYPE,type);
		if (rc) rc = get_field(list_string,NODE,node_id);
		if (rc) rc = get_field(list_string,TOPIC,source_topic);
		
		/* replace comma seperator with LF to create a list display */
		for (sp=source_topic; *sp != NULL; sp++)
			if (*sp == ',') *sp = '\n';
			
		strcpy((**select_node).node_id,node_id);
		strcpy((**select_node).title,title);
		strcpy((**select_node).source,source);
		strcpy((**select_node).path,path);
		strcpy((**select_node).type,type);
		strcpy((**select_node).source_topic,source_topic);
		
		if (*type != SERVER_ITEM && *type != PHONE_ITEM) {
			/* now, get information on the source for this node */
			/* the source_read_info_tr uses the global node_id set above */
			compose_transaction(source_read_info_tr);
			if (rc) rc = cmd_send_message( meta );
			
			if (rc) {
				rc = atoi(gMessage);  /* if source does not exist, rc could be false */
				if (!rc) {			  /* if ok, continue */
					rc = get_field(gMessage,SOURCE_LONG,source_long);
					if (rc) rc = get_field(gMessage,SOURCE_NAME,source_name);
					if (rc) rc = get_field(gMessage,SOURCE_EMAIL,source_email);
					if (rc) rc = get_field(gMessage,SOURCE_PHONE,source_phone);
					
					/* make the display look nice */
					for (sp=source_email; *sp != NULL && *sp != ','; sp++);
					if (*sp == ',') *sp = '\n';
					for (sp=source_name; *sp != NULL && *sp != ','; sp++);
					if (*sp == ',') *sp = '\n';
					for (sp=source_phone; *sp != NULL && *sp != ','; sp++);
					if (*sp == ',') *sp = '\n';
	
					strcpy((**select_node).source_name,source_name);
					strcpy((**select_node).source_email,source_email);
					strcpy((**select_node).source_phone,source_phone);
					strcpy((**select_node).source_long,source_long);
				}
			}
		}
		
	}
	else {
		(long)select_node = GetWRefCon(window);
		strcpy(node_id,(**select_node).node_id);
		strcpy(title,(**select_node).title);
		strcpy(source,(**select_node).source);
		strcpy(path,(**select_node).path);
		strcpy(type,(**select_node).type);
		strcpy(source_topic,(**select_node).source_topic);
		strcpy(source_name,(**select_node).source_name);
		strcpy(source_email,(**select_node).source_email);
		strcpy(source_phone,(**select_node).source_phone);
		strcpy(source_long,(**select_node).source_long);
	}

	/* convert time (unix long int) to a string 
	util_date_conv(dates,&time_string);
	let's not do this anymore.
	*/
				
	new_window = dlog_get_info(window,title,source,path,type,
		node_id,source_long,source_name,source_email,source_phone,source_topic);
		
	/* if this is a new window, save the contents */
	if ( window == NULL && new_window != NULL)
		SetWRefCon(new_window, (long) select_node);
	
	wind_set_cursor(0); 			/* turn cursor into arrow, incase we were in a text wind. */
}

/*     
 *
 * 	cmd_get_version:
 *
 * 	compare the client version and the latest clinet version known by the server.
 */
Boolean
cmd_get_version(interface)
int	interface;
{
	Handle	resHandle; 
	Str255	version;
	Boolean	rc;
	char	*cp;
	int		vers;
	int		base = 6;
	short	ctr;
		
	if ( interface == BROWSER ) {		
		/* append application version number to version string */
		resHandle = GetResource((ResType)'vers',1);
		if (resHandle != NULL) {
			vers = (char)*((*resHandle)+6);
			for (ctr=1, cp = version; ctr <= vers; ctr++)
				*(cp++) = *((*resHandle) + base + ctr);
			*cp = NULL;
			
			compose_transaction(version_browser_tr);
			strcat(meta,":");
			strcat(meta,version);
		}
	}
	else
		if ( interface == PROVIDER ) {
			strcpy(version,PROVIDER_VERSION);
			compose_transaction(version_provider_tr);
		}
		
	rc = cmd_send_message( meta );
		
	if (rc) {
		/* ignore first 4 characters returned from the server */
		if (strcmp(&gMessage[4],version) != 0) {
			rc = dlog_version();
			return rc;  /* the user can continue or stop execution */
		}
	}
	else {
		BigBadError(OBTAIN_VERSION);
		return false;
	}
	
	return true;
}

/*     
 *
 * 	cmd_get_provider:
 *
 * 	Bring up the Provider Menu if the user is authorized.
 */
void
cmd_get_provider()
{

	Boolean rc;
	
	/* get provider version */
	rc = cmd_get_version(PROVIDER);
	
	if (rc)
		/* bring up dialog box */
		rc = cmd_authorize();
	
	if (rc) {
		menu_add( PROVIDER );		/* bring up provider menu */
		gProvider = true;			/* I am a provider        */
	}
	
}

void
cmd_close_provider()
{
	Boolean rc;
	
	compose_transaction(close_provider_tr);
		
	/* tell the server we are no longer a provider */
	rc = cmd_send_message( meta );
	
	/* we use to evaluate the response, but, if the network has
	   closed, then rc will be negative and we don't care. */
	
	menu_delete( PROVIDER );		/* remove the provider menu */
	rc = data_parent(store,'\0');	/* remove the parent    */
	gProvider = false;				/* turn off reorder mode */
}

/*     
 *
 * cmd_remove:
 * 
 *
 */
void
cmd_remove()
{
	Str255	list_buffer;
	Boolean	rc;
	Str255	title;
	Str255	message;
	
	rc = list_last_click_buffer(list_buffer);
	if (rc) {
		get_field(list_buffer,TITLE,title);
	
		/* only display the first thirty characters */
		if ( strlen(title) > 30 ) {
			title[28] = '.';
			title[29] = '.';
			title[30] = '?';
			title[31] = '\0';
		}
		else
			strcat(title,"?");
	
		rc = DeleteDialog(title);
	
		if (rc) get_field(list_buffer,NODE,node_id);
	
		if ( rc ) {
			compose_transaction(remove_tr);
			rc = cmd_send_message( meta );
	
			if (rc) {
				rc = atoi(gMessage);
				if (rc) {
					rc = get_field(gMessage,MSGTEXT,message);
					OpenAlertDialog(REMOVE_ERROR,message);
				}
				
				/* redisplay menu */
				rc = util_query_stack(meta);
				if (rc) rc = cmd_new_display( meta, command, list );
			
			} /* if */
		} /* if */
	} /* if */
} /* cmd_remove */

/*     
 *
 * cmd_reorder_state:
 * 
 *
 */
#pragma segment provider
void
cmd_reorder_state(state)
Boolean	state;
{	
	static ProcPtr old_clickloop;
	ProcPtr new_clickloop;
		
	switch(state){
		case on:
			/* save current clickloop and replace it with the new clickloop */
			list_click_loop(retrieve,&old_clickloop);
			new_clickloop = (ProcPtr)list_clickloop;
			list_click_loop(store,(ProcPtr)&new_clickloop);
			break;
		case off:
			/* restore default list click loop */
			list_click_loop(store,(ProcPtr)&old_clickloop);
			break;
	}

}
	
/*     
 *
 * cmd_reorder:
 * 
 *
 */
#pragma segment provider
void
cmd_reorder(mouse_down,mouse_up)
short	mouse_down;
short	mouse_up;
{

	Str255	    list_buffer;
	Boolean	    rc;
	Str255	    message;
	data_edit	undo_flags;
	char		menu_node_id_down[6];
	char		menu_node_id_up[6];
	Boolean		move_down;
		
	/* what direction are we moving? */
	move_down = (mouse_down < mouse_up ? true : false);
	
	do_find_menu_id(menu_node_id_down,false,mouse_down,move_down);
	do_find_menu_id(menu_node_id_up,true,mouse_up,move_down);
	
	/* get node id of mouse_down cell */
	rc = list_get_buffer( list_buffer, mouse_down );
	rc = get_field(list_buffer,NODE,node_id);
	
	/* get node id of current selected cell */
	rc = list_get_buffer( list_buffer, mouse_up );
	rc = get_field(list_buffer,NODE,parent_id);
	
	if (strcmp(menu_node_id_down, menu_node_id_up)) {
		/* we have a move between menu's */
	
		/*  link requires the following global variables */
		/*  parent_id = node is linked to this node      */
		/*  node_id   = link this node to parent_id      */
		/*  link_id   = node to link item above          */
		
		if (!strcmp(menu_node_id_up,node_id)) {
			strcpy(message,"Illegal move, nice try.");
			OpenAlertDialog(BAD_PROVIDER,message);
			
			/* redisplay menu - easiest way to clear screen */
			rc = util_query_stack(meta);
			if (rc) rc = cmd_new_display( meta, command, list );

			return;
		}
		
		/* create link  */
		strcpy(parent_id,menu_node_id_up);  /* the transaction wants parent_id set */
		/* get node to link item above - null if add to end of menu*/
		do_find_link_id(link_id,mouse_up,move_down);
	
		if (*link_id)
			compose_transaction(move_tr); /* like link_child_tr, but with uses link_id */
		else
			compose_transaction(link_child_tr);
		
		rc = cmd_send_message( meta );
		if (rc) {
			rc = atoi(gMessage);
			if (rc) {
				rc = get_field(gMessage,MSGTEXT,message);
				OpenAlertDialog(BAD_PROVIDER,message);
			}
			
			/* requires the following global variables 		  */
			/*  parent_id = menu where unlink is to occur     */
			/*  node_id   = unlink this node from parent_id   */
			
			/* unlink node from previous location */
			strcpy(parent_id,menu_node_id_down); 
			compose_transaction(unlink_child_tr);
			rc = cmd_send_message( meta );
			if (rc) {
				rc = atoi(gMessage);
				if (rc) {
					rc = get_field(gMessage,MSGTEXT,message);
					OpenAlertDialog(BAD_PROVIDER,message);
				}
			}
			
			/* redisplay menu */
			rc = util_query_stack(meta);
			if (rc) rc = cmd_new_display( meta, command, list );
		}
	}
	else { /* we have a reorder */
		/* requires the following global variables 		*/
		/*  menu_id   = menu where reorder takes place	*/
		/*  parent_id = move node before or after this  */
		/*  node_id   = node that get's moved           */
		
		/* we need to set menu_id */
		strcpy(menu_id,menu_node_id_down);
		
		/* what direction are we moving in? */
		if (mouse_up > mouse_down)
			compose_transaction(reorder_below_tr);
		else
			compose_transaction(reorder_above_tr);
		rc = cmd_send_message( meta );
	
		if (rc) {
			rc = atoi(gMessage);
			if (rc) {
				rc = get_field(gMessage,MSGTEXT,message);
				OpenAlertDialog(REORDER_ERROR,message);
			}
			
			/* it worked, redisplay menu */
			rc = util_query_stack(meta);
			if (rc) rc = cmd_new_display( meta, command, list );
			
			if (rc) {
				/* set Undo Edit menu stuff */
				bzero(&undo_flags,sizeof(undo_flags));
				undo_flags.type = edit_move;
				strcpy(undo_flags.node_a,menu_id);
				strcpy(undo_flags.node_b,node_id);   /* this is cell moved */
				
				/* so, did we move the mouse_up cell in the list? if so, set the
				   description bit in for a possible undo below */
				if ((list_get_size() -1) == mouse_down) {
					undo_flags.desc = true;
					/* substract 1 from mouse_down to use [0:n] range */
					rc = list_get_buffer( list_buffer, mouse_down );
				}
				else
					/* get cell below the one that was just moved  */
					/* as the undo will place it above (mouse_down +1) */
					rc = list_get_buffer( list_buffer, mouse_down + 1 );

				if (rc)	rc = get_field(list_buffer,NODE,parent_id);
				if (rc) strcpy(undo_flags.node_c,parent_id); /* used for undo */
				data_edits(store,&undo_flags);
			}
		}
	}

}	/* cmd_reorder */


/*     
 *
 * cmd_reorder_undo:
 * 
 * called from the edit menu - undo function
 * g transaction = (DELIM,menu_id,DELIM,parent_id,DELIM,node_id)
 */
#pragma segment provider
void
cmd_reorder_undo()
{
	Boolean	    rc;
	Str255	    message;
	data_edit	undo_flags;
		
	/* get informatin from mouse_up move */
	data_edits(retrieve,&undo_flags);

	/* get node id of cell that was moved */
	strcpy(node_id,undo_flags.node_b);
	
	/* get menu id where re-order occured */
	strcpy(menu_id,undo_flags.node_a);
	
	/* get cell where we move above (or below) */
	strcpy(parent_id,undo_flags.node_c);
	
	/* if we moved the mouse_up cell in the list, then use the reorder_below_tr */
	if ( undo_flags.desc )
		compose_transaction(reorder_below_tr);
	else
		compose_transaction(reorder_above_tr);
		
	rc = cmd_send_message( meta );

	if (rc) {
		rc = atoi(gMessage);
		if (rc) {
			rc = get_field(gMessage,MSGTEXT,message);
			OpenAlertDialog(REORDER_ERROR,message);
		}
		else {
			/* turn undo off - can't do another immediate undo */
			bzero(&undo_flags,sizeof(undo_flags));
			data_edits(store,&undo_flags);

			/* it worked, redisplay menu */
			rc = util_query_stack(meta);
			if (rc) rc = cmd_new_display( meta, command, list );
		}
	}

}	/* cmd_reorder_undo */


/*     
 *
 * cmd_cut_undo:
 * 
 *
 */
#pragma segment provider
void
cmd_cut_undo()
{
	data_edit	undo_flags;
	
	/* set Undo Edit menu stuff */
	bzero(&undo_flags,sizeof(undo_flags));
	data_edits(store,&undo_flags);
		
}	/* cmd_cut_undo */

/*     
 *
 * cmd_paste_undo:
 * 
 *
 */
#pragma segment provider
void
cmd_paste_undo()
{
	data_edit	undo_flags;
	
	/* set Undo Edit menu stuff */
	bzero(&undo_flags,sizeof(undo_flags));
	data_edits(store,&undo_flags);
	SysBeep(1);
}	/* cmd_paste_undo */


#define OVERLAY	160

/*     
 *
 * cmd_show_window:
 * 
 *
 */
void
cmd_show_window(index)
int	index;
{
	Boolean			rc;	
	short			active;
	Str255			window_title;
	extern Boolean	gBitBucket;
	
	typedef struct {
		WindowPtr	window;
		short		section;
	} wlist;
	
	wlist	window_list;

	rc = wind_windows_data(retrieve,index,&window_list);
				
	if (rc) {
		/* if documents have multiple sections, get the right section */
		if ( wind_type(window_list.window) == text ) {
			data_text_active(retrieve,&active);
			
			/* do we already have the text in the document window */
			if (active != window_list.section) {
				data_text_nodeid(retrieve,node_id);
				netseek = (int)window_list.section * (int)NETWORK_RECEIVE_SIZE;
				netstop = NETWORK_RECEIVE_SIZE;
				
				/* change window title to display proper section */
				GetWTitle(gTextWindow,&window_title);
				sprintf(&window_title[window_title[0]],"%1d",window_list.section+1);
				SetWTitle(gTextWindow,window_title);
				
				/* if this is not the first section of a multiple section document, then set
					a flag to throw out the first line and display document with an overlay
					of OVERLAY bytes in the previous section */
				if (window_list.section > 0) {
					gBitBucket = true;
					netseek = netseek - OVERLAY;
					netstop = netstop + OVERLAY;
				}
					
				compose_transaction(text_tr);
				rc = cmd_new_display( meta, command, text );
				if (rc)
					data_text_active(store,&window_list.section);
			}
			else {
				SelectWindow(window_list.window);
				ShowWindow(window_list.window);
			}

		}
		else {
			SelectWindow(window_list.window);
			ShowWindow(window_list.window);
		}
	}
}

/*     
 *
 * cmd_configure:
 * Bring up Configure dialog and execute user request.
 *
 */
cmd_configure()
{
	Boolean		doit,active;
	char		host[30];
	char		port[30];
	
	extern Boolean		gDebug;
	
	data_host(retrieve,host);
	data_port(retrieve,port);
	
	/* if user clicked on the open/close button (ie. not the cancel button), then do request */
	doit = networkDialog( host, port);
	if ( doit ) {
		data_host(store,host);
		data_port(store,port);
		active = net_check();
		if ( !active )
			net_open( gDebug );
		else
			net_end();
	}
}

/*     
 *
 * cmd_user_startup:
 * Allow user to change the startup menu or document.
 *
 */
void
cmd_user_startup()
{
	Boolean		rc;
	Boolean		list_button;
	Boolean		text_button;
	Str255		list_title;
	Str255		text_title;
	WindowPtr	mywindow;
	Str255		startup;
	char		list_node[6];
	char		text_node[6];
	Boolean		list_button_old;
	Boolean		text_button_old;
	
	*list_title = NULL;
	*text_title = NULL;
	
	mywindow = wind_find_window(list);
	if (mywindow != NULL && wind_visible(mywindow) ) {
	
		/* get title in list window */
		data_current_nodeid(retrieve,node_id);
		compose_transaction(show_tr);
		rc = cmd_send_message(meta);
		if (rc) rc = get_field(gMessage,S_TITLE,list_title);
		if (rc && strlen(list_title) > 30) {
			list_title[27] = '.';
			list_title[28] = '.';
			list_title[29] = '.';
			list_title[30] = NULL;
		}
	}
		
	mywindow = wind_find_window(text);
	if (mywindow != NULL && wind_visible(mywindow) ) {
	
		/* get title in list window */
		data_text_nodeid(retrieve,node_id);
		compose_transaction(show_tr);
		rc = cmd_send_message(meta);
		if (rc) rc = get_field(gMessage,S_TITLE,text_title);
		if (rc && strlen(text_title) > 30) {
			text_title[27] = '.';
			text_title[28] = '.';
			text_title[29] = '.';
			text_title[30] = NULL;
		}

	}

	/* if list_button and text_button should be checked, initialize them here */
	pref_get_string(STARTUP_ID, startup);		/* get starting nodeid  */
	
	rc = get_field(startup,2,list_node);
	data_current_nodeid(retrieve,node_id);
	if (!strcmp(node_id,list_node))
		list_button = true;
	else
		list_button = false;
		
	rc = get_field(startup,3,text_node);
	data_text_nodeid(retrieve,node_id);
	if (!strcmp(node_id,text_node))
		text_button = true;
	else
		text_button = false;
	
	/* bring up user startup dialog */
	text_button_old = text_button;
	list_button_old = list_button;
	rc = StartupDialog(&list_button, &text_button, list_title, text_title);
	
	if (rc) {
		
		/* since we only support two windows, we force the first node-id field
			to be the menu and the second node-id to be the text */
		/* ie.let's modify the startup string "2:node-id:node-id" */
		
		if (list_button_old != list_button) {
			if (list_button)
				data_current_nodeid(retrieve,list_node);
			else
				list_node[0] = NULL;
		}
		
		if (text_button_old != text_button) {
			if (text_button) 
				data_text_nodeid(retrieve,text_node);
			else
				text_node[0] = NULL;
		}
		
		/* create a new startup string using "protocol" */
		sprintf(startup,"2:%s:%s:",list_node,text_node);
		pref_put_string(STARTUP_ID, startup);
	}
}

/*     
 *
 * cmd_provider_options:
 * provider settable options
 *
 */
void
cmd_provider_options()
{
	Boolean		rc;
	Str255		store_directory;
	Str255		store_directory_old;
	Str255		partial_path;
	Str255		source;
	Str255		tab_setting;
	Str255		tab_setting_old;
	
	pref_get_string(STORE_DIRECTORY_STR, store_directory);		/* get store directory string  */
	strcpy(store_directory_old,store_directory);
	
	pref_get_string(TAB_SETTING, tab_setting);					/* get tab setting string  */
	strcpy(tab_setting_old,tab_setting);

	rc = dlog_prov_options(store_directory, tab_setting);
	
	if (rc) {
		if (strcmp(store_directory_old,store_directory)) {
			/* save this for this session */
			data_source(retrieve,source);
			sprintf(partial_path,"%s/%s",store_directory,source);
			rc = data_path(store,partial_path);

			/* now, save changes for each new session */
			pref_put_string(STORE_DIRECTORY_STR, store_directory);
		}
		
		if (strcmp(tab_setting_old,tab_setting)) 
			pref_put_string(TAB_SETTING, tab_setting);
		
	}
}

/*     
 *
 * cmd_define_item:
 * 
 *
 */
void
cmd_define_item()
{
	Boolean 	button;
	Str255		parent_title;
	Boolean		done;
	Str255		temp_title;
	Str255		save_source;
	int			menu_type;
	Str255		message;
	Boolean		rc;
	char	  	new_node_id[6];
	Boolean	  	text_visible;
	WindowPtr 	next_window;
	int			window_type;
	Str255		save_path;
	Str255		save_locker;
	Str255		store_directory;
	Str255		partial_path;
	Str255		locker_old;
	Str255		filename_old;
	Str255		partial_path_old;
	Boolean		send_document;
	
	enum {bad_result = -1, cancel_result = 0, ok_result, more_result};
	
	*topic = NULL;
	*title = NULL;
	*source = NULL;
	*parent_title = NULL;
	*filename = NULL;
	*locker = NULL;
	*path = NULL;
	dates[0] = '0';
	dates[1] = NULL;
	
	/* get static source */
	data_source(retrieve,source);
	strcpy(save_source,source);
	
	/* get menu id where this item will be added to */
	data_current_nodeid(retrieve,parent_id);
	
	/* get the title for display on the dialog box */
	GetWTitle(gListWindow,&parent_title);
	p2cstr( parent_title );
	
	/* display only the first 30 characters */
	if (strlen(parent_title) > 30 ) {
		parent_title[29] = 'É';
		parent_title[30] = '\0';
	}
	strcpy(temp_title,parent_title);
	sprintf(parent_title,"New item will be added to\"%s\"",temp_title);
	
	/* start with the document radio button on */
	menu_type = text;
	
	/* get/form static locker */
	rc = data_locker(retrieve,locker);
	if (locker[0] == '\0')
		strcpy(locker,"ti_data");
	strcpy(save_locker,locker);

	/* get/form static path */
	rc = data_path(retrieve,partial_path);
	if (!rc) {
		pref_get_string(STORE_DIRECTORY_STR, store_directory);		/* get store directory string  */
		sprintf(partial_path,"%s/%s",store_directory,source);
		rc = data_path(store,partial_path);
	}
	strcpy(save_path,path);

	done = false;
	while( !done) {
		button = dlog_menu_item1( &menu_type, add, topic, title, source, parent_title );	
		switch (button) {
			case cancel_result:
				done = true;
				break;
			case more_result:
				/* save source if it has been changed */
				if (strcmp(save_source,source) != 0) {
					data_source(store,source);
					
					/* now, change the data path */
					pref_get_string(STORE_DIRECTORY_STR, store_directory);		/* get store directory string  */
					sprintf(partial_path,"%s/%s",store_directory,source);
					rc = data_path(store,partial_path);
				}
				
				strcpy(filename_old,filename);
				strcpy(partial_path_old,partial_path);
				strcpy(locker_old,locker);
				button = dlog_menu_item2(filename, partial_path, locker);
				
				switch(button) {
					case ok_result:
						break;  /* no changes need to be made */
					case cancel_result:
						strcpy(filename, filename_old);
						strcpy(partial_path, partial_path_old);
						strcpy(locker, locker_old);
						break;
				}

				break;
			case ok_result:
				/* save source if it has been changed */
				if (strcmp(save_source,source) != 0) {
					data_source(store,source); 
					
					/* now, change the data path */
					pref_get_string(STORE_DIRECTORY_STR, store_directory);		/* get store directory string  */
					sprintf(partial_path,"%s/%s",store_directory,source);
					rc = data_path(store,partial_path);
				}

				switch (menu_type) {
					case list:
						/* formulate the add folder transaction into global meta variable */
						compose_transaction(add_subj_tr);
							
						/* send meta transaction record to the server */
						rc = cmd_send_message( meta );
						
						if ( rc ) {
							rc = get_field(gMessage,MSGTEXT,message);
							rc = atoi(gMessage);
							if ( rc ) 
								OpenAlertDialog(BAD_PROVIDER,message);
								
							else {
								/* get node id just created */
								strcpy(new_node_id,message);
																
								/* link newly created node to parent */
								cmd_link_child ( new_node_id );
							}
							
							/* redisplay the menu */
							rc = util_query_stack(meta);
							if (rc) rc = cmd_new_display( meta, command, list );
						}
							
						break;
						
					case gif:
					case text:
						document_flag = 4;  /* something about unresolved links */

						if ( *filename == NULL )
							document_flag = document_flag + 32;	/* let the server determine the filename and path */
						else {
							/* append filename to the end of path */
							if ((strlen(partial_path) + strlen(filename)) < sizeof(path)) {
								sprintf(path,"%s/%s",partial_path,filename);
							}
						}
							
						/* make sure the node is stored as an image */
						if (menu_type == gif)
							document_flag = document_flag + IMAGE_KEY;
						else
						   if (menu_type == text)
						   	  document_flag = document_flag + TEXT_KEY;
							
						/* formulate the add folder transaction into global meta variable */
						compose_transaction(add_doc_tr);
							
						/* send meta transaction record to the server */
						rc = cmd_send_message( meta );
						
						if ( rc ) {
							rc = get_field(gMessage,MSGTEXT,message);
							rc = atoi(gMessage);
							if ( rc ) 
								OpenAlertDialog(BAD_PROVIDER,message);
							else {
								/* get node id just created */
								strcpy(new_node_id,message);
								
								/* link newly created node to parent */
								cmd_link_child ( new_node_id );
								
								/* save locker if it has been changed */
								if (strcmp(save_locker,locker) != 0) 
									rc = data_locker(store,locker);
			
								/* save path if it has been changed */
								if (strcmp(save_path,partial_path) != 0) 
									rc = data_path(store,partial_path);
									
								/* Determine if there is a visible text window in the window list */
								text_visible = false;
								next_window = FrontWindow();
								while( next_window != nil && IsAppWindow(next_window) ) {
									if (wind_visible(next_window)) {
										window_type = wind_type(next_window);
										if (window_type == text)
											text_visible = true;
									}
									(WindowPeek)next_window = wind_next_window(next_window);
								}
								
								if (text_visible) {
									/* get the title for display on the dialog box */
									GetWTitle(gTextWindow,&parent_title);
									p2cstr( parent_title );
									
									/* display only the first 30 characters */
									if (strlen(parent_title) > 30 ) {
										parent_title[29] = 'É';
										parent_title[30] = '\0';
									}

									send_document = dlog_send_document( parent_title );
									if (send_document)
										cmd_publish_document( new_node_id );
								}
							}
							
							/* redisplay the menu */
							rc = util_query_stack(meta);
							if (rc) rc = cmd_new_display( meta, command, list );
						}
						break;
				}
				
				done = true;
				break;
		}
	}
}

/*     
 *
 * cmd_modify_item:
 * 
 *
 */
void
cmd_modify_item()
{
	Boolean button;
	Str255	list_buffer;
	Boolean	done;
	int		menu_type;
	int		old_menu_type;
	Str255	message;
	Boolean	rc;
	Str255	partial_path;
	char	*filename_ptr;
	Str255	old_topic;
	Str255	old_title;
	Str255	old_source;
	Str255	old_locker;
	Str255	old_path;
	Str255	old_filename;
	Str255	store_directory;
	Str255	filename_tmp;
	Str255	path_tmp;
	Str255	locker_tmp;
	
	enum {bad_result = -1, cancel_result = 0, ok_result, more_result};
	
	/* get highlighted cell information */
	rc = list_last_click_buffer(list_buffer);
	if (rc) rc = get_field(list_buffer,NODE,node_id);
	if (rc) rc = get_field(list_buffer,DATE,dates);
	if (rc) rc = get_field(list_buffer,TOPIC,topic);
	if (rc) rc = get_field(list_buffer,TITLE,title);
	if (rc) rc = get_field(list_buffer,SOURCE,source);
	if (rc) rc = get_field(list_buffer,LOCKER,locker);
	if (rc) rc = get_field(list_buffer,PATH,path); 
	if (rc) rc = get_field(list_buffer,TYPE,type);
	
	/* breakout filename from path */
	if (rc && path[0] != NULL ) {
		for ( filename_ptr=&path[strlen(path)-1];*filename_ptr != '/' && 
			filename_ptr != path;filename_ptr--); 
			
		/* just to be on the safe side ...check that there was a '/' character */
		if (filename_ptr != path ) {
			strcpy(filename,filename_ptr+1);
			
			/* rip out trailing '/' and null terminate the path */
			*filename_ptr = '\0';
		}
	}
	else {
		*filename = NULL;
		
		/* get/form static locker */
		rc = data_locker(retrieve,locker);
		if (locker[0] == '\0')
			strcpy(locker,"ti_data");
	
		/* get/form static path */
		rc = data_path(retrieve,path);
		if (!rc) {
			pref_get_string(STORE_DIRECTORY_STR, store_directory);		/* get store directory string  */
			sprintf(path,"%s/%s",store_directory,source);
		}
	}
	
	/* find the type of item currently exists */
	switch(type[0]) {
		case MENU_ITEM:
		menu_type = list;
		break;
		
		case TEXT_ITEM:
		menu_type = text;
		break;
		
		case IMAGE_ITEM:
		menu_type = gif;
		break;
	}
			
	/* save a copy of the input fields */
	strcpy(old_topic,topic);
	strcpy(old_title,title);
	strcpy(old_source,source);
	strcpy(old_locker,locker);
	strcpy(old_path,path);
	strcpy(old_filename,filename);
	old_menu_type = menu_type;
	
	done = false;
	while( !done) {
		button = dlog_menu_item1( &menu_type, modify, topic, title, source, "" );	
		
		switch (button) {
			case cancel_result:
				done = true;
				break;
			case more_result:
				strcpy(filename_tmp,filename);
				strcpy(path_tmp,path);
				strcpy(locker_tmp,locker);
				button = dlog_menu_item2(filename, path, locker);
				if (button == cancel_result) {
					/* make sure we don't use any changes */
					strcpy(filename,filename_tmp);
					strcpy(path,path_tmp);
					strcpy(locker,locker_tmp);
				}
				break;
			case ok_result:
				switch (menu_type) {
					case list:
						/* find out if there were any changes */
						if ( strcmp(old_source,source) || strcmp(old_title,title) || strcmp(old_topic,topic) ||
							 old_menu_type != menu_type ) {
						
							/* make sure that locker and path are null incase we changed from a document
							 	to a folder */
							path[0] = NULL;
							locker[0] = NULL;
							
							/* formulate the add folder transaction into global meta variable */
							compose_transaction(modify_subj_tr);
								
							/* send meta transaction record to the server */
							rc = cmd_send_message( meta );
							
							if ( rc ) {
								rc = atoi(gMessage);
								if ( rc ) {
									rc = get_field(gMessage,MSGTEXT,message);
									OpenAlertDialog(BAD_PROVIDER,message);
								}
									
								/* redisplay the menu */
								rc = util_query_stack(meta);
								if (rc) rc = cmd_new_display( meta, command, list );
							}
						}
							
						break;
						
					case text:
					case gif:
						if ( strcmp(old_source,source) || strcmp(old_title,title) || strcmp(old_topic,topic) ||
							 strcmp(old_filename,filename) || strcmp(old_path,path) || strcmp(old_locker,locker) ||
							 old_menu_type != menu_type ) {
							 
							document_flag = 4;  /* something about unresolved links */

							if ( *filename == NULL )
								document_flag = document_flag + 32;	/* let the server determine the filename and path */
							else {
								/* append filename to the end of path */
								if ((strlen(partial_path) + strlen(filename)) < sizeof(path)) {
									strcpy(partial_path,path);
									sprintf(path,"%s/%s",partial_path,filename);
								}
							}
							
							/* make sure the node is stored as an image */
							if (menu_type == gif)
								document_flag = document_flag + IMAGE_KEY;
							else
								if (menu_type == text)
									document_flag = document_flag + TEXT_KEY;
								
							/* formulate the add folder transaction into global meta variable */
							compose_transaction(modify_doc_tr);
								
							/* send meta transaction record to the server */
							rc = cmd_send_message( meta );
							
							if ( rc ) {
								rc = atoi(gMessage);
								if ( rc ) {
									rc = get_field(gMessage,MSGTEXT,message);
									OpenAlertDialog(BAD_PROVIDER,message);
								}
									
								/* redisplay the menu */
								rc = util_query_stack(meta);
								if (rc) rc = cmd_new_display( meta, command, list );
							}
						}
						
						break;
				}
				
				done = true;
				break;
		}
	}
}	/* cmd_modify_item */

/*     
 *
 * cmd_other_servers:
 * 
 *
 */
typedef struct stack {
		Handle prev_ptr;
		Str255 body; 
} SERVERS_STACK;
void
cmd_get_other_servers()
{
	Boolean			rc; 
	int				list_size;
	Str255			list_buffer;
	SERVERS_STACK 	*servers_ptr;
	static Handle	servers_stack = NULL;
	Handle			last_ptr = NULL;
	
	/* formulate the add folder transaction into global meta variable */
	compose_transaction(servers_tr);

	if (!servers_stack) {
		rc = cmd_new_display( meta, command, list );

		if (rc) {
			/* cach this information */
			list_size = list_end() - 1;		/* get list size using range [0:n] */
			for(; list_size >= 0; list_size-- ) {
				list_get_buffer(list_buffer,list_size); 
					
				servers_stack = NewHandle(sizeof(SERVERS_STACK));
				servers_ptr = (SERVERS_STACK *)*servers_stack;
				strcpy(servers_ptr -> body, list_buffer);
				servers_ptr -> prev_ptr = last_ptr;
				last_ptr = servers_stack;
			}
		}
	}
	/*  use the cached server list to display in case the current
		server does not support the server_tr */
	else {
		/* parse the linked list and bind each item to the menu */
		for(list_size = 0, last_ptr = servers_stack; last_ptr != NULL; list_size++) {
			servers_ptr = (SERVERS_STACK *)*last_ptr;
			rc = list_Bind(servers_ptr -> body,strlen(servers_ptr -> body),list_size);
			last_ptr = servers_ptr -> prev_ptr;
		}
		
		/* store the local list size - needed by the cmd_new_display function */
		data_local_menu_size(store,&list_size);
		
		/* do the right thing with the list */
		rc = cmd_new_display( meta, local, list );
	}

}	/* cmd_other_servers */

/*     
 *
 * cmd_change_server:
 * 
 *
 */
void
cmd_change_server(host,port) 
char *host;
char *port;
{
	int		rc;

	data_host(store,host);
	data_port(store,port);
	
	net_end();					/* close existing connection */
	rc = net_open( false ); 	/* establish connection to the server, get banner */
		
	if (rc == 0 ) {
		/* let's not do this anymore, really need a protocol transaction 
		version_rc = cmd_get_version(BROWSER); */
		
		/* remove the previous command stack */
		util_delete_stack();
		
		/* remove the provider menu if it exists */
		if (menu_check( PROVIDER ))
			menu_delete( PROVIDER );		
			
		cmd_main_menu();
	}
}


/*     
 *
 * 	cmd_source_info:
 *
 * 	Bring up dialog to enter source directory stuff (contact, name ..)
 */
void
cmd_source_info()
{
	Boolean	rc;
	Str255	message;
	Str255	source_long;
	Str255	source_name;
	Str255	source_email;
	Str255	source_phone;
	Str255  source_short;
	
	source_short[0] = NULL;
	source_name[0] = NULL;
	source_email[0] = NULL;
	source_phone[0] = NULL;
	source_long[0] = NULL;
	
	/* now, get information on the source for this node */
	/* get static source */
	data_source(retrieve,source);
	strcpy(source_short,source);
	
	compose_transaction(source_read_info_tr2);
	rc = cmd_send_message( meta );
	
	if (rc) {
		rc = atoi(gMessage);  /* if source does not exist, rc could be false */
		if (!rc) {			  /* if ok, continue */
			/* parse the source directory information */
			rc = get_field(gMessage,SOURCE_LONG,source_long);
			if (rc) rc = get_field(gMessage,SOURCE_NAME,source_name);
			if (rc) rc = get_field(gMessage,SOURCE_PHONE,source_phone);
			if (rc) rc = get_field(gMessage,SOURCE_EMAIL,source_email);
		}
	}
	
	rc = dlog_source_info(source_short, source_long, source_name, source_phone, source_email);	
	
	if (rc) {  /* it's the modify/ok button */
	
		/* send meta transaction record to the server */
		/* fake it for now */
		sprintf(meta,"%s%s%s%s%s%s%s%s%s%s%s","A",DELIM,source_short,DELIM,source_long,DELIM,source_name,DELIM,source_phone,DELIM,source_email);

		rc = cmd_send_message( meta ); 
						
		if ( rc ) {
			rc = get_field(gMessage,MSGTEXT,message);
			rc = atoi(gMessage);
			if ( rc ) 
				OpenAlertDialog(BAD_PROVIDER,message);
		}
	}
}

/*     
 *
 * 	cmd_source_info:
 *
 * 	This functions determines if there is an owner of a menu.
 *  e.g. phone, keyword search do not have a menu owner.
 */
Boolean
cmd_menu_owner()
{
	Str255	last_command;
	Boolean	rc;

	/* determine how the current menu was created */
	/* if the stack is empty (rc == 0) then assume we are at the startup */
	/* menu and thus has an "owner" and is not from a search, etc...     */
	rc = util_query_stack(last_command);
	if (!rc || (*last_command == 'w' && *(last_command+2) == '2'))  
		return true;
	else
		return false;
}

#ifdef GIFSTUFF
void
cmd_read_gif_file(Boolean fromFile)
{
	GrafPtr		oldPort;

	GetPort( &oldPort );
	GIFtoPICT(fromFile);
	SetPort( oldPort );
}	/* cmd_read_gif_file */

#endif

/*     
 *
 * 	cmd_format_gif_transaction
 *
 * 	This functions returns the formated gif transaction
 */
void
cmd_format_gif_transaction(gif_formated_tr,gif_node_id,offset)
char *gif_formated_tr;
char *gif_node_id;
long offset;
{
	/* node_id and meta are global variables */
	strcpy(node_id,gif_node_id);
	
	/* gif_offset is a global variable */
	gif_offset = offset;
	
	/* create formatted gif transaction - result in in global meta */
	compose_transaction(gif_tr);
	
	/* copy meta into returning argument */
	strcpy(gif_formated_tr,meta);
}


void cmd_generic_save(WindowPtr	whichWindow)
{
	switch (wind_type(whichWindow)) {
		case text:							// is it a text or a list?
		case list:
			cmd_save_text();
			break;
		case gif:							// how about a gif?
			GIFSaveImage(whichWindow);		// save as pict for now
			break;
		default:
			break;
	}
}