2003-06-22 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / qt / message.cpp
1 /* -*- mode: C++; c-file-style: "gnu" -*- */
2 /* message.cpp: Qt wrapper for DBusMessage
3  *
4  * Copyright (C) 2003  Zack Rusin <zack@kde.org>
5  *
6  * Licensed under the Academic Free License version 1.2
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "message.h"
24
25 #include <kdebug.h>
26
27 namespace DBus {
28
29 struct Message::iterator::IteratorData {
30   DBusMessageIter *iter;
31   QVariant         var;
32   bool             end;
33 };
34
35 /**
36  * Iterator.
37  */
38 Message::iterator::iterator()
39 {
40   d = new IteratorData;
41   d->iter = 0; d->end = true;
42 }
43
44 /**
45  * Constructs iterator for the message.
46  * @param msg message whose fields we want to iterate
47  */
48 Message::iterator::iterator( DBusMessage* msg)
49 {
50   d = new IteratorData;
51   d->iter = dbus_message_get_fields_iter( msg );
52   d->end = false;
53 }
54
55 /**
56  * Copy constructor for the iterator.
57  * @param itr iterator
58  */
59 Message::iterator::iterator( const iterator& itr )
60 {
61   d = new IteratorData;
62   dbus_message_iter_ref( itr.d->iter );
63   d->iter = itr.d->iter;
64   d->var  = itr.d->var;
65   d->end  = itr.d->end;
66 }
67
68 /**
69  * Destructor.
70  */
71 Message::iterator::~iterator()
72 {
73   dbus_message_iter_unref( d->iter );
74   delete d; d=0;
75 }
76
77 /**
78  * Creates an iterator equal to the @p itr iterator
79  * @param itr other iterator
80  * @return
81  */
82 Message::iterator&
83 Message::iterator::operator=( const iterator& itr )
84 {
85   //in case we'll ever go fot exception safety
86   dbus_message_iter_ref( itr.d->iter );
87   IteratorData *tmp = new IteratorData;
88   tmp->iter = itr.d->iter;
89   tmp->var  = itr.d->var;
90   tmp->end  = itr.d->end;
91   dbus_message_iter_unref( d->iter );
92   delete d; d=tmp;
93   return *this;
94 }
95
96 /**
97  * Returns the constant QVariant held by the iterator.
98  * @return the constant reference to QVariant held by this iterator
99  */
100 const QVariant&
101 Message::iterator::operator*() const
102 {
103   return d->var;
104 }
105
106 /**
107  * Returns the QVariant held by the iterator.
108  * @return reference to QVariant held by this iterator
109  */
110 QVariant&
111 Message::iterator::operator*()
112 {
113   return d->var;
114 }
115
116 /**
117  * Moves to the next field and return a reference to itself after
118  * incrementing.
119  * @return reference to self after incrementing
120  */
121 Message::iterator&
122 Message::iterator::operator++()
123 {
124   if ( d->end )
125     return *this;
126
127   if (  dbus_message_iter_next( d->iter ) ) {
128     fillVar();
129   } else {
130     d->end = true;
131     d->var = QVariant();
132   }
133   return *this;
134 }
135
136 /**
137  * Moves to the next field and returns self before incrementing.
138  * @return self before incrementing
139  */
140 Message::iterator
141 Message::iterator::operator++(int)
142 {
143   iterator itr( *this );
144   operator++();
145   return itr;
146 }
147
148 /**
149  * Compares this iterator to @p it iterator.
150  * @param it the iterator to which we're comparing this one to
151  * @return true if they're equal, false otherwise
152  */
153 bool
154 Message::iterator::operator==( const iterator& it )
155 {
156   if ( d->end == it.d->end ) {
157     if ( d->end == true ) {
158       return true;
159     } else {
160       return d->var == it.d->var;
161     }
162   } else
163     return false;
164 }
165
166 /**
167  * Compares two iterators.
168  * @param it The other iterator.
169  * @return true if two iterators are not equal, false
170  *         otherwise
171  */
172 bool
173 Message::iterator::operator!=( const iterator& it )
174 {
175   return !operator==( it );
176 }
177
178 /**
179  * Fills QVariant based on what current DBusMessageIter helds.
180  */
181 void
182 Message::iterator::fillVar()
183 {
184   switch ( dbus_message_iter_get_field_type( d->iter ) ) {
185   case DBUS_TYPE_INT32:
186     d->var = QVariant( dbus_message_iter_get_int32( d->iter ) );
187     break;
188   case DBUS_TYPE_UINT32:
189     d->var = QVariant( dbus_message_iter_get_uint32( d->iter ) );
190     break;
191   case DBUS_TYPE_DOUBLE:
192     d->var = QVariant( dbus_message_iter_get_double( d->iter ) );
193     break;
194   case DBUS_TYPE_STRING:
195     d->var = QVariant( QString(dbus_message_iter_get_string( d->iter )) );
196     break;
197   case DBUS_TYPE_BYTE_ARRAY:
198     {
199       QByteArray a;
200       int len;
201       char *ar;
202       ar = reinterpret_cast<char*>( dbus_message_iter_get_byte_array( d->iter, &len ) );
203       a.setRawData( ar, len );
204       QDataStream stream( a, IO_ReadOnly );
205       stream >> d->var;
206       a.resetRawData( ar, len );
207     }
208     break;
209   case DBUS_TYPE_STRING_ARRAY:
210 #warning "String array not implemented"
211     //d->var = QVariant( dbus_message_iter_get_string_array );
212     break;
213   default:
214     kdWarning()<<k_funcinfo<<" Serious problem!! "<<endl;
215     d->var = QVariant();
216     break;
217   }
218 }
219
220 /**
221  * Returns a QVariant help by this iterator.
222  * @return QVariant held by this iterator
223  */
224 QVariant
225 Message::iterator::var() const
226 {
227   return d->var;
228 }
229
230 struct Message::MessagePrivate {
231   DBusMessage *msg;
232 };
233
234 /**
235  * Constructs a new Message with the given service and name.
236  * @param service service service that the message should be sent to
237  * @param name name of the message
238  */
239 Message::Message( const QString& service, const QString& name )
240 {
241   d = new MessagePrivate;
242   d->msg = dbus_message_new( service.latin1(), name.latin1() );
243 }
244
245 /**
246  * Constructs a message that is a reply to some other
247  * message.
248  * @param name the name of the message
249  * @param replayingTo original_message the message which the created
250  * message is a reply to.
251  */
252 Message::Message( const QString& name, const Message& replayingTo )
253 {
254   d = new MessagePrivate;
255   d->msg = dbus_message_new_reply( name.latin1(), replayingTo );
256 }
257
258 /**
259  * Creates a message just like @p other
260  * @param other the copied message
261  */
262 Message::Message( const Message& other )
263 {
264   d = new MessagePrivate;
265   d->msg = dbus_message_new_from_message( other );
266 }
267
268 /**
269  * Destructs message.
270  */
271 Message::~Message()
272 {
273   dbus_message_unref( d->msg );
274   delete d; d=0;
275 }
276
277 /**
278  * Sets the message sender.
279  * @param sender the sender
280  * @return false if unsuccessful
281  */
282 bool
283 Message::setSender( const QString& sender )
284 {
285   return dbus_message_set_sender( d->msg, sender.latin1() );
286 }
287
288 /**
289  * Sets a flag indicating that the message is an error reply
290  * message, i.e. an "exception" rather than a normal response.
291  * @param error true if this is an error message.
292  */
293 void
294 Message::setError( bool error )
295 {
296   return dbus_message_set_is_error( d->msg, error );
297 }
298
299 /**
300  * Returns name of this message.
301  * @return name
302  */
303 QString
304 Message::name() const
305 {
306   return dbus_message_get_name( d->msg );
307 }
308
309 /**
310  * Returns service associated with this message.
311  * @return service
312  */
313 QString
314 Message::service() const
315 {
316   return dbus_message_get_service( d->msg );
317 }
318
319 /**
320  * Returns sender of this message.
321  * @return sender
322  */
323 QString
324 Message::sender() const
325 {
326   return dbus_message_get_sender( d->msg );
327 }
328
329 /**
330  * Checks whether this message is an error indicating message.
331  * @return true if this is an error message
332  */
333 bool
334 Message::isError() const
335 {
336   return dbus_message_get_is_error( d->msg );
337 }
338
339 /**
340  * Message can be casted to DBusMessage* to make it easier to
341  * use it with raw DBus.
342  * @return underlying DBusMessage*
343  */
344 Message::operator DBusMessage*() const
345 {
346   return d->msg;
347 }
348
349 /**
350  * Appends data to this message. It can be anything QVariant accepts.
351  * @param var Data to append
352  */
353 void
354 Message::append( const QVariant& var )
355 {
356   switch ( var.type() ) {
357   case QVariant::Int:
358     dbus_message_append_int32( d->msg, var.toInt() );
359     break;
360   case QVariant::UInt:
361     dbus_message_append_uint32( d->msg, var.toUInt() );
362     break;
363   case QVariant::String: //what about QVariant::CString ?
364     dbus_message_append_string( d->msg, var.toString() );
365     break;
366   case QVariant::Double:
367     dbus_message_append_double( d->msg, var.toDouble() );
368     break;
369   case QVariant::Invalid:
370     break;
371   default: // handles QVariant::ByteArray
372     QByteArray a;
373     QDataStream stream( a, IO_WriteOnly );
374     stream<<var;
375     dbus_message_append_byte_array( d->msg, a.data(), a.size() );
376   }
377 }
378
379
380 /**
381  * Returns the starting iterator for the fields of this
382  * message.
383  * @return starting iterator
384  */
385 Message::iterator
386 Message::begin() const
387 {
388   return iterator( d->msg );
389 }
390
391 /**
392  * Returns the ending iterator for the fields of this
393  * message.
394  * @return ending iterator
395  */
396 Message::iterator
397 Message::end() const
398 {
399   return iterator();
400 }
401
402 /**
403  * Returns the field at position @p i
404  * @param i position of the wanted field
405  * @return QVariant at position @p i or an empty QVariant
406  */
407 QVariant
408 Message::at( int i )
409 {
410   iterator itr( d->msg );
411
412   while ( i-- ) {
413     if ( itr == end() )
414       return QVariant();//nothing there
415     ++itr;
416   }
417   return *itr;
418 }
419
420 /**
421  * The underlying DBusMessage of this class.
422  * @return DBusMessage pointer.
423  */
424 DBusMessage*
425 Message::message() const
426 {
427   return d->msg;
428 }
429
430 }