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