Logo Search packages:      
Sourcecode: affix version File versions

btobex.c

/* 
   Affix - Bluetooth Protocol Stack for Linux
   Copyright (C) 2001 Nokia Corporation
   Dmitry Kasatkin <dmitry.kasatkin@nokia.com>

   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.
*/

/*
   $Id: btobex.c,v 1.17 2003/04/15 14:54:49 kds Exp $

   OBEX server application for Affix

*/

#include <affix/config.h>

#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <getopt.h>

#include <dirent.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>

//#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>

#include <stdint.h>

#include <openobex/obex.h>

#include <affix/btcore.h>
#include <affix/obex.h>

char  *obex_root_path = NULL;

char *file_base_name(char *path)
{
      char *pos = strrchr(path, '/');
      return pos ? pos + 1 : path;
}

int change_dir(char *new_dir, int mode)
{
      char  new_path[PATH_MAX + 1], root_path[PATH_MAX + 1];
      char  last_comp[NAME_MAX + 1] = {0, };
      int   create_dir = 0;
      char  *p;

      if (new_dir == NULL || new_dir[0] == '\0')
            return -1;

      DBPRT("Changing directory to: [%s]\n", new_dir);

      if (realpath(new_dir, new_path) == NULL) {
            if ((mode & CHDIR_CREATE_IF_NOT_EXIST) && errno == ENOENT) {
                  /*
                   * in case we want to create a non existent directory
                   * we should check the validity of the path without the last component
                   * so save the last component and strip it off
                   * don't strip the last component if it's ".." because this should be
                   * taken into account when checking against obex_root_path..
                   */
                  char  buf[PATH_MAX + 1];
                  strcpy(buf, new_dir);
                  if ((p = strrchr(buf, '/')) == NULL)
                        p = buf;
                  else
                        p++;
                  if (strcmp(p, "..") != 0) {
                        strcpy(last_comp, p);
                        if (p == buf)
                              strcpy(buf, "./");
                        else
                              *p = '\0';
                  }
                  if (realpath(buf, new_path)) {
                        strcat(new_path, "/");
                        strcat(new_path, last_comp);
                  } else {
                        if (!(mode & CHDIR_CREATE_RECURSIVE))
                              return -1;
                        strcpy(new_path, new_dir);
                  }
                  create_dir = 1;
            } else
                  return -1;
      }
      
      BTINFO("Creating: %s, create: %s\n", new_path, create_dir?"yes":"no");
      if (!realpath(obex_root_path, root_path) || strncmp(new_path, root_path, strlen(root_path)) != 0)
            return -1;

      if (mode & CHDIR_CHECK_ONLY)
            return 0;
                  
      if (create_dir)   {
            int   err;
            if (mode & CHDIR_CREATE_RECURSIVE)
                  err = rmkdir(new_path, 0700);
            else
                  err = mkdir(new_path, 0700);
            if (err && errno != EEXIST)
                  return -1;
      }
      if (chdir(new_path) != 0)
            return -1;
            
      return 0;
}


int btobex_put(obexsrv_t *srv, char *file, char *name, char *type, int flags)
{
      char  *p;
      int   fd;

      // if path contains folders check if it is valid
      if ((p = strrchr(name, '/')) != NULL) {
            char  dir[PATH_MAX + 1];
            
            strncpy(dir, name, p - name);
            dir[p - name] = '\0';
            if (change_dir(dir, CHDIR_CHECK_ONLY) != 0) {
                  BTERROR(" Invalid path: %s", dir);
                  return -1;
            }
      }
      if (flags & 0x02) // delete
            unlink(name);
      else if (flags & 0x01) {// create empty object
            fd = open(name, O_CREAT, 0600);
            close(fd);
      } else {
              int     status=0;
                pid_t   pid;

                switch (pid = fork()) {
                        case -1:
                                BTERROR("Fork error!\n");
                        case 0:
                                execl("/bin/mv","/bin/mv",file,name,NULL);
                        default:
                                waitpid(pid,&status,0);
                }
      }
      return 0;
}


int btobex_get_listing(obexsrv_t *srv, char *name)
{
      static char header[] = 
            "<?xml version=\"1.0\"?>\n"
            "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">\n"
            "<folder-listing version=\"1.0\">\n";
      static char trailer[] =
            "</folder-listing>\r";

      DIR         *dir;
      char        line_buf[256 + PATH_MAX];
      int         pdir_writeable;
      struct stat f_stat;
      obex_file_t *file;
      
      DBPRT("get_listing: %s\n", name);
      file = obex_create_file(NULL);
      if (!file) {
            DBPRT("unable to create file\n");
            return -1;
      }
      if (name && name[0] != '\0') {
            strcpy(line_buf, name);
            if (change_dir(name, CHDIR_CHECK_ONLY) != 0)
                  goto error;
      } else {
            if (getcwd(line_buf, sizeof(line_buf)) == NULL)
                  goto error;
      }

      dir = opendir(line_buf);
      if (dir == NULL)
            goto error;

      dprintf(file->fd, "%s", header);
      
      if (stat(".", &f_stat) != 0)
            goto error;
      pdir_writeable = (geteuid() == f_stat.st_uid && (f_stat.st_mode & S_IWUSR)) ||
                 (getegid() == f_stat.st_gid && (f_stat.st_mode & S_IWGRP)) ||
                 (f_stat.st_mode & S_IWOTH);
                 
      for (;;) {
            struct dirent     *dent;
            struct tm   *created, *modified, *accessed;
            char        user_perm[4];
            
            dent = readdir(dir);
            if (dent == NULL)
                  break;
            if (stat(dent->d_name, &f_stat) != 0)
                  goto error;
                  
            created = localtime(&f_stat.st_ctime);
            modified = localtime(&f_stat.st_mtime);
            accessed = localtime(&f_stat.st_atime);
            
            user_perm[0] = '\0';
            if ((geteuid() == f_stat.st_uid && f_stat.st_mode & S_IRUSR) ||
                (getegid() == f_stat.st_gid && f_stat.st_mode & S_IRGRP) ||
                (f_stat.st_mode & S_IROTH))
                  strcat(user_perm, "R");
                  
            if ((geteuid() == f_stat.st_uid && f_stat.st_mode & S_IWUSR) ||
                (getegid() == f_stat.st_gid && f_stat.st_mode & S_IWGRP) ||
                (f_stat.st_mode & S_IWOTH))
                  strcat(user_perm, "W");
                  
            if (pdir_writeable)
                  strcat(user_perm, "D");
            
            if (S_ISDIR(f_stat.st_mode) &&
                (strcmp(dent->d_name, ".") == 0 ||
                 strcmp(dent->d_name, "..") == 0))
                  continue;
            dprintf(file->fd, "<%s name=\"%s\" size=\"%lld\" user-perm=\"%s\" "
                                    "created=\"%04d%02d%02dT%02d%02d%02dZ\" "
                                    "modified=\"%04d%02d%02dT%02d%02d%02dZ\" "
                                    "accessed=\"%04d%02d%02dT%02d%02d%02dZ\"/>\n",
                        (S_ISDIR(f_stat.st_mode) ? "folder" : "file"),
                        file_base_name(dent->d_name),
                        (long long unsigned)f_stat.st_size,
                        user_perm,
                        created->tm_year + 1900, created->tm_mon + 1, created->tm_mday,
                              created->tm_hour, created->tm_min, created->tm_sec,
                        modified->tm_year + 1900, modified->tm_mon + 1, modified->tm_mday,
                              modified->tm_hour, modified->tm_min, modified->tm_sec,
                        accessed->tm_year + 1900, accessed->tm_mon + 1, accessed->tm_mday,
                              accessed->tm_hour, accessed->tm_min, accessed->tm_sec
                        );
      }
      dprintf(file->fd, "%s", trailer);

      DBPRT("folder listing written\n");
      //obex_close_file(file);      // not really necessary
      obexsrv_set_file(srv, file->name, 1);
      obex_destroy_file(file, 0);
      return 0;
error:
      obex_destroy_file(file, 1);
      return -1;
}     

int btobex_get_file(obexsrv_t *srv, char *name)
{
      char  *p;
      
      DBPRT("Got a request for %s", name);
      
      if ((p = strrchr(name, '/')) != NULL) {
            char  dir[PATH_MAX + 1];
            
            strncpy(dir, name, p - name);
            dir[p - name] = '\0';
            if (change_dir(dir, CHDIR_CHECK_ONLY) != 0) {
                  BTERROR(" Invalid path.");
                  return -1;
            }
      }
      obexsrv_set_file(srv, name, 0);
      return 0;
}

int btobex_get(obexsrv_t *srv, char *name, char *type)
{
      
      if (type && strcasecmp(type, "x-obex/folder-listing") == 0) {
            /* get folder listing */
            return btobex_get_listing(srv, name);
      } else {
            return btobex_get_file(srv, name);
      }
      return -1;
}

int btobex_setpath(obexsrv_t *srv, char *name, int flags)
{
      DBPRT("");
      
      if (!name) {
            if (flags & 0x80) {
                  if (change_dir(obex_root_path, 0) != 0)
                        goto error;
            } else {
                  if ((flags & 0x03) == 0x03 /*& 1*/) {     // backup a level before applying the name
                        if (change_dir("..", 0) != 0)
                              goto error;
                  }
            }
      } else {
            if (change_dir(name, (flags&0x02)? 0 : CHDIR_CREATE_IF_NOT_EXIST) != 0)
                  goto error;
      }     
      return 0;
error:
      return -1;
}

int btobex_connect(obexsrv_t *srv, obex_target_t *target)
{
      return 1;
}

void btobex_disconnect(obexsrv_t *srv)
{
}

void usage(void)
{
      fprintf(stderr,
            "btobex -d <obex_root_dir> --debug\n"
            "\tobex_root_dir: non-default obex root directory\n"
            );
      BTERROR("Invalid options");
}

//
//
//
int main (int argc, char *argv[])
{
      obexsrv_t   srv;
      int         c, lind;

      struct option     opts[] = {
            {"help", 0, 0, 'h'},
            {"rootdir", 1, 0, 'd'},
            {"debug", 0, 0, 'b'},
            {0, 0, 0, 0}
      };

      openlog(NULL/*argv[0]*/, 0, LOG_DAEMON);
      BTINFO("%s %s started.", argv[0], affix_version);
      
      affix_logmask = BTDEBUG_MODULE;
      for (;;) {
            c = getopt_long(argc, argv, "+hd:", opts, &lind);
            if (c == -1)
                  break;
            switch (c) {
                  case 'h':
                        usage();
                        return 0;
                        break;
                  case 'd':
                        obex_root_path = strdup(optarg);
                        break;
                  case 'b':
                        affix_logmask = BTDEBUG_MODULE;
                        break;
                  case ':':
                        BTERROR("Missing parameters for option: %c\n", optopt);
                        return 1;
                        break;
                  case '?':
                        BTERROR("Unknown option: %c\n", optopt);
                        return 1;
                        break;
            }
      }

      if (!obex_root_path) {
            if (getuid() == 0) {
                  /* root */
                  obex_root_path = strdup("/var/spool/affix/Inbox");
            } else {
                  /* set to home dir */
                  char  buf[80];
                  sprintf(buf, "%s/Inbox", getenv("HOME"));
                  obex_root_path = strdup(buf);
            }
      }
      if (rmkdir(obex_root_path, 0700) != 0 || chdir(obex_root_path) != 0) {
            BTERROR("failed to set the obex_root directory.");
            exit(0);
      }

      /* setup obex object */
      memset(&srv, 0, sizeof(obexsrv_t));
      srv.connect = btobex_connect;
      srv.setpath = btobex_setpath;
      srv.put = btobex_put;
      srv.get = btobex_get;
      srv.disconnect = btobex_disconnect;

      DBPRT("started\n");
      /* start server in a loop */
      obexsrv_run(&srv, 0, 1);

      free(obex_root_path);
      return 0;
}


Generated by  Doxygen 1.6.0   Back to index