Blame src/srvc_ft.c

Packit Service 37472d
Packit Service 37472d
/*
Packit Service 37472d
  Meanwhile - Unofficial Lotus Sametime Community Client Library
Packit Service 37472d
  Copyright (C) 2004  Christopher (siege) O'Brien
Packit Service 37472d
  
Packit Service 37472d
  This library is free software; you can redistribute it and/or
Packit Service 37472d
  modify it under the terms of the GNU Library General Public
Packit Service 37472d
  License as published by the Free Software Foundation; either
Packit Service 37472d
  version 2 of the License, or (at your option) any later version.
Packit Service 37472d
  
Packit Service 37472d
  This library is distributed in the hope that it will be useful,
Packit Service 37472d
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 37472d
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 37472d
  Library General Public License for more details.
Packit Service 37472d
  
Packit Service 37472d
  You should have received a copy of the GNU Library General Public
Packit Service 37472d
  License along with this library; if not, write to the Free
Packit Service 37472d
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service 37472d
*/
Packit Service 37472d
Packit Service 37472d
Packit Service 1bfe49
#include <glib.h>
Packit Service 37472d
Packit Service 37472d
#include "mw_channel.h"
Packit Service 37472d
#include "mw_common.h"
Packit Service 37472d
#include "mw_debug.h"
Packit Service 37472d
#include "mw_error.h"
Packit Service 37472d
#include "mw_message.h"
Packit Service 37472d
#include "mw_service.h"
Packit Service 37472d
#include "mw_session.h"
Packit Service 37472d
#include "mw_srvc_ft.h"
Packit Service 37472d
#include "mw_util.h"
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
#define PROTOCOL_TYPE  0x00000000
Packit Service 37472d
#define PROTOCOL_VER   0x00000001
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** send-on-channel type: FT transfer data */
Packit Service 37472d
#define msg_TRANSFER  0x0001
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** ack received transfer data */
Packit Service 37472d
#define msg_RECEIVED  0x0002
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceFileTransfer {
Packit Service 37472d
  struct mwService service;
Packit Service 37472d
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  GList *transfers;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwFileTransfer {
Packit Service 37472d
  struct mwServiceFileTransfer *service;
Packit Service 37472d
  
Packit Service 37472d
  struct mwChannel *channel;
Packit Service 37472d
  struct mwIdBlock who;
Packit Service 37472d
Packit Service 37472d
  enum mwFileTransferState state;
Packit Service 37472d
Packit Service 37472d
  char *filename;
Packit Service 37472d
  char *message;
Packit Service 37472d
Packit Service 37472d
  guint32 size;
Packit Service 37472d
  guint32 remaining;
Packit Service 37472d
Packit Service 37472d
  struct mw_datum client_data;
Packit Service 37472d
};
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
/** momentarily places a mwLoginInfo into a mwIdBlock */
Packit Service 37472d
static void login_into_id(struct mwIdBlock *to, struct mwLoginInfo *from) {
Packit Service 37472d
  to->user = from->user_id;
Packit Service 37472d
  to->community = from->community;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *ft_state_str(enum mwFileTransferState state) {
Packit Service 37472d
  switch(state) {
Packit Service 37472d
  case mwFileTransfer_NEW:
Packit Service 37472d
    return "new";
Packit Service 37472d
Packit Service 37472d
  case mwFileTransfer_PENDING:
Packit Service 37472d
    return "pending";
Packit Service 37472d
Packit Service 37472d
  case mwFileTransfer_OPEN:
Packit Service 37472d
    return "open";
Packit Service 37472d
Packit Service 37472d
  case mwFileTransfer_CANCEL_LOCAL:
Packit Service 37472d
    return "cancelled locally";
Packit Service 37472d
Packit Service 37472d
  case mwFileTransfer_CANCEL_REMOTE:
Packit Service 37472d
    return "cancelled remotely";
Packit Service 37472d
Packit Service 37472d
  case mwFileTransfer_DONE:
Packit Service 37472d
    return "done";
Packit Service 37472d
Packit Service 37472d
  case mwFileTransfer_ERROR:
Packit Service 37472d
    return "error";
Packit Service 37472d
Packit Service 37472d
  case mwFileTransfer_UNKNOWN:
Packit Service 37472d
  default:
Packit Service 37472d
    return "UNKNOWN";
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void ft_state(struct mwFileTransfer *ft,
Packit Service 37472d
		     enum mwFileTransferState state) {
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(ft != NULL);
Packit Service 37472d
Packit Service 37472d
  if(ft->state == state) return;
Packit Service 37472d
Packit Service 37472d
  g_info("setting ft (%s, %s) state: %s",
Packit Service 37472d
	 NSTR(ft->who.user), NSTR(ft->who.community),
Packit Service 37472d
	 ft_state_str(state));
Packit Service 37472d
Packit Service 37472d
  ft->state = state;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelCreate(struct mwServiceFileTransfer *srvc,
Packit Service 37472d
			       struct mwChannel *chan,
Packit Service 37472d
			       struct mwMsgChannelCreate *msg) {
Packit Service 37472d
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  struct mwGetBuffer *b;
Packit Service 37472d
Packit Service 37472d
  char *fnm, *txt;
Packit Service 37472d
  guint32 size, junk;
Packit Service 37472d
  gboolean b_err;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc->handler != NULL);
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
  
Packit Service 37472d
  b = mwGetBuffer_wrap(&msg->addtl);
Packit Service 37472d
Packit Service 37472d
  guint32_get(b, &junk); /* unknown */
Packit Service 37472d
  mwString_get(b, &fnm;; /* offered filename */
Packit Service 37472d
  mwString_get(b, &txt); /* offering message */
Packit Service 37472d
  guint32_get(b, &size); /* size of offered file */
Packit Service 653353
  /* guint32_get(b, &junk); */ /* unknown */
Packit Service 37472d
  /* and we just skip an unknown guint16 at the end */
Packit Service 37472d
Packit Service 37472d
  b_err = mwGetBuffer_error(b);
Packit Service 37472d
  mwGetBuffer_free(b);
Packit Service 37472d
Packit Service 37472d
  if(b_err) {
Packit Service 37472d
    g_warning("bad/malformed addtl in File Transfer service");
Packit Service 37472d
    mwChannel_destroy(chan, ERR_FAILURE, NULL);
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    struct mwIdBlock idb;
Packit Service 37472d
    struct mwFileTransfer *ft;
Packit Service 37472d
Packit Service 37472d
    login_into_id(&idb, mwChannel_getUser(chan));
Packit Service 37472d
    ft = mwFileTransfer_new(srvc, &idb, txt, fnm, size);
Packit Service 37472d
    ft->channel = chan;
Packit Service 37472d
    ft_state(ft, mwFileTransfer_PENDING);
Packit Service 37472d
Packit Service 37472d
    mwChannel_setServiceData(chan, ft, NULL);
Packit Service 37472d
Packit Service 37472d
    if(handler->ft_offered)
Packit Service 37472d
      handler->ft_offered(ft);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  g_free(fnm);
Packit Service 37472d
  g_free(txt);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelAccept(struct mwServiceFileTransfer *srvc,
Packit Service 37472d
			       struct mwChannel *chan,
Packit Service 37472d
			       struct mwMsgChannelAccept *msg) {
Packit Service 37472d
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  struct mwFileTransfer *ft;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc->handler != NULL);
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
Packit Service 37472d
  ft = mwChannel_getServiceData(chan);
Packit Service 37472d
  g_return_if_fail(ft != NULL);
Packit Service 37472d
Packit Service 37472d
  ft_state(ft, mwFileTransfer_OPEN);
Packit Service 37472d
Packit Service 37472d
  if(handler->ft_opened)
Packit Service 37472d
    handler->ft_opened(ft);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_channelDestroy(struct mwServiceFileTransfer *srvc,
Packit Service 37472d
				struct mwChannel *chan,
Packit Service 37472d
				struct mwMsgChannelDestroy *msg) {
Packit Service 37472d
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  struct mwFileTransfer *ft;
Packit Service 37472d
  guint32 code;
Packit Service 37472d
Packit Service 37472d
  code = msg->reason;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(srvc->handler != NULL);
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
Packit Service 37472d
  ft = mwChannel_getServiceData(chan);
Packit Service 37472d
  g_return_if_fail(ft != NULL);
Packit Service 37472d
Packit Service 37472d
  ft->channel = NULL;
Packit Service 37472d
Packit Service 37472d
  if(! mwFileTransfer_isDone(ft))
Packit Service 37472d
    ft_state(ft, mwFileTransfer_CANCEL_REMOTE);
Packit Service 37472d
Packit Service 37472d
  mwFileTransfer_close(ft, code);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_TRANSFER(struct mwFileTransfer *ft,
Packit Service 37472d
			  struct mwOpaque *data) {
Packit Service 37472d
Packit Service 37472d
  struct mwServiceFileTransfer *srvc;
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  
Packit Service 37472d
  srvc = ft->service;
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
Packit Service 37472d
  g_return_if_fail(mwFileTransfer_isOpen(ft));
Packit Service 37472d
Packit Service 37472d
  if(data->len > ft->remaining) {
Packit Service 37472d
    /* @todo handle error */
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    ft->remaining -= data->len;
Packit Service 37472d
Packit Service 37472d
    if(! ft->remaining)
Packit Service 37472d
      ft_state(ft, mwFileTransfer_DONE);
Packit Service 37472d
    
Packit Service 37472d
    if(handler->ft_recv)
Packit Service 37472d
      handler->ft_recv(ft, data);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv_RECEIVED(struct mwFileTransfer *ft,
Packit Service 37472d
			  struct mwOpaque *data) {
Packit Service 37472d
Packit Service 37472d
  struct mwServiceFileTransfer *srvc;
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  
Packit Service 37472d
  srvc = ft->service;
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
Packit Service 37472d
  if(! ft->remaining)
Packit Service 37472d
    ft_state(ft, mwFileTransfer_DONE);
Packit Service 37472d
Packit Service 37472d
  if(handler->ft_ack)
Packit Service 37472d
    handler->ft_ack(ft);
Packit Service 37472d
Packit Service 37472d
  if(! ft->remaining)
Packit Service 37472d
    mwFileTransfer_close(ft, mwFileTransfer_SUCCESS);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void recv(struct mwService *srvc, struct mwChannel *chan,
Packit Service 37472d
		 guint16 type, struct mwOpaque *data) {
Packit Service 37472d
Packit Service 37472d
  struct mwFileTransfer *ft;
Packit Service 37472d
  
Packit Service 37472d
  ft = mwChannel_getServiceData(chan);
Packit Service 37472d
  g_return_if_fail(ft != NULL);
Packit Service 37472d
Packit Service 37472d
  switch(type) {
Packit Service 37472d
  case msg_TRANSFER:
Packit Service 37472d
    recv_TRANSFER(ft, data);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  case msg_RECEIVED:
Packit Service 37472d
    recv_RECEIVED(ft, data);
Packit Service 37472d
    break;
Packit Service 37472d
Packit Service 37472d
  default:
Packit Service 37472d
    mw_mailme_opaque(data, "unknown message in ft service: 0x%04x", type);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void clear(struct mwServiceFileTransfer *srvc) {
Packit Service 37472d
  struct mwFileTransferHandler *h;
Packit Service 37472d
  
Packit Service 37472d
  h = srvc->handler;
Packit Service 37472d
  if(h && h->clear)
Packit Service 37472d
    h->clear(srvc);
Packit Service 37472d
  srvc->handler = NULL;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *name(struct mwService *srvc) {
Packit Service 37472d
  return "File Transfer";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static const char *desc(struct mwService *srvc) {
Packit Service 37472d
  return "Provides file transfer capabilities through the community server";
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void start(struct mwService *srvc) {
Packit Service 37472d
  mwService_started(srvc);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void stop(struct mwServiceFileTransfer *srvc) {
Packit Service 37472d
  while(srvc->transfers) {
Packit Service 37472d
    mwFileTransfer_free(srvc->transfers->data);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwService_stopped(MW_SERVICE(srvc));
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceFileTransfer *
Packit Service 37472d
mwServiceFileTransfer_new(struct mwSession *session,
Packit Service 37472d
			  struct mwFileTransferHandler *handler) {
Packit Service 37472d
Packit Service 37472d
  struct mwServiceFileTransfer *srvc_ft;
Packit Service 37472d
  struct mwService *srvc;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(session != NULL, NULL);
Packit Service 37472d
  g_return_val_if_fail(handler != NULL, NULL);
Packit Service 37472d
Packit Service 37472d
  srvc_ft = g_new0(struct mwServiceFileTransfer, 1);
Packit Service 37472d
  srvc = MW_SERVICE(srvc_ft);
Packit Service 37472d
Packit Service 37472d
  mwService_init(srvc, session, mwService_FILE_TRANSFER);
Packit Service 37472d
  srvc->recv_create = (mwService_funcRecvCreate) recv_channelCreate;
Packit Service 37472d
  srvc->recv_accept = (mwService_funcRecvAccept) recv_channelAccept;
Packit Service 37472d
  srvc->recv_destroy = (mwService_funcRecvDestroy) recv_channelDestroy;
Packit Service 37472d
  srvc->recv = recv;
Packit Service 37472d
  srvc->clear = (mwService_funcClear) clear;
Packit Service 37472d
  srvc->get_name = name;
Packit Service 37472d
  srvc->get_desc = desc;
Packit Service 37472d
  srvc->start = start;
Packit Service 37472d
  srvc->stop = (mwService_funcStop) stop;
Packit Service 37472d
Packit Service 37472d
  srvc_ft->handler = handler;
Packit Service 37472d
Packit Service 37472d
  return srvc_ft;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwFileTransferHandler *
Packit Service 37472d
mwServiceFileTransfer_getHandler(struct mwServiceFileTransfer *srvc) {
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit Service 37472d
  return srvc->handler;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
const GList *
Packit Service 37472d
mwServiceFileTransfer_getTransfers(struct mwServiceFileTransfer *srvc) {
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit Service 37472d
  return srvc->transfers;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwFileTransfer *
Packit Service 37472d
mwFileTransfer_new(struct mwServiceFileTransfer *srvc,
Packit Service 37472d
		   const struct mwIdBlock *who, const char *msg,
Packit Service 37472d
		   const char *filename, guint32 filesize) {
Packit Service 37472d
  
Packit Service 37472d
  struct mwFileTransfer *ft;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, NULL);
Packit Service 37472d
  g_return_val_if_fail(who != NULL, NULL);
Packit Service 37472d
  
Packit Service 37472d
  ft = g_new0(struct mwFileTransfer, 1);
Packit Service 37472d
  ft->service = srvc;
Packit Service 37472d
  mwIdBlock_clone(&ft->who, who);
Packit Service 37472d
  ft->filename = g_strdup(filename);
Packit Service 37472d
  ft->message = g_strdup(msg);
Packit Service 37472d
  ft->size = ft->remaining = filesize;
Packit Service 37472d
Packit Service 37472d
  ft_state(ft, mwFileTransfer_NEW);
Packit Service 37472d
Packit Service 37472d
  /* stick a reference in the service */
Packit Service 37472d
  srvc->transfers = g_list_prepend(srvc->transfers, ft);
Packit Service 37472d
Packit Service 37472d
  return ft;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
struct mwServiceFileTransfer *
Packit Service 37472d
mwFileTransfer_getService(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, NULL);
Packit Service 37472d
  return ft->service;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
enum mwFileTransferState
Packit Service 37472d
mwFileTransfer_getState(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, mwFileTransfer_UNKNOWN);
Packit Service 37472d
  return ft->state;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
const struct mwIdBlock *
Packit Service 37472d
mwFileTransfer_getUser(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, NULL);
Packit Service 37472d
  return &ft->who;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
const char *
Packit Service 37472d
mwFileTransfer_getMessage(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, NULL);
Packit Service 37472d
  return ft->message;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
const char *
Packit Service 37472d
mwFileTransfer_getFileName(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, NULL);
Packit Service 37472d
  return ft->filename;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
guint32 mwFileTransfer_getFileSize(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, 0);
Packit Service 37472d
  return ft->size;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
guint32 mwFileTransfer_getRemaining(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, 0);
Packit Service 37472d
  return ft->remaining;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwFileTransfer_accept(struct mwFileTransfer *ft) {
Packit Service 37472d
  struct mwServiceFileTransfer *srvc;
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  int ret;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(ft->channel != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(mwFileTransfer_isPending(ft), -1);
Packit Service 37472d
  g_return_val_if_fail(mwChannel_isIncoming(ft->channel), -1);
Packit Service 37472d
  g_return_val_if_fail(mwChannel_isState(ft->channel, mwChannel_WAIT), -1);
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(ft->service != NULL, -1);
Packit Service 37472d
  srvc = ft->service;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(srvc->handler != NULL, -1);
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
Packit Service 37472d
  ret = mwChannel_accept(ft->channel);
Packit Service 37472d
Packit Service 37472d
  if(ret) {
Packit Service 37472d
    mwFileTransfer_close(ft, ERR_FAILURE);
Packit Service 37472d
Packit Service 37472d
  } else {
Packit Service 37472d
    ft_state(ft, mwFileTransfer_OPEN);
Packit Service 37472d
    if(handler->ft_opened)
Packit Service 37472d
      handler->ft_opened(ft);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
static void ft_create_chan(struct mwFileTransfer *ft) {
Packit Service 37472d
  struct mwSession *s;
Packit Service 37472d
  struct mwChannelSet *cs;
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
  struct mwLoginInfo *login;
Packit Service 37472d
  struct mwPutBuffer *b;
Packit Service 37472d
  
Packit Service 37472d
  /* we only should be calling this if there isn't a channel already
Packit Service 37472d
     associated with the conversation */
Packit Service 37472d
  g_return_if_fail(ft != NULL);
Packit Service 37472d
  g_return_if_fail(mwFileTransfer_isNew(ft));
Packit Service 37472d
  g_return_if_fail(ft->channel == NULL);
Packit Service 37472d
		   
Packit Service 37472d
  s = mwService_getSession(MW_SERVICE(ft->service));
Packit Service 37472d
  cs = mwSession_getChannels(s);
Packit Service 37472d
Packit Service 37472d
  chan = mwChannel_newOutgoing(cs);
Packit Service 37472d
  mwChannel_setService(chan, MW_SERVICE(ft->service));
Packit Service 37472d
  mwChannel_setProtoType(chan, PROTOCOL_TYPE);
Packit Service 37472d
  mwChannel_setProtoVer(chan, PROTOCOL_VER);
Packit Service 37472d
Packit Service 37472d
  /* offer all known ciphers */
Packit Service 37472d
  mwChannel_populateSupportedCipherInstances(chan);
Packit Service 37472d
Packit Service 37472d
  /* set the target */
Packit Service 37472d
  login = mwChannel_getUser(chan);
Packit Service 37472d
  login->user_id = g_strdup(ft->who.user);
Packit Service 37472d
  login->community = g_strdup(ft->who.community);
Packit Service 37472d
Packit Service 37472d
  /* compose the addtl create */
Packit Service 37472d
  b = mwPutBuffer_new();
Packit Service 37472d
  guint32_put(b, 0x00);
Packit Service 37472d
  mwString_put(b, ft->filename);
Packit Service 37472d
  mwString_put(b, ft->message);
Packit Service 37472d
  guint32_put(b, ft->size);
Packit Service 37472d
  guint32_put(b, 0x00);
Packit Service 37472d
  guint16_put(b, 0x00);
Packit Service 37472d
Packit Service 37472d
  mwPutBuffer_finalize(mwChannel_getAddtlCreate(chan), b);
Packit Service 37472d
Packit Service 37472d
  ft->channel = mwChannel_create(chan)? NULL: chan;
Packit Service 37472d
  if(ft->channel) {
Packit Service 37472d
    mwChannel_setServiceData(ft->channel, ft, NULL);
Packit Service 37472d
  }
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwFileTransfer_offer(struct mwFileTransfer *ft) {
Packit Service 37472d
  struct mwServiceFileTransfer *srvc;
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(ft->channel == NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(mwFileTransfer_isNew(ft), -1);
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(ft->service != NULL, -1);
Packit Service 37472d
  srvc = ft->service;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(srvc->handler != NULL, -1);
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
Packit Service 37472d
  ft_create_chan(ft);
Packit Service 37472d
  if(ft->channel) {
Packit Service 37472d
    ft_state(ft, mwFileTransfer_PENDING);
Packit Service 37472d
  } else {
Packit Service 37472d
    ft_state(ft, mwFileTransfer_ERROR);
Packit Service 37472d
    mwFileTransfer_close(ft, ERR_FAILURE);
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  return 0;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwFileTransfer_close(struct mwFileTransfer *ft, guint32 code) {
Packit Service 37472d
  struct mwServiceFileTransfer *srvc;
Packit Service 37472d
  struct mwFileTransferHandler *handler;
Packit Service 37472d
  int ret = 0;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, -1);
Packit Service 37472d
Packit Service 37472d
  if(mwFileTransfer_isOpen(ft))
Packit Service 37472d
    ft_state(ft, mwFileTransfer_CANCEL_LOCAL);
Packit Service 37472d
Packit Service 37472d
  if(ft->channel) {
Packit Service 37472d
    ret = mwChannel_destroy(ft->channel, code, NULL);
Packit Service 37472d
    ft->channel = NULL;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  srvc = ft->service;
Packit Service 37472d
  g_return_val_if_fail(srvc != NULL, ret);
Packit Service 37472d
Packit Service 37472d
  handler = srvc->handler;
Packit Service 37472d
  g_return_val_if_fail(handler != NULL, ret);
Packit Service 37472d
Packit Service 37472d
  if(handler->ft_closed)
Packit Service 37472d
    handler->ft_closed(ft, code);
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwFileTransfer_free(struct mwFileTransfer *ft) {
Packit Service 37472d
  struct mwServiceFileTransfer *srvc;
Packit Service 37472d
Packit Service 37472d
  if(! ft) return;
Packit Service 37472d
Packit Service 37472d
  srvc = ft->service;
Packit Service 37472d
  if(srvc)
Packit Service 37472d
    srvc->transfers = g_list_remove(srvc->transfers, ft);
Packit Service 37472d
Packit Service 37472d
  if(ft->channel) {
Packit Service 37472d
    mwChannel_destroy(ft->channel, mwFileTransfer_SUCCESS, NULL);
Packit Service 37472d
    ft->channel = NULL;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  mwFileTransfer_removeClientData(ft);
Packit Service 37472d
Packit Service 37472d
  mwIdBlock_clear(&ft->who);
Packit Service 37472d
  g_free(ft->filename);
Packit Service 37472d
  g_free(ft->message);
Packit Service 37472d
  g_free(ft);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwFileTransfer_send(struct mwFileTransfer *ft,
Packit Service 37472d
			struct mwOpaque *data) {
Packit Service 37472d
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
  int ret;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(mwFileTransfer_isOpen(ft), -1);
Packit Service 37472d
  g_return_val_if_fail(ft->channel != NULL, -1);
Packit Service 37472d
  chan = ft->channel;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(mwChannel_isOutgoing(chan), -1);
Packit Service 37472d
Packit Service 37472d
  if(data->len > ft->remaining) {
Packit Service 37472d
    /* @todo handle error */
Packit Service 37472d
    return -1;
Packit Service 37472d
  }
Packit Service 37472d
Packit Service 37472d
  ret = mwChannel_send(chan, msg_TRANSFER, data);
Packit Service 37472d
  if(! ret) ft->remaining -= data->len;
Packit Service 37472d
  
Packit Service 37472d
  /* we're not done until we receive an ACK for the last piece of
Packit Service 37472d
     outgoing data */
Packit Service 37472d
Packit Service 37472d
  return ret;
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
int mwFileTransfer_ack(struct mwFileTransfer *ft) {
Packit Service 37472d
  struct mwChannel *chan;
Packit Service 37472d
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, -1);
Packit Service 37472d
Packit Service 37472d
  chan = ft->channel;
Packit Service 37472d
  g_return_val_if_fail(chan != NULL, -1);
Packit Service 37472d
  g_return_val_if_fail(mwChannel_isIncoming(chan), -1);
Packit Service 37472d
Packit Service 37472d
  return mwChannel_sendEncrypted(chan, msg_RECEIVED, NULL, FALSE);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwFileTransfer_setClientData(struct mwFileTransfer *ft,
Packit Service 37472d
				  gpointer data, GDestroyNotify clean) {
Packit Service 37472d
  g_return_if_fail(ft != NULL);
Packit Service 37472d
  mw_datum_set(&ft->client_data, data, clean);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
gpointer mwFileTransfer_getClientData(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_val_if_fail(ft != NULL, NULL);
Packit Service 37472d
  return mw_datum_get(&ft->client_data);
Packit Service 37472d
}
Packit Service 37472d
Packit Service 37472d
Packit Service 37472d
void mwFileTransfer_removeClientData(struct mwFileTransfer *ft) {
Packit Service 37472d
  g_return_if_fail(ft != NULL);
Packit Service 37472d
  mw_datum_clear(&ft->client_data);
Packit Service 37472d
}
Packit Service 37472d