Fix crash on logout
[kdenetwork.git] / ksirc / ioDCC.cpp
blob8f8e01da44ba1edcf5e885bd2cf775e2debffdea
1 /**********************************************************************
3 The IO DCC Window
5 $$Id$$
7 Display DCC progress, etc. This in the future should be expanded.
9 **********************************************************************/
11 #include "ioDCC.h"
12 #include "ksircprocess.h"
13 #include "displayMgr.h"
14 #include "control_message.h"
16 #include <kdebug.h>
17 #include <klocale.h>
18 #include <kpassivepopup.h>
20 #include <qregexp.h>
21 //Added by qt3to4:
22 #include <QByteArray>
23 #include <Q3PtrList>
25 extern DisplayMgr *displayMgr;
27 KSircIODCC::KSircIODCC(KSircProcess *_proc) :
28 QObject(),
29 KSircMessageReceiver(_proc)
31 proc = _proc;
32 setBroadcast(FALSE);
33 mgr = new dccTopLevel(0x0, "dccTopLevel Manager");
34 displayMgr->newTopLevel(mgr, FALSE);
35 displayMgr->setCaption(mgr, proc->serverName() + i18n(" DCC Controller"));
37 connect(mgr->mgr(), SIGNAL(dccConnectClicked(dccItem *)), this, SLOT(dccConnectClicked(dccItem *)));
38 connect(mgr->mgr(), SIGNAL(dccResumeClicked(dccItem *)), this, SLOT(dccResumeClicked(dccItem *)));
39 connect(mgr->mgr(), SIGNAL(dccRenameClicked(dccItem *)), this, SLOT(dccRenameClicked(dccItem *)));
40 connect(mgr->mgr(), SIGNAL(dccAbortClicked(dccItem *)), this, SLOT(dccAbortClicked(dccItem *)));
41 connect(mgr->mgr(), SIGNAL(outputLine(QByteArray)), this, SIGNAL(outputLine(QByteArray)));
45 KSircIODCC::~KSircIODCC()
47 // displayMgr->removeTopLevel(mgr);
48 if(mgr)
49 delete (dccTopLevel *) mgr;
52 void KSircIODCC::sirc_receive(QByteArray str, bool )
54 if(!mgr)
55 return;
56 // Parse the string to find out what type it is.
57 // Note the order here.
58 // Most people tend to receive files, so let's
59 // parse the byte xfered messages first since there's lot's of them.
60 // The we get lots of send bytexfer messages so parse them second.
61 // Then we look at the one time start/stop messages. They only arrive
62 // once in a long long time (compared to the byte messages) so if it takes
63 // a few extra clock cycles to find them, who cares?
64 if(str.find("DCC GET read:", 0) != -1){ /*fold01*/
65 QRegExp rx("read: (.+) who: (.+) bytes: (.*)");
66 if(rx.search(str)){
67 QString key = QString("%1/%2").arg(rx.cap(1)).arg(rx.cap(2));
68 uint bytesXfer = rx.cap(3).toUInt();
71 // Only update the display for 1% intervals.
72 // LastSize + 1%Size must be less than the total xfered bytes.
74 if(DCCGetItems[key]){
75 DCCGetItems[key]->setReceivedBytes(bytesXfer/1024);
79 else if(str.find("DCC SEND write:", 0) != -1){ /*fold01*/
80 QRegExp rx("write: (.+) who: (.+) bytes: (.*)");
81 if(rx.search(str)){
82 QString key = QString("%1/%2").arg(rx.cap(1)).arg(rx.cap(2));
83 uint bytesXfer = rx.cap(3).toUInt();
85 if(DCCSendItems[key]){
86 DCCSendItems[key]->setReceivedBytes(bytesXfer/1024);
90 else if(str.find("INBOUND DCC SEND", 0) != -1){ /*FOLD01*/
91 QRegExp rx("who: (.+) file: (.+) size: (.*) ip: (.+) port: (.+)");
92 if(rx.search(str)){
93 QString who = rx.cap(1);
94 QString filename = rx.cap(2);
95 QString size = rx.cap(3);
96 QString ip = rx.cap(4);
97 //QSTring port = rx.cap(5);
99 int fileSize = size.toInt(); // Bytes per step
100 fileSize /= 1024;
102 // setup dcc dialog
103 displayMgr->show(mgr);
104 dccItem *it = mgr->mgr()->newGetItem(filename, who, dccItem::dccGotOffer, fileSize);
105 connect(it, SIGNAL(itemRenamed(dccItem *, QString, QString)),
106 this, SLOT(dccRenameDone(dccItem *, QString, QString)));
107 it->setWhoPostfix("(" + ip + ")");
109 QString key = QString("%1/%2").arg(filename).arg(who);
110 if(DCCGetItems[key]){
112 * don't add duplicates, this cuases real headaches
113 * for both us and the user.
115 QString renamed;
116 dccItem *old = DCCGetItems.take(key);
117 int i;
118 for(i = 0; i <= (int) DCCGetItems.count()+1; i++){
119 renamed = QString("%1 (finished %2)/%3").arg(filename).arg(i+1).arg(old->who());
120 if( DCCGetItems[renamed] == 0x0)
121 break;
123 old->changeFilename(QString("%1 (finished %2)").arg(filename).arg(i+1));
124 DCCGetItems.insert(renamed, it);
127 DCCGetItems.insert(key, it);
129 else {
130 kDebug(5008) << "DCC SEND was unable to parse: " << str << endl;
133 else if(str.find("Sent DCC SEND", 0) != -1){ /*FOLD01*/
134 QRegExp rx("who: (.+) file: (.+) size: (.*)");
135 if(rx.search(str)){
136 QString who = rx.cap(1);
137 QString filename = rx.cap(2);
138 QString size = rx.cap(3);
139 int fileSize = size.toInt(); // Bytes per step
140 fileSize /= 1024;
142 // setup dcc dialog
143 displayMgr->show(mgr);
144 dccItem *it = mgr->mgr()->newSendItem(filename, who, dccItem::dccSentOffer, fileSize);
145 QString key = QString("%1/%2").arg(filename).arg(who);
146 if(DCCSendItems[key]){
148 * don't add duplicates, this cuases real headaches
149 * for both us and the user.
150 * We can get these on repeated sends or old files,
151 * just renamed them, their finished anyways
153 QString renamed;
154 dccItem *old = DCCSendItems.take(key);
155 int i;
156 for(i = 0; i <= (int) DCCSendItems.count()+1; i++){
157 renamed = QString("%1 (sent %2)/%3").arg(filename).arg(i+1).arg(old->who());
158 if( DCCSendItems[renamed] == 0x0)
159 break;
161 old->changeFilename(QString("%1 (sent %2)").arg(filename).arg(i+1));
162 DCCSendItems.insert(renamed, it);
164 DCCSendItems.insert(key, it);
166 else {
167 kDebug(5008) << "DCC SENT was unable to parse: " << str << endl;
170 else if(str.find("DCC CHAT OFFERED", 0) != -1){ /*FOLD01*/
171 QRegExp rx("who: (.+) ip: (.+) port: (.+)");
172 if(rx.search(str)){
173 QString who = rx.cap(1);
174 QString ip = rx.cap(2);
175 QString port = rx.cap(3);
176 // setup dcc dialog
177 displayMgr->show(mgr);
178 dccItem *it = mgr->mgr()->newChatItem(who, dccItem::dccGotOffer);
179 connect(it, SIGNAL(itemRenamed(dccItem *, QString, QString)),
180 this, SLOT(dccRenameDone(dccItem *, QString, QString)));
181 it->setWhoPostfix("(" + ip + ")");
182 DCCChatItems.insert(who, it);
184 else {
185 kDebug(5008) << "DCC CHAT SEND was unable to parse: " << str << endl;
188 else if(str.find("DCC CHAT SEND", 0) != -1){ /*FOLD01*/
189 QRegExp rx("who: (.+)");
190 if(rx.search(str)){
191 QString who = rx.cap(1);
193 // setup dcc dialog
194 displayMgr->show(mgr);
195 dccItem *it = mgr->mgr()->newChatItem(who, dccItem::dccSentOffer);
196 connect(it, SIGNAL(itemRenamed(dccItem *, QString, QString)),
197 this, SLOT(dccRenameDone(dccItem *, QString, QString)));
198 DCCChatItems.insert(who, it);
200 else {
201 kDebug(5008) << "DCC CHAT SEND was unable to parse: " << str << endl;
204 else if(str.find("DCC SEND terminated") != -1){ /*FOLD01*/
205 QRegExp rx("who: (.+) file: (.+) reason: (.*)");
206 if(rx.search(str)){
207 QString who = rx.cap(1);
208 QString filename = rx.cap(2);
209 QString error = rx.cap(3);
210 enum dccItem::dccStatus status = dccItem::dccDone;
212 if(error == "CLOSE"){
213 status = dccItem::dccCancel;
215 if(error != "OK"){
216 status = dccItem::dccError;
217 KPassivePopup::message(i18n("DCC SEND with %1 for %2 failed because of %3", who, filename, error), mgr->mgr());
219 QString key = QString("%1/%2").arg(filename).arg(who);
220 if(DCCSendItems[key]){
221 kDebug(5008) << "SendPercent: " << DCCSendItems[key]->getPercent() << endl;
222 if((status == dccItem::dccDone) && (DCCSendItems[key]->getPercent() < 100))
223 status = dccItem::dccError;
224 DCCSendItems[key]->changeStatus(status);
228 else if(str.find ("DCC GET terminated") != -1){ /*fold01*/
229 kDebug(5008) << "Term: " << str << endl;
230 QRegExp rx("who: (.+) file: (.+) reason: (.*)");
231 if(rx.search(str)){
232 QString who = rx.cap(1);
233 QString filename = rx.cap(2);
234 QString error = rx.cap(3);
235 enum dccItem::dccStatus status = dccItem::dccDone;
237 if(error != "OK"){
238 status = dccItem::dccError;
239 KPassivePopup::message(i18n("DCC GET with %1 for %2 failed because of %3", who, filename, error), mgr->mgr());
241 QString key = QString("%1/%2").arg(filename).arg(who);
242 if(DCCGetItems[key]){
243 kDebug(5008) << "GetPercent: " << DCCGetItems[key]->getPercent() << endl;
244 if((status == dccItem::dccDone) && (DCCGetItems[key]->getPercent() < 100))
245 status = dccItem::dccError;
246 DCCGetItems[key]->changeStatus(status);
249 else {
250 kDebug(5008) << "DCC Get term failed to parse: " << str << endl;
253 else if(str.find("DCC GET resumed") != -1){ /*fold01*/
254 QRegExp rx("who: (.+) file: (.+)");
255 if(rx.search(str)){
256 QString who = rx.cap(1);
257 QString filename = rx.cap(2);
258 QString key = QString("%1/%2").arg(filename).arg(who);
259 if(DCCGetItems[key]){
260 dccItem *it = DCCGetItems[key];
261 kDebug(5008) << "Got DCC GET resumed message..." << it->file() << endl;
262 if(it->status() == dccItem::dccWaitOnResume)
263 dccConnectClicked(it);
264 it->changeStatus(dccItem::dccResumed);
268 else if(str.find("DCC SEND resumed") != -1){ /*fold01*/
269 QRegExp rx("who: (.+) file: (.+)");
270 if(rx.search(str)){
271 QString who = rx.cap(1);
272 QString filename = rx.cap(2);
273 QString key = QString("%1/%2").arg(filename).arg(who);
274 if(DCCSendItems[key]){
275 DCCSendItems[key]->changeStatus(dccItem::dccResumed);
279 else if(str.find("DCC GET established") != -1){ /*fold01*/
280 QRegExp rx("who: (.+) file: (.+)");
281 if(rx.search(str)){
282 QString who = rx.cap(1);
283 QString filename = rx.cap(2);
284 QString key = QString("%1/%2").arg(filename).arg(who);
285 if(DCCGetItems[key]){
286 DCCGetItems[key]->changeStatus(dccItem::dccRecving);
290 else if(str.find("DCC SEND established") != -1){ /*fold01*/
291 QRegExp rx("who: (.+) file: (.+) ip: (\\S+)");
292 if(rx.search(str)){
293 QString who = rx.cap(1);
294 QString filename = rx.cap(2);
295 QString ip = rx.cap(3);
296 QString key = QString("%1/%2").arg(filename).arg(who);
297 if(DCCSendItems[key]){
298 DCCSendItems[key]->setWhoPostfix("(" + ip + ")");
299 DCCSendItems[key]->changeStatus(dccItem::dccSending);
303 else if(str.find("DCC CHAT established") != -1){ /*FOLD01*/
304 QRegExp rx("who: (.+)");
305 if(rx.search(str)){
306 QString who = rx.cap(1);
307 if(DCCChatItems[who]){
308 DCCChatItems[who]->changeStatus(dccItem::dccOpen);
309 proc->new_toplevel(KSircChannel(proc->serverName(), QString("=") + who.lower()));
313 else if(str.find("DCC CHAT inbound established") != -1){ /*FOLD01*/
314 QRegExp rx("who: (.+) ip: (.+)");
315 if(rx.search(str)){
316 QString who = rx.cap(1);
317 QString ip = rx.cap(2);
318 if(DCCChatItems[who]){
319 DCCChatItems[who]->setWhoPostfix("(" + ip + ")");
320 DCCChatItems[who]->changeStatus(dccItem::dccOpen);
321 proc->new_toplevel(KSircChannel(proc->serverName(), QString("=") + who.lower()));
325 else if(str.find("DCC GET failed") != -1){ /*fold01*/
326 QRegExp rx("who: (.+) file: (.+) reason: (.*)");
327 if(rx.search(str)){
328 QString who = rx.cap(1);
329 QString filename = rx.cap(2);
330 QString error = rx.cap(3);
331 QString key = QString("%1/%2").arg(filename).arg(who);
332 if(DCCGetItems[key]){
333 DCCGetItems[key]->changeStatus(dccItem::dccError);
335 KPassivePopup::message(i18n("DCC Get with %1 for %2 failed because of %3", who, filename, error), mgr->mgr());
338 else if(str.find("DCC CHAT failed") != -1){ /*FOLD01*/
339 QRegExp rx("who: (.+) reason: (.*)");
340 if(rx.search(str)){
341 QString who = rx.cap(1);
342 QString error = rx.cap(2);
343 if(DCCChatItems[who]){
344 DCCChatItems[who]->changeStatus(dccItem::dccError);
346 KPassivePopup::message(i18n("DCC Chat with %1 failed because of %2", who, error), mgr->mgr());
349 else if(str.find("DCC CHAT renamed") != -1){ /*FOLD01*/
350 QRegExp rx("who: (.+) to: (.+)");
351 if(rx.search(str)){
352 QString oldwho = rx.cap(1);
353 QString newwho = rx.cap(2);
355 QString oldwin = "=" + oldwho;
356 if(proc->getWindowList().find(oldwin)){
357 proc->getWindowList().find(oldwin)->control_message(CHANGE_CHANNEL,QString("=" +newwho).lower());
361 else if(str.find("Closing DCC GET") != -1){ /*fold01*/
362 QRegExp rx("who: (.+) file: (.+)");
363 if(rx.search(str)){
364 QString who = rx.cap(1);
365 QString filename = rx.cap(2);
366 QString key = QString("%1/%2").arg(filename).arg(who);
367 if(DCCGetItems[key]){
368 DCCGetItems[key]->changeStatus(dccItem::dccCancel);
372 // else if(str.find("Closing DCC SEND") != -1){ /*FOLD01*/
373 // QRegExp rx("who: (.+) file: (.+)");
374 // if(rx.search(str)){
375 // QString who = rx.cap(1);
376 // QString filename = rx.cap(2);
377 // QString key = QString("%1/%2").arg(filename).arg(who);
378 // if(DCCSendItems[key]){
379 // DCCSendItems[key]->changeStatus(dccItem::dccCancel);
380 // }
381 // }
382 // }
383 else if(str.find("Closing DCC CHAT") != -1){ /*fold01*/
384 QRegExp rx("who: (.+)");
385 if(rx.search(str)){
386 QString who = rx.cap(1);
387 if(DCCChatItems[who]){
388 DCCChatItems[who]->changeStatus(dccItem::dccDone);
392 else if(str.find("No DCC SEND") != -1){ /*fold01*/
393 QRegExp rx("who: (.+) file: (.+)");
394 if(rx.search(str)){
395 QString who = rx.cap(1);
396 QString filename = rx.cap(2);
398 //QString key = QString("%1/%2").arg(filename).arg(who);
400 Q3PtrList<dccItem> toDel;
401 Q3Dict<dccItem> new_list;
402 Q3DictIterator<dccItem> it( DCCSendItems );
403 for(;it.current(); ++it){
404 if((it.current()->who() == who) &&
405 (it.current()->file() == filename)
407 toDel.append(it.current());
409 else {
410 new_list.insert(it.currentKey(), it.current());
413 DCCSendItems = new_list;
414 toDel.setAutoDelete(true);
415 toDel.clear();
418 else if(str.find("No DCC GET") != -1){ /*fold01*/
419 QRegExp rx("who: (.+) file: (.+)");
420 if(rx.search(str)){
421 QString who = rx.cap(1);
422 QString filename = rx.cap(2);
424 Q3PtrList<dccItem> toDel;
425 Q3Dict<dccItem> new_list;
426 Q3DictIterator<dccItem> it( DCCGetItems );
427 for(;it.current(); ++it){
428 if((it.current()->who() == who) &&
429 (it.current()->file() == filename)
431 toDel.append(it.current());
433 else {
434 new_list.insert(it.currentKey(), it.current());
437 DCCGetItems = new_list;
438 toDel.setAutoDelete(true);
439 toDel.clear();
442 else if(str.find("No DCC CHAT") != -1){ /*fold01*/
443 QRegExp rx("who: (.+)");
444 if(rx.search(str)){
445 QString who = rx.cap(1);
447 Q3PtrList<dccItem> toDel;
448 Q3Dict<dccItem> new_list;
449 Q3DictIterator<dccItem> it( DCCChatItems );
450 for(;it.current(); ++it){
451 if(it.current()->who() == who){
452 toDel.append(it.current());
454 else {
455 new_list.insert(it.currentKey(), it.current());
458 DCCChatItems = new_list;
459 toDel.setAutoDelete(true);
460 toDel.clear();
463 else{ /*FOLD01*/
464 proc->getWindowList()["!default"]->sirc_receive(str);
469 void KSircIODCC::control_message(int, QString)
473 void KSircIODCC::cancelTransfer(QString filename)
475 //if(DlgList[filename]){
476 //emit outputLine(DCCStatus[filename]->cancelMessage.ascii());
477 //delete DlgList[filename];
478 //DlgList.remove(filename);
479 //delete DCCStatus[filename];
480 //DCCStatus.remove(filename);
484 void KSircIODCC::getFile()
487 QString text = pending->fileListing()->text(pending->fileListing()->currentItem());
488 int pos = text.find(" ", 0);
489 QString nick = text.mid(0, pos);
490 pos = text.find(" ", pos+1) + 1;
491 QString filename = text.mid(pos, text.length() - pos);
492 //if(DlgList[filename]->isVisible() == FALSE)
493 // DlgList[filename]->show();
494 QString command = "/dcc get " + nick + " " + filename + "\n";
495 emit outputLine(command.ascii());
496 for(uint i = 0; i < pending->fileListing()->count(); i++)
497 if(QString(pending->fileListing()->text(i)) == (nick + " offered " + filename))
498 pending->fileListing()->removeItem(i);
500 if(pending->fileListing()->count() == 0)
501 pending->hide();
505 void KSircIODCC::forgetFile()
508 QString text = pending->fileListing()->text(pending->fileListing()->currentItem());
509 int pos = text.find(" ", 0);
510 QString nick = text.mid(0, pos);
511 pos = text.find(" ", pos+1) + 1;
512 QString filename = text.mid(pos, text.length() - pos);
513 QString command = "/dcc close get " + nick + " " + filename + "\n";
514 emit outputLine(command.ascii());
515 for(uint i = 0; i < pending->fileListing()->count(); i++)
516 if(QString(pending->fileListing()->text(i)) == (nick + " offered " + filename))
517 pending->fileListing()->removeItem(i);
519 if(pending->fileListing()->count() == 0)
520 pending->hide();
525 filterRuleList *KSircIODCC::defaultRules()
528 // filterRule *fr;
529 filterRuleList *frl = new filterRuleList();
530 frl->setAutoDelete(TRUE);
532 fr = new filterRule();
533 fr->desc = "Capture DCC IO Messages";
534 fr->search = "^\\*D\\*";
535 fr->from = "^";
536 fr->to = "~!dcc~";
537 frl->append(fr);
539 return frl;
543 void KSircIODCC::dccConnectClicked(dccItem *it)
545 QString str;
546 kDebug(5008) << "Got connect click on " << it->who() << " " << it->type() << endl;
547 switch(it->type()){
548 case dccItem::dccGet:
549 str = "/dcc get " + it->who() + " " + it->file() + "\n";
550 emit outputLine(str.ascii());
551 break;
552 case dccItem::dccChat:
553 str = "/dcc chat " + it->who() + "\n";
554 emit outputLine(str.ascii());
555 break;
556 default:
557 break;
561 void KSircIODCC::dccResumeClicked(dccItem *it)
563 QString str;
564 kDebug(5008) << "Got resume click on " << it->who() << " " << it->type() << endl;
565 switch(it->type()){
566 case dccItem::dccGet:
567 it->changeStatus(dccItem::dccWaitOnResume);
568 str = "/resume " + it->who() + " " + it->file() + "\n";
569 emit outputLine(str.ascii());
570 break;
571 default:
572 break;
576 void KSircIODCC::dccRenameClicked(dccItem *it)
578 it->doRename();
580 void KSircIODCC::dccAbortClicked(dccItem *it)
582 QString str;
583 switch(it->status()){
584 case dccItem::dccDone:
585 case dccItem::dccCancel:
586 case dccItem::dccError:
587 switch(it->type()) {
588 case dccItem::dccGet:
589 DCCGetItems.remove(QString("%1/%2").arg(it->file()).arg(it->who()));
590 break;
591 case dccItem::dccSend:
592 DCCSendItems.remove(QString("%1/%2").arg(it->file()).arg(it->who()));
593 break;
594 case dccItem::dccChat:
595 DCCChatItems.remove(it->who());
596 break;
598 delete it;
599 break;
600 default:
601 switch(it->type()) {
602 case dccItem::dccGet:
603 str = "/dcc close get " + it->who() + " " + it->file() + "\n";
604 emit outputLine(str.ascii());
605 break;
606 case dccItem::dccSend:
607 str = "/dcc close send " + it->who() + " " + it->file() + "\n";
608 emit outputLine(str.ascii());
609 break;
610 case dccItem::dccChat:
611 str = "/dcc close chat " + it->who() + "\n";
612 emit outputLine(str.ascii());
613 break;
618 void KSircIODCC::dccRenameDone(dccItem *it, QString oldWho, QString oldFile)
620 if(it->type() == dccItem::dccGet){
621 QString str = QString("/dcc rename %1 %2 %3\n").arg(oldWho).arg(oldFile).arg(it->file());
622 QString key = QString("%1/%2").arg(oldFile).arg(oldWho);
623 if(DCCGetItems[key]){
624 DCCGetItems.take(key);
625 QString newkey = QString("%1/%2").arg(it->file()).arg(it->who());
626 DCCGetItems.insert(newkey, it);
628 emit outputLine(str.ascii());
630 else if(it->type() == dccItem::dccChat){
631 if(DCCChatItems[oldWho]){
632 DCCChatItems.take(oldWho);
633 DCCChatItems.insert(it->who(), it);
635 QString str = QString("/dcc rchat %1 %2\n").arg(oldWho).arg(it->who());
636 emit outputLine(str.ascii());
641 void KSircIODCC::showMgr()
643 displayMgr->show(mgr);
646 #include "ioDCC.moc"