/*
 * Copyright (c) 2001 Tommy Bohlin <tommy@gatespace.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/* dumpobex.c
 */

#include <obexformat.h>

#include <stdio.h>
#include <unistd.h>

char *hiname[] = {
    "count",
    "name",
    "type",
    "length",
    "date",
    "description",
    "target",
    "http",
    "body",
    "end-of-body",
    "who",
    "connection-id",
    "app-parameters",
    "auth-challenge",
    "auth-response",
    "class"
};

int main(int argc, char** argv)
{
  int hi,c1,c2,len;
  int raw=0;
  int usage=0;
  char* file=0;

  while((c1=getopt(argc,argv,"rf:h"))!=-1) {
    switch(c1) {
    case 'r': raw=1;
    case 'f': file=optarg; break;
    case 'h': usage=1; break;
    case '?': usage=1; break;
    }
  }

  if(usage) {
    fprintf(stderr,"Dump the body of an OBEX file\n");
    fprintf(stderr,"Usage: %s [-r] [-f file]\n",argv[0]);
    return 0;
  }

  if(file && !freopen(file,"r",stdin)) {
    fprintf(stderr,"Can't open input file\n");
    return -1;
  }

  while((hi=getchar())!=EOF) {
    switch(hi&TYPE_MASK) {
    case TYPE_UNICODE:
    case TYPE_BYTES:
      c1=getchar();
      c2=getchar();
      if(c1==EOF || c2==EOF) {
	fprintf(stderr,"End of file in header!\n");
	return -1;
      }
      len=((c1<<8)|c2)-3;
      if(len<0) {
	fprintf(stderr,"Bad header length!\n");
	return -2;
      }
      break;
    case TYPE_INT1:
      len=1;
      break;
    case TYPE_INT4:
      len=4;
      break;
    }
    if(raw){
	unsigned int i;
	if ((hi&~TYPE_MASK)<sizeof(hiname)/sizeof(hiname[0]))
	    printf("%s\t", hiname[hi&~TYPE_MASK]);
	else
	    printf("[%d]\t", hi&~TYPE_MASK);
	switch(hi&TYPE_MASK) {
	case TYPE_UNICODE:
	    printf("unicode: ``");
	    while (len>0) {
		c1=getchar();
		c2=getchar();
		len -= 2;
		if(c1==EOF || c2==EOF) {
		    fprintf(stderr,"End of file in unicode!\n");
		    return -1;
		}
		i=((c1<<8)|c2);
		if (i==0 && len == 0)
		    continue;
		printf("%c",
		       (i>=0x20 && i<0x7f) || (i>=0xa0 && i<0xff) ? i : '.');
	    }
	    printf("´'\n");
	    len = 0;
	    break;
	case TYPE_BYTES:
	    printf("%d bytes\n", len);
	    break;
	case TYPE_INT1:
	    i = getchar();
	    if (i==EOF) {
		fprintf(stderr,"End of file in int1!\n");
		return -1;
	    }
	    printf("int1: %d / 0x%02x / %c\n", i, i,
		   (i>=0x20 && i<0x7f) || (i>=0xa0 && i<0xff) ? i : '.');
	    --len;
	    break;
	case TYPE_INT4:
	    i = 0;
	    while (len--) {
		c1=getchar();
		if (c1==EOF) {
		    fprintf(stderr,"End of file in int4!\n");
		    return -1;
		}
		i = (i<<8) | c1;
	    }
	    printf("int4: %u / 0x%08x / ", i, i);
	    for (c1=24; c1>=0; c1-=8) {
		c2 = (i>>c1) & 0xff;
		printf("%c", 
		       (c2>=0x20 && c2<0x7f) || (c2>=0xa0 && c2<0xff)
		       ? c2 : '.');
	    }
	    printf("\n");
	    len = 0;
	    break;
	default:
	    printf("unknown[%d]: %d bytes)\n", hi&TYPE_MASK, len);
	    break;
	}
	fseek(stdin,len,SEEK_CUR);
    }
    else {
	if((hi==(TYPE_BYTES|HI_BODY)) || (hi==(TYPE_BYTES|HI_END_OF_BODY))) {
	    char buf[1024];
	    while(len>0) {
		int k=len<sizeof buf ? len : sizeof buf;
		if(fread(buf,1,k,stdin)!=k) {
		    perror("Read error");
		    return -3;
		}
		if(fwrite(buf,1,k,stdout)!=k) {
		    perror("Write error");
		    return -4;
		}
		len-=k;
	    }
	} else {
	    fseek(stdin,len,SEEK_CUR);
	}
    }
  }

  return 0;
}
