// // 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; } // ---