/*
 *
 *  AM --- AmigaMail
 *  (C) 1991, 1992 by Christian Riede
 *
 *  AM is distributed in the hope that it will be useful, but WITHOUT ANY
 *  WARRANTY.  No author or distributor accepts responsibility to anyone
 *  for the consequences of using it or for whether it serves any
 *  particular purpose or works at all, unless he says so in writing.
 *  Refer to the GNU General Public License, Version 1, for full details.
 *  
 *  Everyone is granted permission to copy, modify and redistribute AM,
 *  but only under the conditions described in the GNU General Public
 *  License, Version 1.  A copy of this license is supposed to have been 
 *  given to you along with AM so you can know your rights and responsi-
 *  bilities.  It should be in a file named COPYING.  Among other things,
 *  the copyright notice and this notice must be preserved on all copies.
 *
 *  
 *
 */

#include "am.h"

struct MsgPort *ServerPort;

/* pass given message to server, return the reply of the server */
/* returns 0 on failure */
struct AMMessage *AskServer(struct AMMessage *msg)
{
	struct AMMessage *Return=0;
	struct MsgPort *ClientPort;

	/* server running ?*/
	if (ServerPort)
	{
		/* to be reentrant we must create our own port */
		if (!(ClientPort = CreatePort(0,0)))
			return(0);

		msg->AMMsg.mn_ReplyPort = ClientPort;

#if DEBUG
		kprintf("Sending..\nAction: %ld\nUsername: %s\nMsgId: %s\nNumber: %ld\nFolder: %s\n",
			msg->Action,msg->Username,msg->MsgId,msg->Number,msg->Folder);
#endif

		/* give him the message */
		PutMsg(ServerPort,(struct Message *)msg);

		/* receive reply */	
		/* since all requests are done syncronously */
		/* the first message must be the reply to our request */
		if (!(Return = (struct AMMessage *)GetMsg(ClientPort)))
		{
			/* wait for reply */
			WaitPort(ClientPort);

			/* return the replied message */
			Return = (struct AMMessage *)GetMsg(ClientPort);
		}

		/* "Der Mohr hat seine Schuldigkeit getan, der Mohr kann gehen" :-) */
		DeletePort(ClientPort);

#if DEBUG
		kprintf("Got Back:\nAction: %ld\nUsername: %s\nMsgId: %s\nNumber: %ld\nFolder: %s\nRC: %d\n",
			msg->Action,msg->Username,msg->MsgId,msg->Number,msg->Folder,msg->rc);
#endif

	}

	return(Return);
}


/* kill the server process */
/* returns TRUE on success, FALSE on failure */
int KillServer(void)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_DIE;

	AskServer(Msg);

	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));
	
	return(ret);
}


/* returns TRUE on success, FALSE on failure */
int LockContents(char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_LOCKCONTENTS;
	Msg->Username = Username;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* returns TRUE on success, FALSE on failure */
int UnLockContents(char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_UNLOCKCONTENTS;
	Msg->Username = Username;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* returns TRUE on success, FALSE on failure */
int GetContents(struct List *Mailbox,char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_GETCONTENTS;
	Msg->Username = Username;
	Msg->Mailbox = Mailbox;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));
	
	return(ret);
}

/* returns pointer to struct Mail for the new item, 0 on failure */
/* you will have to free the structure yourself if/when you don't need it */
struct Mail *AddItem(ULONG num,char *folder)
{
	struct AMMessage *Msg;
	struct Mail *New;

	if (!(Msg = AllocAMMsg()))
		return(0);

	Msg->Action = ACT_ADD_ITEM;
	Msg->Username = Username;
	Msg->Number = num;
	Msg->Folder = folder;

	AskServer(Msg);

	New = Msg->NewMail;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(New);
}


/* returns TRUE on success, FALSE on failure */
int MarkRead(ULONG num,char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_MARK_READ;
	Msg->Username = Username;
	Msg->Number = num;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* returns TRUE on success, FALSE on failure */
int MarkUnread(ULONG num,char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_MARK_UNREAD;
	Msg->Username = Username;
	Msg->Number = num;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* returns TRUE on success, FALSE on failure */
int MarkOld(ULONG num,char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_MARK_OLD;
	Msg->Username = Username;
	Msg->Number = num;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* returns TRUE on success, FALSE on failure */
int DeleteItem(ULONG num,char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_DELETE_ITEM;
	Msg->Username = Username;
	Msg->Number = num;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* returns new seq for given folder or 0 on failure */
ULONG NewSeq(char *folder)
{
	struct AMMessage *Msg;
	ULONG seq;

	if (!(Msg = AllocAMMsg()))
		return(0);

	Msg->Action = ACT_NEW_SEQ;
	Msg->Username = Username;
	Msg->Folder = folder;

	AskServer(Msg);

	seq = Msg->Number;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(seq);
}

/* request notification for changes in the given folder on a port */
/* returns TRUE on success, FALSE on failure */
int NotifyOn(struct MsgPort *NotifyPort,char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_NOTIFY_ON;
	Msg->Username = Username;
	Msg->NotifyPort = NotifyPort;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* turns notification off for the given folder/port */
/* returns TRUE on success, FALSE on failure */
int NotifyOff(struct MsgPort *NotifyPort,char *folder)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_NOTIFY_OFF;
	Msg->Username = Username;
	Msg->NotifyPort = NotifyPort;
	Msg->Folder = folder;

	AskServer(Msg);
	ret = Msg->rc;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}

/* gives a new unique string for use as msgid, tmp. file, etc. */
/* returns pointer to provided buffer for easy use in printf etc. */
/* Buffer must be at least 20 bytes long */
char *NewMsgId(char *s)
{
	struct AMMessage *Msg;

	if (!(Msg = AllocAMMsg()))
		return(0);

	Msg->Action = ACT_NEW_MSGID;
	Msg->MsgId = s;

	AskServer(Msg);

	FreeMem(Msg,sizeof(struct AMMessage));

	return(s);
}

/* check if the server has the same version as we */
int CmpVersion(void)
{
	struct AMMessage *Msg;
	int ret;

	if (!(Msg = AllocAMMsg()))
		return(FALSE);

	Msg->Action = ACT_VERSION;

	AskServer(Msg);

	if (Msg->MsgId) /* very old servers (before 1.7) do not respond to ACT_VERSION */
		ret = !strcmp(Msg->MsgId,AMIGAMAIL_VERSION);
	else
		ret = FALSE;

	FreeMem(Msg,sizeof(struct AMMessage));

	return(ret);
}
