pcb 4.1.1
An interactive printed circuit board layout editor.

dbus.c

Go to the documentation of this file.
00001 
00028 #define DBUS_API_SUBJECT_TO_CHANGE
00029 #include <dbus/dbus.h>
00030 #include <string.h>
00031 
00032 #include "dbus.h"
00033 #include "dbus-pcbmain.h"
00034 #include "dbus-introspect.h"
00035 #include "global.h"
00036 #include "data.h"
00037 
00038 /* For lrealpath */
00039 #include "lrealpath.h"
00040 
00041 
00042 #define PCB_DBUS_CANONICAL_NAME    "org.seul.geda.pcb"
00043 #define PCB_DBUS_OBJECT_PATH       "/org/seul/geda/pcb"
00044 #define PCB_DBUS_INTERFACE         "org.seul.geda.pcb"
00045 #define PCB_DBUS_ACTIONS_INTERFACE "org.seul.geda.pcb.actions"
00046 
00047 static DBusConnection *pcb_dbus_conn;
00048 
00049 
00050 static DBusHandlerResult
00051 handle_get_filename (DBusConnection * connection, DBusMessage * message,
00052                      void *data)
00053 {
00054   DBusMessage *reply;
00055   DBusMessageIter iter;
00056   DBusHandlerResult result;
00057   char *filename;
00058 
00059   result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00060 
00061   // TODO: Should check the message signature matches what we expect?
00062 
00063   reply = dbus_message_new_method_return (message);
00064   if (reply == NULL)
00065     {
00066       fprintf (stderr, "pcb_dbus: Couldn't create reply message\n");
00067       return result;
00068     }
00069   dbus_message_iter_init_append (reply, &iter);
00070 
00071   if (PCB->Filename)
00072     filename = lrealpath (PCB->Filename);
00073   else
00074     filename = NULL;
00075 
00076   if (filename == NULL)
00077     {
00078 #ifdef DEBUG
00079       fprintf (stderr,
00080                "pcb_dbus: DEBUG: Couldn't get working filename, assuming none\n");
00081 #endif
00082       filename = strdup ("");
00083       if (filename == NULL)
00084         {
00085           fprintf (stderr,
00086                    "pcb_dbus: Couldn't strdup( \"\" ) for the filename\n");
00087           goto out;
00088         }
00089     }
00090   if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &filename))
00091     {
00092       fprintf (stderr,
00093                "pcb_dbus: Couldn't append return filename string to message reply, Out Of Memory!\n");
00094       free (filename);
00095       goto out;
00096     }
00097   free (filename);
00098   if (!dbus_connection_send (connection, reply, NULL))
00099     {
00100       fprintf (stderr, "pcb_dbus: Couldn't send message, Out Of Memory!\n");
00101       goto out;
00102     }
00103   result = DBUS_HANDLER_RESULT_HANDLED;
00104 
00105 out:
00106   dbus_message_unref (reply);
00107   return result;
00108 }
00109 
00110 
00111 static DBusHandlerResult
00112 handle_exec_action (DBusConnection * connection, DBusMessage * message,
00113                     void *data)
00114 {
00115   DBusMessage *reply;
00116   DBusMessageIter iter;
00117   DBusHandlerResult result;
00118   DBusError err;
00119   dbus_uint32_t retval;
00120   char *action_name;
00121   char **argv;
00122   int argc;
00123 #ifdef DEBUG
00124   int i;
00125 #endif
00126 
00127   result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00128 
00129   // TODO: Should check the message signature matches what we expect?
00130 
00131   // initialise the error struct
00132   dbus_error_init (&err);
00133 
00134   /* DON'T FREE action_name, as it belongs to DBUS,
00135    * DO    FREE argv, using dbus_free_string_array()
00136    */
00137   argv = NULL;
00138   if (!dbus_message_get_args (message,
00139                               &err,
00140                               DBUS_TYPE_STRING, &action_name,
00141                               DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &argv, &argc,
00142                               DBUS_TYPE_INVALID))
00143     {
00144       fprintf (stderr, "Failed to read method arguments\n");
00145       if (argv)
00146         dbus_free_string_array (argv);
00147       return result;
00148     }
00149 
00150 #ifdef DEBUG
00151   fprintf (stderr, "pcb_dbus: DEBUG: Executing action: %s(", action_name);
00152   if (argc > 0)
00153     fprintf (stderr, " \"%s\"", argv[0]);
00154   for (i = 1; i < argc; i++)
00155     fprintf (stderr, ", \"%s\"", argv[i]);
00156   fprintf (stderr, " )\n");
00157 #endif
00158 
00159   // TODO: Proper return value from actions
00160   hid_actionv (action_name, argc, argv);
00161   retval = 0;
00162 
00163   dbus_free_string_array (argv);
00164 
00165   reply = dbus_message_new_method_return (message);
00166   if (reply == NULL)
00167     {
00168       fprintf (stderr, "pcb_dbus: Couldn't create reply message\n");
00169       return result;
00170     }
00171   dbus_message_iter_init_append (reply, &iter);
00172   if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &retval))
00173     {
00174       fprintf (stderr, "pcb_dbus: Couldn't sent message, Out Of Memory!\n");
00175       goto out;
00176     }
00177 
00178   if (!dbus_connection_send (connection, reply, NULL))
00179     {
00180       fprintf (stderr, "pcb_dbus: Couldn't send message, Out Of Memory!\n");
00181       goto out;
00182     }
00183 
00184   result = DBUS_HANDLER_RESULT_HANDLED;
00185 out:
00186   dbus_message_unref (reply);
00187   return result;
00188 }
00189 
00190 
00191 static DBusHandlerResult
00192 handle_introspect (DBusConnection * connection, DBusMessage * message,
00193                    void *data)
00194 {
00195   DBusMessage *reply;
00196   DBusMessageIter iter;
00197   DBusHandlerResult result;
00198 
00199   result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00200   reply = dbus_message_new_method_return (message);
00201   if (reply == NULL)
00202     {
00203       fprintf (stderr, "pcb_dbus: Couldn't create reply message\n");
00204       return result;
00205     }
00206   dbus_message_iter_init_append (reply, &iter);
00207   if (!dbus_message_iter_append_basic
00208       (&iter, DBUS_TYPE_STRING, &pcb_dbus_introspect_xml))
00209     {
00210       fprintf (stderr,
00211                "pcb_dbus: Couldn't add introspect XML to message return\n");
00212       goto out;
00213     }
00214   if (!dbus_connection_send (pcb_dbus_conn, reply, NULL))
00215     {
00216       fprintf (stderr,
00217                "pcb_dbus: Couldn't queue reply message for sending\n");
00218       goto out;
00219     }
00220   result = DBUS_HANDLER_RESULT_HANDLED;
00221 out:
00222   dbus_message_unref (reply);
00223   return result;
00224 }
00225 
00226 static void
00227 unregister_dbus_handler (DBusConnection * connection, void *data)
00228 {
00229 }
00230 
00231 
00232 static DBusHandlerResult
00233 handle_dbus_message (DBusConnection * connection, DBusMessage * message,
00234                      void *data)
00235 {
00236   int msg_type;
00237   msg_type = dbus_message_get_type (message);
00238 
00239   switch (msg_type)
00240     {
00241     case DBUS_MESSAGE_TYPE_METHOD_CALL:
00242       {
00243         const char *method_name;
00244         const char *interface_name;
00245 
00246         method_name = dbus_message_get_member (message);
00247         if (method_name == NULL)
00248           {
00249             fprintf (stderr, "pcb_dbus: Method had no name specified\n");
00250             break;
00251           }
00252 
00253         interface_name = dbus_message_get_interface (message);
00254         if (interface_name == NULL)
00255           {
00256             fprintf (stderr, "pcb_dbus: Method had no interface specified\n");
00257             break;
00258           }
00259 
00260         if (strcmp (interface_name, PCB_DBUS_INTERFACE) == 0)
00261           {
00262             if (strcmp (method_name, "GetFilename") == 0)
00263               {
00264                 return handle_get_filename (connection, message, data);
00265               }
00266             fprintf (stderr, "pcb_dbus: Interface '%s' has no method '%s'\n",
00267                      interface_name, method_name);
00268             break;
00269           }
00270         else if (strcmp (interface_name, PCB_DBUS_ACTIONS_INTERFACE) == 0)
00271           {
00272             if (strcmp (method_name, "ExecAction") == 0)
00273               {
00274                 return handle_exec_action (connection, message, data);
00275               }
00276             fprintf (stderr, "pcb_dbus: Interface '%s' has no method '%s'\n",
00277                      interface_name, method_name);
00278             break;
00279           }
00280         else if (strcmp (interface_name, DBUS_INTERFACE_INTROSPECTABLE) == 0)
00281           {
00282             if (strcmp (method_name, "Introspect") == 0)
00283               {
00284                 return handle_introspect (connection, message, data);
00285               }
00286             fprintf (stderr, "pcb_dbus: Interface '%s' has no method '%s'\n",
00287                      interface_name, method_name);
00288             break;
00289           }
00290         else
00291           {
00292             fprintf (stderr, "pcb_dbus: Interface '%s' was not recognised\n",
00293                      interface_name);
00294             break;
00295           }
00296       }
00297       break;
00298 
00299     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
00300       fprintf (stderr, "pcb_dbus: DBUG: Method return message\n");
00301       // WON'T ACTUALLY BE ANY UNLESS WE MAKE AN ASYNCRONOUS CALL?
00302       break;
00303 
00304     case DBUS_MESSAGE_TYPE_ERROR:
00305       fprintf (stderr, "pcb_dbus: DEBUG: Error message\n");
00306       // HOPE NOT!
00307       break;
00308 
00309     case DBUS_MESSAGE_TYPE_SIGNAL:
00310       fprintf (stderr, "pcb_dbus: DEBUG: Signal message\n");
00311       // NONE AT PRESENT
00312       break;
00313 
00314     default:
00315       fprintf (stderr,
00316                "pcb_dbus: DEBUG: Message type wasn't one we know about!\n");
00317       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00318     }
00319 
00320   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00321 }
00322 
00323 
00328 void
00329 pcb_dbus_setup (void)
00330 {
00331   DBusError err;
00332   int ret;
00333   const DBusObjectPathVTable object_vtable = {
00334     unregister_dbus_handler,
00335     handle_dbus_message,
00336     NULL, NULL, NULL, NULL
00337   };
00338 
00339   // Initialise the error variable
00340   dbus_error_init (&err);
00341 
00342   // Connect to the bus
00343   pcb_dbus_conn = dbus_bus_get_private (DBUS_BUS_SESSION, &err);
00344   if (dbus_error_is_set (&err))
00345     {
00346       fprintf (stderr, "pcb_dbus: DBus connection Error (%s)\n", err.message);
00347       dbus_error_free (&err);
00348     }
00349   if (pcb_dbus_conn == NULL)
00350     return;
00351 
00352   // Request the canonical name for PCB on the bus
00353   ret = dbus_bus_request_name (pcb_dbus_conn, PCB_DBUS_CANONICAL_NAME,
00354                                DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
00355   if (dbus_error_is_set (&err))
00356     {
00357       fprintf (stderr, "pcb_dbus: DBus name error (%s)\n", err.message);
00358       dbus_error_free (&err);
00359     }
00360   if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER
00361       && ret != DBUS_REQUEST_NAME_REPLY_IN_QUEUE)
00362     {
00363       fprintf (stderr,
00364                "pcb_dbus: Couldn't gain ownership or queued ownership of the canonical DBus name\n");
00365       return;
00366     }
00367 
00368   if (!dbus_connection_register_object_path (pcb_dbus_conn, PCB_DBUS_OBJECT_PATH, &object_vtable, NULL  // void * user_data
00369       ))
00370     {
00371       fprintf (stderr, "pcb_dbus: Couldn't register DBUS handler for %s\n",
00372                PCB_DBUS_OBJECT_PATH);
00373       return;
00374     }
00375 
00376   // Setup intergration with the pcb mainloop
00377   pcb_dbus_connection_setup_with_mainloop (pcb_dbus_conn);
00378 
00379 //  dbus_error_free(&err);
00380   return;
00381 }
00382 
00383 
00384 
00388 void
00389 pcb_dbus_finish (void)
00390 {
00391   DBusError err;
00392 
00393   // Initialise the error variable
00394   dbus_error_init (&err);
00395 
00396   // TODO: Could emit a "goodbye" signal here?
00397 
00398   dbus_connection_flush (pcb_dbus_conn);
00399 
00400   dbus_connection_unregister_object_path (pcb_dbus_conn,
00401                                           PCB_DBUS_OBJECT_PATH);
00402 
00403   dbus_bus_release_name (pcb_dbus_conn, PCB_DBUS_CANONICAL_NAME, &err);
00404 
00405   dbus_error_free (&err);
00406 
00407   pcb_dbus_connection_finish_with_mainloop (pcb_dbus_conn);
00408 
00409   dbus_connection_close (pcb_dbus_conn);
00410   dbus_connection_unref (pcb_dbus_conn);
00411 
00412   // Call DBus shutdown. This doesn't work with shared connections,
00413   // only private ones (like we took out earlier).
00414   // If any future module / plugin to PCB wants to use DBus too,
00415   // we must remove this call. DBus will get shut-down when the app exits.
00416   dbus_shutdown ();
00417 }