* qt/Makfile.am:
[platform/upstream/dbus.git] / mono / Message.cs
1 namespace DBus 
2 {
3   
4   using System;
5   using System.Runtime.InteropServices;
6   using System.Diagnostics;
7   using System.Collections;
8   
9   public class Message : IDisposable
10   {
11     private static Stack stack = new Stack ();
12           
13     static public Message Current {
14       get 
15         {
16           return stack.Count > 0 ? (Message) stack.Peek () : null;
17         }
18     }
19
20     static internal void Push (Message message)
21     {
22       stack.Push (message);
23     }
24
25     static internal void Pop ()
26     {
27       stack.Pop ();
28     }
29           
30     
31     /// <summary>
32     /// A pointer to the underlying Message structure
33     /// </summary>
34     private IntPtr rawMessage;
35     
36     /// <summary>
37     /// The current slot number
38     /// </summary>
39     private static int slot = -1;
40     
41     // Keep in sync with C
42     public enum MessageType 
43     {
44       Invalid = 0,
45       MethodCall = 1,
46       MethodReturn = 2,
47       Error = 3,
48       Signal = 4
49     }
50
51     private Arguments arguments = null;
52
53     protected Service service = null;
54     protected string pathName = null;
55     protected string interfaceName = null;
56     protected string name = null;    
57     private string key= null;
58
59     protected Message()
60     {
61       // An empty constructor for the sake of sub-classes which know how to construct theirselves.
62     }
63     
64     protected Message(IntPtr rawMessage, Service service)
65     {
66       RawMessage = rawMessage;
67       this.service = service;
68     }
69     
70     protected Message(MessageType messageType) 
71     {
72       // the assignment bumps the refcount
73       RawMessage = dbus_message_new((int) messageType);
74       
75       if (RawMessage == IntPtr.Zero) {
76         throw new OutOfMemoryException();
77       }
78       
79       dbus_message_unref(RawMessage);
80     }
81     
82     protected Message(MessageType messageType, Service service) : this(messageType) 
83     {
84       this.service = service;
85     }
86
87     public void Dispose() 
88     {
89       Dispose(true);
90       GC.SuppressFinalize(this);
91     }
92     
93     public void Dispose (bool disposing) 
94     {
95       if (disposing) {
96         if (this.arguments != null)
97           this.arguments.Dispose ();
98       }
99
100       RawMessage = IntPtr.Zero; // free the native object
101     }     
102
103     ~Message() 
104     {
105       Dispose (false);
106     }
107     
108     public static Message Wrap(IntPtr rawMessage, Service service) 
109     {
110       if (slot > -1) {
111         // If we already have a Message object associated with this rawMessage then return it
112         IntPtr rawThis = dbus_message_get_data(rawMessage, slot);
113         if (rawThis != IntPtr.Zero && ((GCHandle)rawThis).Target == typeof(DBus.Message))
114           return (DBus.Message) ((GCHandle)rawThis).Target;
115       } 
116       // If it doesn't exist then create a new Message around it
117       Message message = null;
118       MessageType messageType = (MessageType) dbus_message_get_type(rawMessage);
119       
120       switch (messageType) {
121       case MessageType.Signal:
122         message = new Signal(rawMessage, service);
123         break;
124       case MessageType.MethodCall:
125         message = new MethodCall(rawMessage, service);
126         break;
127       case MessageType.MethodReturn:
128         message = new MethodReturn(rawMessage, service);
129         break;
130       case MessageType.Error:
131         message = new ErrorMessage(rawMessage, service);
132         break;
133       default:
134         throw new ApplicationException("Unknown message type to wrap: " + messageType);
135       }
136
137       return message;
138     }
139     
140     internal IntPtr RawMessage 
141     {
142       get 
143         {
144           return rawMessage;
145         }
146       set 
147         {
148           if (value == rawMessage) 
149             return;
150           
151           if (rawMessage != IntPtr.Zero) 
152             {
153               // Get the reference to this
154               IntPtr rawThis = dbus_message_get_data(rawMessage, Slot);
155               Debug.Assert (rawThis != IntPtr.Zero);
156               
157               // Blank over the reference
158               dbus_message_set_data(rawMessage, Slot, IntPtr.Zero, IntPtr.Zero);
159               
160               // Free the reference
161               ((GCHandle) rawThis).Free();
162               
163               // Unref the connection
164               dbus_message_unref(rawMessage);
165             }
166           
167           this.rawMessage = value;
168           
169           if (rawMessage != IntPtr.Zero) 
170             {
171               GCHandle rawThis;
172               
173               dbus_message_ref(rawMessage);
174               
175               // We store a weak reference to the C# object on the C object
176               rawThis = GCHandle.Alloc(this, GCHandleType.WeakTrackResurrection);
177               
178               dbus_message_set_data(rawMessage, Slot, (IntPtr) rawThis, IntPtr.Zero);
179             }
180         }
181     }
182     
183     public void Send(ref int serial) 
184     {
185       if (!dbus_connection_send (Service.Connection.RawConnection, RawMessage, ref serial))
186         throw new OutOfMemoryException ();
187
188       Service.Connection.Flush();
189     }
190     
191     public void Send() 
192     {
193       int ignored = 0;
194       Send(ref ignored);
195     }
196
197     public void SendWithReply() 
198     {
199       IntPtr rawPendingCall = IntPtr.Zero;
200       
201       if (!dbus_connection_send_with_reply (Service.Connection.RawConnection, RawMessage, rawPendingCall, Service.Connection.Timeout))
202         throw new OutOfMemoryException();
203     }
204      
205     public MethodReturn SendWithReplyAndBlock()
206     {
207       Error error = new Error();
208       error.Init();
209
210       IntPtr rawMessage = dbus_connection_send_with_reply_and_block(Service.Connection.RawConnection, 
211                                                                     RawMessage, 
212                                                                     Service.Connection.Timeout, 
213                                                                     ref error);
214
215       if (rawMessage != IntPtr.Zero) {
216         MethodReturn methodReturn = new MethodReturn(rawMessage, Service);
217         // Ownership of a ref is passed onto us from
218         // dbus_connection_send_with_reply_and_block().  It gets reffed as
219         // a result of being passed into the MethodReturn ctor, so unref
220         // the extra one here.
221         dbus_message_unref (rawMessage);
222
223         return methodReturn;
224       } else {
225         throw new DBusException(error);
226       }
227     }
228
229     public MessageType Type
230     {
231       get 
232         {
233           return (MessageType) dbus_message_get_type(RawMessage);
234         }
235     }
236     
237     public Service Service
238     {
239       set 
240         {
241           if (this.service != null && (value.Name != this.service.Name)) {
242             if (!dbus_message_set_destination(RawMessage, value.Name)) {
243               throw new OutOfMemoryException();
244             }
245           }
246           
247           this.service = value;
248         }
249       get 
250         {
251           return this.service;
252         }
253     }
254     
255     protected virtual string PathName
256     {
257       set 
258         {
259           if (value != this.pathName) 
260             {
261               if (!dbus_message_set_path(RawMessage, value)) {
262                 throw new OutOfMemoryException();
263               }
264               
265               this.pathName = value;
266             }
267         }
268       get 
269         {
270           if (this.pathName == null) {
271             this.pathName = Marshal.PtrToStringAnsi(dbus_message_get_path(RawMessage));
272           }
273           
274           return this.pathName;
275         }
276     }
277     
278     protected virtual string InterfaceName
279     {
280       set 
281         {
282           if (value != this.interfaceName)
283             {
284               dbus_message_set_interface (RawMessage, value);
285               this.interfaceName = value;
286             }
287         }
288       get 
289         {
290           if (this.interfaceName == null) {
291             this.interfaceName = Marshal.PtrToStringAnsi(dbus_message_get_interface(RawMessage));
292           }
293
294           return this.interfaceName;
295         }
296     }
297     
298     protected virtual string Name
299     {
300       set {
301         if (value != this.name) {
302           dbus_message_set_member(RawMessage, value);
303           this.name = value;
304         }
305       }
306       get {
307         if (this.name == null) {
308           this.name = Marshal.PtrToStringAnsi(dbus_message_get_member(RawMessage));
309         }
310
311         return this.name;
312       }
313     }
314
315     public string Key
316     {
317       get {
318         if (this.key == null) {
319           this.key = Name + " " + Arguments;
320         }
321         
322         return this.key;
323       }
324     }
325
326     public Arguments Arguments
327     {
328       get 
329         {
330           if (this.arguments == null) {
331             this.arguments = new Arguments(this);
332           }
333           
334           return this.arguments;
335         }
336     }
337
338     public string Sender 
339     {
340       get
341         {
342           return Marshal.PtrToStringAnsi(dbus_message_get_sender(RawMessage));
343         }
344     }
345
346     public string Destination
347     {
348       get
349         {
350           return Marshal.PtrToStringAnsi(dbus_message_get_destination(RawMessage));
351         }
352     }
353             
354     protected int Slot
355     {
356       get 
357         {
358           if (slot == -1) 
359             {
360               // We need to initialize the slot
361               if (!dbus_message_allocate_data_slot (ref slot))
362                 throw new OutOfMemoryException ();
363               
364               Debug.Assert (slot >= 0);
365             }
366           
367           return slot;
368         }
369     }
370     
371     [DllImport ("dbus-1", EntryPoint="dbus_message_new")]
372     protected extern static IntPtr dbus_message_new (int messageType);
373     
374     [DllImport ("dbus-1", EntryPoint="dbus_message_unref")]
375     protected extern static void dbus_message_unref (IntPtr ptr);
376     
377     [DllImport ("dbus-1", EntryPoint="dbus_message_ref")]
378     protected extern static void dbus_message_ref (IntPtr ptr);
379     
380     [DllImport ("dbus-1", EntryPoint="dbus_message_allocate_data_slot")]
381     protected extern static bool dbus_message_allocate_data_slot (ref int slot);
382     
383     [DllImport ("dbus-1", EntryPoint="dbus_message_free_data_slot")]
384     protected extern static void dbus_message_free_data_slot (ref int slot);
385     
386     [DllImport ("dbus-1", EntryPoint="dbus_message_set_data")]
387     protected extern static bool dbus_message_set_data (IntPtr ptr,
388                                                         int    slot,
389                                                         IntPtr data,
390                                                         IntPtr free_data_func);
391     
392     [DllImport ("dbus-1", EntryPoint="dbus_message_get_data")]
393     protected extern static IntPtr dbus_message_get_data (IntPtr ptr,
394                                                           int    slot);
395     
396     [DllImport ("dbus-1", EntryPoint="dbus_connection_send")]
397     private extern static bool dbus_connection_send (IntPtr  ptr,
398                                                      IntPtr  message,
399                                                      ref int client_serial);
400
401     [DllImport ("dbus-1", EntryPoint="dbus_connection_send_with_reply")]
402     private extern static bool dbus_connection_send_with_reply (IntPtr rawConnection, IntPtr rawMessage, IntPtr rawPendingCall, int timeout);
403
404     [DllImport ("dbus-1", EntryPoint="dbus_connection_send_with_reply_and_block")]
405     private extern static IntPtr dbus_connection_send_with_reply_and_block (IntPtr rawConnection, IntPtr  message, int timeout, ref Error error);
406
407     [DllImport("dbus-1")]
408     private extern static int dbus_message_get_type(IntPtr rawMessage);
409
410     [DllImport("dbus-1")]
411     private extern static bool dbus_message_set_path(IntPtr rawMessage, string pathName);
412
413     [DllImport("dbus-1")]
414     private extern static IntPtr dbus_message_get_path(IntPtr rawMessage);
415     
416     [DllImport("dbus-1")]
417     private extern static bool dbus_message_set_interface (IntPtr rawMessage, string interfaceName);
418
419     [DllImport("dbus-1")]
420     private extern static IntPtr dbus_message_get_interface(IntPtr rawMessage);
421     
422     [DllImport("dbus-1")]
423     private extern static bool dbus_message_set_member(IntPtr rawMessage, string name);
424
425     [DllImport("dbus-1")]
426     private extern static IntPtr dbus_message_get_member(IntPtr rawMessage);
427
428     [DllImport("dbus-1")]
429     private extern static bool dbus_message_set_destination(IntPtr rawMessage, string serviceName);
430
431     [DllImport("dbus-1")]
432     private extern static IntPtr dbus_message_get_destination(IntPtr rawMessage);
433
434     [DllImport("dbus-1")]
435     private extern static IntPtr dbus_message_get_sender(IntPtr rawMessage);
436   }
437 }