1 /***********************************************************************
7 Main io controller. Reads and writes strings to sirc. Input
8 received in the following 2 formats:
10 1. ~window name~<message>
13 each is handled diffrently. The window name is extracted from #1 and
14 if the window exists the message portion is sent to it. If the
15 window doesn't exist, or case 2 is found the window is sent to the
16 control window "!default". !default is NOT a constant window but
17 rather follows focus arround. This is the easiest way to solve the
18 problem of output to commands that don't have a fixed destination
19 window. (/whois, /help, etc )
23 Friends with KSircProcess allows easy access to TopList. Makes sence
24 and means that IOController has access to TopList, etc. The two work
28 holder: used to hold partital lines between writes.
29 *proc: the acutally sirc client process.
30 *ksircproc: the companion ksircprocess GUI controller
31 stdout_notif: access to SocketNotifier, why is this global to the
33 counter: existance counter.
37 KSircIOController(KProcess*, KSircProcess*):
38 - Object constructor takes two arguements the KProcess
39 that holds a running copy of sirc.
40 - KSircProcess is saved for access latter to TopList.
41 - The receivedStdout signal from KProcess is connected to
42 stdout_read and the processExited is connected to the sircDied
45 ~KSircIOController: does nothing at this time.
48 stdout_read(KProcess *, _buffer, buflen):
49 - Called by kprocess when data arrives.
50 - This function does all the parsing and sending of messages
53 stderr_read(KProcess*, _buffer, buflen):
54 - Should be called for stderr data, not connected, does
58 - Slot that get's connected to by KSircProcess to each
59 window. QString shold be written un touched! Let the
60 writter figure out what ever he wants to do.
63 - Should restart sirc or something....
64 - Becarefull not to get it die->start->die->... etc
66 ***********************************************************************/
71 #include "control_message.h"
72 #include "iocontroller.h"
73 #include "ksircprocess.h"
74 #include "messageReceiver.h"
77 #include <q3listbox.h>
78 #include <qtextcodec.h>
80 #include <QTextStream>
82 #include <kcharsets.h>
84 #include <q3popupmenu.h>
87 #include <kdeversion.h>
89 #include <kstandarddirs.h>
90 #include <kfiledialog.h>
92 int KSircIOController::counter
= 0;
94 KSircIOController::KSircIOController(KProcess
*_proc
, KSircProcess
*_ksircproc
)
100 proc
= _proc
; // save proc
101 ksircproc
= _ksircproc
; // save ksircproce
106 // Connect the data arrived
107 // to sirc receive for adding
108 // the main text window
109 connect(proc
, SIGNAL(receivedStdout(KProcess
*, char *, int)),
110 this, SLOT(stdout_read(KProcess
*, char*, int)));
112 // Connect the stderr data
113 // to sirc receive for adding
114 // the main text window
115 connect(proc
, SIGNAL(receivedStderr(KProcess
*, char *, int)),
116 this, SLOT(stderr_read(KProcess
*, char*, int)));
118 connect(proc
, SIGNAL(processExited(KProcess
*)),
119 this, SLOT(sircDied(KProcess
*)));
120 // Notify on sirc dying
121 connect(proc
, SIGNAL(wroteStdin(KProcess
*)),
122 this, SLOT(procCTS(KProcess
*)));
125 showDebugTraffic(true);
129 void my_print(const char *c
){
132 fprintf(stderr
, "<%02X>", 0xff & *c
);
134 fprintf(stderr
, "%c", *c
);
137 fprintf(stderr
, "\n");
140 void KSircIOController::stdout_read(KProcess
*, char *_buffer
, int buflen
)
145 Main reader reads from sirc and ships it out to the right
148 Problem trying to solve:
150 _buffer holds upto 1024 (it seems) block of data. We need to
151 take it, split into lines figure out where each line should go,
154 We watch for broken end of lines, ie partial lines and reattach
155 them to the front on the next read.
157 We also stop all processing in the windows while writting the
163 _buffer original buffer, holds just, icky thing, NOT NULL terminated!
164 buf: new clean just the right size buf that is null terminated.
165 pos, pos2, pos3 used to cut the string up into peices, etc.
166 name: destination window.
167 line: line to ship out.
170 1. read and copy buffer, make sure it's valid.
171 2. If we're holding a broken line, append it.
172 3. Check for a broken line, and save the end if it is.
173 4. Stop updates in all windows.
174 5. Step through the data and send the lines out to the right
176 6. Cleanup and continue.
181 QByteArray name
, line
;
183 assert(_buffer
!= 0);
186 QByteArray
buffer(_buffer
, buflen
+1);
187 //fprintf(stderr, "first print: \n");
189 //kDebug(5008) << "<-- read: " << buffer << endl;
193 if(holder
.length() > 0){
194 buffer
.prepend(holder
);
198 if(buffer
[buffer
.length()-1] != '\n'){
199 pos
= buffer
.findRev('\n');
201 holder
= buffer
.right(buffer
.length()-(pos
+1));
202 buffer
.truncate(pos
+1);
205 /* there is _NO_ linefeeds in this line at all, means we're
206 * only part of a string, buffer it all!!
207 * (lines are linefeed delimeted)
216 KSircMessageReceiver
* rec
= ksircproc
->TopList
["!all"];
223 rec
->control_message(STOP_UPDATES
, "");
225 m_debugLB
->setUpdatesEnabled(false);
228 pos2
= buffer
.find('\n', pos
);
231 pos2
= buffer
.length();
233 line
= buffer
.mid(pos
, pos2
- pos
);
235 QString s
= QString::fromUtf8(line
);
236 m_debugLB
->insertItem(s
);
239 //kDebug(5008) << "Line: " << line << endl;
241 if((line
.length() > 0) && (line
[0] == '~')){
242 pos3
= line
.find('~', 1);
244 name
= line
.mid(1,pos3
-1).lower();
246 line
.remove(0, pos3
+1);
249 QString enc
= KGlobal::charsets()->encodingForName( ksopts
->channel
["global"]["global"].encoding
);
250 QTextCodec
*qtc
= KGlobal::charsets()->codecForName( enc
);
251 QString qsname
= qtc
->toUnicode(name
);
253 char *b = qstrdup(line);
254 kDebug(5008) << "----------------------------------------" << endl;
255 kDebug(5008) << "Line: " << b << endl;
256 fprintf(stderr, "My_print: " ); my_print(b);
257 fprintf(stderr, "fprintf: %s\n", (const char *)b);
258 kDebug(5008) << "Codec: " << qtc->name() << " (" << ksopts->channel["global"]["global"].encoding << ")" << " Name: " << name << " qsname: " << qsname << endl;
259 kDebug(5008) << "Line(de): " << qtc->toUnicode(b) << endl;
260 kDebug(5008) << "----------------------------------------" << endl;
263 if(!(ksircproc
->TopList
[qsname
])){
264 // Ignore ssfe control messages with `
265 // we left channel, don't open a window for a control message
266 bool noticeCreate
= true;
267 if(ksopts
->autoCreateWinForNotice
== false && (line
[0] == '-' || line
[0] == '*'))
268 noticeCreate
= false;
269 if(ksopts
->autoCreateWin
== TRUE
&& line
[0] != '`' && line
[1] != '#' && line
[1] != '&' && noticeCreate
) {
270 //kDebug(5008) << "Creating window for: " << qsname << " because of: " << line.data() << endl;
271 ksircproc
->new_toplevel(KSircChannel(ksircproc
->serverName(), qsname
));
272 assert(ksircproc
->TopList
[qsname
] != 0x0);
281 ksircproc
->TopList
[qsname
]->sirc_receive(line
);
285 } while((uint
) pos
< buffer
.length());
287 ksircproc
->TopList
["!all"]->control_message(RESUME_UPDATES
, "");
289 m_debugLB
->triggerUpdate(true);
290 m_debugLB
->setContentsPos( 0, m_debugLB
->contentsHeight()-m_debugLB
->visibleHeight());
291 m_debugLB
->setUpdatesEnabled(true);
292 m_debugLB
->triggerUpdate(false);
298 KSircIOController::~KSircIOController()
303 void KSircIOController::stderr_read(KProcess
*p
, char *b
, int l
)
305 stdout_read(p
, b
, l
);
308 void KSircIOController::stdin_write(QByteArray s
)
310 if (!proc
->isRunning())
312 kDebug(5008) << "writing to a dead process! (" << s
<< ")\n";
316 //kDebug(5008) << "--> wrote: " << s;
318 //fprintf(stderr, "Buffer output: ");
321 if(proc_CTS
== TRUE
){
322 int len
= buffer
.length();
324 qWarning("KProcess barfed in all clear signal again");
327 send_buf
= new char[len
];
328 memcpy(send_buf
, buffer
.data(), len
);
329 if(proc
->writeStdin(send_buf
, len
) == FALSE
){
330 kDebug(5008) << "Failed to write but CTS HIGH! Setting low!: " << s
<< endl
;
334 QString s
= QString::fromUtf8(buffer
);
335 m_debugLB
->insertItem(s
);
336 m_debugLB
->setContentsPos( 0, m_debugLB
->contentsHeight());
343 if(buffer
.length() > 5000){
344 kDebug(5008) << "IOController: KProcess barfing again!\n";
346 // write(sirc_stdin, s, s.length());
350 void KSircIOController::sircDied(KProcess
*process
)
352 if ( process
->exitStatus() == 0 )
354 kDebug(5008) << "IOController: KProcess died!\n";
355 ksircproc
->TopList
["!all"]->sirc_receive("*E* DSIRC IS DEAD");
356 ksircproc
->TopList
["!all"]->sirc_receive("*E* KSIRC WINDOW HALTED");
357 ksircproc
->TopList
["!all"]->sirc_receive( QByteArray( "*E* Tried to run: " ) + KGlobal::dirs()->findExe("dsirc").ascii() + QByteArray( "\n" ) );
358 ksircproc
->TopList
["!all"]->sirc_receive("*E* DID YOU READ THE INSTALL INTRUCTIONS?");
361 void KSircIOController::procCTS ( KProcess
*)
366 if(!buffer
.isEmpty()){
372 void KSircIOController::showContextMenuOnDebugWindow(Q3ListBoxItem
*, const QPoint
&pos
)
377 Q3PopupMenu
popup(m_debugLB
);
378 popup
.insertItem("Save Contents to File...", 1);
379 if (popup
.exec( pos
) != 1)
382 QString path
= KFileDialog::getSaveFileName();
387 if (!file
.open(QIODevice::WriteOnly
))
390 QTextStream
stream(&file
);
392 for (uint i
= 0; i
< m_debugLB
->count(); ++i
)
393 stream
<< m_debugLB
->text(i
) << endl
;
396 void KSircIOController::showDebugTraffic(bool show
)
398 kDebug(5008) << "Got show request: " << show
<< endl
;
399 if(m_debugLB
== 0 && show
== true){
400 m_debugLB
= new Q3ListBox(0x0, QByteArray(this->name()) + "_debugWindow");
401 m_debugLB
->resize(600, 300);
403 connect(m_debugLB
,SIGNAL(contextMenuRequested(Q3ListBoxItem
*,const QPoint
&)),
404 this,SLOT(showContextMenuOnDebugWindow(Q3ListBoxItem
*,const QPoint
&)));
406 else if(m_debugLB
!= 0 && show
== false){
413 bool KSircIOController::isDebugTraffic()
421 void KSircIOController::appendDebug(QString s
)
424 m_debugLB
->insertItem(s
);
425 m_debugLB
->setContentsPos( 0, m_debugLB
->contentsHeight()-m_debugLB
->visibleHeight());
429 #include "iocontroller.moc"