[p900] obex_p900.c

  • From: Alfonso Martone <a.martone@xxxxxxxxxxx>
  • To: p900@xxxxxxxxxxxxx
  • Date: Sat, 20 Dec 2003 09:05:06 +0100

//
//  obex_p900.c   release 1   www.alfonsomartone.itb.it  December 2003
//
//      -- derived from irobex_palm3.c by Pontus Fuchs (see below)
//      -- placed under GNU GPL License (see below)
//
//      description:
//     slightly modified "irobex_palm3" utility to send a file to the
//     SonyEricsson P900 phone from Linux; the original "irobex_palm3"
//     is already good at sending to the P900; my modifications are
//     just a few hacks (enabling also the openobex bluetooth support)
//
//      usage example syntax:
//         obex_p900              waits for a file on infrared port
//         obex_p900 bt           waits for a file on bluetooth
//         obex_p900 filename     sends a file on infrared port
//         obex_p900 bt filename  sends a file on bluetooth connection
//
//      warning:
//      if you cannot send/receive files on bluetooth connection,
//      then you have to debug the openobex library, NOT this program
//      (because this simply asks to the openobex to use the bt stack)
//
//      more important warning:
//         this software, in receive-file mode,overwrites any existing
//         file of the same name of that sent without asking confirmat
//
//      compiling:
//         you need openobex library installed to compile this program
//         if you don't have it in your Linux distribution (I found it
//         in my SuSE 9.0, http://www.suse.com) then get it at
//         http://openobex.sf.net
//         compile with:
//            cc -Wall -O2 irobex_p900.c -o irobex_p900 -lopenobex
//            strip -s -R .comment -R .note irobex_p900
//
//      I used a number of files and documentation from openobex 1.0
//      package; this file is mainly derived from irobex_palm3.c,
//      from which original comments follow:
//
/*********************************************************************
 *                
 * Filename:      irobex_palm3.c
 * Version:       0.3
 * Description:   Demonstrates use of PUT command
 * Status:        Experimental.
 * Author:        Pontus Fuchs <pontus.fuchs@xxxxxxxxx>
 * Created at:    Tue Mar 23 09:44:56 1999
 * Modified at:   Sun Aug 13 09:25:40 PM CEST 2000
 * Modified by:   Pontus Fuchs <pontus.fuchs@xxxxxxxxx>
 * 
 *     Copyright (c) 1999, 2000 Ponts Fuchs, All Rights Reserved.
 *     
 *     This program is free software; you can redistribute it and/or 
 *     modify it under the terms of the GNU General Public License as 
 *     published by the Free Software Foundation; either version 2 of 
 *     the License, or (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the
 *     GNU General Public License 
 *     along with this program; if not, write to the Free Software 
 *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
 *     MA 02111-1307 USA
 *
 *
 *     The Palm 3 always send a HEADER_CREATORID (0xcf).
 *
 *     Start without arguments to receive a file.
 *     Start with filename as argument to send a file. 
 *     
 ********************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <openobex/obex.h>


#define HEADER_CREATOR_ID  0xcf

int safe_save_file(char *name, const uint8_t *buf, int len);

volatile int finished = 0;
volatile int last_rsp = OBEX_RSP_BAD_REQUEST;


/*
 * Function put_done()
 *
 *    Parse what we got from a PUT
 *
 */
void put_done(obex_object_t *object, obex_t *handle)
{
  obex_headerdata_t hv;
  uint8_t hi;
  int hlen;

  const uint8_t *body = NULL;
  int body_len = 0;
  char *name = NULL;
  char *namebuf = NULL;

  while(OBEX_ObjectGetNextHeader(handle, object, &hi, &hv, &hlen))
  {
    switch(hi)
    {

    case OBEX_HDR_BODY:
      body = hv.bs;
      body_len = hlen;
      break;

    case OBEX_HDR_NAME:
      if( (namebuf = malloc(hlen / 2)))
      {
        OBEX_UnicodeToChar(namebuf, hv.bs, hlen);
        name = namebuf;
      }
      break;

    case OBEX_HDR_LENGTH:
      printf("\nsize = %d bytes\n", hv.bq4);
      break;

    case OBEX_HDR_TYPE:
      printf("type = %s\n", hv.bs);
      break;

    case OBEX_HDR_TIME:
      printf("date = %s\n", hv.bs);
      break;

    case HEADER_CREATOR_ID:
      printf("creator ID = 0x%x\n", hv.bq4);
      break;

    default:
      printf("%s(): skipped header 0x%02x\n", __FUNCTION__, hi);
    }
  }
  if(!body)  {
    printf("%s(): got a PUT without a body\n", __FUNCTION__);
    return;
  }
  if(!name)  {
    name = "unknown_object.bin";
    printf("-- warning: no filename received; changing to %s\n", 
name);
  }
  safe_save_file(name, body, body_len);
  free(namebuf);
}


/*
 * Function server_indication()
 *
 * Called when a request is about to come or has come.
 *
 */
void server_request(obex_object_t *object, obex_t *handle, int event, 
int cmd)
{
  switch(cmd)  {
  case OBEX_CMD_SETPATH:
    printf("Received SETPATH command\n");
    OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
    break;
  case OBEX_CMD_PUT:
    OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
    put_done(object, handle);
    break;
  case OBEX_CMD_CONNECT:
    OBEX_ObjectSetRsp(object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
    break;
  case OBEX_CMD_DISCONNECT:
    OBEX_ObjectSetRsp(object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
    break;
  default:
    printf("%s() Denied %02x request\n", __FUNCTION__, cmd);
    OBEX_ObjectSetRsp(object, OBEX_RSP_NOT_IMPLEMENTED, 
OBEX_RSP_NOT_IMPLEMENTED);
    break;
  }
  return;
}


/*
 * Function obex_event()
 *
 *    Called by the obex-layer when some event occurs.
 *
 */
void obex_event(obex_t *handle, obex_object_t *object, int mode,
                int event, int obex_cmd, int obex_rsp)
{
  switch(event)
  {

  case OBEX_EV_PROGRESS:
    printf(".");
    fflush(stdout);
    break;

  case OBEX_EV_REQDONE:
    if(mode == OBEX_CLIENT)
    {
      last_rsp = obex_rsp;
      finished = 1;
    }
    else
    {
      if(obex_cmd==OBEX_CMD_DISCONNECT) finished = 1;
    }
    break;

  case OBEX_EV_REQHINT:
    /* Comes BEFORE the lib parses anything. */
    switch(obex_cmd) {
    case OBEX_CMD_PUT:
    case OBEX_CMD_CONNECT:
    case OBEX_CMD_DISCONNECT:
      OBEX_ObjectSetRsp(object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
      break;
    default:
      OBEX_ObjectSetRsp(object, OBEX_RSP_NOT_IMPLEMENTED, 
OBEX_RSP_NOT_IMPLEMENTED);
      break;
    }
    break;

  case OBEX_EV_REQ:
    /* Comes when a server-request has been received. */
    server_request(object, handle, event, obex_cmd);
    break;

  case OBEX_EV_LINKERR:
    printf("Link broken (this does not have to be an error)!\n");
    finished = 1;
    break;

  default:
    printf("Unknown event 0x%x!\n", event);
    break;
  }
}

/*
 * Function wait_for_rsp()
 *
 *    Wait for a request to finish!
 *
 * Timeout set to 10s. Should be good enough for most transport.
 */
int wait_for_rsp(obex_t *handle)
{
  int ret;

  while(!finished)
  {
    ret = OBEX_HandleInput(handle, 10);
    if(ret<0) return ret;
  }
  return last_rsp;
}


/*
 * Function do_sync_request()
 *
 *    Execute an OBEX-request synchronously.
 */
int do_sync_request(obex_t *handle, obex_object_t *object, int async)
{
  int ret;
  OBEX_Request(handle, object);
  ret = wait_for_rsp(handle);
  finished = 0;
  return ret;
}


int get_filesize(const char *filename)
{
  struct stat stats;
  stat(filename, &stats);
  return (int) stats.st_size;
}


//
// Read a file and alloc a buffer for it
//
uint8_t* easy_readfile(const char *filename, int *file_size)
{
  int actual;
  int fd;
  uint8_t *buf;

  *file_size = get_filesize(filename);
  printf("%s (%d bytes)\n", filename, *file_size);

  fd = open(filename, O_RDONLY, 0);
  if (fd == -1) {
    return NULL;
  }
  
  if(! (buf = malloc(*file_size)) )  {
    return NULL;
  }

  actual = read(fd, buf, *file_size);
  close(fd); 

  *file_size = actual;
  return buf;
}


obex_object_t *build_object_from_file(obex_t *handle, const char 
*filename)
{
  obex_headerdata_t hdd;
  uint8_t unicode_buf[200];
  int namebuf_len;
  obex_object_t *object;
  int file_size;
  uint8_t *buf;

  buf = easy_readfile(filename, &file_size);
  if(buf == NULL) return NULL;

  object = OBEX_ObjectNew(handle, OBEX_CMD_PUT);

  namebuf_len = OBEX_CharToUnicode(unicode_buf, filename, 
sizeof(unicode_buf));

  hdd.bs = unicode_buf;
  OBEX_ObjectAddHeader(handle, object, OBEX_HDR_NAME,
        hdd, namebuf_len, 0);

  hdd.bq4 = file_size;
  OBEX_ObjectAddHeader(handle, object, OBEX_HDR_LENGTH,
        hdd, sizeof(uint32_t), 0);

  hdd.bs = buf;
  OBEX_ObjectAddHeader(handle, object, OBEX_HDR_BODY,
        hdd, file_size, 0);

  free(buf);
  return object;
}


/*
 * Function safe_save_file ()
 *
 *    save a file and write a message when it was done
 *
 */
int safe_save_file(char *filename, const uint8_t *buf, int len)
{
  int fd, actual;
  printf("file = %s\n", filename);
  fd = open(filename, O_RDWR | O_CREAT, DEFFILEMODE);
  if(fd<0)
  {
    perror( filename);
    return -1;
  }
  actual = write(fd, buf, len);
  close(fd);
  printf( "wrote: %s (%d bytes)\n", filename, actual);
  return actual;
}



int main(int argc, char *argv[])
{
  int layer=OBEX_TRANS_IRDA;
  obex_object_t *object;
  obex_t *handle = NULL;

  int ret, exitval = EXIT_SUCCESS, arg=1;
  char *port="on IrDA port";

  fprintf(stderr, "obex_p900: ");
  fflush(stderr);

  if((argc>1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], 
"-h"))) ||
    argc>4)
  {
    fprintf(stderr, "usage is: %s [bt] [filename_to_send]\n", 
argv[0]); 
    return 1;
  }

  if(argc>1 && !strcasecmp(argv[1], "bt"))
  {
    layer=OBEX_TRANS_BLUETOOTH;
    port="via BlueTooth";
    arg=2;
  }

  handle=OBEX_Init(layer, obex_event, 0);

  if(argc==arg)
  {
    fprintf(stderr, "waiting a file %s\n", port);
    fflush(stderr);
    IrOBEX_ServerRegister(handle, "OBEX");

    while(!finished) OBEX_HandleInput(handle, 1);
    return exitval;
  }

  printf("send ");
  ret = IrOBEX_TransportConnect(handle, "OBEX");
  if(ret<0)
  {
    fprintf(stderr, "-- sorry, unable to connect!\n");
    return EXIT_FAILURE;
  }

  object = OBEX_ObjectNew(handle, OBEX_CMD_CONNECT);
  ret = do_sync_request(handle, object, 0);

  if ((last_rsp != OBEX_RSP_SUCCESS) || (ret < 0))
  {
    printf("-- sorry, unable to send!\n");
    return EXIT_FAILURE;
  }

  if ((object = build_object_from_file(handle, argv[arg])))
  {
    ret = do_sync_request(handle, object, 0);
    if ((last_rsp != OBEX_RSP_SUCCESS) || (ret < 0))
      exitval = EXIT_FAILURE;
  }
  else
    exitval = EXIT_FAILURE;

  object = OBEX_ObjectNew(handle, OBEX_CMD_DISCONNECT);
  ret = do_sync_request(handle, object, 0);

  if ((last_rsp != OBEX_RSP_SUCCESS) || (ret < 0)) exitval = 
EXIT_FAILURE;

  printf("-- %s\n", exitval==EXIT_SUCCESS ? "OK" : 
"error: PUT failed\n");

  return exitval;
}

// ---


Other related posts:

  • » [p900] obex_p900.c