/**************************************************************************

		|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
		|             PickCDID - Tool               |
		|            -----------------              |
		|                                           |
		|               Version 0.9                 |
		|___________________________________________|

	Autor	 : Martin Kresse [mak]
	Copyright: Freeware

   Was: Programm, das CDIDs eingelegter CDs aus einem Verzeichnis in
		ein anderes kopiert.

   Umgebung	: Maxon C++ light auf Amiga 12oo OS3.0 68o3o 2MB Chip 12MB Fast

   Status	: 1. Release mit ACDPlay 1.5

   Bugs		: keine bekannt


   Autor   Version   Datum      Veränderungen
  ------- --------- --------   ------------------------------------------
	mak		0.1		22.04.97	- Programmgerüst (Window+Gads und Timer...)
			0.2		23.04.97	- CD-Zeugs eingebaut
								- DiskFiles werden eingelesen und im LV angezeigt
								- Windowgröße ist jetzt veränderbar
			0.3		24.04.97	- ShowTitles() und OpenFile() eingefügt
			0.4		25.04.97	- Programm kopiert jetzt nicht vorhandene IDs
								- Parameter per Tooltypes
			0.9		26.04.97	- kosmetische Änderungen
								- Tastaturunterstützung
								- ShowMsgA() benutzt ReqToolsLib falls vorhanden
								- ToolType AUTOEJECT dazu

**************************************************************************/

static char prog_version[] = "\0$VER: PickCDID V0.9 ("__DATE2__")";


/*----- Includes ---------------< >-*/
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <libraries/gadtools.h>
#include <devices/timer.h>
#include <devices/scsidisk.h>

#include <clib/alib_protos.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/icon_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <wbstartup.h>
#include <string.h>
#include <stdio.h>

#include "CD-ROM.h"

/*----- globale Variablen ------< >-*/
struct Library *IntuitionBase = NULL;
struct Library *IconBase	  = NULL;
struct Library *GadToolsBase  = NULL;
struct Library *GfxBase		  = NULL;
struct Library *ReqToolsBase  = NULL;

#define GAD_LIST	0
#define GAD_DELETE	1
#define ANZ_GADS	2

struct Window		*window;
struct Gadget		*mygad[ANZ_GADS];
struct MsgPort		*timer_mp;
struct timerequest	*timereq;
struct CDxRequest	*cdx;

char *devicename, *destpath, *sourcepath;
ULONG unit = 0, lun = 0;
BOOL autoej = FALSE;

struct CDIDNode
{
	struct Node		cdid_Node;		/* ln_Name zeigt auf CD-ID */
	char			cdid_CDID[20];
};


/*----- interne Funktionen -----< >-*/
struct List *GetDirContents(char *dirname);
void ShowTitles(struct List *list, ULONG pos);
void DeleteTitle(struct List *list, ULONG item);

BOOL InitAll(char *progname);
void FreeAll(void);
BOOL InitTimer(void);
void FreeTimer(void);
void AddTimeRequest(ULONG micro);

BOOL OpenLibs(void);
void CloseLibs(void);
char *OpenFile(char * name);
void FreeList(List *list);
LONG FindNodeName(List *list, char *name);
Node *FindNode(List * list, ULONG number);

/*----- externe Funktionen -----< >-*/
#include "Quick.h"



/*------------------ main() -----------------------------------< >-*/
int main(int argc, char *argv[])
{
	struct Gadget *glist, *aktgad;
	struct IntuiMessage *imsg;
	struct Screen *screen;
	struct List	*idlist;

	APTR visualinfo;
	BOOL terminate = FALSE;
	UBYTE laststatus = AUDIO_STAT_NO_DISK;
	UWORD imsgcode, fontY;
	WORD lastitem = ~0;
	ULONG rc = RETURN_FAIL, imsgclass, seconds, lastseconds=0, micros, lastmicros=0;

	if (!OpenLibs())
	{
		CloseLibs();
		return(rc);
	}

	if (InitAll(argv[0]))
	{
		if (screen = LockPubScreen("Workbench"))
		{
			fontY = screen->Font->ta_YSize;

			if (visualinfo = GetVisualInfo(screen, TAG_END))
			{
				if (aktgad = CreateContext(&glist))
				{
					struct NewGadget ng = {	screen->WBorLeft + 4,		// ng_LeftEdge,
											screen->WBorTop+2*fontY+8,	// ng_TopEdge,
											192 - screen->WBorLeft - screen->WBorRight,	// ng_Width,
											8*fontY,			// ng_Height,
											"Known CDs",		// ng_GadgetText,
											NULL, 				// ng_TextAttr,
											GAD_LIST,			// ng_GadgetID,
											0,					// ng_Flags,
											visualinfo,			// ng_VisualInfo,
											NULL		};		// ng_UserData

					idlist = GetDirContents(destpath);
					mygad[GAD_LIST] = aktgad = CreateGadget(LISTVIEW_KIND, aktgad, &ng, GTLV_ShowSelected, FALSE, GTLV_Labels, idlist, GTLV_ScrollWidth, 2*fontY, TAG_END);

					ng.ng_GadgetID		= GAD_DELETE;
					ng.ng_TopEdge		+= ng.ng_Height+1;
					ng.ng_Width			= aktgad->Width;
					ng.ng_Height		= fontY+6;
					ng.ng_GadgetText	= "_Delete";
					mygad[GAD_DELETE] = aktgad = CreateGadget(BUTTON_KIND, aktgad, &ng, GT_Underscore, '_', GA_Disabled, IsListEmpty(idlist), TAG_END);

					if (window = OpenWindowTags(NULL,
							WA_Left,		220,
							WA_Top,			100,
							WA_Width,		200,
							WA_Height,		aktgad->TopEdge + aktgad->Height + 14,
							WA_Title,		"PickCDID V0.9",
							WA_Gadgets,		glist,
							WA_PubScreen,	screen,
							WA_Flags,		WFLG_SIZEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_SIZEBBOTTOM | WFLG_ACTIVATE,
							WA_IDCMP,		LISTVIEWIDCMP | BUTTONIDCMP | IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_NEWSIZE,
							WA_AutoAdjust,	TRUE,
							WA_MinWidth,	100,
							WA_MinHeight,	100,
							WA_MaxWidth,	~0,
							WA_MaxHeight,	~0,
							TAG_END))
					{
						GT_RefreshWindow(window, NULL);
						AddTimeRequest(10);

						while (!terminate)
						{
							Wait((1L << window->UserPort->mp_SigBit) | (1L << timer_mp->mp_SigBit));

							if (GetMsg(timer_mp))
							{
								/* Update wird fällig */
								CDUpdateA(cdx);
								if (cdx->cdx_AudioStatus != laststatus)
								{
									/* wurde CD eingelegt? */
									if (laststatus == AUDIO_STAT_NO_DISK)
									{
										char IDBuffer[20];
										ULONG i;
										strcpy(IDBuffer, "ID");
										strncat(IDBuffer, cdx->cdx_TOCData->CDID, 17);

										/* Diskfile der eingelegten CD nicht vorhanden? */
										if ((i = FindNodeName(idlist, IDBuffer)) == ~0)
										{
											char filename[256];
											char *file;

											strcpy(filename, sourcepath);
											AddPart(filename, IDBuffer, 255);

											/* Diskfile aus der Sammlung laden */
											if (file = OpenFile(filename))
											{
												BPTR fh;
												strcpy(filename, destpath);
												AddPart(filename, IDBuffer, 255);

												/* Diskfile ins Zielverzeichnis kopieren */
												if (fh = Open(filename, MODE_NEWFILE))
												{
													struct CDIDNode *tempnode;

													Write(fh, file+4, *(ULONG *)file);
													Close(fh);
													SetProtection(filename, FIBF_EXECUTE);

													/* neues Listview-Item dazu */
													if (tempnode = GetVecA(sizeof(struct CDIDNode), MEMF_PUBLIC | MEMF_CLEAR))
													{
														strncpy(tempnode->cdid_CDID, IDBuffer, 19);
														tempnode->cdid_Node.ln_Name = tempnode->cdid_CDID;
														GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Labels, ~0, TAG_END);
														AddTail(idlist, (struct Node *)tempnode);
														lastitem = i = FindNodeName(idlist, IDBuffer);
														GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Labels, idlist, GTLV_Selected, i, GTLV_MakeVisible, i, TAG_END);
														/* Liste nicht mehr leer? */
														if (i==0)
															GT_SetGadgetAttrs(mygad[GAD_DELETE], window, NULL, GA_Disabled, FALSE, TAG_END);
														if (autoej)
															CDEjectA(cdx, TRUE);
													}
												}
												FreeVec(file);
											}
											else DisplayBeep(NULL);
										}
										else
										{
											GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Selected, i, GTLV_MakeVisible, i, TAG_END);
											lastitem = i;
										}
									}
									laststatus = cdx->cdx_AudioStatus;
								}

								/* Damit immer ein Item selektiert ist */
								if (lastitem == ~0 && !IsListEmpty(idlist))
								{
									GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Selected, 0, TAG_END);
									lastitem = 0;
								}

								/* In 0,25s nächstes Update */
								AddTimeRequest(250000);
							}

							while (imsg = GT_GetIMsg(window->UserPort))
							{
								aktgad = (struct Gadget *)imsg->IAddress;
								imsgclass = imsg->Class;
								imsgcode = imsg->Code;
								seconds = imsg->Seconds;
								micros = imsg->Micros;

								GT_ReplyIMsg(imsg);

								switch(imsgclass)
								{
									case IDCMP_NEWSIZE:
										RemoveGList(window, glist, -1);
										FreeGadgets(glist);

										EraseRect(window->RPort,	window->BorderLeft, window->BorderTop,
																	window->Width  - window->BorderRight  - 1,
																	window->Height - window->BorderBottom - 1);
										RefreshWindowFrame(window);

										aktgad = CreateContext(&glist);

										ng.ng_LeftEdge	= window->BorderLeft + 4;
										ng.ng_TopEdge	= window->BorderTop + fontY + 7;
										ng.ng_Width		= window->Width - window->BorderLeft - window->BorderRight - 8;
										ng.ng_Height	= window->Height - window->BorderTop - window->BorderBottom - 2*fontY - 16;
										ng.ng_GadgetText= "Known CDs";
										ng.ng_GadgetID	= GAD_LIST;
										mygad[GAD_LIST] = aktgad = CreateGadget(LISTVIEW_KIND, aktgad, &ng, GTLV_ShowSelected, FALSE, GTLV_Labels, idlist, GTLV_ScrollWidth, 2*fontY, GTLV_Selected, lastitem, GTLV_MakeVisible, lastitem, TAG_END);

										ng.ng_TopEdge		+= (ng.ng_Height+aktgad->Height)/2 + 1;
										ng.ng_Width			= aktgad->Width;
										ng.ng_Height		= fontY+6;
										ng.ng_GadgetText	= "_Delete";
										ng.ng_GadgetID		= GAD_DELETE;
										mygad[GAD_DELETE] = aktgad = CreateGadget(BUTTON_KIND, aktgad, &ng, GT_Underscore, '_', GA_Disabled, IsListEmpty(idlist), TAG_END);

										AddGList(window, glist, ~0, -1, NULL);
										RefreshGList(glist, window, NULL, -1);
										GT_RefreshWindow(window, NULL);
										break;

									case IDCMP_GADGETUP:
										switch(aktgad->GadgetID)
										{
											case GAD_LIST:
												if (lastitem == imsgcode && DoubleClick(lastseconds, lastmicros, seconds, micros))
												{
													ShowTitles(idlist, lastitem);

													lastseconds = 0;
													lastmicros	= 0;
												}
												else
												{
													lastseconds = seconds;
													lastmicros	= micros;
													lastitem = imsgcode;
												}
												break;

											case GAD_DELETE:
												if (lastitem != ~0 && !IsListEmpty(idlist))
												{
													DeleteTitle(idlist, lastitem);
													/* Wenn unterstes Item eines LVs gelöscht wird rutscht das LV nach oben */
													if (lastitem >= ListLengthA(idlist))
														lastitem = ListLengthA(idlist)-1;
												}
										}
										break;

									case IDCMP_VANILLAKEY:
										switch (imsgcode)
										{
											case 13:	/* Return */
												ShowTitles(idlist, lastitem);
												break;
											case 32:	/* Space */
												if (!CDTestUnitA(cdx) || (cdx->cdx_Flags & SPECIALF_JUSTCLOSED))
													CDEjectA(cdx, TRUE);
												else
													CDEjectA(cdx, FALSE);
												break;
											case 'd':
											case 'D':
											case 127:	/* Delete */
												if (lastitem != ~0 && !IsListEmpty(idlist))
												{
													DeleteTitle(idlist, lastitem);
													if (lastitem >= ListLengthA(idlist))
														lastitem = ListLengthA(idlist)-1;
												}
												break;
											case 27:	/* ESC */
												terminate = TRUE;
										}
										break;

									case IDCMP_RAWKEY:
										if (lastitem != ~0 && !IsListEmpty(idlist))
										{
											switch (imsgcode)
											{
												case 0x4C:	/* Cursor hoch */
													if (lastitem > 0)
													{
														lastitem--;
														GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Selected, lastitem, GTLV_MakeVisible, lastitem, TAG_END);
													}
													break;
												case 0x4D:	/* Cursor runter */
													if (lastitem < ListLengthA(idlist)-1)
													{
														lastitem++;
														GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Selected, lastitem, GTLV_MakeVisible, lastitem, TAG_END);
													}
													break;
											}
										}
										break;

									case IDCMP_CLOSEWINDOW:
										terminate = TRUE;
										break;

									case IDCMP_REFRESHWINDOW:
										GT_BeginRefresh(window);
										GT_EndRefresh(window, TRUE);
								}
							}
						}
						CloseWindow(window);
						/* Damit nicht auf Antwort gewartet werden muß */
						if (!GetMsg(timer_mp))
						{
							AbortIO((struct IORequest *)timereq);
							WaitIO((struct IORequest *)timereq);
						}

						rc = RETURN_OK;
					}
					FreeGadgets(glist);
					FreeList(idlist);
				}
				FreeVisualInfo(visualinfo);
			}
			UnlockPubScreen(NULL, screen);
		}
		FreeAll();
	}

	CloseLibs();

	return rc;
}

/*------------------ GetDirContents() -------------------------< >-*/
struct List *GetDirContents(char *dirname)
{
	BPTR filelock;
	struct FileInfoBlock *fib;
	struct List *dirlist = NULL;

	if (filelock = Lock(dirname, SHARED_LOCK))
	{
		if (fib = (struct FileInfoBlock *)AllocDosObject(DOS_FIB, NULL))
		{
			if (Examine(filelock, fib) != DOSFALSE)
			{
				/* Directory-Test */
				if (fib->fib_DirEntryType >= 0 && fib->fib_DirEntryType != ST_SOFTLINK)
				{
					if (dirlist = GetVecA(sizeof(struct List), MEMF_PUBLIC | MEMF_CLEAR))
					{
						struct CDIDNode *tempnode;
						NewList(dirlist);

						while (ExNext(filelock, fib) != DOSFALSE)
						{
							/* Nur Files mit den Anfangsbuchstaben "ID" werden akzeptiert */
							if ((fib->fib_DirEntryType == ST_FILE || fib->fib_DirEntryType == ST_LINKFILE) && *(UWORD *)fib->fib_FileName == 0x4944)
							{
								if (tempnode = GetVecA(sizeof(struct CDIDNode), MEMF_PUBLIC | MEMF_CLEAR))
								{
									strncpy(tempnode->cdid_CDID, fib->fib_FileName, 20);
									tempnode->cdid_Node.ln_Name = tempnode->cdid_CDID;
									AddTail(dirlist, (struct Node *)tempnode);
								}
							}
						}
					}
				}
			}
			FreeDosObject(DOS_FIB, (APTR)fib);
		}
		UnLock(filelock);
	}

	return (dirlist);
}
/*------------------ ShowTitles() -----------------------------< >-*/
void ShowTitles(List *list, ULONG pos)
{
	struct Node *node;
	char filename[256];
	char *file;

	if (node = FindNode(list, pos))
	{
		strcpy(filename, destpath);
		AddPart(filename, node->ln_Name, 256);

		if (file = (char *)OpenFile(filename))
		{
			if (IntuitionBase->lib_Version >= 39)
				SetWindowPointer(window, WA_BusyPointer, TRUE, TAG_END);

			ShowMsgA("CD Info", "%s", file+4);

			if (IntuitionBase->lib_Version >= 39)
				SetWindowPointer(window, WA_BusyPointer, FALSE, TAG_END);

			FreeVec(file);
		}
	}
}
/*------------------ DeleteTitle() ----------------------------< >-*/
void DeleteTitle(struct List *list, ULONG item)
{
	char buffer[256];
	struct Node *node = FindNode(list, item);

	if (node)
	{
		strcpy(buffer, destpath);
		AddPart(buffer, node->ln_Name, 255);
		if (DeleteFile(buffer))
		{
			GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Labels, ~0, TAG_END);
			Remove(node);
			FreeVec(node);
			GT_SetGadgetAttrs(mygad[GAD_LIST], window, NULL, GTLV_Labels, list, TAG_END);
			if (IsListEmpty(list))
				GT_SetGadgetAttrs(mygad[GAD_DELETE], window, NULL, GA_Disabled, TRUE, TAG_END);
		}
	}
}

/*------------------ InitAll() --------------------------------< >-*/
BOOL InitAll(char *progname)
{
	if (devicename = GetVecA(32+256+256, MEMF_PUBLIC | MEMF_CLEAR))
	{
		struct DiskObject *dobj;
		destpath = devicename + 32;
		sourcepath = destpath + 256;

		/* Tooltypes auslesen */
		if (dobj = GetDiskObject(progname))
		{
			char **toolarray, *s;
			toolarray = dobj->do_ToolTypes;

			if (s = (char *)FindToolType((UBYTE **)toolarray, "DEVICE"))
				strncpy(devicename, s, 31);
			if (s = (char *)FindToolType((UBYTE **)toolarray, "SOURCEPATH"))
				strncpy(sourcepath, s, 255);
			if (s = (char *)FindToolType((UBYTE **)toolarray, "DESTPATH"))
				strncpy(destpath, s, 255);
			if (s = (char *)FindToolType((UBYTE **)toolarray, "AUTOEJECT"))
				if (!strcmp(s, "NO") || !strcmp(s, "no"))
					autoej = FALSE;
				else
					autoej = TRUE;
			if (s = (char *)FindToolType((UBYTE **)toolarray, "UNIT"))
				if (s[0] >= '0' && s[0] <= '7')
					unit = (ULONG)(s[0]-48);
			if (s = (char *)FindToolType((UBYTE **)toolarray, "LUN"))
				if (s[0] >= '0' && s[0] <= '7')
					lun = (ULONG)(s[0]-48);

			FreeDiskObject(dobj);
		}


		if (cdx = CDOpenDeviceA(devicename, unit, lun))
		{
			if (InitTimer())
			{
				return (TRUE);
			}
			CDCloseDeviceA(cdx);
		}
		FreeVec(devicename);
	}
	return (FALSE);
}
/*------------------ FreeAll() --------------------------------< >-*/
void FreeAll(void)
{
	FreeTimer();
	CDCloseDeviceA(cdx);
	FreeVec(devicename);
}
/*------------------ InitTimer() ------------------------------< >-*/
BOOL InitTimer(void)
{
	if (timer_mp = CreateMsgPort())
	{
		if (timereq = CreateIORequest(timer_mp, sizeof(struct timerequest)));
		{
			if (!OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *)timereq, 0L))
			{
				return (TRUE);
			}
			DeleteIORequest(timereq);
		}
		DeleteMsgPort(timer_mp);
	}

	return (FALSE);
}
/*------------------ FreeTimer() ------------------------------< >-*/
void FreeTimer(void)
{
	CloseDevice((struct IORequest *)timereq);
	DeleteIORequest(timereq);
	DeleteMsgPort(timer_mp);
}
/*------------------ AddTimeRequest() -------------------------< >-*/
void AddTimeRequest(ULONG micro)
{
	timereq->tr_node.io_Command = TR_ADDREQUEST;
	timereq->tr_time.tv_secs	= 0;
	timereq->tr_time.tv_micro	= micro;
	SendIO((struct IORequest *)timereq);
}

/*------------------ OpenLibs() -------------------------------< >-*/
BOOL OpenLibs(void)
{
	if (IntuitionBase=OpenLibrary("intuition.library",37))
	{
		if (IconBase=OpenLibrary("icon.library",37))
		{
			if (GadToolsBase=OpenLibrary("gadtools.library",37))
			{
				if (GfxBase=OpenLibrary("graphics.library",37))
				{
					ReqToolsBase=OpenLibrary("reqtools.library", 37);
					return(TRUE);
				}
			}
		}
	}

	return(FALSE);
}
/*------------------ CloseLibs() ------------------------------< >-*/
void CloseLibs(void)
{
	if (GfxBase)		CloseLibrary(GfxBase);
	if (GadToolsBase)	CloseLibrary(GadToolsBase);
	if (IconBase)		CloseLibrary(IconBase);
	if (IntuitionBase)	CloseLibrary(IntuitionBase);
}
/*------------------ OpenFile() -------------------------------< >-*/
char * OpenFile(char * name)
{
	BPTR filehandle;
	struct FileInfoBlock *fib;
	APTR buffer = NULL;

	/* Datei öffnen */
	if (filehandle = Open(name, MODE_OLDFILE))
	{
		if (fib = (struct FileInfoBlock *)AllocDosObject(DOS_FIB, NULL))
		{
			/* FileInfoblock auslesen, für Dateigröße */
			if (ExamineFH(filehandle, fib) == DOSTRUE)
			{
				if (fib->fib_Size)
				{
					/* Speicher für File, Filelänge und Nullbyte reservieren */
					if (buffer = (char *)GetVecA(fib->fib_Size+5, MEMF_PUBLIC | MEMF_CLEAR))
					{
						*(ULONG *)buffer = fib->fib_Size;
						/* Datei in Speicher schreiben */
						if (Read(filehandle, (char *)buffer+4, fib->fib_Size) != fib->fib_Size)
						{
							FreeVec(buffer);
							buffer = NULL;
						}
					}
				}
			}
			FreeDosObject(DOS_FIB, (APTR)fib);
		}
		/* Datei schließen */
		Close(filehandle);
	}
	return ((char *)buffer);
}
/*------------------ FreeList() -------------------------------< >-*/
void FreeList(List *list)
{
	if (list)
	{
		Node *temp_node, *next_temp_node;

		for (temp_node = list->lh_Head; temp_node->ln_Succ;)
		{
			next_temp_node = temp_node->ln_Succ;
			FreeVec(temp_node);
			temp_node = next_temp_node;
		}

		FreeVec(list);
	}
}
/*------------------ FindNodeName() ---------------------------< >-*/
LONG FindNodeName(List *list, char *name)
{
	register Node *node = list->lh_Head;
	register LONG i=0;

	for (node = list->lh_Head ; node->ln_Succ && strcmp(name, node->ln_Name) ; node = node->ln_Succ)
		i++;

	return (node->ln_Succ?i:~0);
}
/*------------------ FindNode() -------------------------------< >-*/
Node *FindNode(List * list, ULONG number)
{
	register Node *tempnode = list->lh_Head;
	ULONG i;

	for (i = 0; i < number; i++)
	{
		if (tempnode->ln_Succ)
			tempnode = tempnode->ln_Succ;
		else
			break;
	}

	return (tempnode->ln_Succ?tempnode:NULL);
}