{-----------------------------------------------------------------
  说明:
      在IBB中增加 taskinfo 用于表示任务类型，如果没有则作为普通
      IBB处理。格式如下:
      <iq type="set" id="inband_1" to="joe@blow.com/Home">
        <query xmlns="http://jabber.org/protocol/ibb" sid="mySID">
           <taskinfo tasktype="getsharelist">
           </taskinfo>
        </query>
      </iq>

      暂时确定的tasktype有
        getsharelist      请求、接收共享列表
        sendsharelist     发送共享列表

        getsharefile      请求、接收共享文件
        sendsharefile     发送共享文件

        sendinstantmail   发送即时文件
        rcvinstantmail    接收即时文件

        sendfile          发送文件
        rcvfile           接收文件

      以上tasktype成对使用。

        whiteboard        白板数据


      仅在请求时发送一次。程序根据 taskinfo 对该任务进行处理。
      另外增加 totalseq 用来表示传送的总包数，以方便进度显示。
      格式如下:
      <iq type="set" id="inband_2" to="joe@blow.com/Home">
        <query xmlns="http://jabber.org/protocol/ibb" sid="mySID" seq="0"
         totalseq="874">
           <data>
           </data>
        </query>
      </iq>

 -----------------------------------------------------------------}

unit IBB;

interface
uses
  IdCoderMIME, zlib,
    // Exodus things
  XMLTag, Dockable, ExRichEdit, RichEdit2, buttonFrame,
    // Normal Delphi things
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls, ExtCtrls;

type
  TJabberIBBTask = class;

  TIBBNotifyEvent = procedure(tag: TXMLTag) of object;
  TIBBSendEvent = procedure(sender: TJabberIBBTask) of object;

  TJabberIBBController = class;

  TJabberIBBTask = class
  private
    FOnDestroy: TNotifyEvent;
    FOnTimeOut: TNotifyEvent;
    FOnProcessReceive: TIBBNotifyEvent;
  protected
    _Timer: TTimer;
    _Tick: Integer;
    procedure DoTimeout(Sender: TObject);
  public
    TimeOut: Integer;
    IBBController: TJabberIBBController;
    IBBSID: widestring;
    TOJID: widestring;
    constructor Create; virtual;
    destructor Destroy; override;
    procedure ProcessReceive(tag: TXMLTag); virtual;
    procedure Close; virtual;
  published
    property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
    property OnTimeOut: TNotifyEvent read FOnTimeOut write FOnTimeOut;
    property OnProcessReceive: TIBBNotifyEvent read FOnProcessReceive write FOnProcessReceive;

  end;

  TJITGetShareList = class(TJabberIBBTask)
  public
    _GetMode: Integer;
    _GetFileName: string;
    _SaveFileName: string;
    _FileSize: Integer;
    BufStream: TStream;
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure Start;
  end;

  TJITSendShareList = class(TJabberIBBTask)
  public
    Buffer: string;
    BlockSize: Integer;
    sending: Boolean;
    seqNo: cardinal;
    seqCount: cardinal;
    constructor Create; override;
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure Startsend;
    procedure continuesend;
  end;

  TJITGetShareFile = class(TJabberIBBTask)
  public
    FBuffer: array[0..4999] of char;
    FZRec: TZStreamRec;
    _getmode : Integer;
    _GetFileName: string;
    _SaveFileName: string;
    _FileSize: Integer;
    BufStream: TStream;

    ShareFileName: widestring;
    destructor Destroy; override;
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure Start;
  end;

  TJITSendShareFile = class(TJabberIBBTask)
  public
    FBuffer: array[0..4999] of char;
    ShareFileName: widestring;
    fs: TFileStream;
    FZRec: TZStreamRec;
    Buffer: string;
    BlockSize: Integer;
    sending: Boolean;
    seqNo: cardinal;
    seqCount: cardinal;
    constructor Create; override;
    destructor Destroy; override;
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure startsend;
    procedure continuesend;
  end;

  TJITRcvInstantMail = class(TJabberIBBTask)
  public
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure SendReady(ReadyID: widestring);
  end;

  TJITSendInstantMail = class(TJabberIBBTask)
  private
    FOnSend: TIBBSendEvent;
  public
    InmFileName: widestring;
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure AskReady(ReadyID: widestring);
    procedure startsend;
  published
    property OnSend: TIBBSendEvent read FOnSend write FOnSend;
  end;

  TJITRcvFile = class(TJabberIBBTask)
  public
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure SendReady(ReadyID: widestring);
  end;

  TJITSendFile = class(TJabberIBBTask)
  private
    FOnSend: TIBBSendEvent;
  public
    FileName: widestring;
    procedure ProcessReceive(tag: TXMLTag); override;
    procedure AskReady(ReadyID: widestring);
    procedure startsend;
  published
    property OnSend: TIBBSendEvent read FOnSend write FOnSend;
  end;

  TJabberIBBController = class(TStringList)
  private
  protected
  public
    constructor Create;
    destructor Destroy; override;

    function FindTask(sid: string): TJabberIBBTask;
    procedure AddTask(sid: string; Task: TJabberIBBTask);
    procedure RemoveTask(sid: string);
  end;

procedure ibbReceive(tag: TXMLTag); //overload;

var
  MainIBBController: TJabberIBBController;

implementation

uses Session, JabberConst, DateUtils, ShareUnit, InstantMail, IdCoder3to4, ZLibConst,
  whiteboard, Transfer;

function CCheck(code: Integer): Integer;
begin
  Result := code;
  if code < 0 then
    raise ECompressionError.Create(sError); //!!
end;

procedure ibbReceive(tag: TXMLTag);
var
  From, SID: Widestring;
  qtag, taskinfo: TXMLTag;
  tasktype: widestring;
  task: TJabberIBBTask;
begin
  From := tag.GetAttribute('from');
  qtag := tag.GetFirstTag('query');
  if qtag = nil then exit;

  SID := qtag.GetAttribute('sid');
  if SID = '' then exit;

  if MainIBBController.FindTask(SID) <> nil then
    MainIBBController.FindTask(SID).ProcessReceive(tag)
  else
  begin
    if tag.GetAttribute('type') <> 'set' then
      exit;
    tasktype := '';
    taskinfo := qtag.GetFirstTag('taskinfo');

    if taskinfo <> nil then
      tasktype := taskinfo.GetAttribute('tasktype');

    if tasktype = '' then
    begin
      task := TJabberIBBTask.Create;
      task.IBBController := MainIBBController;
      task.IBBSID := SID;
      task.TOJID := From;
      MainIBBController.AddTask(SID, task);
      Task.ProcessReceive(tag);
      exit;
    end;

    if tasktype = 'getsharelist' then
    begin
      task := TJITSendShareList.Create;
      task.IBBController := MainIBBController;
      task.IBBSID := SID;
      task.TOJID := From;
      MainIBBController.AddTask(SID, task);
      Task.ProcessReceive(tag);
      exit;
    end;

    if tasktype = 'sendinstantmail' then
    begin
      InstantMailReceive(tag);
      exit;
    end;

    if tasktype = 'sendfile' then
    begin
      FileRcv(tag);
      exit;
    end;

    if tasktype = 'getsharefile' then
    begin
      task := TJITSendSharefile.Create;
      task.IBBController := MainIBBController;
      task.IBBSID := SID;
      task.TOJID := From;
      TJITSendSharefile(task).ShareFileName := taskinfo.GetBasicText('filename');
      MainIBBController.AddTask(SID, task);
      Task.ProcessReceive(tag);
      exit;
    end;

    if tasktype = 'whiteboard' then
    begin
      Processwhiteboard(tag);
      exit;
    end;
  end;
end;

{ TJabberIBBTask }

procedure TJabberIBBTask.Close;
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', MainSession.generateID());
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    AddTag('close');
  end;
  MainSession.SendTag(_iq);
  IBBController.RemoveTask(IBBSID);
end;

constructor TJabberIBBTask.Create;
begin
  inherited Create;
  _timer := TTimer.Create(nil);
  _timer.Interval := 1000;
  _timer.Enabled := false;
  _Tick := 0;
  _timer.OnTimer := DoTimeout;
  FonTimeOut := nil;
end;

destructor TJabberIBBTask.Destroy;
begin
  _timer.Free;
  if assigned(FOnDestroy) then
    FOnDestroy(self);
  inherited;
end;

procedure TJabberIBBTask.DoTimeout(Sender: TObject);
begin
  inc(_tick);
  if (_tick >= timeout) then begin
    _timer.Enabled := false;
    if Assigned(FonTimeOut) then
      FonTimeOut(self);
    Self.Free;
  end;
end;

procedure TJabberIBBTask.ProcessReceive(tag: TXMLTag);
var
  t: Widestring;
  qtag: TXMLTag;
begin
  _Tick := 0;
  t := tag.GetAttribute('type');

  if t = 'set' then
  begin
    qtag := Tag.GetFirstTag('query');
    if qtag = nil then exit;
    if qtag.TagExists('close') then
      IBBController.RemoveTask(IBBSID);
  end;

  if t = 'error' then
    IBBController.RemoveTask(IBBSID);

  if assigned(FOnProcessReceive) then
    FOnProcessReceive(tag);
end;

{ TJabberIBBController }

procedure TJabberIBBController.AddTask(sid: string; Task: TJabberIBBTask);
begin
  AddObject(sid, task);
end;

constructor TJabberIBBController.Create;
begin
  inherited;
end;

destructor TJabberIBBController.Destroy;
var
  i: integer;
begin
  for i := 0 to Self.Count - 1 do
    TJabberIBBTask(Objects[i]).Free;
  inherited;
end;

function TJabberIBBController.FindTask(sid: string): TJabberIBBTask;
var
  i: integer;
begin
  result := nil;
  i := IndexOf(sid);
  if i >= 0 then
    Result := TJabberIBBTask(objects[i]);
end;

procedure TJabberIBBController.RemoveTask(sid: string);
var
  i: integer;
begin
  i := IndexOf(sid);
  if i >= 0 then
  begin
    TJabberIBBTask(objects[i]).Free;
    delete(i);
  end;
end;

{ TJITGetShareList }

procedure TJITGetShareList.ProcessReceive(tag: TXMLTag);
begin
  inherited;

end;

procedure TJITGetShareList.Start;
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', MainSession.generateID());
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    with AddTag('taskinfo') do
      setAttribute('tasktype', 'getsharelist');
  end;
  MainSession.SendTag(_iq);
end;

{ TJITSendShareList }

procedure TJITSendShareList.continuesend;
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', MainSession.generateID());
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    setAttribute('seq', inttostr(seqNo));
    setAttribute('totalseq', inttostr(seqcount));
    with AddTag('data') do
      AddCData(copy(Buffer, seqNo * BlockSize + 1, BlockSize));
    inc(seqNo);
    if seqNo >= seqcount then
      AddTag('close');
  end;
  MainSession.SendTag(_iq);
  sending := seqNo < seqcount;
end;

constructor TJITSendShareList.Create;
begin
  inherited;
  sending := false;
  BlockSize := 4096;
end;

procedure TJITSendShareList.ProcessReceive(tag: TXMLTag);
var
  qtag, taskinfo: TXMLTag;
  SID, tasktype: widestring;
  _iq: TXMLTag;
begin
  qtag := tag.GetFirstTag('query');
  if qtag = nil then exit;

  SID := qtag.GetAttribute('sid');
  if SID <> IBBSID then exit;

  if tag.GetAttribute('type') = 'set' then
  begin
    _iq := TXMLTag.Create('iq');
    _iq.setAttribute('id', qtag.GetAttribute('id'));
    _iq.setAttribute('type', 'result');
    with _iq.AddTag('query') do
    begin
      setAttribute('xmlns', XMLNS_IBB);
      setAttribute('sid', qtag.GetAttribute('sid'));
    end;

    _iq.setAttribute('to', TOJID);
    MainSession.SendTag(_iq);

    tasktype := '';
    taskinfo := qtag.GetFirstTag('taskinfo');

    if taskinfo <> nil then
      tasktype := taskinfo.GetAttribute('tasktype');

    if tasktype = 'getsharelist' then
    begin
      startsend;
    end;
  end;

  if tag.GetAttribute('type') = 'result' then
    if sending then
      continuesend;

  inherited;
end;

procedure TJITSendShareList.Startsend;
var
  sl: TStringList;
  compstream: TMemoryStream;
  Compresser: TCompressionStream;
  EnCoder: TIdEncoderMIME;
  _iq: TXMLTag;
begin
  //如果正在创建共享列表则等待创建完成
  while ShareListBuilding do
    Application.ProcessMessages;
  sl := TStringList.Create;
  sl.LoadFromFile(ShareListFileName);
  compstream := TMemoryStream.Create;
  Compresser := TCompressionStream.Create(zlib.clDefault, compstream);
  Compresser.WriteBuffer(sl.Text[1], length(sl.text));
  Compresser.Free;
  EnCoder := TIdEncoderMIME.Create(nil);
  compstream.Seek(0, soFromBeginning);
  Buffer := EnCoder.Encode(compstream);
  EnCoder.Free;
  sl.Free;

  seqNo := 0;
  seqCount := length(Buffer) div BlockSize;
  if (length(Buffer) mod BlockSize) <> 0 then
    inc(seqCount);

  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', MainSession.generateID());
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    setAttribute('seq', inttostr(seqNo));
    setAttribute('totalseq', inttostr(seqcount));
    with AddTag('data') do
      AddCData(copy(Buffer, seqNo * BlockSize + 1, BlockSize));
    inc(seqNo);
    if seqNo >= seqcount then
      AddTag('close');
  end;
  MainSession.SendTag(_iq);

  sending := seqNo < seqcount;
  while sending do
  begin
    continuesend;
    Application.ProcessMessages;
  end;
end;

{ TJITGetShareFile }

destructor TJITGetShareFile.Destroy;
begin
  if BufStream<>nil then
    FreeAndNil(BufStream);
  inherited;
end;

procedure TJITGetShareFile.ProcessReceive(tag: TXMLTag);
begin
  inherited;

end;

procedure TJITGetShareFile.Start;
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', MainSession.generateID());
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    with AddTag('taskinfo') do
    begin
      setAttribute('tasktype', 'getsharefile');
      AddBasicTag('filename', ShareFileName);
    end;
  end;
  MainSession.SendTag(_iq);
end;

{ TJITSendShareFile }

procedure TJITSendShareFile.continuesend;
var
  EnCoder: TIdEncoderMIME;
  _iq: TXMLTag;
  buf: array[0..4095] of byte;
  CM: TMemoryStream;
  bufsize: integer;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', MainSession.generateID());
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    setAttribute('seq', inttostr(seqNo));
    setAttribute('totalseq', inttostr(seqcount));

    EnCoder := TIdEncoderMIME.Create(nil);
    bufsize := fs.Read(buf, 4096);
    FillChar(FBuffer, 5000, #0);

    FZRec.next_out := FBuffer;
    FZRec.avail_out := sizeof(FBuffer);

    FZRec.next_in := @buf;
    FZRec.avail_in := bufsize;
    while (FZRec.avail_in > 0) do
    begin
      CCheck(deflate(FZRec, 2));
    end;

    inc(seqNo);
    if seqNo >= seqcount then
    begin
      while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
        and (FZRec.avail_out = 0) do
      begin
        FZRec.next_out := FBuffer;
        FZRec.avail_out := sizeof(FBuffer);
      end;
    end;
    bufsize := 5000 - FZRec.avail_out;

    CM := TMemoryStream.Create;
    bufsize := cm.Write(FBuffer, bufsize);
    cm.Seek(0, soFromBeginning);
    bufsize := (bufsize + 2) - ((bufsize + 2) mod 3);
    Buffer := EnCoder.Encode(cm, bufsize);
    CM.Free;
    EnCoder.Free;
    with AddTag('data') do
      AddCData(copy(Buffer, 1, length(Buffer)));
    if seqNo >= seqcount then
    begin
      CCheck(deflateEnd(FZRec));
      AddTag('close');
      FreeAndNil(fs);
    end;
  end;
  MainSession.SendTag(_iq);
  sending := seqNo < seqcount;
end;

constructor TJITSendShareFile.Create;
begin
  inherited;
  FZRec.zalloc := zlibAllocMem;
  FZRec.zfree := zlibFreeMem;
  sending := false;
  BlockSize := 4096;
end;

destructor TJITSendShareFile.Destroy;
begin
  if assigned(fs) then
    FreeAndNil(fs);
  inherited;
end;

procedure TJITSendShareFile.ProcessReceive(tag: TXMLTag);
var
  qtag, taskinfo: TXMLTag;
  SID, tasktype: widestring;
  _iq: TXMLTag;
begin
  qtag := tag.GetFirstTag('query');
  if qtag = nil then exit;

  SID := qtag.GetAttribute('sid');
  if SID <> IBBSID then exit;

  if tag.GetAttribute('type') = 'set' then
  begin
    _iq := TXMLTag.Create('iq');
    _iq.setAttribute('id', qtag.GetAttribute('id'));
    _iq.setAttribute('type', 'result');
    with _iq.AddTag('query') do
    begin
      setAttribute('xmlns', XMLNS_IBB);
      setAttribute('sid', qtag.GetAttribute('sid'));
    end;

    _iq.setAttribute('to', TOJID);
    MainSession.SendTag(_iq);

    tasktype := '';
    taskinfo := qtag.GetFirstTag('taskinfo');

    if taskinfo <> nil then
      tasktype := taskinfo.GetAttribute('tasktype');

    if tasktype = 'getsharefile' then
    begin
      startsend;
    end;
  end;

  if tag.GetAttribute('type') = 'result' then
    if sending then
      continuesend;

  inherited;
end;

procedure TJITSendShareFile.startsend;
var
  EnCoder: TIdEncoderMIME;
  _iq: TXMLTag;
  buf: array[0..4095] of byte;
  CM: TMemoryStream;
  bufsize: integer;
begin
  //如果正在创建共享列表则等待创建完成
  fs := TFileStream.Create(ShareFileName, fmOpenRead);

  seqNo := 0;
  seqCount := (fs.Size) div (BlockSize * 3 div 4);
  if (fs.Size * 4) mod (BlockSize * 3) <> 0 then
    inc(seqCount);

  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', MainSession.generateID());
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    setAttribute('seq', inttostr(seqNo));
    setAttribute('totalseq', inttostr(seqcount));

    EnCoder := TIdEncoderMIME.Create(nil);
    bufsize := fs.Read(buf, 4096);

    FillChar(FBuffer, 5000, #0);
    FZRec.next_out := FBuffer;
    FZRec.avail_out := sizeof(FBuffer);
    CCheck(deflateInit_(FZRec, -1, zlib_version, sizeof(FZRec)));

    FZRec.next_in := @buf;
    FZRec.avail_in := bufsize;
    while (FZRec.avail_in > 0) do
    begin
      CCheck(deflate(FZRec, 2));
    end;
    bufsize := 5000 - FZRec.avail_out;

    CM := TMemoryStream.Create;
    bufsize := cm.Write(FBuffer, bufsize);
    cm.Seek(0, soFromBeginning);

    bufsize := (bufsize + 2) - ((bufsize + 2) mod 3);
    Buffer := EnCoder.Encode(cm, bufsize);
    CM.Free;
    EnCoder.Free;
    with AddTag('data') do
    begin
      AddCData(copy(Buffer, 1, length(Buffer)));
    end;
    inc(seqNo);
    if seqNo >= seqcount then
      AddTag('close');
  end;
  MainSession.SendTag(_iq);

  sending := seqNo < seqcount;
  while sending do
  begin
    continuesend;
    Application.ProcessMessages;
  end;
end;

{ TJITRcvInstantMail }

procedure TJITRcvInstantMail.ProcessReceive(tag: TXMLTag);
begin
  inherited;

end;

procedure TJITRcvInstantMail.SendReady(ReadyID: widestring);
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', ReadyID);
  _iq.setAttribute('type', 'result');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
  end;
  MainSession.SendTag(_iq);
end;

{ TJITSendInstantMail }

procedure TJITSendInstantMail.ProcessReceive(tag: TXMLTag);
begin
  inherited;

end;

procedure TJITSendInstantMail.AskReady(ReadyID: widestring);
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', ReadyID);
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    with AddTag('taskinfo') do
    begin
      setAttribute('tasktype', 'sendinstantmail');
      AddBasicTag('filename', InmFileName);
    end;
  end;
  MainSession.SendTag(_iq);
end;

procedure TJITSendInstantMail.startsend;
begin
  if assigned(Fonsend) then
    FOnSend(self);
end;

{ TJITRcvFile }

procedure TJITRcvFile.ProcessReceive(tag: TXMLTag);
begin
  inherited;

end;

procedure TJITRcvFile.SendReady(ReadyID: widestring);
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', ReadyID);
  _iq.setAttribute('type', 'result');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
  end;
  MainSession.SendTag(_iq);
end;

{ TJITSendFile }

procedure TJITSendFile.AskReady(ReadyID: widestring);
var
  _iq: TXMLTag;
begin
  _iq := TXMLTag.Create('iq');
  _iq.setAttribute('id', ReadyID);
  _iq.setAttribute('type', 'set');
  _iq.setAttribute('to', TOJID);
  with _iq.AddTag('query') do
  begin
    setAttribute('xmlns', XMLNS_IBB);
    setAttribute('sid', IBBSID);
    with AddTag('taskinfo') do
    begin
      setAttribute('tasktype', 'sendfile');
      AddBasicTag('filename', FileName);
    end;
  end;
  MainSession.SendTag(_iq);
end;

procedure TJITSendFile.ProcessReceive(tag: TXMLTag);
begin
  inherited;

end;

procedure TJITSendFile.startsend;
begin
  if assigned(Fonsend) then
    FOnSend(self);
end;

initialization
  MainIBBController := TJabberIBBController.Create;

finalization
  MainIBBController.Free;
  MainIBBController := nil;

end.
