/*********************************************************************** IO Controller Object $$Id$$ Main io controller. Reads and writes strings to sirc. Input received in the following 2 formats: 1. ~window name~ 2. each is handled diffrently. The window name is extracted from #1 and if the window exists the message portion is sent to it. If the window doesn't exist, or case 2 is found the window is sent to the control window "!default". !default is NOT a constant window but rather follows focus arround. This is the easiest way to solve the problem of output to commands that don't have a fixed destination window. (/whois, /help, etc ) Implementation: Friends with KSircProcess allows easy access to TopList. Makes sence and means that IOController has access to TopList, etc. The two work closely together. Variables: holder: used to hold partital lines between writes. *proc: the acutally sirc client process. *ksircproc: the companion ksircprocess GUI controller stdout_notif: access to SocketNotifier, why is this global to the class? counter: existance counter. Functions: public: KSircIOController(TDEProcess*, KSircProcess*): - Object constructor takes two arguements the TDEProcess that holds a running copy of sirc. - KSircProcess is saved for access latter to TopList. - The receivedStdout signal from TDEProcess is connected to stdout_read and the processExited is connected to the sircDied slot. ~KSircIOController: does nothing at this time. public slots: stdout_read(TDEProcess *, _buffer, buflen): - Called by kprocess when data arrives. - This function does all the parsing and sending of messages to each window. stderr_read(TDEProcess*, _buffer, buflen): - Should be called for stderr data, not connected, does nothing. stdin_write(TQString): - Slot that get's connected to by KSircProcess to each window. TQString shold be written un touched! Let the writter figure out what ever he wants to do. sircDied: - Should restart sirc or something.... - Becarefull not to get it die->start->die->... etc ***********************************************************************/ #include #include "ksopts.h" #include "control_message.h" #include "iocontroller.h" #include "ksircprocess.h" #include "messageReceiver.h" #include "ksopts.h" #include #include #include #include #include #include #include #include #include #include int KSircIOController::counter = 0; KSircIOController::KSircIOController(TDEProcess *_proc, KSircProcess *_ksircproc) : TQObject() { counter++; proc = _proc; // save proc ksircproc = _ksircproc; // save ksircproce send_buf = 0x0; m_debugLB = 0; // Connect the data arrived // to sirc receive for adding // the main text window connect(proc, TQT_SIGNAL(receivedStdout(TDEProcess *, char *, int)), this, TQT_SLOT(stdout_read(TDEProcess*, char*, int))); // Connect the stderr data // to sirc receive for adding // the main text window connect(proc, TQT_SIGNAL(receivedStderr(TDEProcess *, char *, int)), this, TQT_SLOT(stderr_read(TDEProcess*, char*, int))); connect(proc, TQT_SIGNAL(processExited(TDEProcess *)), this, TQT_SLOT(sircDied(TDEProcess *))); // Notify on sirc dying connect(proc, TQT_SIGNAL(wroteStdin(TDEProcess*)), this, TQT_SLOT(procCTS(TDEProcess*))); proc_CTS = TRUE; #if 0 showDebugTraffic(true); #endif } void my_print(const char *c){ while(*c != 0x0){ if(*c & 0x80) fprintf(stderr, "<%02X>", 0xff & *c); else fprintf(stderr, "%c", *c); c++; } fprintf(stderr, "\n"); } void KSircIOController::stdout_read(TDEProcess *, char *_buffer, int buflen) { /* Main reader reads from sirc and ships it out to the right (hopefully) window. Problem trying to solve: _buffer holds upto 1024 (it seems) block of data. We need to take it, split into lines figure out where each line should go, and ship it there. We watch for broken end of lines, ie partial lines and reattach them to the front on the next read. We also stop all processing in the windows while writting the lines. Implementation: Variables: _buffer original buffer, holds just, icky thing, NOT NULL terminated! buf: new clean just the right size buf that is null terminated. pos, pos2, pos3 used to cut the string up into peices, etc. name: destination window. line: line to ship out. Steps: 1. read and copy buffer, make sure it's valid. 2. If we're holding a broken line, append it. 3. Check for a broken line, and save the end if it is. 4. Stop updates in all windows. 5. Step through the data and send the lines out to the right window. 6. Cleanup and continue. */ int pos,pos2,pos3; TQCString name, line; assert(_buffer != 0); assert(buflen > 0); TQCString buffer(_buffer, buflen+1); //fprintf(stderr, "first print: \n"); //my_print(buffer); //kdDebug(5008) << "<-- read: " << buffer << endl; name = "!default"; if(holder.length() > 0){ buffer.prepend(holder); holder.truncate(0); } if(buffer[buffer.length()-1] != '\n'){ pos = buffer.findRev('\n'); if(pos != -1){ holder = buffer.right(buffer.length()-(pos+1)); buffer.truncate(pos+1); } else { /* there is _NO_ linefeeds in this line at all, means we're * only part of a string, buffer it all!! * (lines are linefeed delimeted) */ holder = buffer; return; } } pos = pos2 = 0; KSircMessageReceiver * rec = ksircproc->TopList["!all"]; if (0 == rec) { return; } rec->control_message(STOP_UPDATES, ""); if(m_debugLB) m_debugLB->setUpdatesEnabled(false); do{ pos2 = buffer.find('\n', pos); if(pos2 == -1) pos2 = buffer.length(); line = buffer.mid(pos, pos2 - pos); if(m_debugLB){ TQString s = TQString::fromUtf8(line); m_debugLB->insertItem(s); } //kdDebug(5008) << "Line: " << line << endl; if((line.length() > 0) && (line[0] == '~')){ pos3 = line.find('~', 1); if(pos3 > 1){ name = line.mid(1,pos3-1).lower(); name = name.lower(); line.remove(0, pos3+1); } } TQString enc = TDEGlobal::charsets()->encodingForName( ksopts->channel["global"]["global"].encoding ); TQTextCodec *qtc = TDEGlobal::charsets()->codecForName( enc ); TQString qsname = qtc->toUnicode(name); /* char *b = tqstrdup(line); kdDebug(5008) << "----------------------------------------" << endl; kdDebug(5008) << "Line: " << b << endl; fprintf(stderr, "My_print: " ); my_print(b); fprintf(stderr, "fprintf: %s\n", (const char *)b); kdDebug(5008) << "Codec: " << qtc->name() << " (" << ksopts->channel["global"]["global"].encoding << ")" << " Name: " << name << " qsname: " << qsname << endl; kdDebug(5008) << "Line(de): " << qtc->toUnicode(b) << endl; kdDebug(5008) << "----------------------------------------" << endl; */ if(!(ksircproc->TopList[qsname])){ // Ignore ssfe control messages with ` // we left channel, don't open a window for a control message bool noticeCreate = true; if(ksopts->autoCreateWinForNotice == false && (line[0] == '-' || line[0] == '*')) noticeCreate = false; if(ksopts->autoCreateWin == TRUE && line[0] != '`' && line[1] != '#' && line[1] != '&' && noticeCreate) { //kdDebug(5008) << "Creating window for: " << qsname << " because of: " << line.data() << endl; ksircproc->new_toplevel(KSircChannel(ksircproc->serverName(), qsname)); } if (!ksircproc->TopList[qsname]) { qsname = "!default"; if(line[0] == '`') qsname = "!discard"; } assert(ksircproc->TopList[qsname]); } ksircproc->TopList[qsname]->sirc_receive(line); pos = pos2+1; } while((uint) pos < buffer.length()); ksircproc->TopList["!all"]->control_message(RESUME_UPDATES, ""); if(m_debugLB){ m_debugLB->triggerUpdate(true); m_debugLB->setContentsPos( 0, m_debugLB->contentsHeight()-m_debugLB->visibleHeight()); m_debugLB->setUpdatesEnabled(true); m_debugLB->triggerUpdate(false); } } KSircIOController::~KSircIOController() { delete m_debugLB; } void KSircIOController::stderr_read(TDEProcess *p, char *b, int l) { stdout_read(p, b, l); } void KSircIOController::stdin_write(TQCString s) { if (!proc->isRunning()) { kdDebug(5008) << "writing to a dead process! (" << s << ")\n"; return; } //kdDebug(5008) << "--> wrote: " << s; buffer += s; //fprintf(stderr, "Buffer output: "); //my_print(buffer); if(proc_CTS == TRUE){ int len = buffer.length(); if(send_buf != 0x0){ tqWarning("TDEProcess barfed in all clear signal again"); delete[] send_buf; } send_buf = new char[len]; memcpy(send_buf, buffer.data(), len); if(proc->writeStdin(send_buf, len) == FALSE){ kdDebug(5008) << "Failed to write but CTS HIGH! Setting low!: " << s << endl; } else{ if(m_debugLB){ TQString s = TQString::fromUtf8(buffer); m_debugLB->insertItem(s); m_debugLB->setContentsPos( 0, m_debugLB->contentsHeight()); } buffer.truncate(0); } proc_CTS = FALSE; } if(buffer.length() > 5000){ kdDebug(5008) << "IOController: TDEProcess barfing again!\n"; } // write(sirc_stdin, s, s.length()); } void KSircIOController::sircDied(TDEProcess *process) { if ( process->exitStatus() == 0 ) return; kdDebug(5008) << "IOController: TDEProcess died!\n"; ksircproc->TopList["!all"]->sirc_receive("*E* DSIRC IS DEAD"); ksircproc->TopList["!all"]->sirc_receive("*E* KSIRC WINDOW HALTED"); ksircproc->TopList["!all"]->sirc_receive( TQCString( "*E* Tried to run: " ) + TDEGlobal::dirs()->findExe("dsirc").ascii() + TQCString( "\n" ) ); ksircproc->TopList["!all"]->sirc_receive("*E* DID YOU READ THE INSTALL INTRUCTIONS?"); } void KSircIOController::procCTS ( TDEProcess *) { proc_CTS = true; delete[] send_buf; send_buf = 0x0; if(!buffer.isEmpty()){ TQCString str = ""; stdin_write(str); } } void KSircIOController::showContextMenuOnDebugWindow(TQListBoxItem *, const TQPoint &pos) { if (!m_debugLB) return; TQPopupMenu popup(m_debugLB); popup.insertItem("Save Contents to File...", 1); if (popup.exec( pos ) != 1) return; TQString path = KFileDialog::getSaveFileName(); if (path.isEmpty()) return; TQFile file(path); if (!file.open(IO_WriteOnly)) return; TQTextStream stream(&file); for (uint i = 0; i < m_debugLB->count(); ++i) stream << m_debugLB->text(i) << endl; } void KSircIOController::showDebugTraffic(bool show) { kdDebug(5008) << "Got show request: " << show << endl; if(m_debugLB == 0 && show == true){ m_debugLB = new TQListBox(0x0, TQCString(this->name()) + "_debugWindow"); m_debugLB->resize(600, 300); m_debugLB->show(); connect(m_debugLB,TQT_SIGNAL(contextMenuRequested(TQListBoxItem *,const TQPoint &)), this,TQT_SLOT(showContextMenuOnDebugWindow(TQListBoxItem *,const TQPoint &))); } else if(m_debugLB != 0 && show == false){ delete m_debugLB; m_debugLB = 0x0; } } bool KSircIOController::isDebugTraffic() { if(m_debugLB != 0) return true; else return false; } void KSircIOController::appendDebug(TQString s) { if(m_debugLB){ m_debugLB->insertItem(s); m_debugLB->setContentsPos( 0, m_debugLB->contentsHeight()-m_debugLB->visibleHeight()); } } #include "iocontroller.moc"