1 /**********************************************************************
7 Display DCC progress, etc. This in the future should be expanded.
9 **********************************************************************/
12 #include "ksircprocess.h"
13 #include "displayMgr.h"
14 #include "control_message.h"
18 #include <kpassivepopup.h>
25 extern DisplayMgr
*displayMgr
;
27 KSircIODCC::KSircIODCC(KSircProcess
*_proc
) :
29 KSircMessageReceiver(_proc
)
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);
49 delete (dccTopLevel
*) mgr
;
52 void KSircIODCC::sirc_receive(QByteArray str
, bool )
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: (.*)");
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.
75 DCCGetItems
[key
]->setReceivedBytes(bytesXfer
/1024);
79 else if(str
.find("DCC SEND write:", 0) != -1){ /*fold01*/
80 QRegExp
rx("write: (.+) who: (.+) bytes: (.*)");
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: (.+)");
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
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.
116 dccItem
*old
= DCCGetItems
.take(key
);
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)
123 old
->changeFilename(QString("%1 (finished %2)").arg(filename
).arg(i
+1));
124 DCCGetItems
.insert(renamed
, it
);
127 DCCGetItems
.insert(key
, it
);
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: (.*)");
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
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
154 dccItem
*old
= DCCSendItems
.take(key
);
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)
161 old
->changeFilename(QString("%1 (sent %2)").arg(filename
).arg(i
+1));
162 DCCSendItems
.insert(renamed
, it
);
164 DCCSendItems
.insert(key
, it
);
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: (.+)");
173 QString who
= rx
.cap(1);
174 QString ip
= rx
.cap(2);
175 QString port
= rx
.cap(3);
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
);
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: (.+)");
191 QString who
= rx
.cap(1);
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
);
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: (.*)");
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
;
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: (.*)");
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
;
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
);
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: (.+)");
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: (.+)");
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: (.+)");
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+)");
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: (.+)");
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: (.+)");
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: (.*)");
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: (.*)");
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: (.+)");
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: (.+)");
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);
383 else if(str
.find("Closing DCC CHAT") != -1){ /*fold01*/
384 QRegExp
rx("who: (.+)");
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: (.+)");
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());
410 new_list
.insert(it
.currentKey(), it
.current());
413 DCCSendItems
= new_list
;
414 toDel
.setAutoDelete(true);
418 else if(str
.find("No DCC GET") != -1){ /*fold01*/
419 QRegExp
rx("who: (.+) file: (.+)");
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());
434 new_list
.insert(it
.currentKey(), it
.current());
437 DCCGetItems
= new_list
;
438 toDel
.setAutoDelete(true);
442 else if(str
.find("No DCC CHAT") != -1){ /*fold01*/
443 QRegExp
rx("who: (.+)");
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());
455 new_list
.insert(it
.currentKey(), it
.current());
458 DCCChatItems
= new_list
;
459 toDel
.setAutoDelete(true);
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)
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)
525 filterRuleList
*KSircIODCC::defaultRules()
529 filterRuleList
*frl
= new filterRuleList();
530 frl
->setAutoDelete(TRUE
);
532 fr = new filterRule();
533 fr->desc = "Capture DCC IO Messages";
534 fr->search = "^\\*D\\*";
543 void KSircIODCC::dccConnectClicked(dccItem
*it
)
546 kDebug(5008) << "Got connect click on " << it
->who() << " " << it
->type() << endl
;
548 case dccItem::dccGet
:
549 str
= "/dcc get " + it
->who() + " " + it
->file() + "\n";
550 emit
outputLine(str
.ascii());
552 case dccItem::dccChat
:
553 str
= "/dcc chat " + it
->who() + "\n";
554 emit
outputLine(str
.ascii());
561 void KSircIODCC::dccResumeClicked(dccItem
*it
)
564 kDebug(5008) << "Got resume click on " << it
->who() << " " << it
->type() << endl
;
566 case dccItem::dccGet
:
567 it
->changeStatus(dccItem::dccWaitOnResume
);
568 str
= "/resume " + it
->who() + " " + it
->file() + "\n";
569 emit
outputLine(str
.ascii());
576 void KSircIODCC::dccRenameClicked(dccItem
*it
)
580 void KSircIODCC::dccAbortClicked(dccItem
*it
)
583 switch(it
->status()){
584 case dccItem::dccDone
:
585 case dccItem::dccCancel
:
586 case dccItem::dccError
:
588 case dccItem::dccGet
:
589 DCCGetItems
.remove(QString("%1/%2").arg(it
->file()).arg(it
->who()));
591 case dccItem::dccSend
:
592 DCCSendItems
.remove(QString("%1/%2").arg(it
->file()).arg(it
->who()));
594 case dccItem::dccChat
:
595 DCCChatItems
.remove(it
->who());
602 case dccItem::dccGet
:
603 str
= "/dcc close get " + it
->who() + " " + it
->file() + "\n";
604 emit
outputLine(str
.ascii());
606 case dccItem::dccSend
:
607 str
= "/dcc close send " + it
->who() + " " + it
->file() + "\n";
608 emit
outputLine(str
.ascii());
610 case dccItem::dccChat
:
611 str
= "/dcc close chat " + it
->who() + "\n";
612 emit
outputLine(str
.ascii());
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
);