// irda.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#define  MAX_ATTRIB_LEN  (64)

CHAR* Hint1[]={"PnP",
	           "PDA",
               "Computer",
			   "Printer",
			   "Modem",
			   "Fax",
			   "Lan",
			   "Extension"
};

CHAR* Hint2[]={"Phone",
               "File server",
			   "IrCOMM",
			   "Message",
			   "HTTP",
			   "OBEX",
			   "Unknown1",
			   "Extension"
};

char* Classes[]={"IrDA:IrCOMM",
                 "IrDA:IrCOMM",
                 "OBEX:IrXfer",
                 "OBEX",
                 "JetSend",
				 "IrNetv1",
				 "IrModem",
                 "IrLAN",
				 "IrLPT",
				 "IrLPT",
                 "IrTranPv1"
};

char* Attributes[]={"IrDA:TinyTP:LsapSel",
                    "IrDA:IRLMP:LsapSel",
                    "IrDA:TinyTP:LsapSel",
                    "IrDA:TinyTP:LsapSel",
                    "IrDA:TinyTP:LsapSel",
                    "IrDA:TinyTP:LsapSel",
                    "IrDA:TinyTP:LsapSel",
                    "IrDA:TinyTP:LsapSel",
                    "IrDA:IrLMP:LsapSel",
                    "IrDA:IrLMP:lsapSel",
                    "IrDA:TinyTP:LsapSel"
};

typedef enum {
	CLASS_IRCOMM,
	CLASS_OBEX,
	CLASS_Netv1,
	CLASS_IrModem
} IRDA_CLASSES;

int
QueryIASForBinaryData(
    SOCKET   QuerySock,
    u_char  *pirdaDeviceID,
    char    *pClassName,
    char    *pAttribute,
	BYTE    *Buffer,
	ULONG   *BufferLength
	)

{
    IAS_QUERY   IASQuery;
	int         QueryLength=sizeof(IASQuery);
    int         Result;

	ZeroMemory(&IASQuery,sizeof(IASQuery));

    lstrcpyA(
		IASQuery.irdaClassName,
		pClassName
		);

	lstrcpyA(
		IASQuery.irdaAttribName,
		pAttribute
		);

	CopyMemory(
		&IASQuery.irdaDeviceID[0],
		pirdaDeviceID,
		4
		);


	Result=getsockopt(
		QuerySock,
		SOL_IRLMP,
		IRLMP_IAS_QUERY,
		(char*)&IASQuery,
		&QueryLength
		);

	if (Result == SOCKET_ERROR) {

		return Result;

	}

    if (IASQuery.irdaAttribType != IAS_ATTRIB_OCTETSEQ) {

		return SOCKET_ERROR;
	}

    if (IASQuery.irdaAttribute.irdaAttribOctetSeq.Len > *BufferLength) {

		return SOCKET_ERROR;
	}

	CopyMemory(
		Buffer,
        &IASQuery.irdaAttribute.irdaAttribOctetSeq.OctetSeq[0],
        IASQuery.irdaAttribute.irdaAttribOctetSeq.Len
		);

	*BufferLength=IASQuery.irdaAttribute.irdaAttribOctetSeq.Len;

    return 0;
}


int
QueryIASForInteger(SOCKET   QuerySock,
                   u_char  *pirdaDeviceID,
                   char    *pClassName,
                   char    *pAttribute,
                   int     *pValue)
{
    BYTE        IASQueryBuff[sizeof(IAS_QUERY) - 3 + MAX_ATTRIB_LEN];
    int          IASQueryLen = sizeof(IASQueryBuff);
    PIAS_QUERY  pIASQuery   = (PIAS_QUERY) &IASQueryBuff;


    RtlCopyMemory(&pIASQuery->irdaDeviceID[0], pirdaDeviceID, 4);

	lstrcpyA(&pIASQuery->irdaClassName[0],  pClassName);
	lstrcpyA(&pIASQuery->irdaAttribName[0], pAttribute);


    if (getsockopt(QuerySock, SOL_IRLMP, IRLMP_IAS_QUERY,
                   (char *) pIASQuery, &IASQueryLen) == SOCKET_ERROR)
    {
#if 0
        printf("IRMON: IAS Query [\"%s\",\"%s\"] failed\n",
                 pIASQuery->irdaClassName,
                 pIASQuery->irdaAttribName
				 );
#endif                 
        return SOCKET_ERROR;
    }

    if (pIASQuery->irdaAttribType != IAS_ATTRIB_INT)
    {
        printf("IRMON: IAS Query [\"%s\",\"%s\"] irdaAttribType not int (%d)\n",
                 pIASQuery->irdaClassName,
                 pIASQuery->irdaAttribName,
               pIASQuery->irdaAttribType
			   );
        return SOCKET_ERROR;
    }

    *pValue = pIASQuery->irdaAttribute.irdaAttribInt;

    return(0);
}

int
QueryIASForString(SOCKET    QuerySock,
                  u_char   *pirdaDeviceID,
                  char     *pClassName,
                  char     *pAttribute,
                  char     *pValue,
                  int      *pValueLen)          // including trailing NULL
{
    BYTE        IASQueryBuff[sizeof(IAS_QUERY) - 3 + MAX_ATTRIB_LEN];
    int         IASQueryLen = sizeof(IASQueryBuff);
    PIAS_QUERY  pIASQuery   = (PIAS_QUERY) &IASQueryBuff;


    RtlCopyMemory(&pIASQuery->irdaDeviceID[0], pirdaDeviceID, 4);

	lstrcpyA(&pIASQuery->irdaClassName[0],  pClassName);
	lstrcpyA(&pIASQuery->irdaAttribName[0], pAttribute);

 
    if (getsockopt(QuerySock, SOL_IRLMP, IRLMP_IAS_QUERY,
                   (char *) pIASQuery, &IASQueryLen) == SOCKET_ERROR)
    {
//        DEBUGMSG(("IRMON: IAS Query [\"%s\",\"%s\"] failed %ws\n",
//                 pIASQuery->irdaClassName,
//                 pIASQuery->irdaAttribName,
//                 GetLastErrorText()));
        return SOCKET_ERROR;
    }

    if (pIASQuery->irdaAttribType != IAS_ATTRIB_STR)
    {
//        DEBUGMSG(("IRMON: IAS Query [\"%s\",\"%s\"] irdaAttribType not string (%d)\n",
//                 pIASQuery->irdaClassName,
//                 pIASQuery->irdaAttribName,
//                 pIASQuery->irdaAttribType));
        return SOCKET_ERROR;
    }

    if (pIASQuery->irdaAttribute.irdaAttribUsrStr.CharSet != LmCharSetASCII)
    {
//        DEBUGMSG(("IRMON: IAS Query [\"%s\",\"%s\"] CharSet not ASCII (%d)\n",
//                 pIASQuery->irdaClassName,
//                 pIASQuery->irdaAttribName,
//                 pIASQuery->irdaAttribute.irdaAttribUsrStr.CharSet));
        return SOCKET_ERROR;

    }

    // set ValueLen to data bytes to copy, allow room for NULL
    if (pIASQuery->irdaAttribute.irdaAttribUsrStr.Len + 1 >= (unsigned) *pValueLen)
    {
        // allow room for NULL
        (*pValueLen)--;
    }
    else
    {
        *pValueLen = pIASQuery->irdaAttribute.irdaAttribUsrStr.Len;
    }

    RtlCopyMemory(pValue, pIASQuery->irdaAttribute.irdaAttribUsrStr.UsrStr, *pValueLen);

    // append NULL
    pValue[(*pValueLen)++] = 0;

    return(0);
}


int __cdecl main(int argc, char* argv[])
{

	SOCKET  SocketHandle=INVALID_SOCKET;
    WORD        WSAVerReq = MAKEWORD(2,0);
    WSADATA     WSAData;
    INT         Result;
    UCHAR       Temp[4096];
    PDEVICELIST DeviceList=(PDEVICELIST)Temp;
    int         DeviceListSize=sizeof(Temp);
    UINT        i;

    Result=WSAStartup(
        WSAVerReq,
        &WSAData
        );

    if (Result != 0) {

        printf("WSAStartUp() Failed %d\n",Result);

        goto CleanUp;
    }

	SocketHandle=socket(
        AF_IRDA,
        SOCK_STREAM,
        0
        );

    if (SocketHandle == INVALID_SOCKET) {

        printf("socket() faled %d\n",WSAGetLastError());
    }


    Result=getsockopt(
        SocketHandle,
        SOL_IRLMP,
        IRLMP_ENUMDEVICES,
        (char*)DeviceList,
        &DeviceListSize
        );

    if (Result == SOCKET_ERROR) {

        goto CleanUp;
    }

	printf("\n%d Irda devices found\n\n",DeviceList->numDevice);

    for (i=0; i< DeviceList->numDevice; i++) {

        PIRDA_DEVICE_INFO    DeviceInfo=&DeviceList->Device[i];
        PULONG               DeviceId=(PULONG)&DeviceInfo->irdaDeviceID;
		int                  LsapSel=-1;
		UINT                 j;
		int                  k;

        if ((DeviceInfo->irdaCharSet == 0xff)) {

		    wprintf(L"Device Name(UNICODE): %s\n",&DeviceInfo->irdaDeviceName[0]);

		} else {

            printf("Device Name(ANSI): %s\n",&DeviceInfo->irdaDeviceName[0]);
		}

		printf("Hints:\n");

		for (j=0; j<7; j++) {

			if ( DeviceInfo->irdaDeviceHints1 & (1 << j)) {
				printf("\t%s\n",Hint1[j]);
            }   
        }


		for (j=0; j<7; j++) {

			if ( DeviceInfo->irdaDeviceHints2 & (1 << j)) {
				printf("\t%s\n",Hint2[j]);
            }   
        }

        printf("\nDoing IAS queries\n");

        for (j=0; j<sizeof(Classes)/sizeof(char*); j++) {

            Result=QueryIASForInteger(
			    SocketHandle,
			    &DeviceInfo->irdaDeviceID[0],
                Classes[j],
			    Attributes[j],
			    &LsapSel
			    );

            if (Result == 0) {

                printf("\tResult for %13s -- %s : %d\n",Classes[j],Attributes[j],LsapSel);

		    }
		}

        if ((DeviceInfo->irdaDeviceHints2 & 4) || (DeviceInfo->irdaDeviceHints1 & LM_HB1_Printer)) {
 
			BYTE   Buffer[4096];
			ULONG  BufferLength=sizeof(Buffer);
            CHAR   InstanceName[256];
            int    InstanceLength;

            printf("\nChecking for IrComm Parameters\n");

            Result=QueryIASForBinaryData(
				SocketHandle,
                &DeviceInfo->irdaDeviceID[0],
                Classes[0],
			    "Parameters",
				&Buffer[0],
				&BufferLength
				);

			if (Result == 0) {

				ULONG   k;

				for (k=0; k < BufferLength; ) {

					switch (Buffer[k]) {

			    		case 0:
							printf("\tServiceType- %s, %s, %s, %s\n",
								Buffer[k+2] & 1 ? "3 Wire raw" : "",
                                Buffer[k+2] & 2 ? "3 Wire" : "",
                                Buffer[k+2] & 4 ? "9 Wire" : "",
                                Buffer[k+2] & 8 ? "Centronics" : ""
				    			);
							break;

						case 1:

							printf("\tPort Type- %s, %s\n",
								Buffer[k+2] & 1 ?  "Serial" : "",
                                Buffer[k+2] & 2 ?  "Parallel" : ""
					    		);

							break;

						case 2:

							printf("\tPort Name- %s\n",&Buffer[k+2]);
							break;

						default:

                            printf("\tPI=%x, pl=%d\n",Buffer[k],Buffer[k+1]);
							break;

					}

					k+=Buffer[k+1]+2;

                }
        	}

            InstanceLength=sizeof(InstanceName);

            Result=QueryIASForString(
				SocketHandle,
                &DeviceInfo->irdaDeviceID[0],
                Classes[0],
			    "IrDA:IrLMP:InstanceName",
				&InstanceName[0],
				&InstanceLength
				);

			if (Result == 0) {

                printf("\tInstanceName: %s\n",InstanceName);
			}

        }
        if (1) {
        //if (DeviceInfo->irdaDeviceHints1 & LM_HB1_PnP) {

			CHAR    DeviceId[100];
			int     BufferSize=sizeof(DeviceId);
			int     CompatIds=0;

            printf("\nChecking PnP parameters\n");

            Result=QueryIASForString(
			    SocketHandle,
			    &DeviceInfo->irdaDeviceID[0],
                "PnP",
			    "Name",
                DeviceId,
				&BufferSize
				);

			if (Result == 0) {

				printf("\tName: %s\n",DeviceId);
			}


            BufferSize=sizeof(DeviceId);

            Result=QueryIASForString(
			    SocketHandle,
			    &DeviceInfo->irdaDeviceID[0],
                "PnP",
			    "Manufacturer",
                DeviceId,
				&BufferSize
				);

			if (Result == 0) {

				printf("\tManufactured by: %s\n",DeviceId);
			}


            BufferSize=sizeof(DeviceId);


            Result=QueryIASForString(
			    SocketHandle,
			    &DeviceInfo->irdaDeviceID[0],
                "PnP",
			    "DeviceID",
                DeviceId,
				&BufferSize
				);

			if (Result == 0) {

				printf("\tPnP device id is %s\n",DeviceId);
			}

            Result=QueryIASForInteger(
			    SocketHandle,
			    &DeviceInfo->irdaDeviceID[0],
                "PnP",
			    "CompCnt",
			    &CompatIds
				);

			if (Result == 0) {

				printf("\tDevice has %d compatible ids\n",CompatIds);
			}


			for (k=0; k<CompatIds; k++) {

                CHAR    Attribute[100];

				wsprintfA(Attribute,"Comp#%02d",k+1);
 
                BufferSize=sizeof(DeviceId);

                Result=QueryIASForString(
			        SocketHandle,
			        &DeviceInfo->irdaDeviceID[0],
                    "PnP",
			        Attribute,
                    DeviceId,
				    &BufferSize
				    );

			    if (Result == 0) {

				    printf("\tCompatible id for %s, device id is %s\n",Attribute,DeviceId);

				} else {

   				    printf("\tcould not get Compatible id for %s\n",Attribute);
				}


            }

		}


		printf("\n");
		

    }








CleanUp:


	
	return 0;
}