adding missing includes; trivial fix - comparison with string literal. by
[centerim.git] / libicq2000 / src / FileTransferClient.cpp
blob5e2c174b9077a0dff5aebd5cbeab613debaf4b83
1 /*
2 * FileTransferClient
4 * Copyright (C) 2001 Barnaby Gray <barnaby@beedesign.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "FileTransferClient.h"
24 #include "ICQ.h"
25 #include "constants.h"
27 #include "sstream_fix.h"
29 #include <stdlib.h>
30 #include <unistd.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <dirent.h>
36 #include <iostream>
37 #include <algorithm>
39 using std::string;
40 using std::ostringstream;
41 using std::endl;
42 using std::ofstream;
43 using std::min;
44 using std::max;
46 namespace ICQ2000
49 * Constructor when receiving an incoming connection
51 FileTransferClient::FileTransferClient(ContactRef self, MessageHandler *mh,
52 ContactTree *cl, unsigned int ext_ip, FileTransferEvent* ev)
53 : m_state(WAITING_FOR_INIT), m_recv(),
54 m_self_contact(self), m_contact(NULL), m_contact_list(cl),
55 m_message_handler(mh), m_incoming(true), m_local_ext_ip(ext_ip),
56 m_ev(ev)
58 Init();
59 m_listenserver.StartServer();
63 * Constructor for making an outgoing connection
65 FileTransferClient::FileTransferClient(ContactRef self, ContactRef c, MessageHandler *mh, unsigned int ext_ip, FileTransferEvent* ev)
66 : m_state(NOT_CONNECTED), m_recv(), m_self_contact(self),
67 m_contact(c), m_message_handler(mh), m_incoming(false), m_local_ext_ip(ext_ip),
68 m_ev(ev)
71 Init();
72 m_socket = new TCPSocket();
73 m_remote_uin = c->getUIN();
76 FileTransferClient::~FileTransferClient()
78 if (m_listenserver.isStarted())
80 SignalRemoveSocket( m_listenserver.getSocketHandle() );
81 m_listenserver.Disconnect();
84 if ( m_socket->getSocketHandle() > -1)
85 SignalRemoveSocket( m_socket->getSocketHandle() );
87 delete m_socket;
89 if (m_fout.is_open()) m_fout.close();
90 if (m_fin.is_open()) m_fin.close();
93 void FileTransferClient::Init()
95 m_more = false;
96 m_continue = false;
97 m_msgqueue = false;
98 m_senddir = false;
99 m_base_dir = NULL;
100 m_timestamp = time(NULL);
101 m_timeout = 60; // will time out in 60 seconds
104 void FileTransferClient::Connect()
106 m_remote_tcp_version = m_contact->getTCPVersion();
107 if (m_remote_tcp_version >= 7) m_eff_tcp_version = 7;
108 else if (m_remote_tcp_version == 6) m_eff_tcp_version = 6;
109 else throw DisconnectedException("Cannot direct connect to client with too old TCP version");
111 m_socket->setRemoteIP( m_contact->getLanIP() );
112 m_socket->setRemotePort( m_ev->getPort() );
113 m_socket->setBlocking(false);
114 m_socket->Connect();
115 SignalAddSocket( m_socket->getSocketHandle(), SocketEvent::WRITE );
117 if (m_contact->getDCCookie() != 0)
118 m_session_id = m_contact->getDCCookie();
119 else
120 m_session_id = (unsigned int)(0xffffffff*(rand()/(RAND_MAX+1.0)));
122 m_state = WAITING_FOR_INIT_ACK;
125 void FileTransferClient::FinishNonBlockingConnect()
127 SendInitPacket();
130 void FileTransferClient::clearoutMessagesPoll()
132 if ((m_state != CONNECTED) &&
133 (time(NULL) > (m_timestamp + m_timeout)))
134 expired();
137 void FileTransferClient::SendFile() {
138 if (m_state == CONNECTED && m_msgqueue)
140 SendPacket0x00();
141 m_msgqueue = false;
143 else if (m_continue)
145 if (m_more)
147 SendPacket0x06();
149 else if (m_ev->getCurrFile() < m_ev->getTotalFiles())
151 SendPacket0x02();
152 m_continue = false;
153 m_more = false;
155 else
157 m_ev->setState(FileTransferEvent::COMPLETE);
158 SignalLog(LogEvent::INFO, "FileTransfer is Complete");
159 throw DisconnectedException("FileTransfer is Complete");
161 m_continue = false;
164 m_message_handler->handleUpdateFT(m_ev);
167 void FileTransferClient::expired()
169 m_ev->setFinished(false);
170 m_ev->setDelivered(false);
171 m_ev->setDirect(true);
172 m_ev->setState(FileTransferEvent::TIMEOUT);
173 messageack.emit(m_ev);
176 void FileTransferClient::Recv()
180 while ( m_socket->connected() )
182 if ( !m_socket->Recv(m_recv) ) break;
183 Parse();
186 catch(SocketException e)
188 ostringstream ostr;
189 ostr << "Failed on recv: " << e.what();
190 throw DisconnectedException( ostr.str() );
192 catch(ParseException e)
194 ostringstream ostr;
195 ostr << "Failed parsing: " << e.what();
196 throw DisconnectedException( ostr.str() );
200 void FileTransferClient::Parse()
202 if (m_recv.empty()) return;
204 unsigned short length;
206 while (!m_recv.empty())
208 m_recv.setPos(0);
210 m_recv.setLittleEndian();
211 m_recv >> length;
212 if (length > Incoming_Packet_Limit) throw ParseException("Received too long incoming packet");
213 if (length == 0) return;
214 if (m_recv.remains() < length) return; // waiting for more of the packet
216 // Optimize??? not create new buffer and copy and erase in old.
217 Buffer sb;
218 m_recv.chopOffBuffer( sb, length+2 );
220 if (m_state != CONNECTED)
222 ostringstream ostr;
223 ostr << "Received filepacket from " << IPtoString( m_socket->getRemoteIP() ) << ":" << m_socket->getRemotePort() << endl << sb;
224 SignalLog(LogEvent::DIRECTPACKET, ostr.str());
227 if (m_state == WAITING_FOR_INIT)
229 ParseInitPacket(sb);
231 if (m_incoming) {
232 SendInitAck();
233 SendInitPacket();
234 m_state = WAITING_FOR_INIT_ACK;
235 } else {
236 SendInitAck();
237 m_state = CONNECTED;
238 flush_queue();
239 connected.emit(this);
243 else if (m_state == WAITING_FOR_INIT_ACK)
245 ParseInitAck(sb);
247 if (m_incoming) {
248 // Incoming
249 ConfirmUIN();
250 m_state = CONNECTED; // v5 is done handshaking now
251 flush_queue();
252 connected.emit(this);
255 else
257 // Outgoing - next packet should be their INIT
258 m_state = WAITING_FOR_INIT;
262 else if (m_state == WAITING_FOR_INIT2)
264 ParseInit2(sb);
265 // This is a V7 only packet
267 if (m_incoming)
269 SendInit2();
270 ConfirmUIN();
273 m_state = CONNECTED;
274 flush_queue();
275 connected.emit(this);
278 else if (m_state == CONNECTED)
280 ParsePacket(sb);
283 if (sb.beforeEnd())
285 ostringstream ostr;
286 ostr << "Buffer pointer not at end after parsing packet was: 0x" << std::hex << sb.pos()
287 << " should be: 0x" << sb.size();
288 SignalLog(LogEvent::WARN, ostr.str());
295 void FileTransferClient::ConfirmUIN()
297 if ( m_contact_list->exists(m_remote_uin) )
299 ContactRef c = (*m_contact_list)[ m_remote_uin ];
300 if ( (c->getExtIP() == m_local_ext_ip && c->getLanIP() == getIP() )
301 /* They are behind the same masquerading box,
302 * and the Lan IP matches
304 || c->getExtIP() == getIP())
306 m_contact = c;
308 else
310 // spoofing attempt most likely
311 ostringstream ostr;
312 ostr << "Refusing direct connection from someone that claims to be UIN "
313 << m_remote_uin << " since their IP " << IPtoString( getIP() ) << " != " << IPtoString( c->getExtIP() );
314 throw DisconnectedException( ostr.str() );
318 else
320 // don't accept direct connections from contacts not on contact list
321 throw DisconnectedException("Refusing direct connection to contact not on contact list");
325 void FileTransferClient::SendInitPacket()
327 Buffer b;
328 b.setLittleEndian();
329 Buffer::marker m1 = b.getAutoSizeShortMarker();
331 b << (unsigned char)0xff; // start byte
332 b << (unsigned short)0x0007; // tcp version
333 Buffer::marker m2 = b.getAutoSizeShortMarker();
335 b << m_remote_uin;
336 b << (unsigned short)0x0000;
337 b << (unsigned int)m_local_server_port;
339 b << m_self_contact->getUIN();
340 b.setBigEndian();
341 b << m_local_ext_ip;
342 b << m_socket->getLocalIP();
343 b << (unsigned char)0x04; // mode
344 b.setLittleEndian();
345 b << (unsigned int)m_local_server_port;
346 b << m_session_id;
348 b << (unsigned int)0x00000050; // unknown
349 b << (unsigned int)0x00000003; // unknown
350 if (m_eff_tcp_version == 7)
351 b << (unsigned int)0x00000000; // unknown
353 b.setAutoSizeMarker(m1);
354 b.setAutoSizeMarker(m2);
356 Send(b);
359 void FileTransferClient::ParseInitPacket(Buffer &b)
361 b.setLittleEndian();
362 unsigned short length;
363 b >> length;
365 unsigned char start_byte;
366 b >> start_byte;
367 if (start_byte != 0xff) throw ParseException("Init Packet didn't start with 0xff");
369 unsigned short tcp_version;
370 b >> tcp_version;
371 b.advance(2); // revision or a length ??
373 if (m_incoming)
375 m_remote_tcp_version = tcp_version;
376 if (tcp_version <= 5) throw ParseException("Too old client < ICQ99");
377 if (tcp_version == 6) m_eff_tcp_version = 6;
378 else m_eff_tcp_version = 7;
380 else
382 if (tcp_version != m_remote_tcp_version)
383 throw ParseException("Client claiming different TCP versions");
386 unsigned int our_uin;
387 b >> our_uin;
388 if (our_uin != m_self_contact->getUIN())
389 throw ParseException("Local UIN in Init Packet not same as our Local UIN");
391 // 00 00
392 // xx xx senders open port
393 // 00 00
394 b.advance(6);
396 unsigned int remote_uin;
397 b >> remote_uin;
398 if (m_incoming)
400 m_remote_uin = remote_uin;
402 else
404 if (m_remote_uin != remote_uin)
405 throw ParseException("Remote UIN in Init Packet for Remote Client not what was expected");
408 // xx xx xx xx senders external IP
409 // xx xx xx xx senders lan IP
410 b.advance(8);
412 b >> m_tcp_flags;
414 // xx xx senders port again
415 // 00 00
416 b.advance(4);
418 // xx xx xx xx session id
419 unsigned int session_id;
420 b >> session_id;
421 if (m_incoming)
423 m_session_id = session_id;
425 else
427 if (m_session_id != session_id) throw ParseException("Session ID from Remote Client doesn't match the one we sent");
430 // 50 00 00 00 unknown
431 // 03 00 00 00 unknown
432 b.advance(8);
434 if (m_eff_tcp_version == 7)
436 b.advance(4); // 00 00 00 00 unknown
441 void FileTransferClient::ParseInitAck(Buffer &b)
443 b.setLittleEndian();
444 unsigned short length;
445 b >> length;
446 if (length != 4) throw ParseException("Init Ack not as expected");
448 unsigned int a;
449 b >> a; // should be 0x00000001 really
452 void FileTransferClient::ParseInit2(Buffer &b)
454 b.setLittleEndian();
455 unsigned short length;
456 b >> length;
457 if (length != 0x0021)
458 throw ParseException("V7 final handshake packet incorrect length");
460 unsigned char type;
461 b >> type;
462 if (type != 0x03)
463 throw ParseException("Expecting V7 final handshake packet, received something else");
465 unsigned int unknown;
466 b >> unknown // 0x0000000a
467 >> unknown;// 0x00000001 on genuine connections, otherwise some weird connections which we drop
468 if (unknown != 0x00000001) throw DisconnectedException("Ignoring weird direct connection");
469 b.advance(24); // unknowns
472 void FileTransferClient::SendInit2()
474 Buffer b;
475 b.setLittleEndian();
476 Buffer::marker m1 = b.getAutoSizeShortMarker();
477 b << (unsigned char) 0x03 // start byte
478 << (unsigned int) 0x0000000a // unknown
479 << (unsigned int) 0x00000001 // unknown
480 << (unsigned int) (m_incoming ? 0x00000001 : 0x00000000) // unknown
481 << (unsigned int) 0x00000000 // unknown
482 << (unsigned int) 0x00000000; // unknown
483 if (m_incoming)
485 b << (unsigned int) 0x00040001 // unknown
486 << (unsigned int) 0x00000000 // unknown
487 << (unsigned int) 0x00000000; // unknown
489 else
491 b << (unsigned int) 0x00000000 // unknown
492 << (unsigned int) 0x00000000 // unknown
493 << (unsigned int) 0x00040001; // unknown
495 b.setAutoSizeMarker(m1);
496 Send(b);
499 void FileTransferClient::ParsePacket(Buffer& b)
501 b.setLittleEndian();
502 unsigned short length;
504 b >> length;
506 unsigned char type;
507 b >> type;
509 switch (type)
511 case 0: ParsePacket0x00(b);
512 SendPacket0x05();
513 SendPacket0x01();
514 break;
515 case 1: ParsePacket0x01(b);
516 SendPacket0x02();
517 break;
518 case 2: ParsePacket0x02(b);
519 SendPacket0x03(0,m_ev->getCurrFile());
520 break;
521 case 3: ParsePacket0x03(b);
522 m_continue = true;
523 SendFile();
524 break;
525 case 5: ParsePacket0x05(b);
526 break;
527 case 6: ParsePacket0x06(b);
528 break;
529 default:
530 SignalLog(LogEvent::WARN, "Received unknown FileTransfer Packet");
534 void FileTransferClient::ParsePacket0x00(Buffer& b)
536 unsigned int x1, t_num_files, t_size, speed;
537 string nick;
539 b >> x1
540 >> t_num_files
541 >> t_size
542 >> speed;
543 b.UnpackUint16StringNull(nick);
545 m_ev->setTotalSize(t_size);
546 m_ev->setTotalFiles(t_num_files);
547 m_ev->setCurrFile(0);
548 m_ev->setSpeed(speed);
550 m_path = m_ev->getSavePath();
553 void FileTransferClient::ParsePacket0x01(Buffer& b)
555 unsigned int speed;
556 std::string nick;
558 b >> speed;
559 b.UnpackUint16StringNull(nick);
561 m_ev->setSpeed(speed);
564 void FileTransferClient::ParsePacket0x02(Buffer& b)
566 unsigned int size, speed;
567 string filename, subdir;
568 unsigned char file_or_dir, tmp1;
570 b >> file_or_dir;
571 b.UnpackUint16StringNull(filename);
572 b.UnpackUint16StringNull(subdir);
573 b >> size;
574 b >> tmp1;
575 b >> tmp1;
576 b >> tmp1;
577 b >> tmp1;
579 b >> speed;
581 m_ev->setSize(size);
582 m_ev->setPos(0);
583 m_ev->setCurrFile(m_ev->getCurrFile()+1);
584 m_ev->setSpeed(speed);
586 m_path = m_ev->getSavePath();
587 // Add backslash if missing in path
588 if (m_path.find_last_of('/') != (m_path.length()-1))
590 m_path += "/";
593 int pos = 0;
594 while ((pos = subdir.find('\\')) != std::string::npos)
596 subdir[pos] = '/';
599 m_path += subdir;
600 // Add backslash if missing in path again
601 if (m_path.find_last_of('/') != (m_path.length()-1))
603 m_path += "/";
606 if (file_or_dir == 1)
608 m_path += filename;
609 m_path += "/";
610 mkdir(m_path.c_str(), S_IXUSR |
611 S_IWUSR |
612 S_IRUSR |
613 S_IXGRP |
614 S_IRGRP |
615 S_IXOTH |
616 S_IROTH);
618 else
620 if (m_ev->getCurrFile() > 1)
622 if (m_fout.is_open())
624 m_fout.close();
628 m_fout.open(std::string(m_path+filename).c_str(), std::ios::out | std::ios::binary);
629 if (!m_fout.good())
631 ostringstream ostr;
632 ostr << "Opening "
633 << m_path << filename
634 << " for writing.";
635 m_ev->setState(FileTransferEvent::ERROR);
636 m_ev->setError(ostr.str());
637 throw DisconnectedException("I/O error");
641 // Notify the Gui that an new file is on it's way..
642 m_message_handler->handleUpdateFT(m_ev);
645 void FileTransferClient::ParsePacket0x03(Buffer& b)
647 unsigned int npos, nfiles, x1, x2;
649 b >> npos
650 >> x1
651 >> x2
652 >> nfiles;
654 // Resume is handled
655 m_ev->setPos(npos);
656 m_ev->setTotalPos(m_ev->getTotalPos()+npos);
657 m_ev->setCurrFile(nfiles);
659 if (npos > m_ev->getSize())
661 ostringstream ostr;
662 ostr << "FileTransfer resume request got wrong offset: "
663 << npos << " when file only is " << m_ev->getSize();
664 m_ev->setState(FileTransferEvent::ERROR);
665 m_ev->setError(ostr.str());
666 throw DisconnectedException("I/O error");
668 else
670 // We support resume
671 ostringstream ostr;
672 ostr << "Resuming filetransfer " << npos << "/" << m_ev->getSize();
673 SignalLog(LogEvent::INFO, ostr.str());
674 m_fin.seekg(npos);
677 if (!m_senddir)
679 m_more = true;
683 void FileTransferClient::ParsePacket0x05(Buffer& b)
685 unsigned int speed;
687 b >> speed;
688 m_ev->setSpeed(speed);
691 void FileTransferClient::ParsePacket0x06(Buffer& b)
693 unsigned short length;
694 length = b.remains();
696 m_ev->setPos(m_ev->getPos()+length);
697 m_ev->setTotalPos(m_ev->getTotalPos()+length);
699 while ( length>0 )
701 b.Unpack( m_const_buf, min(length, (unsigned short)MAX_FileChunk) );
702 m_fout.write((const char*)m_const_buf, std::min(length, (unsigned short)MAX_FileChunk) );
703 length = max(0, length-(unsigned short)MAX_FileChunk);
705 m_fout.flush(); //prob. isn't needed.. but I feel safer ;)
707 if (m_ev->getTotalPos() >= m_ev->getTotalSize())
709 m_ev->setState(FileTransferEvent::COMPLETE);
710 throw DisconnectedException("FileTransfer is Complete");
714 void FileTransferClient::SendPacket0x00()
716 Buffer b;
717 unsigned int tmp_speed = m_ev->getSpeed();
718 unsigned int tmp_tot_nr = m_ev->getTotalFiles();
719 unsigned int tmp_tot_size = m_ev->getTotalSize();
720 b.setLittleEndian();
722 Buffer::marker m1 = b.getAutoSizeShortMarker();
723 b << (unsigned char)0x00;
724 b << (unsigned int)0x00000000; //0x00000000 X1
725 b << tmp_tot_nr; //total number of files to send CHANGE!!!!
726 b << tmp_tot_size; //total number of bytes to send CHANGE!!!!
727 b << tmp_speed;
728 b.PackUint16StringNull(m_self_contact->getAlias());
729 b.setAutoSizeMarker(m1);
731 Send(b);
734 void FileTransferClient::SendPacket0x01()
736 Buffer b;
737 unsigned int tmp_speed = m_ev->getSpeed();
738 b.setLittleEndian();
740 Buffer::marker m1 = b.getAutoSizeShortMarker();
741 b << (unsigned char)0x01;
742 b << tmp_speed; //Speed CHANGE!!!!
743 b.PackUint16StringNull(m_self_contact->getAlias());
744 b.setAutoSizeMarker(m1);
746 Send(b);
749 void FileTransferClient::SendPacket0x02()
751 Buffer b;
752 string tmp_name = m_ev->getFile();
753 unsigned int tmp_size;
754 unsigned int tmp_speed = m_ev->getSpeed();
755 struct stat tmp_stat;
756 unsigned char file_or_dir;
758 stat(tmp_name.c_str(), &tmp_stat);
759 if (S_ISDIR(tmp_stat.st_mode))
761 file_or_dir = 1;
762 tmp_size = 0;
763 m_senddir = true;
765 //setting base_dir
766 if (m_base_dir == NULL)
768 m_base_dir = new std::string(tmp_name.substr(0, tmp_name.find_last_of('/', tmp_name.find_last_not_of('/'))+1));
772 else if (S_ISREG(tmp_stat.st_mode))
774 file_or_dir = 0;
775 tmp_size = tmp_stat.st_size;
777 //setting base_dir
778 if (m_base_dir == NULL)
780 m_base_dir = new std::string("");
783 m_senddir = false;
785 if (m_fin.is_open())
787 m_fin.clear();
788 m_fin.close();
791 m_fin.open(tmp_name.c_str(), std::ios::in | std::ios::binary);
792 if (!m_fin.good())
794 ostringstream ostr;
795 ostr << "Opening "
796 << tmp_name
797 << " for Reading.";
799 m_ev->setState(FileTransferEvent::ERROR);
800 m_ev->setError(ostr.str());
801 throw DisconnectedException("I/O error");
805 else
807 ostringstream ostr;
808 ostr << "Trying to send unknown file type: "<< tmp_name;
809 SignalLog(LogEvent::WARN, ostr.str());
810 return;
813 std::string subdir = "";
815 if (m_base_dir->length() != 0)
816 subdir =
817 tmp_name.substr(m_base_dir->length(),
818 tmp_name.find_last_of('/', tmp_name.find_last_not_of('/')));
820 int pos = 0;
821 while ((pos = subdir.find('/')) != std::string::npos)
822 subdir[pos] = '\\';
824 // Chopping of so just name is sent.
825 pos = tmp_name.find_last_of('/');
826 if (pos == tmp_name.length()-1)
828 tmp_name = tmp_name.substr(0,pos);
829 pos = tmp_name.find_last_of('/');
831 tmp_name = tmp_name.substr(pos+1, tmp_name.length()-pos);
833 // Chopping of filename
834 if (m_base_dir->length() != 0)
835 subdir = subdir.substr(0, subdir.length() - tmp_name.length() -1);
838 // Remove last backslash from subdir
839 if ((file_or_dir == 1) &&
840 (subdir.find_last_of('\\') == (subdir.length()-1)))
841 subdir = subdir.substr(0, subdir.length() -1);
843 m_ev->setCurrFile(m_ev->getCurrFile()+1);
844 m_ev->setPos(0);
845 m_ev->setSize(tmp_size);
847 b.setLittleEndian();
849 Buffer::marker m1 = b.getAutoSizeShortMarker();
850 b << (unsigned char)0x02;
851 b << file_or_dir;
852 b.PackUint16StringNull(tmp_name); //name of next file.
853 b.PackUint16StringNull(subdir); //subdir
854 b << tmp_size;
855 b << (unsigned char)0x00;
856 b << (unsigned char)0x00;
857 b << (unsigned char)0x00;
858 b << (unsigned char)0x00;
859 b << tmp_speed;
860 b.setAutoSizeMarker(m1);
862 Send(b);
865 void FileTransferClient::SendPacket0x03(unsigned int npos, unsigned int nfiles)
867 Buffer b;
868 unsigned int speed = m_ev->getSpeed();
869 b.setLittleEndian();
870 Buffer::marker m1 = b.getAutoSizeShortMarker();
871 b << (unsigned char)0x03;
872 b << npos; //filepos RESUME?
873 b << (unsigned int)0x00000000; // X1 Unknown
874 b << speed; //(unsigned int)0x00000064; // speed
875 b << nfiles;
877 b.setAutoSizeMarker(m1);
879 Send(b);
882 void FileTransferClient::SendPacket0x05()
884 Buffer b;
885 unsigned int speed;
886 b.setLittleEndian();
887 Buffer::marker m1 = b.getAutoSizeShortMarker();
889 speed = m_ev->getSpeed();
891 b << (unsigned char)0x05;
892 b << speed;
894 b.setAutoSizeMarker(m1);
896 Send(b);
899 void FileTransferClient::SendPacket0x06()
901 Buffer b;
902 unsigned short length;
903 b.setLittleEndian();
904 Buffer::marker m1 = b.getAutoSizeShortMarker();
906 if (!m_fin.good())
908 m_ev->setState(FileTransferEvent::ERROR);
909 m_ev->setError("I/O error while sending data");
910 throw DisconnectedException("I/O error in SendPacket0x06");
913 m_fin.read((char*)m_const_buf, 2048);
914 length = m_fin.gcount();
916 b << (unsigned char)0x06;
918 b.Pack(m_const_buf, length);
919 b.setAutoSizeMarker(m1);
921 m_ev->setPos(m_ev->getPos()+length);
922 m_ev->setTotalPos(m_ev->getTotalPos()+length);
924 Send(b);
926 // Send more?
927 if (m_ev->getPos() < m_ev->getSize())
929 m_more = true;
931 else
933 m_more = false;
934 if (m_ev->getFilesInQueue() == 0)
936 m_ev->setState(FileTransferEvent::COMPLETE);
937 SignalLog(LogEvent::INFO, "FileTransfer is Complete");
938 throw DisconnectedException("FileTransfer is Complete");
943 void FileTransferClient::SendInitAck()
945 Buffer b;
946 b.setLittleEndian();
947 Buffer::marker m1 = b.getAutoSizeShortMarker();
948 b << (unsigned int)0x00000001;
949 b.setAutoSizeMarker(m1);
950 Send(b);
953 void FileTransferClient::SendPacketAck(ICQSubType *icqsubtype)
955 Buffer b;
957 b.setLittleEndian();
958 b << (unsigned int)0x00000000 // checksum (filled in by Encrypt)
959 << V6_TCP_ACK
960 << (unsigned short)0x000e
961 << icqsubtype->getSeqNum()
962 << (unsigned int)0x00000000
963 << (unsigned int)0x00000000
964 << (unsigned int)0x00000000;
966 icqsubtype->Output(b);
967 Buffer c;
968 //Encrypt(b,c);
969 Send(c);
972 void FileTransferClient::Send(Buffer &b)
976 m_socket->Send(b);
978 catch(SocketException e)
980 ostringstream ostr;
981 ostr << "Failed to send: " << e.what();
982 throw DisconnectedException( ostr.str() );
986 void FileTransferClient::SendEvent(MessageEvent *ev)
988 if (m_state == CONNECTED)
990 // send straight away
991 SendFile();
993 else
995 // queue message
996 m_msgqueue = true;
1000 void FileTransferClient::flush_queue()
1002 if (m_msgqueue)
1004 SendFile();
1008 unsigned int FileTransferClient::getUIN() const { return m_remote_uin; }
1010 unsigned int FileTransferClient::getIP() const { return m_socket->getRemoteIP(); }
1012 unsigned short FileTransferClient::getPort() const { return m_socket->getRemotePort(); }
1014 unsigned short FileTransferClient::getlistenPort() const { return m_listenserver.getPort(); }
1016 int FileTransferClient::getfd() const { return m_socket->getSocketHandle(); }
1018 int FileTransferClient::getlistenfd() { return m_listenserver.getSocketHandle(); }
1020 TCPSocket* FileTransferClient::getSocket() const { return m_socket; }
1022 void FileTransferClient::setSocket()
1024 m_socket = m_listenserver.Accept();
1025 SignalLog(LogEvent::INFO, "Accepting incoming filetransfer");
1028 void FileTransferClient::setContact(ContactRef c) { m_contact = c; }
1030 ContactRef FileTransferClient::getContact() const { return m_contact; }
1032 bool FileTransferClient::SetupFileTransfer(FileTransferEvent *ev)
1034 struct stat tmp_stat;
1035 std::string str = ev->getDescription();
1036 stat(str.c_str(), &tmp_stat);
1037 /* MITZ - what's the idea?!
1038 if (S_ISDIR(tmp_stat.st_mode))
1040 int size = 0;
1041 int files = 0;
1042 int dirs = 0;
1043 listDirectory(str, size, files, dirs, ev);
1045 ev->setTotalSize(size);
1046 ostringstream ostr;
1047 ostr << files << " files in " << dirs << " directories";
1048 ev->setDescription(ostr.str());
1051 else if (S_ISREG(tmp_stat.st_mode))
1053 ev->addFile(str);
1054 ev->setTotalSize(tmp_stat.st_size);
1055 // Chopping of so just name is sent.
1056 int pos = str.find_last_of('/');
1057 if (pos == str.length()-1)
1059 str = str.substr(0,pos);
1060 pos = str.find_last_of('/');
1062 str = str.substr(pos+1, str.length()-pos);
1063 ev->setDescription(str);
1065 else
1067 return false;
1071 ev->setTotalFiles(ev->getFilesInQueue());
1072 ev->setCurrFile(0);
1074 return true;
1077 void FileTransferClient::listDirectory(std::string str, int &size, int &files, int &dirs, FileTransferEvent *ev)
1079 struct stat tmp_stat;
1080 if (str.length() > 1
1081 && (str.substr(str.length()-1, str.length()) == "."
1082 || str.substr(str.length()-2, str.length()) == ".."))
1083 return;
1085 // Add backslash if missing in path
1086 if (str.find_last_of('/') != (str.length()-1))
1087 str += "/";
1088 ev->addFile(str);
1089 dirs++;
1090 DIR *dir = opendir(str.c_str());
1091 if (dir == NULL)
1092 return;
1093 struct dirent *dent = readdir(dir);
1095 std::string tmp_str;
1097 while (dent != NULL)
1099 tmp_str = str;
1100 tmp_str += dent->d_name;
1101 stat(tmp_str.c_str(), &tmp_stat);
1102 if (S_ISREG(tmp_stat.st_mode))
1104 ev->addFile(tmp_str);
1105 size += tmp_stat.st_size;
1106 files++;
1108 else if (S_ISDIR(tmp_stat.st_mode))
1110 listDirectory(tmp_str, size, files, dirs, ev);
1113 dent = readdir(dir); //delete on old dent?
1115 closedir(dir);
1118 FileTransferEvent* FileTransferClient::getEvent()
1120 return m_ev;