Blame src/srvc_ft.c.fix-glib-headers

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