unit GetShare;

interface

uses
  XMLTAG, Dockable, zlib, udp,
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, ExtCtrls, StdCtrls, IdBaseComponent, IdCoder,
  IdCoder3to4, IdCoderMIME, RxCombos, ImgList, CommCtrl, IdAntiFreezeBase,
  IdAntiFreeze, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP,
  ShellCtrls, Buttons;

type
  TfmGetShare = class(TfrmDockable)
    Panel3: TPanel;
    Button1: TButton;
    Panel1: TPanel;
    TVShare: TTreeView;
    Splitter1: TSplitter;
    LVShare: TListView;
    ImageList1: TImageList;
    IdDecoderMIME1: TIdDecoderMIME;
    btnRefresh: TButton;
    Button3: TButton;
    Panel4: TPanel;
    Splitter2: TSplitter;
    pnlLocal: TPanel;
    lvTask: TListView;
    ProgressBar1: TProgressBar;
    shcomboLocal: TShellComboBox;
    shlvlocal: TShellListView;
    spbtnLocalUp: TSpeedButton;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure TVShareExpanding(Sender: TObject; Node: TTreeNode;
      var AllowExpansion: Boolean);
    procedure Button1Click(Sender: TObject);
    procedure LVShareData(Sender: TObject; Item: TListItem);
    procedure TVShareChange(Sender: TObject; Node: TTreeNode);
    procedure LVShareDblClick(Sender: TObject);
//    procedure IdHTTP1WorkEnd(Sender: TObject; AWorkMode: TWorkMode);
    procedure FormDestroy(Sender: TObject);
//    procedure IdHTTP1WorkBegin(Sender: TObject; AWorkMode: TWorkMode;
//      const AWorkCountMax: Integer);
//    procedure IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
//      const AWorkCount: Integer);
    procedure btnRefreshClick(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure spbtnLocalUpClick(Sender: TObject);
    procedure pnlLocalResize(Sender: TObject);
    procedure lvTaskData(Sender: TObject; Item: TListItem);
    procedure lvTaskCustomDrawSubItem(Sender: TCustomListView;
      Item: TListItem; SubItem: Integer; State: TCustomDrawState;
      var DefaultDraw: Boolean);
    procedure FormShow(Sender: TObject);
    procedure shlvlocalDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure lvTaskDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure lvTaskDragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure shlvlocalDragDrop(Sender, Source: TObject; X, Y: Integer);
  private
    { Private declarations }
//    _task: TAnyQUDPTask;
    TaskList: TList;
    _taskpos: Integer;
    _sidPos: Integer;
//    _taskhost: TStringList;
//    _GetMode: Integer;  //0: 列表； 1: 文件
//    _GetFileName: string;

    procedure GetShareListCallback(event: string; tag: TXMLTag);
    procedure GetShareFileCallback(event: string; tag: TXMLTag);
    procedure resetlvtask;
    procedure DeleteTask(TaskID: TGUID);
  public
    { Public declarations }
    _JID: widestring;
//    _SID: widestring;
    SIDList: TStringList;
    Buf: widestring;
    BufStream: TStream;
    SeqNo: cardinal;
    SeqCount: cardinal;
    ShareTag: TXMLTAG;
//    TaskID: TGUID;

    procedure UdpRcv(sender: TObject; Adata: TStream);
    procedure UdpRcvStatus(sender: TObject);
    procedure UdpFail(sender: TObject);
    procedure UdpTimeout(Sender: TObject);
    procedure UdpRcvTimeout(Sender: TObject);
    procedure InitRcv(Sender: TObject);

    procedure StartGetShare;
    procedure StartGetShareIBB;
    procedure StartGetShareFile(FileName: widestring; savepath: string = ''; filesize: Integer = maxint);
    procedure StartGetShareFileIBB(FileName: widestring; savepath: string = ''; filesize: Integer = maxint);
    procedure ProcessReceive(tag: TXMLTag);
    procedure ProcessFileReceive(tag: TXMLTag);
    procedure BuildShareView;
    procedure IBBTaskDestroy(Sender: TObject);
  end;

var
  fmGetShare: TfmGetShare;

procedure GetShareList(JID: widestring);

implementation

uses IBB, Session, XMLUtils, JabberConst, JabberID, presence, Roster, Zlibconst,
  XMLParser, shellapi, iq, ShareUnit, math, RiserWindow, IdCompressionIntercept,
  Jabber1;

{$R *.dfm}

Type
  TShareShellComboBox = class(TShellComboBox);

  TShareTask = class(TAnyQBaseUDPTask)
  private

  public
    FBuffer: array[0..4999] of char;
    FZRec: zlib.TZStreamRec;
    _GetMode: Integer;
    _GetFileName: string;
    _SaveFileName: string;
    _FileSize: Integer;
    BufStream: TStream;
    constructor Create(Controller: TAnyQUDPController; GUID: TGUID); override;
    destructor Destroy; override;
    procedure InitRcv;
  end;

  TGetFileIQ = Class(TJabberIQ)
  published
    procedure Timeout(Sender: TObject); override;
  end;

function sizestr(sizes: widestring): widestring;
var
  size: Int64;
begin
  Result := '';
  try
    size := StrToInt64(sizes);
  except
    exit;
  end;
  size := Ceil(size / 1024);
  Result := FormatFloat('#,##0 KB', size);
end;

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

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

function SlashSep(const Path, S: string): string;
begin
  if AnsiLastChar(Path)^ <> '\' then
    Result := Path + '\' + S
  else
    Result := Path + S;
end;

procedure GetShareList(JID: widestring);
var
  tmp_id: TJabberID;
  ip, tmps: string;
  pri: TJabberPres;
  ritem: TJabberRosterItem;
  p: integer;
begin
  tmp_id := TJabberID.Create(JID);
  if (tmp_id.resource = '') then begin
    pri := MainSession.ppdb.FindPres(tmp_id.jid, '');
    if (pri = nil) then begin
      ShowRiserWindow(nil, '只能获取联机用户的共享列表!', ico_info);
      //MessageBox(application.Handle, '只能获取联机用户的共享列表!', '错误', MB_OK OR MB_ICONERROR);
      exit;
    end;
    tmps := pri.fromJID.full;
  end
  else
    tmps := JID;

  JID := tmps;
  tmp_id.Free();

  if JID = '' then exit;
  with TfmGetShare.create(Application) do
  begin
    _JID := JID;
    Show;
    StartGetShare;
  end;
end;


procedure TfmGetShare.BuildShareView;
var
  Parser: TXMLTagParser;
  clist, cclist: TXMLTagList;
  Root, Node: TTreeNode;
  i, j: Integer;
  fn: widestring;
begin
  ProgressBar1.Max := 100;
  ProgressBar1.Position := 0;

  Parser := TXMLTagParser.Create;
  Parser.ParseString(Buf, '');
  Buf := '';
  if Parser.Count > 0 then
    ShareTag := Parser.popTag;
  Parser.free;
  if ShareTag = nil then exit;
  TVShare.Items.Clear;
  LVShare.Clear;
  Root := TVShare.Items.AddChild(nil, _JID);
  Root.Data := ShareTag;
  clist := ShareTag.ChildTags;
  for i := 0 to clist.Count - 1 do
  begin
    if clist.Tags[i].Name = 'DIR' then
    begin
      fn := clist.Tags[i].GetAttribute('name');
      if fn[length(fn)] = '\' then
        Delete(fn, length(fn), 1);
      if fn[length(fn)] = ':' then
        Delete(fn, length(fn), 1);

      Node := TVShare.Items.AddChild(Root, ExtractFilename(fn));
      Node.ImageIndex := 1;
      Node.SelectedIndex := 2;
      Node.Data := clist.Tags[i];
      node.HasChildren := false;
      cclist := clist.Tags[i].ChildTags;
      for j := 0 to cclist.Count - 1 do
        if cclist.Tags[j].Name = 'DIR' then
        begin
          node.HasChildren := true;
          break;
        end;
      cclist.Free;
    end;
  end;
  clist.Free;
end;

procedure TfmGetShare.FormClose(Sender: TObject; var Action: TCloseAction);
begin
{  if IdHTTP1.Connected then
    IdHTTP1.DisconnectSocket;    {}
  Action := caFree;
end;

procedure TfmGetShare.ProcessReceive(tag: TXMLTag);
var
  qtag, taskinfo: TXMLTag;
  SID, tasktype: widestring;
  _iq: TXMLTag;
  DecBuf: Pointer;
  DecompressSize: Integer;
  decstr: string;
begin
  qtag := tag.GetFirstTag('query');
  if qtag = nil then exit;

  if tag.GetAttribute('type') = 'set' then
  begin
   SID := qtag.GetAttribute('sid');
    if qtag.GetAttribute('seq') <> '' then
    begin
      seqNo := strtoint(qtag.GetAttribute('seq'));
    end;

    if qtag.GetAttribute('totalseq') <> '' then
    begin
      seqcount := strtoint(qtag.GetAttribute('totalseq'));
    end;

    if qtag.GetFirstTag('data') <> nil then
      buf := Buf + qtag.GetFirstTag('data').Data;

    ProgressBar1.Position := (SeqNo + 1) * 100 div seqcount;

    _iq := TXMLTag.Create('iq');
    _iq.setAttribute('id', tag.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', _jid);
    MainSession.SendTag(_iq);

    if qtag.GetFirstTag('close') <> nil then
    begin
      decstr := IdDecoderMIME1.DecodeToString(Buf);
      DecompressBuf(@decstr[1], length(decstr), 0, DecBuf, DecompressSize);
      SetLength(decstr, DecompressSize);
      move(Decbuf^, decstr[1], DecompressSize);
      Buf := UTF8Decode(decstr);
//      Buf := decstr;
      BuildShareView;
      if SIDList.IndexOf(SID)>=0 then
      begin
        TJITGetShareList(SIDList.Objects[SIDList.IndexOf(SID)]).Free;
        SIDList.Delete(SIDList.IndexOf(SID));
      end;
      resetlvtask;
    end;
  end;
end;

procedure TfmGetShare.StartGetShare;
var
  i: Integer;
  iq: TJabberIQ;
  taskguid: TGUID;
  hosts: Tstringlist;
  _task: TShareTask;
begin
  btnRefresh.Enabled := false;
//  _GetMode := 0;
  ProgressBar1.Max := MaxInt;
  BufStream := TStringStream.Create('');
  CreateGUID(taskguid);
//  TaskID := taskguid;
  try
    _Task := TShareTask.Create(UDPController, taskguid);
    _Task._GetMode := 0;
    _Task.OnRcvData := UdpRcv;
    _Task.OnRcvStatus := UdpRcvStatus;
    _Task.OnFail := UdpFail;
    _Task.OnTimeOut := UdpTimeout;

    TaskList.Add(_task);
    hosts := TStringList.Create;
    UDPController.GetUDPInfo(hosts);

    iq := TJabberIQ.Create(MainSession, GUIDToString(_Task.TaskID), GetShareListCallback);
    with iq do begin
      Namespace := XMLNS_AnyQUDP;
      iqType := 'set';
      toJid := _JID;
      qTag.AddBasicTag('taskid', GUIDToString(_Task.TaskID));
      qTag.AddBasicTag('type', 'sharelist');
      qTag.AddBasicTag('sync', 'true');
      for i:= 0 to hosts.Count-1 do
        qTag.AddBasicTag('host', hosts[i]);
      Send();
    end;
    FreeAndNil(hosts);
//    iq.Send;
//    MainSession.SendTag(iq);
  except
    for i:= TaskList.Count-1 downto 0 do
    begin
      if IsEqualGUID(taskguid, TshareTask(TaskList.Items[i]).TaskID) then
      begin
//        TshareTask(TaskList.Items[i]).Free;
        TaskList.Delete(i);
        break;
      end;
    end;
    StartGetShareIBB;
  end;
  resetlvtask;   {}
end;
{var
  f: file of byte;
  iq: TXMLTag;
  hosts: Tstringlist;
  i: Integer;
  taskguid: TGUID;
begin
  CreateGUID(taskguid);
  TaskID := taskguid;
  try
    _Task := TAnyQUDPTask.Create(UDPController, taskguid);
    _Task.SyncDataSend := true;
    _Task.OnRcvData := UdpRcv;
    _Task.OnConnected := UdpConnected;
    _Task.OnConnectFail := UdpConnectFail;
    hosts := TStringList.Create;
    UDPController.GetUDPInfo(hosts);
    iq := TXMLTag.Create('iq');
    with iq do begin
      setAttribute('to', _jid);
      setAttribute('id', MainSession.generateID());
      setAttribute('type', 'set');
      with AddTag('query') do begin
        setAttribute('xmlns', XMLNS_AnyQUDP);
        AddBasicTag('taskid', GUIDToString(_Task.TaskID));
        AddBasicTag('type', 'sharelist');
        AddBasicTag('sync', 'true');
        with AddBasicTag('desc', '') do
        begin
          setAttribute('filename', ExtractFileName(filename));
          AssignFile(f, filename);
          Reset(f);
          setAttribute('filesize', inttostr(FileSize(f)));
          CloseFile(f);
        end;
        for i:= 0 to hosts.Count-1 do
          AddBasicTag('host', hosts[i]);
      end;
    end;
    MainSession.SendTag(iq);
  except
    StartGetShareIBB;
//    sendbyibb;
  end;
end;
{}
{
var
  iq: TJabberIQ;
begin
  iq := TJabberIQ.Create(MainSession, MainSession.generateID, GetShareListCallback);
  with iq do begin
    Namespace := XMLNS_IQOOB;
    iqType := 'set';
    toJid := _JID;
    qTag.AddBasicTag('task', 'getsharelist');
    Send();
  end;
end;
{}

procedure TfmGetShare.FormCreate(Sender: TObject);
var
  icon: Ticon;
  si: TSHFILEINFO;
  ImageListHandle: THandle;
begin
  inherited;
  TShareShellComboBox(shcomboLocal).Style := csExDropDownList;
  icon := Ticon.Create;
  SHGetFileInfo('\\user', FILE_ATTRIBUTE_NORMAL, si, sizeof(si), SHGFI_USEFILEATTRIBUTES or SHGFI_ICON or SHGFI_SMALLICON);
  icon.Handle := si.hIcon;
  ImageList1.AddIcon(icon);
  DestroyIcon(si.hIcon);
  SHGetFileInfo('user', FILE_ATTRIBUTE_DIRECTORY, si, sizeof(si), SHGFI_USEFILEATTRIBUTES or SHGFI_ICON or SHGFI_SMALLICON);
  icon.Handle := si.hIcon;
  ImageList1.AddIcon(icon);
  DestroyIcon(si.hIcon);
  SHGetFileInfo('user', FILE_ATTRIBUTE_DIRECTORY, si, sizeof(si), SHGFI_USEFILEATTRIBUTES or SHGFI_ICON or SHGFI_SMALLICON or SHGFI_OPENICON);
  icon.Handle := si.hIcon;
  ImageList1.AddIcon(icon);
  DestroyIcon(si.hIcon);
  icon.free;
  TaskList := TList.Create;
  SIDList := TStringList.Create;

  ImageListHandle := SHGetFileInfo('C:\',
    0,
    SI,
    SizeOf(SI),
    SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  SendMessage(LVShare.Handle, LVM_SETIMAGELIST, LVSIL_SMALL, ImageListHandle);    {}
end;

procedure TfmGetShare.TVShareExpanding(Sender: TObject; Node: TTreeNode;
  var AllowExpansion: Boolean);
var
  i, j: Integer;
  clist, cclist: TXMLTagList;
  cNode: TTreeNode;
begin
  if (Node.Count = 0) and Node.HasChildren then
  begin
    clist := TXMLTAG(Node.Data).ChildTags;
    for i := 0 to clist.Count - 1 do
    begin
      if clist.Tags[i].Name = 'DIR' then
      begin
        cNode := TVShare.Items.AddChild(Node, clist.Tags[i].GetAttribute('name'));
        cNode.ImageIndex := 1;
        cNode.SelectedIndex := 2;
        cNode.Data := clist.Tags[i];
        cnode.HasChildren := false;
        cclist := clist.Tags[i].ChildTags;
        for j := 0 to cclist.Count - 1 do
          if cclist.Tags[j].Name = 'DIR' then
          begin
            cnode.HasChildren := true;
            break;
          end;
        cclist.Free;
      end;
    end;
    clist.free;
  end;
end;

procedure TfmGetShare.Button1Click(Sender: TObject);
begin
  self.Close;
end;

procedure TfmGetShare.LVShareData(Sender: TObject; Item: TListItem);
var
  clist: TXMLTagList;
  tag: TXMLTag;
  si: TSHFILEINFO;
  fn: widestring;
begin
  if TVShare.Selected = nil then
    exit;
  clist := TXMLTAG(TVShare.Selected.data).ChildTags;
  item.Data := clist.Tags[item.index];
  fn := clist.Tags[item.index].GetAttribute('name');
  if fn[length(fn)] = '\' then
    Delete(fn, length(fn), 1);
  if fn[length(fn)] = ':' then
    Delete(fn, length(fn), 1);

  item.Caption := ExtractFileName(fn);

  clist.Free;
  tag := TXMLTag(item.Data);
  if tag.name = 'DIR' then
  begin
    SHGetFileInfo(pchar(item.Caption), FILE_ATTRIBUTE_DIRECTORY, si, sizeof(si),
      SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_TYPENAME);
    Item.ImageIndex := si.iIcon;
    item.SubItems.add('');
    item.SubItems.add(si.szTypeName);
  end
  else
  begin
    SHGetFileInfo(pchar(item.Caption), FILE_ATTRIBUTE_NORMAL, si, sizeof(si),
      SHGFI_USEFILEATTRIBUTES or SHGFI_SYSICONINDEX or SHGFI_SMALLICON or SHGFI_TYPENAME);
    Item.ImageIndex := si.iIcon;
    item.SubItems.add(sizestr(tag.GetAttribute('size')));
    item.SubItems.add(si.szTypeName);
  end;
//  if
end;

procedure TfmGetShare.TVShareChange(Sender: TObject; Node: TTreeNode);
var
  clist: TXMLTagList;
begin
  if TVShare.Selected = nil then
  begin
    LVShare.Items.Count := 0;
    exit;
  end;
  clist := TXMLTAG(TVShare.Selected.data).ChildTags;
  LVShare.Items.Count := clist.Count;
  clist.Free;
  LVShare.Invalidate;
end;

procedure TfmGetShare.LVShareDblClick(Sender: TObject);
var
  i: Integer;
begin
  if LVShare.Selected = nil then exit;
  if TXMLTag(LVShare.Selected.Data).Name = 'DIR' then
  begin
    TVShare.Selected.Expand(false);
    for i := 0 to TVShare.Selected.Count - 1 do
      if TVShare.Selected.Item[i].Text = LVShare.Selected.Caption then
      begin
        TVShare.Selected.Item[i].Selected := true;
        exit;
      end;
  end;
end;

procedure TfmGetShare.StartGetShareIBB;
var
  task: TJITGetShareList;
begin
//  _GetMode := 0;
  task := TJITGetShareList.Create;
  with task do
  begin
    _GetMode := 0;
    TOJID := _JID;
    IBBController := MainIBBController;
    IBBSID := Sha1Hash(FormatDateTime('MMDDYYYYHHMM', now) + _jid +
      MainSession.Username + MainSession.Server);
//    _SID := IBBSID;
    OnProcessReceive := self.ProcessReceive;
    OnDestroy := self.IBBTaskDestroy;
  end;
  SIDList.AddObject(task.IBBSID, task);
  MainIBBController.AddTask(task.IBBSID, task);
  SeqNo := 0;
  SeqCount := 0;
  Buf := '';
  ShareTag := nil;
  task.Start;
  resetlvtask;
end;

procedure TfmGetShare.GetShareListCallback(event: string; tag: TXMLTag);
var
  url: string;
  tmptag: TXMLTag;
  i: Integer;
  id: string;
  taskid: TGUID;
begin
  if ((event = 'xml') or (event = 'cache')) then begin
    if (tag.GetAttribute('type') = 'error') then
    begin
      with tag.GetFirstTag('error') do
      begin
        if GetAttribute('code') = '' then
        begin
          ShowRiserWindow(nil, '您没有获取该用户共享文件的权限', ico_info);
          //MessageBox(application.Handle, '您没有获取该用户共享文件的权限', '错误', MB_OK OR MB_ICONERROR);
          Close;
          exit;
        end;
      end;
    end;

    tmptag := tag.GetFirstTag('query');
    if tmptag<> nil then
      tmptag := tmptag.GetFirstTag('desc');

    if (tag.GetAttribute('type') = 'set') then
    begin
      if tmptag <> nil then
        ProgressBar1.Max := StrToInt(tmptag.GetAttribute('filesize'))
    end
    else
    begin
      id := tag.GetAttribute('id');
      if id<>'' then
      begin
        taskid := StringToGUID(id);
        for i:= TaskList.Count-1 downto 0 do
        begin
          if IsEqualGUID(taskid, TShareTask(TaskList.Items[i]).TaskID) then
          begin
            TShareTask(TaskList.Items[i]).Free;
            TaskList.Delete(i);
            break;
          end;
        end
      end;

      FreeAndNil(BufStream);
      StartGetShareIBB;{}
    end;
{    if (tag.GetAttribute('type') = 'set') then begin
      if assigned(BufStream) then
        BufStream.Free;
      BufStream := TstringStream.Create('');
      tmptag := tag.GetFirstTag('query');
      url := tmptag.GetBasicText('url');
      try
        try
          if IdHTTP1.Intercept = nil then
            IdHTTP1.Intercept := TIdCompressionIntercept.Create(nil);
          TIdCompressionIntercept(IdHTTP1.Intercept).CompressionLevel := 9;
          IdHTTP1.Get(url, BufStream);
          IdHTTP1.Disconnect;
          if IdHTTP1.Intercept <> nil then
            IdHTTP1.Intercept.Free;
          IdHTTP1.Intercept := nil;
        except
          StartGetShareIBB;
        end;
      finally
        FreeAndNil(BufStream);
      end;
    end
    else
      StartGetShareIBB;{}
  end
  else begin
    ShowRiserWindow(nil, '对方网络繁忙，无法获取共享列表', ico_info);
    btnRefresh.Enabled := true;
    exit;
//    StartGetShareIBB;
  end;
end;
{
procedure TfmGetShare.IdHTTP1WorkEnd(Sender: TObject;
  AWorkMode: TWorkMode);
begin
  Buf := UTF8Decode(TStringStream(BufStream).DataString);
  BuildShareView;
end;
{}
procedure TfmGetShare.FormDestroy(Sender: TObject);
var
  i: integer;
begin
  for i:= SIDList.Count-1 downto 0 do
  begin
    if MainIBBController.FindTask(SIDList[i]) <> nil then
      MainIBBController.FindTask(SIDList[i]).Close;
  end;

  lvTask.Items.Count := 0;
  for i:= TaskList.Count-1 downto 0 do
    TSharetask(TaskList.Items[i]).Free;

  TaskList.Free;
  SIDList.Free;

  if BufStream <> nil then
    FreeAndNil(BufStream);
  if assigned(ShareTag) then
    FreeAndNil(ShareTag);   {}
  inherited;
end;
{
procedure TfmGetShare.IdHTTP1WorkBegin(Sender: TObject;
  AWorkMode: TWorkMode; const AWorkCountMax: Integer);
begin
  ProgressBar1.Max := AWorkCountMax;
end; {}
{
procedure TfmGetShare.IdHTTP1Work(Sender: TObject; AWorkMode: TWorkMode;
  const AWorkCount: Integer);
begin
  ProgressBar1.Position := AWorkCount;
end;
{}
procedure TfmGetShare.btnRefreshClick(Sender: TObject);
begin
  StartGetShare;
end;

type
  TStartGetThread = class(TThread)
  private
  protected
    procedure run;
    procedure Execute; override;
  public
    frm: TfmGetShare;
    fileName: String;
    SaveFilename: string;
    size: Integer;
  end;


procedure TfmGetShare.Button3Click(Sender: TObject);
var
  Node: TTreeNode;
  fullfilename: widestring;
  filesize: Integer;
  Tag: TXMLTag;
begin
  if LVShare.Selected = nil then exit;
  if TXMLTag(LVShare.Selected.Data).Name = 'DIR' then exit;
  fullfilename := TXMLTag(LVShare.Selected.Data).GetAttribute('name');
  filesize := strtoint(TXMLTag(LVShare.Selected.Data).GetAttribute('size'));
  Node := TVShare.Selected;
  while Node.Level >= 1 do
  begin
    Tag := TXMLTag(Node.data);
    fullfilename := SlashSep(Tag.GetAttribute('name'), fullfilename);
    Node := Node.Parent;
  end;
{  with TStartGetThread.Create(True) do
  begin
    frm := self;
    FreeOnTerminate := true;
    fileName := fullfilename;
    SaveFilename := '';
    size := filesize;
    Resume;
  end;    {}
  StartGetShareFile(fullfilename, '', filesize);
  //
end;

procedure TfmGetShare.StartGetShareFile(FileName: widestring; savepath: string = ''; filesize: Integer = maxint);
var
  i: Integer;
  iq: TJabberIQ;
  taskguid: TGUID;
  hosts: Tstringlist;
  fn, tmpfn, tmpext: Widestring;
  _task: TShareTask;
begin
  if TaskList.Count>=3 then
  begin
    ShowRiserWindow(nil,'一次不能同时下载超过三个文件！',ico_info);
    exit;
  end;
//  _GetMode := 1;
  ProgressBar1.Max := MaxInt;
  fn := ExtractFileName(FileName);
  if savepath='' then
    fn := SlashSep(shcomboLocal.Path, fn)
  else
    fn := SlashSep(savepath, fn);

//  ForceDirectories(MainSession.Prefs.getString('xfer_path'));
//  fn := SlashSep(MainSession.Prefs.getString('xfer_path'), fn);
  tmpfn := fn;
  tmpext := ExtractFileExt(fn);
  i := 1;
  while FileExists(tmpfn) do
  begin
    inc(i);
    tmpfn := fn;
    tmpfn := ChangeFileExt(tmpfn, '');
    tmpfn := tmpfn + ' (' + inttostr(i) + ')';
    tmpfn := tmpfn + tmpext;
  end;
  fn := tmpfn;

  CreateGUID(taskguid);
//  TaskID := taskguid;
  try
    _Task := TShareTask.Create(UDPController, taskguid);
    _Task._GetMode := 1;
    _Task.OnRcvData := UdpRcv;
    _Task.OnRcvData := UdpRcv;
    _Task.OnRcvStatus := UdpRcvStatus;
    _Task.OnFail := UdpFail;
    _Task.OnTimeOut := UdpTimeout;

    _task._GetFileName := FileName;
    _task._SaveFileName := fn;
    _task._FileSize := filesize;
    TaskList.Add(_task);
    resetlvtask;
    hosts := TStringList.Create;
    UDPController.GetUDPInfo(hosts, true);

    iq := TGetFileIQ.Create(MainSession, GUIDToString(_Task.TaskID), GetShareFileCallback);
    with iq do begin
      Namespace := XMLNS_AnyQUDP;
      iqType := 'set';
      toJid := _JID;
      qTag.AddBasicTag('taskid', GUIDToString(_Task.TaskID));
      qTag.AddBasicTag('type', 'sharefile');
      qTag.AddBasicTag('sync', 'true');
      with qTag.AddBasicTag('desc', '') do
        setAttribute('filename', filename);
      for i:= 0 to hosts.Count-1 do
        qTag.AddBasicTag('host', hosts[i]);
      Send();
    end;
    FreeAndNil(hosts);
//    iq.Send;
//    MainSession.SendTag(iq);
  except
    for i:= TaskList.Count-1 downto 0 do
    begin
      if IsEqualGUID(taskguid, TshareTask(TaskList.Items[i]).TaskID) then
      begin
//        TshareTask(TaskList.Items[i]).Free;
        TaskList.Delete(i);
        resetlvtask;
        break;
      end;
    end;
    StartGetShareFileIBB(FileName, savepath, filesize);
  end;
  resetlvtask;
{var
  iq: TJabberIQ;
begin
  _GetMode := 1;
  iq := TJabberIQ.Create(MainSession, MainSession.generateID, GetShareFileCallback);
  with iq do begin
    Namespace := XMLNS_IQOOB;
    iqType := 'set';
    toJid := _JID;
    qTag.AddBasicTag('task', 'getsharefile');
    qTag.GetFirstTag('task').setAttribute('name', FileName);
    Send();
  end;  {}
end;

procedure TfmGetShare.StartGetShareFileIBB(FileName: widestring; savepath: string = ''; filesize: Integer = maxint);
var
  task: TJITGetShareFile;
  fn, tmpfn, tmpext: Widestring;
  i: integer;
begin
//  _GetMode := 1;
  fn := ExtractFileName(FileName);
  if savepath='' then
    fn := SlashSep(shcomboLocal.Path, fn)
  else
    fn := SlashSep(savepath, fn);

//  ForceDirectories(MainSession.Prefs.getString('xfer_path'));
//  fn := SlashSep(MainSession.Prefs.getString('xfer_path'), fn);
  tmpfn := fn;
  tmpext := ExtractFileExt(fn);
  i := 1;
  while FileExists(tmpfn) do
  begin
    inc(i);
    tmpfn := fn;
    tmpfn := ChangeFileExt(tmpfn, '');
    tmpfn := tmpfn + ' (' + inttostr(i) + ')';
    tmpfn := tmpfn + tmpext;
  end;
  fn := tmpfn;

  task := TJITGetShareFile.Create;
  with task do
  begin
    _GetMode := 1;
    _GetFileName := FileName;
    _SaveFileName := fn;
    _FileSize := filesize;
    BufStream := TFileStream.Create(fn, fmCreate);
    TOJID := _JID;
    IBBController := MainIBBController;
    IBBSID := Sha1Hash(FormatDateTime('MMDDYYYYHHMM', now) + _jid +
      MainSession.Username + MainSession.Server);
//    _SID := IBBSID;
    OnProcessReceive := self.ProcessFileReceive;
    OnDestroy := self.IBBTaskDestroy;

    ShareFileName := FileName;
  end;
  SIDList.AddObject(task.IBBSID, task);
  MainIBBController.AddTask(task.IBBSID, task);
  SeqNo := 0;
  SeqCount := 0;
  Buf := '';
  ShareTag := nil;


  with task do
  begin
    FZRec.zalloc := zlibAllocMem;
    FZRec.zfree := zlibFreeMem;
    FZRec.next_in := FBuffer;
    FZRec.avail_in := 0;
    DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
  end;

  task.Start;
  resetlvtask;
end;

procedure TfmGetShare.DeleteTask(TaskID: TGUID);
var
  i: Integer;
begin
  for i:= TaskList.Count-1 downto 0 do
  begin
    if IsEqualGUID(TaskID, TShareTask(TaskList.Items[i]).TaskID) then
    begin
      TShareTask(TaskList.Items[i]).Free;
      TaskList.Delete(i);
      break;
    end;
  end;
  resetlvtask;
end;

procedure TfmGetShare.GetShareFileCallback(event: string; tag: TXMLTag);
var
  url: string;
  tmptag: TXMLTag;
  i: Integer;
  id: string;
  taskid: TGUID;
  fn,path: string;
  filesize: integer;
  sType: string;
//  sErr: string;
begin
  if ((event = 'xml') or (event = 'cache')) then begin
    sType := tag.GetAttribute('type');
    if (sType = 'error') then
    begin
      with tag.GetFirstTag('error') do
      begin
        ShowRiserWindow(nil, Data, ico_info);
        id := tag.GetAttribute('id');
        if id<>'' then
        begin
          taskid := StringToGUID(id);
          DeleteTask(taskid);
        end;
        exit;
{        if GetAttribute('code') = '' then
        begin
          ShowRiserWindow(nil, '您没有获取该用户共享文件的权限', ico_info);
          //MessageBox(application.Handle, '您没有获取该用户共享文件的权限', '错误', MB_OK OR MB_ICONERROR);
          Close;
        end;{}
      end;
    end;

    tmptag := tag.GetFirstTag('query');
    if tmptag<> nil then
      tmptag := tmptag.GetFirstTag('desc');

    if (sType = 'set') then
    begin
      if tmptag<> nil then
        ProgressBar1.Max := StrToInt(tmptag.GetAttribute('filesize'))
    end
    else
    begin
      id := tag.GetAttribute('id');
      if id<>'' then
      begin
        taskid := StringToGUID(id);
        for i:= TaskList.Count-1 downto 0 do
        begin
          if IsEqualGUID(taskid, TShareTask(TaskList.Items[i]).TaskID) then
          begin
            fn := TShareTask(TaskList.Items[i])._GetFileName;
            path := ExtractFilePath(TShareTask(TaskList.Items[i])._SaveFileName);
            filesize := TShareTask(TaskList.Items[i])._FileSize;
            TShareTask(TaskList.Items[i]).Free;
            TaskList.Delete(i);
            sType := '';
            StartGetShareFileIBB(fn, path, filesize);
            break;
          end;
        end;
      end;
    end;
  end
  else
  begin
    ShowRiserWindow(nil, '对方网络繁忙，无法获取共享文件', ico_info);
    id := tag.GetAttribute('id');
    if id<>'' then
    begin
      taskid := StringToGUID(id);
      DeleteTask(taskid);
    end;
    exit;
//    StartGetShareFileIBB(_GetFileName);
  end;
end;
//var
//  url: string;
//  tmptag: TXMLTag;
//  fs: TFileStream;
//  fn, tmpfn, tmpext: Widestring;
//  i: integer;
//begin
//  tmptag := tag.GetFirstTag('query');
//  if ((event = 'xml') or (event = 'cache')) then begin
//    if (tag.GetAttribute('type') = 'set') then begin
//      url := tmptag.GetBasicText('url');
//      try
//        try
//          fn := ExtractFileName(tmptag.GetFirstTag('task').GetAttribute('name'));
//          fn := SlashSep(MainSession.Prefs.getString('xfer_path'), fn);
//          tmpfn := fn;
//          tmpext := ExtractFileExt(fn);
//          i := 1;
//          while FileExists(tmpfn) do
//          begin
//            inc(i);
//            tmpfn := fn;
//            tmpfn := ChangeFileExt(tmpfn, '');
//            tmpfn := tmpfn + ' (' + inttostr(i) + ')';
//            tmpfn := ChangeFileExt(tmpfn, tmpext);
//          end;
//          fn := tmpfn;
//
//          ForceDirectories(ExtractFilePath(fn));
//          fs := TFileStream.Create(fn, fmCreate);
//          if IdHTTP2.Intercept = nil then
//            IdHTTP2.Intercept := TIdCompressionIntercept.Create(nil);
//          TIdCompressionIntercept(IdHTTP2.Intercept).CompressionLevel := 9;
//          IdHTTP2.Get(url, fs);
//          IdHTTP2.Disconnect;
//          if IdHTTP2.Intercept <> nil then
//            IdHTTP2.Intercept.Free;
//          IdHTTP2.Intercept := nil;
//
//          showmessage('文件获取完毕，保存在' + fn);
//        except
//          if assigned(fs) then
//            FreeAndNil(fs);
//          DeleteFile(fn);
//          StartGetShareFileIBB(tmptag.GetFirstTag('task').GetAttribute('name'));
//        end;
//      finally
//        if assigned(fs) then
//          FreeAndNil(fs);
//      end;
//    end
//    else
//      StartGetShareFileIBB(tmptag.GetFirstTag('task').GetAttribute('name'));
//  end
//  else begin
//    StartGetShareFileIBB(tmptag.GetFirstTag('task').GetAttribute('name'));
//  end;
//end;

procedure TfmGetShare.ProcessFileReceive(tag: TXMLTag);
var
  qtag, taskinfo: TXMLTag;
  SID, tasktype: widestring;
  _iq: TXMLTag;
  decstr: string;
  decpos: Integer;
  decbuf: array[0..4095] of byte;
  decsize: Integer;
  i: Integer;
  SIDIndex: Integer;
  Rect: Trect;
begin
  qtag := tag.GetFirstTag('query');
  if qtag = nil then exit;

  if tag.GetAttribute('type') = 'set' then
  begin
    SID := qtag.GetAttribute('sid');
    if qtag.GetAttribute('seq') <> '' then
    begin
      seqNo := strtoint(qtag.GetAttribute('seq'));
    end;

    if qtag.GetAttribute('totalseq') <> '' then
    begin
      seqcount := strtoint(qtag.GetAttribute('totalseq'));
    end;

    if qtag.GetFirstTag('data') <> nil then
    begin
      decstr := qtag.GetFirstTag('data').Data;
      decstr := IdDecoderMIME1.DecodeToString(decstr);

      if SIDList.IndexOf(SID)>=0 then
      begin
        SIDIndex := SIDList.IndexOf(SID);

        with TJITGetShareFile(SIDList.Objects[SIDIndex]) do
        begin
          FZRec.next_out := @decbuf;
          FZRec.avail_out := 4096;
          FZRec.next_in := @decstr[1];
          FZRec.avail_in := length(decstr);
          decsize := 4096;
          while (FZRec.avail_out > 0) do
          begin
            if FZRec.avail_in = 0 then
            begin
              decsize := 4096 - FZRec.avail_out;
              break;
            end;
            DCheck(inflate(FZRec, 0));
          end;
        end;

        TJITGetShareFile(SIDList.Objects[SIDIndex]).BufStream.Write(decbuf, decsize);
        if SIDIndex>_sidPos then
          SIDIndex := SIDIndex-1;
        SIDIndex := SIDIndex+TaskList.Count;
        if _taskpos < TaskList.Count then
          SIDIndex := SIDIndex-1;
        Rect := lvTask.Items[SIDIndex].DisplayRect(drBounds);
        InvalidateRect(lvTask.Handle, @Rect,false);
      end;
    end;

    ProgressBar1.Position := (SeqNo + 1) * 100 div seqcount;

    _iq := TXMLTag.Create('iq');
    _iq.setAttribute('id', tag.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', _jid);
    MainSession.SendTag(_iq);

    if qtag.GetFirstTag('close') <> nil then
    begin
      if SIDList.IndexOf(SID)>=0 then
      begin
        SIDIndex := SIDList.IndexOf(SID);

        with TJITGetShareFile(SIDList.Objects[SIDIndex]) do
          inflateEnd(FZRec);
      end;
//      FreeAndNil(BufStream);
      ShowRiserWindow(nil, '文件获取完毕！', ico_info);
      if SIDList.IndexOf(SID)>=0 then
      begin
        TJITGetShareFile(SIDList.Objects[SIDList.IndexOf(SID)]).Free;
        SIDList.Delete(SIDList.IndexOf(SID));
      end;
      resetlvtask;
    end;
  end;
end;

procedure TfmGetShare.InitRcv(Sender: TObject);
begin
  TShareTask(sender).InitRcv;
{  while FileExists(filename) do
  begin
    if MessageBox(application.Handle, '文件已经存在，要覆盖吗？','文件已存在', MB_ICONQUESTION or MB_YESNO) = IDYes then
      break;
    if OpenDialog1.Execute then
      filename := OpenDialog1.FileName;
  end;

  AssignFile(_rcvfile, filename);
  Rewrite(_rcvfile); {}
end;

procedure TfmGetShare.UdpFail(sender: TObject);
var
  fn: string;
  i: integer;
  savepath: string;
  Filesize: integer;
  Mode: Integer;
begin
  if TAnyQBaseUDPTask(Sender).Status='connecting' then
  begin
    fn := TSharetask(Sender)._GetFileName;
    TSharetask(Sender).BufStream.Free;
    for i:= TaskList.Count-1 downto 0 do
    begin
      if IsEqualGUID(TSharetask(Sender).TaskID, TSharetask(TaskList.Items[i]).TaskID) then
      begin
        savepath := ExtractFilePath(TSharetask(TaskList.Items[i])._SaveFileName);
        Filesize := TSharetask(TaskList.Items[i])._FileSize;
        Mode := TSharetask(TaskList.Items[i])._GetMode;
        TSharetask(TaskList.Items[i]).Free;
        TaskList.Delete(i);
        break;
      end;
    end;
    case Mode of
      0: StartGetShareIBB;
      1: StartGetShareFileIBB(fn, savepath, Filesize);
    end;
  end
  else
  begin
    for i:= TaskList.Count-1 downto 0 do
    begin
      if IsEqualGUID(TSharetask(Sender).TaskID, TSharetask(TaskList.Items[i]).TaskID) then
      begin
        TSharetask(TaskList.Items[i]).Free;
        TaskList.Delete(i);
        resetlvtask;
        break;
      end;
    end;
  end;
end;

procedure TfmGetShare.UdpRcv(sender: TObject; Adata: TStream);
var
  TmpBuf: array of Byte;
  decsize: integer;
  tmpStr: UTF8String;
  i: integer;
  Rect : TRect;
begin
  AData.Seek(0,0);
  if AData.Size = 0 then
  begin
    with Tsharetask(sender) do
      CCheck(inflateEnd(FZRec));
    case Tsharetask(sender)._GetMode of
      0: begin
          tmpStr := TStringStream(BufStream).DataString;
          Buf := UTF8Decode(tmpStr);
          BuildShareView;
          btnRefresh.Enabled := true;
        end;
      1: ShowRiserWindow(nil, '文件获取完毕！', ico_info);
    end;
    if assigned(BufStream) then
      FreeAndNil(BufStream);
    for i:= TaskList.Count-1 downto 0 do
      if IsEqualGUID(Tsharetask(sender).TaskID, Tsharetask(TaskList.Items[i]).TaskID) then
      begin
 //       Tsharetask(TaskList.Items[i]).free;
        TaskList.Delete(i);
        break;
      end;
    resetlvtask;
  end
  else
  begin
    with Tsharetask(sender) do
    begin
      setlength(TmpBuf, AData.Size);
      AData.Read(TmpBuf[0], AData.Size);

      FZRec.next_out := @FBuffer[0];
      FZRec.avail_out := 4096;
      FZRec.next_in := @TmpBuf[0];
      FZRec.avail_in := AData.Size;
      decsize := 0;
    end;

    while TshareTask(Sender).FZRec.avail_in > 0 do
    begin
      if TshareTask(Sender).FZRec.avail_out = 0 then
      begin
        case TshareTask(Sender)._GetMode of
          0: BufStream.Write(TshareTask(Sender).FBuffer[0], decsize);
          1: TShareTask(Sender).BufStream.Write(TshareTask(Sender).FBuffer[0], decsize);
        end;
        with Tsharetask(sender) do
        begin
          FZRec.next_out := @FBuffer[0];
          FZRec.avail_out := 4096;
        end;
      end;
      with Tsharetask(sender) do
      begin
        DCheck(inflate(FZRec, 0));
        decsize := 4096 - FZRec.avail_out;
      end;  
    end;

    case TshareTask(Sender)._GetMode of
      0:
        begin
          BufStream.Write(Tsharetask(sender).FBuffer[0], decsize);
          ProgressBar1.Position := BufStream.Size;
        end;
      1:
        begin
          with Tsharetask(sender) do
            BufStream.Write(FBuffer[0], decsize);
          for i:= TaskList.Count-1 downto 0 do
            if IsEqualGUID(Tsharetask(sender).TaskID, Tsharetask(TaskList.Items[i]).TaskID) then
            begin
              if i>_taskpos then
                Rect := lvTask.Items[i-1].DisplayRect(drBounds)
              else
                Rect := lvTask.Items[i].DisplayRect(drBounds);
              InvalidateRect(lvTask.Handle, @Rect, false);
              break;
            end;
        end;
    end;
  end;
end;

procedure TfmGetShare.UdpRcvTimeout(Sender: TObject);
begin
{  if TShareTask(Sender).Connected=true then
    ShowRiserWindow(nil,'由于网络传输问题，获取共享列表失败',ico_info);
  UdpConnectFail(sender);   {}
end;

procedure TfmGetShare.UdpTimeout(Sender: TObject);
var
  i: integer;
begin
  if  TAnyQBaseUDPTask(Sender).Receiving then
  begin
    TSharetask(Sender).BufStream.Free;
    for i:= TaskList.Count-1 downto 0 do
    begin
      if IsEqualGUID(TSharetask(Sender).TaskID, TSharetask(TaskList.Items[i]).TaskID) then
      begin
//        TSharetask(TaskList.Items[i]).Free;
        TaskList.Delete(i);
        break;
      end;
    end;
  end;
end;

procedure TfmGetShare.spbtnLocalUpClick(Sender: TObject);
begin
  inherited;
  shlvlocal.Back;
end;

procedure TfmGetShare.pnlLocalResize(Sender: TObject);
begin
  inherited;
  spbtnLocalUp.Left := pnlLocal.Width-25;
  shcomboLocal.Width := pnlLocal.Width-28;
  shlvlocal.Height := pnlLocal.Height-24;
  //
end;

{ TShareTask }

constructor TShareTask.Create(Controller: TAnyQUDPController; GUID: TGUID);
begin
  inherited;
  BufStream := nil;
end;

destructor TShareTask.Destroy;
begin
  if BufStream<> nil then
    Freeandnil(BufStream);
  inherited;
end;

procedure TfmGetShare.resetlvtask;
var
  i: Integer;
begin
  _taskpos := TaskList.Count;
  _sidPos := SIDList.Count;
  for i:= 0 to TaskList.Count-1 do
   if TShareTask(TaskList.Items[i])._SaveFileName='' then
   begin
     _taskpos := i;
     break;
   end;

  for i:= 0 to SIDList.Count-1 do
   if TObject(SIDList.Objects[i]) is TJITGetShareList then
   begin
     _sidPos := i;
     break;
   end;

  lvTask.Items.Count := SIDList.Count+TaskList.Count;
  if (_taskpos<TaskList.Count) or (_sidPos < SIDList.Count) then
    lvTask.Items.Count := lvTask.Items.Count-1;
  lvTask.Refresh;  
end;

procedure TfmGetShare.lvTaskData(Sender: TObject; Item: TListItem);
var
  taskCount: integer;
  pos: Integer;
begin
  taskCount := TaskList.Count;
  if _taskpos<TaskList.Count then
    taskCount := taskCount-1;

  pos := item.Index;
  if pos >= taskCount then
  begin
    Pos := Pos - TaskList.Count;
    if Pos>=_sidPos then
      Pos := Pos+1;
    Item.Caption := ExtractFileName(TJITGetShareFile(SIDList.Objects[pos])._GetFileName);
    Item.SubItems.Clear;
    Item.SubItems.Add(TJITGetShareFile(SIDList.Objects[pos])._SaveFileName);
    Item.SubItems.Add(sizestr(inttostr(TJITGetShareFile(SIDList.Objects[pos])._FileSize)));
    Item.SubItems.Add('');
  end
  else
  begin
    if Pos>=_taskpos then
      Pos := Pos+1;
    Item.Caption := ExtractFileName(TShareTask(TaskList.Items[pos])._GetFileName);
    Item.SubItems.Clear;
    Item.SubItems.Add(TShareTask(TaskList.Items[pos])._SaveFileName);
    Item.SubItems.Add(sizestr(inttostr(TShareTask(TaskList.Items[pos])._FileSize)));
    Item.SubItems.Add('');
  end;   {}
end;

procedure TfmGetShare.lvTaskCustomDrawSubItem(Sender: TCustomListView;
  Item: TListItem; SubItem: Integer; State: TCustomDrawState;
  var DefaultDraw: Boolean);
var
  rect: Trect;
  taskCount: integer;
  pos: Integer;
  SizeTotal, SizeCurrent: Integer;
  OldColor: Tcolor;
begin
  inherited;
//  DefaultDraw := true;
  if SubItem=3 then
  begin
    DefaultDraw := False;
    Rect := item.DisplayRect(drBounds);
    Rect.Left := rect.Left+lvTask.Columns[0].Width+lvTask.Columns[1].Width+lvTask.Columns[2].Width;
    Sender.Canvas.FillRect(rect);
    InflateRect(rect, -2, -2);
    Sender.Canvas.Pen.Color := clGray;
    Sender.Canvas.Rectangle(rect);
    InflateRect(rect, -1, -1);
    OldColor := Sender.Canvas.Brush.Color;
    Sender.Canvas.Brush.Color := clBlue;

    taskCount := TaskList.Count;
    if _taskpos<TaskList.Count then
      taskCount := taskCount-1;

    pos := item.Index;
    if pos >= taskCount then
    begin
      Pos := Pos - TaskList.Count;
      if Pos>=_sidPos then
        Pos := Pos+1;
      SizeTotal := TJITGetShareFile(SIDList.Objects[pos])._FileSize;
      if assigned(TJITGetShareFile(SIDList.Objects[pos]).BufStream) then
        SizeCurrent := TJITGetShareFile(SIDList.Objects[pos]).BufStream.Size
      else
        SizeCurrent := 0;
    end
    else
    begin
      if Pos>=_taskpos then
        Pos := Pos+1;
      SizeTotal := TShareTask(TaskList.Items[pos])._FileSize;
      if assigned(TShareTask(TaskList.Items[pos]).BufStream) then
        SizeCurrent := TShareTask(TaskList.Items[pos]).BufStream.Size
      else
        SizeCurrent := 0;
    end;

    if SizeTotal>0 then
      Rect.Right := rect.Left + trunc((Rect.Right - rect.Left)*(SizeCurrent/SizeTotal));
    Sender.Canvas.FillRect(Rect);
    Sender.Canvas.Brush.Color := OldColor;
  end;    {}
end;

procedure TfmGetShare.FormShow(Sender: TObject);
var
  path: string;
  i: integer;
begin
  inherited;
  path := MainSession.Prefs.getString('xfer_path');
  ForceDirectories(Path);
  shcomboLocal.Path := path;
  TShareShellComboBox(shcomboLocal).Change;{}
end;

procedure TfmGetShare.shlvlocalDragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
begin
//  inherited;
  Accept := (Source = LVShare) and (TXMLTag(LVShare.Selected.Data).Name <> 'DIR');
  if shlvlocal.GetItemAt(x,y)<> nil then
  begin
    Accept := Accept and shlvlocal.Folders[shlvlocal.GetItemAt(x,y).Index].IsFolder;
    if shlvlocal.Folders[shlvlocal.GetItemAt(x,y).Index].IsFolder then
      shlvlocal.Selected := shlvlocal.GetItemAt(x,y);
  end;
end;

procedure TfmGetShare.lvTaskDragOver(Sender, Source: TObject; X,
  Y: Integer; State: TDragState; var Accept: Boolean);
begin
//  inherited;
  Accept := (Source = LVShare) and shlvlocal.RootFolder.IsFolder;
  Accept := Accept and (TXMLTag(LVShare.Selected.Data).Name <> 'DIR');
  Accept := Accept and (TaskList.Count<3);
end;

procedure TfmGetShare.lvTaskDragDrop(Sender, Source: TObject; X,
  Y: Integer);
var
  Node: TTreeNode;
  fullfilename: widestring;
  filesize: Integer;
  Tag: TXMLTag;
begin
//  inherited;
  if LVShare.Selected = nil then exit;
  if TXMLTag(LVShare.Selected.Data).Name = 'DIR' then exit;
  fullfilename := TXMLTag(LVShare.Selected.Data).GetAttribute('name');
  filesize := strtoint(TXMLTag(LVShare.Selected.Data).GetAttribute('size'));
  Node := TVShare.Selected;
  while Node.Level >= 1 do
  begin
    Tag := TXMLTag(Node.data);
    fullfilename := SlashSep(Tag.GetAttribute('name'), fullfilename);
    Node := Node.Parent;
  end;
  with TStartGetThread.Create(True) do
  begin
    frm := self;
    FreeOnTerminate := true;
    fileName := fullfilename;
    SaveFilename := '';
    size := filesize;
    Resume;
  end;
//  StartGetShareFile(fullfilename, '', filesize);
end;

procedure TfmGetShare.shlvlocalDragDrop(Sender, Source: TObject; X,
  Y: Integer);
var
  Node: TTreeNode;
  fullfilename: widestring;
  filesize: Integer;
  Tag: TXMLTag;
begin
//  inherited;

  if LVShare.Selected = nil then exit;
  if TXMLTag(LVShare.Selected.Data).Name = 'DIR' then exit;
  fullfilename := TXMLTag(LVShare.Selected.Data).GetAttribute('name');
  filesize := strtoint(TXMLTag(LVShare.Selected.Data).GetAttribute('size'));
  Node := TVShare.Selected;
  while Node.Level >= 1 do
  begin
    Tag := TXMLTag(Node.data);
    fullfilename := SlashSep(Tag.GetAttribute('name'), fullfilename);
    Node := Node.Parent;
  end;

  if shlvlocal.Selected = nil then
  begin
//    StartGetShareFile(fullfilename, '', filesize)
    with TStartGetThread.Create(True) do
    begin
      frm := self;
      FreeOnTerminate := true;
      fileName := fullfilename;
      SaveFilename := '';
      size := filesize;
      Resume;
    end;
  end
  else
    if shlvlocal.SelectedFolder.IsFolder then
    begin
      with TStartGetThread.Create(True) do
      begin
        frm := self;
        FreeOnTerminate := true;
        fileName := fullfilename;
        SaveFilename := '';
        size := filesize;
        Resume;
      end;
//      StartGetShareFile(fullfilename, shlvlocal.SelectedFolder.PathName, filesize);
    end;
end;

procedure TShareTask.InitRcv;
begin
  if _SaveFileName<>'' then
    BufStream := TFileStream.Create(_SaveFileName, fmCreate);
  FZRec.zalloc := zlibAllocMem;
  FZRec.zfree := zlibFreeMem;
  FZRec.next_in := FBuffer;
  FZRec.avail_in := 0;
  DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
end;

{ TStartGetThread }

procedure TStartGetThread.Execute;
begin
  Synchronize(run);
end;

procedure TStartGetThread.run;
begin
  frm.StartGetShareFile(filename, SaveFilename, size);
end;

procedure TfmGetShare.UdpRcvStatus(sender: TObject);
begin
  if TAnyQBaseUDPTask(Sender).Status='connected' then
    TShareTask(sender).InitRcv;
end;

procedure TfmGetShare.IBBTaskDestroy(Sender: TObject);
var
//  i: integer;
  Sid: WideString;
begin
  Sid := TJabberIBBTask(Sender).IBBSID;
  if SIDList.IndexOf(SID)>=0 then
  begin
//    TJITGetShareFile(SIDList.Objects[SIDList.IndexOf(SID)]).Free;
    SIDList.Delete(SIDList.IndexOf(SID));
  end;
  resetlvtask;
end;

{ TGetFileIQ }

procedure TGetFileIQ.Timeout(Sender: TObject);
begin
  inc(_ticks);

  if (_ticks >= _timeout) then begin
    _timer.Enabled := false;
    _callback('timeout', Self.qTag);
    _js.UnRegisterCallback(_cbIndex);
    _cbIndex := -1;
    Self.Free;
  end;
end;

end.
