Blame src/srvc_ft.c

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