
#include "microdot.h"

#include "ogre.h"
#include "ogre_protos.h"

#include "asyncio.h"

static void *ulkey;
static struct MinList userlist;

static int edituser;
void loaduserlist(void)
{
	struct AsyncFile *f;	
	struct user u;
	struct muser *n;

	ulkey=LibCreatePool( MEMF_CLEAR, sizeof( struct muser ) * 16, sizeof( struct muser ) * 8 );
	NewList( (struct List*) &userlist );
	pushhomedir();
	f = OpenAsync( "microdot.userdb", MODE_READ, sizeof( struct user ) * 16 );
	popdir();
	if(!f) return;

	while(ReadAsync(f,&u,sizeof(struct user))==sizeof( struct user ))
	{
		n=LibAllocPooled(ulkey,sizeof(struct muser));
		if(!n) break;
		n->u=u;
		AddTail((struct List*)&userlist,(struct Node*)n);
	}
	CloseAsync( f );
}

static int __stdargs usercmp( struct muser **u1, struct muser **u2 )
{
	char *p1, *p2;

	p1 = (*u1)->u.realname[0] ? (*u1)->u.realname : (*u1)->u.net;
	p2 = (*u2)->u.realname[0] ? (*u2)->u.realname : (*u2)->u.net;

	return( stricmp( p1, p2 ) );
}

void sortuserlist( void )
{
	int uc = GetNumEntries( ( struct List * ) &userlist );
	struct muser **mu;
	int c;

	if( !uc )
		return;

	mu = AllocMem( uc * 4, 0 );

	if( !mu )
		return;

	for( c = 0; c < uc; c++ )
	{
		mu[c] = (struct muser *) RemHead( &userlist );
	}

	qsort( mu, uc, 4, usercmp );

	for( c = 0; c < uc; c++ )
	{
		AddTail( &userlist, (struct Node *) mu[c] );
	}

	FreeMem( mu, uc * 4 );
}


int getuser(char *name,struct user *u)
{
	struct muser *n=(struct muser*)userlist.mlh_Head;
	char rname[ 128 ], *p;

	strncpy( rname, name, 127 );
	rname[ 127 ] = 0;
	if( ( p = strchr( rname, ' ' ) ) )
		*p = 0;

	while(n->n.mln_Succ) {
		if(!stricmp(n->u.net,rname))
		{
			if( u )
				*u = n->u;
			return(0);
		}
		n=(struct muser*)n->n.mln_Succ;
	}
	return(-1);
}

struct user *getusernum(int num)
{
	struct muser *n = ( struct muser * ) GetEntry( ( struct List * ) &userlist,num);
	if( n )
		return( &n->u );
	else
		return( NULL );
}

void ul2ogl(struct ogwin *ogw,UWORD id )
{
	struct muser *n=(struct muser*)userlist.mlh_Head;

	while(n->n.mln_Succ)
	{
		ogreLVAddEntry( ogw, id, n->u.realname[0]?n->u.realname:n->u.net, 2, n);
		n=(struct muser*)n->n.mln_Succ;
	}
}

#define adduserlist ul2sl

void freeuserlist(BOOL save)
{
	struct AsyncFile *f;
	struct muser *mu=(struct muser*)userlist.mlh_Head;

	if(save) {
		pushhomedir();
		DeleteFile( "microdot.userdb.bak" );
		Rename( "microdot.userdb", "microdot.userdb.bak" );
		f=OpenAsync( "microdot.userdb", MODE_WRITE, sizeof( struct user ) * 16 );
		popdir();
		if(f)
		{
			while(mu->n.mln_Succ)
			{
				WriteAsync(f,&mu->u,sizeof(struct user));
				mu=(struct muser*)mu->n.mln_Succ;
			}
			CloseAsync( f );
		}
		else displaybeep();
	}

	if(ulkey)
	{
		LibDeletePool(ulkey);
		ulkey = NULL;
	}
}

#define UGID_LV 1
#define UGID_NAME 2
#define UGID_REAL 3
#define UGID_COMMENT 4
#define UGID_PHONE 5
#define UGID_USEPGP 6
#define UGID_ADD 7
#define UGID_DEL 8
#define UGID_OK 9
#define UGID_CANCEL 10
#define UGID_POST 11
#define UGID_PGPID 12
#define UGID_PGP_TESTKEY 13
#define UGID_PGP_KEYREQ 14
#define UGID_PGP_EDITKEY 15

static void doedituser( struct ogwin *ogw, BOOL activate)
{
	struct muser *mu;

	if( edituser >= 0 )
	{
		mu=(struct muser*)GetEntry((struct List*)&userlist,edituser);
		if( mu )
		{
			ogreSetStringValue( ogw, UGID_NAME, mu->u.net );
			ogreSetStringValue( ogw, UGID_REAL, mu->u.realname );
			ogreSetStringValue( ogw, UGID_COMMENT, mu->u.comment );
			ogreSetStringValue( ogw, UGID_PHONE, mu->u.telefon );
			ogreSetStringValue( ogw, UGID_POST, mu->u.adresse );
			ogreSetStringValue( ogw, UGID_PGPID, mu->u.pgp_id );
			ogreSetValue( ogw, UGID_USEPGP, mu->u.flags & UF_PGP );
	
		}
		if( activate )
			ogreActivate( ogw, UGID_NAME );
	}
}

static void donewuser( struct ogwin *ogw )
{
	struct muser *n;

	n = LibAllocPooled( ulkey, sizeof(struct muser) );
	if( !n ) return;

	strcpy( n->u.net, "-- Neuer Eintrag --" );
	AddTail( (struct List *) &userlist, (struct Node *) n);
	ogreLVAddEntry( ogw, UGID_LV, n->u.net, TRUE, n );
	ogreLVRefresh( ogw, UGID_LV );
	edituser = GetNumEntries((struct List*)&userlist)-1;
}

static void dodelcurrentuser( struct ogwin *ogw )
{
	struct muser *mu=(struct muser*)GetEntry((struct List*)&userlist,edituser);

	if( mu )
	{
		Remove( (struct Node *) mu );
		ogreLVRemEntry( ogw, UGID_LV, edituser );
		ogreLVRefresh( ogw, UGID_LV );
		edituser = -1;
	}
}

static void saveuser( struct ogwin *ogw )
{
	if( edituser >= 0 )
	{
		struct muser *mu = ( struct muser * ) GetEntry( ( struct List * ) &userlist, edituser );

		ogreCopyStringValue( ogw, UGID_NAME, mu->u.net );
		ogreCopyStringValue( ogw, UGID_REAL, mu->u.realname );
		ogreCopyStringValue( ogw, UGID_COMMENT, mu->u.comment );
		ogreCopyStringValue( ogw, UGID_PHONE, mu->u.telefon );
		ogreCopyStringValue( ogw, UGID_POST, mu->u.adresse );
		ogreCopyStringValue( ogw, UGID_PGPID, mu->u.pgp_id );

		ogreSetFlags32( ogw, UGID_USEPGP, UF_PGP, &mu->u.flags );
	}
}

char *getuserpgpid( struct user *u )
{
	static char id[ 128 ];

	if( u->pgp_id[ 0 ] )
		strcpy( id, u->pgp_id );
	else
		sprintf( id, "%s <%s>", u->realname, u->net );

	return( id );
}

static void testuser( struct ogwin *ogw )
{
	if( edituser >= 0 )
	{
		struct muser *mu = ( struct muser * ) GetEntry( ( struct List * ) &userlist, edituser );
		if( mu )
		{
			int rc = getpubkey( getuserpgpid( &mu->u ), "T:mdtemp.pgp" );
			char exec[ 128 ];

			if( !rc )
			{
				mu->u.flags &= ~ UF_PGP;
				askreq( "Kein PGP-Key mit der ID\n%s\ngefunden.", "Ok", getuserpgpid( &mu->u ) );
			}
			else
			{
				mu->u.flags |= UF_PGP;
				sprintf( exec, "-kvc \"%s\" \"%s\"", getuserpgpid( &mu->u ), rc == 2 ? prefs.pgp_ring2 : prefs.pgp_ring1 );
				runpgp( exec, 0, 1 );
			} 
			doedituser( ogw, FALSE );
			DeleteFile( "T:mdtemp.pgp" );
		}
	}
}

static void dokeyreq( struct ogwin *ogw )
{
	if( edituser >= 0 )
	{
		struct muser *mu = ( struct muser * ) GetEntry( ( struct List * ) &userlist, edituser );
		if( mu )
		{
			sendshortmail(
				mu->u.net,
				"PGP-Keyrequest",
				"Automatisch erzeugte Key-Anforderung",
				NULL,
				"PGP", "REQUEST", 2
			);
		}
	}
}


static void editkeyuser( struct ogwin *ogw )
{
	if( edituser >= 0 )
	{
		struct muser *mu = ( struct muser * ) GetEntry( ( struct List * ) &userlist, edituser );
		if( mu )
		{
			int rc = getpubkey( getuserpgpid( &mu->u ), "T:mdtemp.pgp" );
			char exec[ 128 ];

			if( !rc )
			{
				mu->u.flags &= ~UF_PGP;
				askreq( "Kein PGP-Key mit der ID\n%s\ngefunden.", "Ok", getuserpgpid( &mu->u ) );
			}
			else
			{
				mu->u.flags |= UF_PGP;
				sprintf( exec, "-ke \"%s\" \"%s\"", getuserpgpid( &mu->u ), rc == 2 ? prefs.pgp_ring2 : prefs.pgp_ring1 );
				runpgp( exec, 0, 5 );
			} 
			doedituser( ogw, FALSE );
			DeleteFile( "T:mdtemp.pgp" );
		}
	}
}

void doulwin( void )
{
	struct ogwin *ogw;
	struct Window *iw;
	struct IntuiMessage *im;
	int    Done = FALSE;

	loaduserlist();
	sortuserlist();
	edituser = -1;

	ogw = ogreInitWindow( scr, WFLG_RMBTRAP, 0, "UserInnenliste" );

	ogreAddGroup( ogw, 0, OGFRAME_NONE, NULL );
	ogreAddList( ogw, 0, 0xff, NULL, UGID_LV, 50, 8, 0, NULL );
	ogreLVInit( ogw, UGID_LV );
	ul2ogl( ogw, UGID_LV );
	ogreAddButton( ogw, 1, 'n', "_Neu", UGID_ADD );
	ogreAddButton( ogw, 1, 'l', "_Löschen", UGID_DEL );

	ogreAddString( ogw, 2, 'u', "_Username:", UGID_NAME, "", 42, 256 );
	ogreAddString( ogw, 3, 0, "Realname:", UGID_REAL, "", 42, 40 );
	ogreAddString( ogw, 4, 0, "Kommentar:", UGID_COMMENT, "", 42, 40 );
	ogreAddString( ogw, 5, 0, "Telefon:", UGID_PHONE, "", 42, 32 );
	ogreAddString( ogw, 6, 0, "Post-Adresse:", UGID_POST, "", 42, 64 );
	ogreAddString( ogw, 7, 0, "PGP-Id:", UGID_PGPID, "", 42, 40 );

	ogreAddCheckbox( ogw, 8, 'p', "_PGP benutzen", UGID_USEPGP, 0 );
	ogreAddButton( ogw, 8, 't', "PGP-Key-_Test", UGID_PGP_TESTKEY );
	ogreAddButton( ogw, 8, 'k', "_Key editieren", UGID_PGP_EDITKEY );
	ogreAddButton( ogw, 8, 'r', "Key-_Request", UGID_PGP_KEYREQ );

	ogreAddButton( ogw, 9 | OGB_ONENTER, 'o', "_Ok", UGID_OK );
	ogreAddHelp( ogw, 9 );
	ogreAddButton( ogw, 9 | OGB_ONESC, 'a', "_Abbruch", UGID_CANCEL );

	ogreEnable( ogw, FALSE, UGID_NAME, UGID_REAL, UGID_COMMENT, UGID_PHONE, UGID_POST, UGID_PGPID, UGID_USEPGP,
		UGID_DEL, UGID_PGP_TESTKEY, UGID_PGP_KEYREQ, UGID_PGP_EDITKEY, 0 );

	iw = ogreOpenWindow( ogw );
	if( !iw )
		return;

	while( !Done )
	{
		im = ogreWaitIM( ogw );

		if( im->Class == IDCMP_GADGETHELP)
			showguidenum( "ulwin_gads", im->Code );
		else if( im->Class == IDCMP_GADGETUP )
		{
			switch( im->Code )
			{
				case UGID_OK:
					Done = 2;
					break;

				case UGID_CANCEL:
					Done = 1;
					break;

				case UGID_LV:
					edituser = ogreValue( ogw, UGID_LV );
					doedituser( ogw, im->Qualifier );
					break;

				case UGID_DEL:
					dodelcurrentuser( ogw );
					doedituser( ogw, FALSE );
					break;

				case UGID_ADD:
					donewuser( ogw );
					doedituser( ogw, TRUE );
					break;

				case UGID_PGP_TESTKEY:
					testuser( ogw );
					break;

				case UGID_PGP_EDITKEY:
					editkeyuser( ogw );
					break;

				case UGID_PGP_KEYREQ:
					dokeyreq( ogw );
					break;

				default:
					saveuser( ogw );
					break;

			}
		}
		ogreIMReply( ogw, im );

		ogreEnable( ogw, edituser >= 0, UGID_NAME, UGID_REAL, UGID_COMMENT, UGID_PHONE, UGID_POST, 
			UGID_DEL, 0 );

		ogreEnable( ogw, edituser >= 0 && pgpavail, UGID_USEPGP, UGID_PGPID, UGID_PGP_TESTKEY, UGID_PGP_KEYREQ, UGID_PGP_EDITKEY, 0 );
	}

	ogreExitWindow( ogw );

	freeuserlist( Done == 2 );
}
