File indexing completed on 2024-04-28 04:02:59

0001 //
0002 // C++ Implementation: cnotifymanager
0003 //
0004 // Description: Notification manager for the /notify macro
0005 //
0006 /*
0007 Copyright 2005-2011 Tomas Mecir <kmuddy@kmuddy.com>
0008 Copyright 2005 Alex Bache <alexbache@ntlworld.com>
0009 
0010 This program is free software; you can redistribute it and/or
0011 modify it under the terms of the GNU General Public License as
0012 published by the Free Software Foundation; either version 2 of 
0013 the License, or (at your option) any later version.
0014 
0015 This program is distributed in the hope that it will be useful,
0016 but WITHOUT ANY WARRANTY; without even the implied warranty of
0017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0018 GNU General Public License for more details.
0019 
0020 You should have received a copy of the GNU General Public License
0021 along with this program.  If not, see <http://www.gnu.org/licenses/>.
0022 */
0023 
0024 #include "cnotifymanager.h"
0025 
0026 #include "kdebug.h"
0027 #include <QTcpSocket>
0028 
0029 cNotifyManager::cNotifyManager ()
0030 {
0031   notifications.clear();
0032 }
0033 
0034 cNotifyManager::~cNotifyManager()
0035 {
0036 }
0037 
0038 /** send information to external IP port */
0039 void cNotifyManager::doNotify(const int  port,
0040                              QString   &ip_data)
0041 {
0042   std::list <cEventNotification *>::iterator ptr  = notifications.begin();
0043   std::list <cEventNotification *>::iterator last = notifications.end();
0044 
0045   while ((ptr                != last)&&
0046           ((*ptr)->port_num() != port)  )
0047   {
0048     ++ptr;
0049   } // endwhile more 'in progress' event notifications to search
0050 
0051   if (ptr == last)
0052   {
0053     cEventNotification *notify_event = new cEventNotification(port,ip_data);
0054 
0055     notifications.push_back(notify_event);
0056 
0057     connect(notify_event,
0058             SIGNAL (finished(cEventNotification *)),
0059             this,
0060             SLOT (portNotified(cEventNotification *)));
0061 
0062     notify_event->send();
0063 
0064   } // endif no other notifications in progress to this IP port at this time
0065   else
0066   {
0067     // Queue data for sending later
0068     (*ptr)->queue(ip_data);
0069 
0070   } // endelse need to queue notification
0071 
0072 }
0073 
0074 
0075 void cNotifyManager::portNotified(cEventNotification *event_notify)
0076 {
0077   std::list<cEventNotification *>::iterator ptr  = notifications.begin();
0078   std::list<cEventNotification *>::iterator last = notifications.end();
0079 
0080   while ((ptr  != last)        &&
0081           (*ptr != event_notify)  )
0082   {
0083     ++ptr;
0084   } // endwhile event notification not found
0085 
0086   if (ptr != last)
0087   {
0088     delete *ptr;
0089 
0090     notifications.erase(ptr);
0091   } // endif found relevant event notification
0092 
0093 }
0094 
0095 
0096 // cEventNotification implementation from here on
0097 
0098 //***************************************************************
0099 // Constructor - set up signals and initialise variables
0100 //***************************************************************
0101 
0102 cEventNotification::cEventNotification(const int      ip_port,
0103                                        const QString &ip_data)
0104 {
0105   QString data;
0106 
0107   port = ip_port;
0108   data = ip_data+"\n";
0109 
0110   data_list.push_back(data);
0111 
0112   // Set up signal handling
0113 
0114   sock = new QTcpSocket;
0115 
0116   connect(sock, SIGNAL(connected()), this, SLOT(connected()));
0117   connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error()));
0118   connect(sock, SIGNAL(bytesWritten(qint64)), this, SLOT(wroteAll()));
0119   connect(sock, SIGNAL(disconnected()), this, SLOT (connectionClosed()));
0120 } // cEventNotification::cEventNotification
0121 
0122 
0123 //***************************************************************
0124 // Destructor
0125 //***************************************************************
0126 
0127 cEventNotification::~cEventNotification()
0128 {
0129   connectionClosed ();
0130 } // cEventNotification::~cEventNotification
0131 
0132 
0133 //***************************************************************
0134 // Function to initiate information sending to the specified IP port
0135 //***************************************************************
0136 
0137 void cEventNotification::send()
0138 {
0139   sock->connectToHost ("127.0.0.1", port);
0140 } // cEventNotification::send
0141 
0142 
0143 //***************************************************************
0144 // Queue data for sending at next opportunity
0145 //***************************************************************
0146 
0147 void cEventNotification::queue(const QString &ip_data)
0148 {
0149   QString data = ip_data+"\n";
0150 
0151   data_list.push_back(data);
0152 
0153   if (data_list.size() == 1)
0154     writeNext ();
0155 } // cEventNotification::queue
0156 
0157 
0158 //***************************************************************
0159 // Called when connected to IP port successfully
0160 //***************************************************************
0161 
0162 void cEventNotification::connected()
0163 {
0164   writeNext ();
0165 } // cEventNotification::connected
0166 
0167 
0168 
0169 //***************************************************************
0170 // Wrote some data to the IP port
0171 //***************************************************************
0172 
0173 void cEventNotification::wroteAll()
0174 {
0175    // At this point, we can try writing more data
0176   data_list.pop_front();
0177 
0178   writeNext();
0179 } // cEventNotification::wroteAll
0180 
0181 
0182 
0183 //***************************************************************
0184 // Connection closed - all done
0185 //***************************************************************
0186 
0187 void cEventNotification::connectionClosed()
0188 {
0189    // Empty notification queue
0190   data_list.clear();
0191 
0192   if (!sock) return;
0193 
0194   sock->blockSignals (true);
0195 
0196    // delete socket
0197   sock->deleteLater();
0198   sock = 0;
0199 
0200   if (port != -1)
0201   {
0202     port = -1;
0203     emit finished(this);
0204   } // endif not already announced we're finished
0205 
0206 } // cEventNotification::connectionClosed
0207 
0208 
0209 //***************************************************************
0210 // An error occured
0211 //***************************************************************
0212 
0213 void cEventNotification::error()
0214 {
0215    // Usually called when we attempt to connect to a port that's no longer
0216    // got a server attached to it.
0217 
0218   data_list.clear();
0219 
0220   if (port != -1)
0221   {
0222     port = -1;
0223 
0224     emit finished(this);
0225 
0226   } // endif not already announced we're finished
0227 
0228 } // cEventNotification::error
0229 
0230 void cEventNotification::writeNext ()
0231 {
0232   if (data_list.empty()) return;
0233   std::list<QString>::iterator ptr = data_list.begin();
0234 
0235    // Note: this might not buffer the entire message contents.  Not completely sure
0236   qint64 written = sock->write(ptr->toLatin1());
0237 
0238   if (written != ptr->length())
0239   {
0240       // NOTE: Far as I can tell, this never happens.  It's just here in case it ever does
0241     kWarning() << "/notify warning: write() was unable to buffer all data" << endl;
0242   } // endif unable to buffer all requested data
0243 
0244   if (written == -1)
0245   {
0246      // NOTE: This shouldn't ever happen because we wait until the buffer is empty before
0247      // trying to send any more data, but just in case...
0248     kWarning() << "/notify warning: write() buffer is full" << endl;
0249     data_list.clear();
0250 
0251     connectionClosed();
0252   } // endif unable to write data (write buffer is full)
0253 }
0254 
0255 #include "moc_cnotifymanager.cpp"