diff --git a/Makefile.am b/Makefile.am
index 99fdb76..ecca9d8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,8 +12,8 @@ builtin_sources =
 builtin_cflags =
 builtin_libadd =
 
-builtin_modules += ofono
-builtin_sources += plugins/ofono.c
+builtin_modules += ofono modemmanager
+builtin_sources += plugins/ofono.c plugins/modemmanager.c
 
 libexec_PROGRAMS = src/mmsd
 
@@ -24,7 +24,7 @@ src_mmsd_SOURCES = $(gdbus_sources) $(gweb_sources)
$(builtin_sources) \
                        src/push.h src/push.c src/store.h src/store.c \
                        src/wsputil.h src/wsputil.c src/mmsutil.h
src/mmsutil.c
 
-src_mmsd_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ -lresolv
-ldl
+src_mmsd_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@
@MMGLIB_LIBS@ -lresolv -ldl
 
 src_mmsd_LDFLAGS = -Wl,--export-dynamic
 
@@ -41,7 +41,7 @@ src/plugin.$(OBJEXT): src/builtin.h
 src/builtin.h: src/genbuiltin $(builtin_sources)
        $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
 
-AM_CFLAGS = @GLIB_CFLAGS@ @DBUS_CFLAGS@ $(builtin_cflags) \
+AM_CFLAGS = @GLIB_CFLAGS@ @DBUS_CFLAGS@ @MMGLIB_CFLAGS@
$(builtin_cflags) \
                                        -DMMS_PLUGIN_BUILTIN \
                                        -DPLUGINDIR=\""$(plugindir)"\"
\
                                        -DPUSHCONFDIR=\""$(pushconfdir)
"\"
diff --git a/README b/README
index cecc99f..d9da9f5 100644
--- a/README
+++ b/README
@@ -16,12 +16,33 @@ Please note that mmsd alone will not get MMS
working! It is designed to work
 with a higher level chat application to facilitate fetching and 
 sending MMS. It interfaces with other applications via the dbus.
 
+Modem Manager specific notes
+===========================
+Upon start up, mmsd looks for and tracks the state of the modem
+that has Modem Messaging (i.e. SMS) capabilities. Since mmsd is a
lower 
+level program, mmsd assumes that other parts of the OS stack/the 
+higher level chat application track/manage mobile connectivity and
SMS. 
+This design decision was made as to not conflict with the OS stack and
the
+chat application.
+    
+This decision has two primary consequences to be aware of:
+    - mmsd does NOT manage mobile connectivity, and does not track the
state of 
+      mobile connectivity.
+    - mmsd also NOT watch the Modem Manager SMS dbus interface for new
SMS.
+
+Please note that due to limitations of Modem Manager, mmsd does not
support
+having multiple APNs at the same time (for carriers that seperate MMS
APN 
+from Mobile Data APNs).
+    
+Please read "Configuring the Modem Manager Plugin" for configuration.
+
 Compiling mmsd
 ============================
 In order to compile proxy daemon you need following software packages:
        - GCC compiler
        - D-Bus library
        - GLib library
+       - Modem Manager Library
 
 Installing mmsd
 ============================
@@ -74,4 +95,62 @@ TotalMaxAttachmentSize
         The maximum size all of your attachments can be before mmsd
rejects it.
         NOTE: This value is carrier specific! Changing this value to a
higher
               number may cause your carrier to silently reject MMSes
you send.
-              CHANGE AT YOUR OWN RISK!
\ No newline at end of file
+              CHANGE AT YOUR OWN RISK!
+
+Configuring the Modem Manager Plugin
+===========================
+On first run, mmsd will write a settings file at
+"$HOME/.mms/modemmanager/ModemManagerSettings"
+
+IMPORTANT NOTE: If you change any settings through the file,
+                mmsd MUST BE RESTARTED for the changes to take
effect! 
+                
+                You can change CarrierMMSC, CarrierMMSProxy, or
MMS_APN via 
+                dbus and they will take effect right away, but any
+                   messages sent to the mmsd queue need to be
processed 
+                   again. The easiest way to do this is to reset mmsd.
+                   But it can be done with the dbus proxy call
ProcessMessageQueue().
+
+This settings file needs to be changed before mmsd will connect! The
settings
+are as follows:
+
+CarrierMMSC
+        Get this from your carrier.
+               
+        Carrier MMSC Format: "http://mms.example.com"
+        
+CarrierMMSProxy 
+        Get this from your carrier.
+               
+        MMS Proxy Format: "proxy.example.com:80" or "NULL"
+            Both the proxy address AND port are required, or else mmsd
will not work!
+            The proxy is "proxy.example.com" 
+            The proxy port is "80"
+            If you do NOT have a proxy, set this to "NULL"
+            
+MMS_APN
+        Note that at this point, this plugin can only support one
bearer at 
+        a time (this works fine for carriers with a combined
Internet/MMS APN
+        but will not function with carriers that have two APNS
seperating 
+        the two)
+        
+        MMS APN Format: "apn.example.com"
+
+AutoProcessOnConnection
+        Tell mmsd to automatically send and recieve messages when the
modem
+        is connected. This will also allow mmsd to auto send/recieve
if the
+        modem is disconnected and reconnects, suspends and unsuspends,
etc.
+        
+        AutoProcessOnConnection Options: "true" or "false"
+        
+        
+An example of what you are looking for is here:
+
https://www.t-mobile.com/support/devices/not-sold-by-t-mobile/byod-t-mobile-data-and-apn-settings
+
+From this:
+
+CarrierMMSC=http://mms.msg.eng.t-mobile.com/mms/wapenc
+MMS_APN=fast.t-mobile.com
+CarrierMMSProxy=NULL
+
+
diff --git a/configure.ac b/configure.ac
index 6b5e1b1..721eb19 100644
--- a/configure.ac
+++ b/configure.ac
@@ -78,4 +78,9 @@ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.2, dummy=yes,
 AC_SUBST(DBUS_CFLAGS)
 AC_SUBST(DBUS_LIBS)
 
+PKG_CHECK_MODULES(MMGLIB, mm-glib >= 1.10, dummy=yes,
+                               AC_MSG_ERROR(mm-glib >= 1.10 is
required))
+AC_SUBST(MMGLIB_CFLAGS)
+AC_SUBST(MMGLIB_LIBS)
+
 AC_OUTPUT(Makefile)
diff --git a/doc/modem-manager-api.txt b/doc/modem-manager-api.txt
new file mode 100644
index 0000000..4a7f67f
--- /dev/null
+++ b/doc/modem-manager-api.txt
@@ -0,0 +1,102 @@
+Message hierarchy
+=================
+
+Service                org.ofono.mms
+Interface      org.ofono.mms.ModemManager
+Object path    /org/ofono/mms
+
+NOTE: This is an independent bus from the rest of mmsd. In order to
talk to 
+      Modem Manager, this plugin must work with dbus 2.0. The rest of
mmsd
+      operates on dbus 1.0. Be sure to connect independently to this
bus!
+
+Methods                                    
+
+    PushNotify()
+    
+               Send mmsd the contents of an SMS WAP for it to process
+               See purple-mm-sms for how this is used
+        
+        Gvariant input Format String    (ay)
+            This is the data contents of the SMS WAP
+
+       ChangeSettings()
+           IMPORTANT NOTE: Settings changed here will work right away,
but any
+                           messages sent to the mmsd queue need to be
processed 
+                           again. The easiest way to do this is to
reset mmsd.
+                           But it can be done with the dbus proxy
call 
+                           ProcessMessageQueue()
+           
+           This sets and saves the Carrier MMSC, MMS Proxy, and MMS
APN
+           
+           Gvariant Input Format String    ((sss))
+               Argument 1: Carrier MMSC
+               Argument 2: MMS Proxy
+               Argument 3: MMS APN
+               
+               Carrier MMSC
+                   Get this from your carrier.
+               
+                   Carrier MMSC Format: "http://mms.example.com"
+               
+            MMS Proxy 
+                Get this from your carrier.
+                       
+                   MMS Proxy Format: "proxy.example.com:80" or "NULL"
+                       The proxy is "proxy.example.com" 
+                       The Proxy port is "80"
+                    Both the proxy address AND port is required, or
else mmsd will not work!
+                       If you do NOT have a proxy, set this to "NULL"
+                   
+               MMS APN
+                   Note that at this point, this plugin can only
support one bearer at 
+                   a time (this works fine for carriers with a
combined Internet/MMS APN
+                   but will not function with carriers that have two
APNS seperating 
+                   the two)
+               
+                   MMS APN Format: "apn.example.com"
+               
+           Example Python Program to call "ChangeSettings":
+       
+            #!/usr/bin/python
+
+            import pydbus
+            from pydbus import SessionBus
+            bus = SessionBus()
+            TestServer = bus.get("org.ofono.mms.ModemManager",
"/org/ofono/mms")
+            TestServer.ChangeSettings(("http://mms.invalid", "NULL",
"apn.invalid"))
+            #TestServer.ChangeSettings(("http://mms.invalid",
"proxy.invalid:80", "apn.invalid"))
+
+    ProcessMessageQueue()
+        This manually activates the Modem Manager Bearer to process
any messages
+        not sent or recieved yet. The primary idea behind is two
fold: 
+        
+        a) If the Bearer Handler is misconfigured, the OS/higher level
program
+           can change the settings via the dbus and test the bearer
handler 
+           to confirm it works.
+           
+        b) If modem data is disconnected (manually or due to modem
suspend), 
+           the OS/higher level program can also track this and can
command 
+           mmsd to now process any messages it needs to send/recieve
once
+           modem data is active.
+           
+        Since BearerHandlerError() emits a signal for any errors
activating the
+        modem contect, ProcessMessageQueue() does not return any
value.        
+
+Signals                
+    BearerHandlerError()
+        If the bearer handler has an issue activating the context, it
will emit
+        a signal of the error. The errors are shown above. 
+        
+        NOTE: MMSD_MM_MODEM_CONTEXT_ACTIVE will never be emitted as a
signal.
+        
+        Gvariant Output Format String    (h)
+            enum {
+                  MMSD_MM_MODEM_MMSC_MISCONFIGURED, //the MMSC is the
default value
+                  MMSD_MM_MODEM_NO_BEARERS_ACTIVE, //The Modem has no
bearers
+                  MMSD_MM_MODEM_INTERFACE_DISCONNECTED, //mmsd found
the right bearer, but it is disconnected
+                  MMSD_MM_MODEM_INCORRECT_APN_CONNECTED, //no APN is
connected that matches the settings
+                  MMSD_MM_MODEM_FUTURE_CASE_DISCONNECTED, //Reserved
for future case
+                  MMSD_MM_MODEM_CONTEXT_ACTIVE //No error, context
activated properly
+            } mm_context_connection;
+
+Properties     None
diff --git a/plugins/modemmanager.c b/plugins/modemmanager.c
new file mode 100644
index 0000000..1d67736
--- /dev/null
+++ b/plugins/modemmanager.c
@@ -0,0 +1,993 @@
+/*
+ *
+ *  Multimedia Messaging Service
+ *
+ *  Copyright (C) 2010-2011  Intel Corporation. All rights reserved.
+ *  Updated 2021: kop316, fuzzy7k, craftyguy, Mohammad Sadiq
+ *
+ *  Adapted from: https://source.puri.sm/Librem5/purple-mm-sms
+ *                Copyright (C) 2018 Purism SPC
+ *
+ *  This program is free software; you can redistribute it and/or
modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-
1301  USA
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <errno.h>
+#include <gio/gio.h>
+#include <stdlib.h>
+#include <libmm-glib.h>
+#include "mms.h"
+
+// SETTINGS_STORE is synced with services.c
+#define SETTINGS_STORE "ModemManagerSettings"
+// SETTINGS_GROUP is where we store our settings for this plugin
+#define SETTINGS_GROUP "Modem Manager"
+//Identifier of the plugin
+#define IDENTIFIER     "modemmanager"
+//dbus default timeout for Modem
+#define MMSD_MM_MODEM_TIMEOUT       20000
+
+enum {
+  MMSD_MM_STATE_NO_MANAGER,
+  MMSD_MM_STATE_MANAGER_FOUND,
+  MMSD_MM_STATE_NO_MODEM,
+  MMSD_MM_STATE_MODEM_FOUND,
+  MMSD_MM_STATE_NO_MESSAGING_MODEM,
+  MMSD_MM_STATE_MODEM_DISABLED,
+  MMSD_MM_STATE_MODEM_UNLOCK_ERROR,
+  MMSD_MM_STATE_READY
+} e_mmsd_connection;
+
+enum {
+  MMSD_MM_MODEM_MMSC_MISCONFIGURED,       //the MMSC is the default
value
+  MMSD_MM_MODEM_NO_BEARERS_ACTIVE,        //The Modem has no bearers
+  MMSD_MM_MODEM_INTERFACE_DISCONNECTED,   //mmsd found the right
bearer, but it is disconnected
+  MMSD_MM_MODEM_INCORRECT_APN_CONNECTED,  //no APN is connected that
matches the settings
+  MMSD_MM_MODEM_FUTURE_CASE_DISCONNECTED, //Reserved for future case
+  MMSD_MM_MODEM_CONTEXT_ACTIVE            //No error, context
activated properly
+} mm_context_connection;
+
+struct modem_data {
+    struct   mms_service *service; //Do not mess with the guts of this
in plugin.c!
+    GKeyFile *modemsettings;
+    //These are pulled from the settings file, and can be set via the
Dbus
+    char *message_center;                     // The mmsc
+    char *mms_apn;                            // The MMS APN
+    char *MMS_proxy;                          // I *think* this is
where mms proxy goes?
+    // These are for settings the context (i.e. APN settings and if
the bearer is active)
+    char              *context_interface;     // Bearer interface here
(e.g. "wwan0")
+    char              *context_path;          // Dbus path of the
bearer
+    dbus_bool_t       context_active;         // Whether the context
is active
+    //The Bus org.ofono.mms.ModemManager
+    GDBusConnection   *master_connection;
+    guint             owner_id;         
+    guint             registration_id;   
+    // This is a way to track the state of the modem if it is disabled
+    MmGdbusModem      *gdbus_modem;
+    gulong            modem_state_watch_id;
+    //These are modem manager related settings
+    MMManager         *mm;
+    guint             mm_watch_id;
+    MMObject          *object; 
+    MMModem           *modem;
+    char              *path;
+    MMSim             *sim;
+    gchar             *imsi;
+    MMModemMessaging  *modem_messaging;
+    MMModemState      state;
+    GPtrArray         *device_arr;
+    gboolean          modem_available;
+    gboolean          manager_available;
+    gboolean          plugin_registered;
+    gboolean          auto_process_on_connection;
+};
+
+typedef struct {
+  MMObject *object;
+  MMModem  *modem;
+  MMSim    *sim;
+} PurMmDevice;
+
+/* Introspection data for the service we are exporting */
+static const gchar introspection_xml[] =
+  "<node>"
+  "  <interface name='org.ofono.mms.ModemManager'>"
+  "    <annotation name='org.ofono.mms.ModemManager'
value='OnInterface'/>"
+  "    <annotation name='org.ofono.mms.ModemManager'
value='AlsoOnInterface'/>"
+  "    <method name='PushNotify'>"
+  "      <annotation name='org.ofono.mms.ModemManager'
value='OnMethod'/>"
+  "      <arg type='ay' name='smswap' direction='in'/>"
+  "    </method>"
+  "    <method name='ChangeSettings'>"
+  "      <annotation name='org.ofono.mms.ModemManager'
value='OnMethod'/>"
+  "      <arg type='(sss)' name='greeting' direction='in'/>"
+  "    </method>"
+  "    <method name='ProcessMessageQueue'>"
+  "      <annotation name='org.ofono.mms.ModemManager'
value='OnMethod'/>"
+  "    </method>"
+  "    <signal name='BearerHandlerError'>"
+  "      <annotation name='org.ofono.mms.ModemManager'
value='Onsignal'/>"
+  "      <arg type='h' name='ContextError'/>"
+  "    </signal>"
+
+  "  </interface>"
+  "</node>";
+
+
+static GDBusNodeInfo *introspection_data = NULL;
+struct modem_data *modem;
+
+static void mmsd_mm_state (int state);
+static void mmsd_plugin_connect (void);
+static void mmsd_plugin_disconnect (void);
+static void free_device (PurMmDevice *device);
+static void bearer_handler(mms_bool_t active, void *user_data);
+static int set_context (void);
+static void cb_mm_manager_new (GDBusConnection *connection,
GAsyncResult *res, gpointer user_data);
+static void mm_appeared_cb (GDBusConnection *connection, const gchar
*name, const gchar *name_owner, gpointer user_data);
+static void mm_vanished_cb (GDBusConnection *connection, const gchar
*name, gpointer user_data);
+static void mm_get_modem_manager (void);
+static int modemmanager_init(void);
+static void modemmanager_exit(void);
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+  if (g_strcmp0 (method_name, "PushNotify") == 0)
+    { 
+       
+        GVariant *smswap;
+           const unsigned char *data;
+           gsize data_len;
+           if (modem->modem_available == TRUE) {
+
+               g_variant_get (parameters, "(@ay)", &smswap);
+               data_len = g_variant_get_size (smswap);
+               data = g_variant_get_fixed_array (smswap, &data_len,
1);
+               mms_error("ModemManagerPlugin(): %s",__func__);
+
+               mms_service_push_notify(modem->service, data,
data_len);
+               g_dbus_method_invocation_return_value (invocation,
NULL);
+
+          } else {
+               g_dbus_method_invocation_return_dbus_error (invocation,
+                                                      "org.ofono.mms.M
odemManager",
+                                                      "Modem is not
active!");
+          }
+
+    } 
+    else if (g_strcmp0 (method_name, "ChangeSettings") == 0) {
+
+        const gchar *mmsc, *mmsproxy, *mmsapn;
+        g_variant_get (parameters, "((sss))", &mmsc,
+                                              &mmsproxy,
+                                              &mmsapn);
+        mms_error("ModemManagerPlugin(): args MMSC:%s MMS Proxy:%s MMS
APN:%s", mmsc, mmsproxy, mmsapn);                          
+        modem->modemsettings = mms_settings_open(IDENTIFIER,
SETTINGS_STORE);
+        
+        if (g_strcmp0(mmsc, "") != 0) {
+            g_free(modem->message_center);
+            modem->message_center = g_strdup(mmsc);
+            g_key_file_set_string(modem->modemsettings,
SETTINGS_GROUP,
+                                  "CarrierMMSC", modem-
>message_center);
+        }
+        
+        if (g_strcmp0(mmsproxy, "") != 0) {
+            g_free(modem->MMS_proxy);
+            modem->MMS_proxy = g_strdup(mmsproxy);
+            g_key_file_set_string(modem->modemsettings,
SETTINGS_GROUP,
+                                  "CarrierMMSProxy", modem-
>MMS_proxy);
+            if (g_strcmp0 (modem->MMS_proxy, "NULL") == 0) {
+              g_free(modem->MMS_proxy);
+              modem->MMS_proxy = NULL;
+            }
+        }
+        
+        if (g_strcmp0(mmsapn, "") != 0) {
+             g_free(modem->mms_apn);
+             modem->mms_apn = g_strdup(mmsapn);
+             g_key_file_set_string(modem->modemsettings,
SETTINGS_GROUP,
+                                   "MMS_APN", modem->mms_apn);
+        }
+        mms_settings_close(IDENTIFIER, SETTINGS_STORE,
+                           modem->modemsettings, TRUE); 
+        
+        g_dbus_method_invocation_return_value (invocation, NULL);
+    }  
+    else if (g_strcmp0 (method_name, "ProcessMessageQueue") == 0) {
+       if (modem->modem_available == TRUE) {
+
+          /*
+           * Prevent a race condition from the connection turning
active to usable
+           * for mmsd
+           */
+           sleep(1);
+       
+           activate_bearer(modem->service);
+           g_dbus_method_invocation_return_value (invocation, NULL);
+          } else {
+               g_dbus_method_invocation_return_dbus_error (invocation,
+                                                      "org.ofono.mms.M
odemManager",
+                                                      "Modem is not
active!");
+          }
+    }
+} 
+
+static const GDBusInterfaceVTable interface_vtable =
+{
+  handle_method_call
+};
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+                 const gchar     *name,
+                 gpointer         user_data)
+{
+  
+  modem->master_connection = connection;
+
+  modem->registration_id = g_dbus_connection_register_object
(connection,
+                                                       "/org/ofono/mms
",
+                                                       introspection_d
ata->interfaces[0],
+                                                       &interface_vtab
le,
+                                                       NULL,  /*
user_data */
+                                                       NULL,  /*
user_data_free_func */
+                                                       NULL); /*
GError** */
+                                                      
+  g_assert (modem->registration_id > 0);
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+                  const gchar     *name,
+                  gpointer         user_data)
+{
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+              const gchar     *name,
+              gpointer         user_data)
+{
+}
+
+static void
+mmsd_mm_init_modem (MMObject *obj)
+{
+
+  modem->object = obj;
+  modem->modem = mm_object_get_modem (MM_OBJECT(obj));
+  modem->path = mm_modem_dup_path (modem->modem);
+
+  g_dbus_proxy_set_default_timeout (G_DBUS_PROXY(modem->modem),
+                                    MMSD_MM_MODEM_TIMEOUT);
+                                    
+  modem->modem_messaging = mm_object_get_modem_messaging
(MM_OBJECT(obj)); 
+  g_return_if_fail (MM_IS_MODEM_MESSAGING (modem-
>modem_messaging));                
+
+  mms_error("ModemManagerPlugin(): %s", __func__);
+}
+
+static void
+free_device (PurMmDevice *device)
+{
+  if (!device)
+    return;
+
+  g_clear_object (&device->sim);
+  g_clear_object (&device->modem);
+  g_clear_object (&device->object);
+  g_free (device);
+}
+
+static gboolean
+device_match_by_object (PurMmDevice *device,
+                        GDBusObject *object)
+
+{
+  g_return_val_if_fail (G_IS_DBUS_OBJECT(object), FALSE);
+  g_return_val_if_fail (MM_OBJECT(device->object), FALSE);
+  
+  return object == G_DBUS_OBJECT (device->object);
+}
+
+static void
+mmsd_mm_add_object (MMObject *obj)
+{
+  PurMmDevice *device;
+  const gchar *object_path;
+
+  object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (obj));
+
+  g_return_if_fail (object_path);
+
+  if (g_ptr_array_find_with_equal_func (modem->device_arr,
+                                        obj,
+                                        (GEqualFunc)device_match_by_ob
ject,
+                                        NULL)) {
+    mms_error("ModemManagerPlugin(): Device %s already added",
object_path);
+
+    return;
+  }
+
+  mms_error("ModemManagerPlugin(): Added device at: %s", object_path);
+
+  // TODO choose default modem if devices->len > 1
+
+  device = g_new0 (PurMmDevice, 1);
+  device->object = g_object_ref (MM_OBJECT (obj));
+  device->modem = mm_object_get_modem (MM_OBJECT(obj));
+  g_ptr_array_add (modem->device_arr, device);
+
+  mmsd_mm_init_modem (obj);
+
+  mmsd_mm_state (MMSD_MM_STATE_MODEM_FOUND);
+}
+
+static void
+mmsd_mm_get_modems (void)
+{
+  GList *list, *l;
+  gboolean has_modem = FALSE;
+
+  g_return_if_fail (MM_IS_MANAGER (modem->mm));
+
+  list = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER
(modem->mm));
+
+  for (l = list; l != NULL; l = l->next) {
+    if (!mm_object_peek_modem_messaging (l->data))
+      continue;
+
+    has_modem = TRUE;
+    mmsd_mm_add_object (MM_OBJECT(l->data));
+  }
+
+  if (!has_modem) {
+    mmsd_mm_state (MMSD_MM_STATE_NO_MODEM);
+  } else if (list) {
+    g_list_free_full (list, g_object_unref);
+  }
+}
+
+
+static void
+cb_object_added (GDBusObjectManager *manager,
+                 GDBusObject        *object,
+                 gpointer            user_data)
+{
+  mms_error("ModemManagerPlugin(): %s", __func__);
+  if (mm_object_peek_modem_messaging (MM_OBJECT (object))) {
+    mms_error("ModemManagerPlugin(): New Object does not have
Messaging feature, ignoring....");
+    mmsd_mm_add_object (MM_OBJECT(object));
+  }
+
+  
+}
+
+
+
+static void
+cb_object_removed (GDBusObjectManager *manager,
+                   GDBusObject        *object,
+                   gpointer            user_data)
+{
+  guint index;
+
+
+  g_return_if_fail (G_IS_DBUS_OBJECT(object));
+  g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER(manager));
+
+  if (g_ptr_array_find_with_equal_func (modem->device_arr,
+                                        object,
+                                        (GEqualFunc)device_match_by_ob
ject,
+                                        &index)) {
+    g_ptr_array_remove_index_fast (modem->device_arr, index);
+  }
+
+  if (MM_OBJECT(object) == modem->object) {
+    mmsd_mm_state (MMSD_MM_STATE_NO_MODEM);
+  }
+
+  mms_error("ModemManagerPlugin(): Modem removed: %s",
g_dbus_object_get_object_path (object));
+}
+
+
+static void
+cb_name_owner_changed (GDBusObjectManager *manager,
+                       GDBusObject        *object,
+                       gpointer            user_data)
+{
+  gchar *name_owner;
+
+  name_owner = g_dbus_object_manager_client_get_name_owner
(G_DBUS_OBJECT_MANAGER_CLIENT (manager));
+
+  if (!name_owner) {
+    mmsd_mm_state (MMSD_MM_STATE_NO_MANAGER);
+  }
+
+  mms_error("ModemManagerPlugin(): Name owner changed");
+
+  g_free (name_owner);
+}
+
+static void
+cb_mm_manager_new (GDBusConnection *connection,
+                   GAsyncResult    *res,
+                   gpointer         user_data)
+{
+  gchar             *name_owner;
+  g_autoptr(GError)  error = NULL;
+
+
+  modem->mm = mm_manager_new_finish (res, &error);
+  modem->device_arr = g_ptr_array_new_with_free_func ((GDestroyNotify)
free_device);
+
+  if (modem->mm) {
+  
+    mmsd_mm_state (MMSD_MM_STATE_MANAGER_FOUND);
+
+    g_signal_connect (modem->mm,
+                      "interface-added",
+                      G_CALLBACK (cb_object_added),
+                      NULL);
+
+    g_signal_connect (modem->mm,
+                      "object-added",
+                      G_CALLBACK (cb_object_added),
+                      NULL);
+
+    g_signal_connect (modem->mm,
+                      "object-removed",
+                      G_CALLBACK (cb_object_removed),
+                      NULL);
+
+    g_signal_connect (modem->mm,
+                      "notify::name-owner",
+                      G_CALLBACK (cb_name_owner_changed),
+                      NULL);
+
+    name_owner = g_dbus_object_manager_client_get_name_owner
(G_DBUS_OBJECT_MANAGER_CLIENT (modem->mm));
+    mms_error("ModemManagerPlugin(): ModemManager found: %s\n",
name_owner);
+    g_free (name_owner);
+
+    mmsd_mm_get_modems ();
+
+  } else {
+    mms_error("ModemManagerPlugin(): Error connecting to ModemManager:
%s\n", error->message);
+
+    mmsd_mm_state (MMSD_MM_STATE_NO_MANAGER);
+  }
+
+}
+
+static void
+cb_get_sim_ready (MMModem      *MMmodem,
+                  GAsyncResult *res,
+                  gpointer      user_data)
+{
+  modem->sim = mm_modem_get_sim_finish (MMmodem, res, NULL);
+  
+  modem->imsi = mm_sim_dup_imsi (modem->sim);
+
+  mms_error("ModemManagerPlugin(): Got SIM Path: %s Identifier: %s,
imsi: %s", mm_sim_get_path (modem->sim),
+             mm_sim_get_identifier (modem->sim), modem->imsi);
+}
+
+static void
+mmsd_mm_get_modem_state (void)
+{
+  g_autoptr(GError) error = NULL;
+
+  if (!modem->modem) {
+    mmsd_mm_state (MMSD_MM_STATE_NO_MODEM);
+    return;
+  }
+
+  if (!modem->modem_messaging) {
+    mmsd_mm_state (MMSD_MM_STATE_NO_MESSAGING_MODEM);
+    return;
+  }
+
+  if (modem->state < MM_MODEM_STATE_ENABLED) {
+      mms_error("ModemManagerPlugin(): Something May be wrong with the
modem, checking....");
+      switch (modem->state) {
+      case MM_MODEM_STATE_FAILED:
+        mms_error("ModemManagerPlugin(): MM_MODEM_STATE_FAILED");
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+      case MM_MODEM_STATE_UNKNOWN:
+        mms_error("ModemManagerPlugin(): MM_MODEM_STATE_UNKNOWN");
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+      case MM_MODEM_STATE_LOCKED:
+        mms_error("ModemManagerPlugin(): MM_MODEM_STATE_FAILED");
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+      case MM_MODEM_STATE_INITIALIZING:
+        mms_error("ModemManagerPlugin():
MM_MODEM_STATE_INITIALIZING");
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+      case MM_MODEM_STATE_DISABLED:
+        mms_error("ModemManagerPlugin(): MM_MODEM_STATE_DISABLED");
+        mms_error("ModemManagerPlugin(): Turning on Modem....");
+        mm_modem_set_power_state_sync (modem->modem,
MM_MODEM_POWER_STATE_ON, NULL, &error);
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+      case MM_MODEM_STATE_DISABLING:
+        mms_error("ModemManagerPlugin(): MM_MODEM_STATE_DISABLING");
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+      case MM_MODEM_STATE_ENABLING:
+        mms_error("ModemManagerPlugin(): MM_MODEM_STATE_ENABLING");
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+      default:
+        mms_error("ModemManagerPlugin(): MM_MODEM_OTHER_BAD_STATE:
%d", modem->state);
+        mmsd_mm_state (MMSD_MM_STATE_MODEM_DISABLED);
+        return;
+    }
+  }
+  mms_error("ModemManagerPlugin(): MM_MODEM_GOOD_STATE: %d", modem-
>state);
+  mmsd_mm_state (MMSD_MM_STATE_READY);
+  
+  /* Automatically process unsent/unrecieved messages when the modem
is connected */
+  if (modem->state == MM_MODEM_STATE_CONNECTED) {
+      if (modem->auto_process_on_connection == TRUE) {
+          mms_error("Auto processing unsent/unrecieved messages per
settings.");
+          /*
+           * Prevent a race condition from the connection 
+           * turning active to usable for mmsd
+           */
+          sleep(1);
+      
+          activate_bearer(modem->service);
+      } else {
+          mms_error("Not auto processing unsent/unrecieved messages
per settings.");
+      }
+   }
+  return;
+}
+
+static void 
+modem_state_changed_cb (MMModem                  *cb_modem,
+                        MMModemState              old,
+                        MMModemState              new,
+                        MMModemStateChangeReason  reason)
+{
+    mms_error("ModemManagerPlugin(): State Change: Old State: %d New
State: %d, Reason: %d", old, new, reason);
+    modem->state = new;
+    mmsd_mm_get_modem_state ();    
+    
+}
+
+
+
+static void
+mmsd_mm_state (int state)
+{
+
+  switch (state) {
+    case MMSD_MM_STATE_MODEM_FOUND:
+      if (!modem->modem_available) {
+        if (modem->modem) {
+          mm_modem_get_sim (modem->modem,
+                            NULL,
+                            (GAsyncReadyCallback)cb_get_sim_ready,
+                            NULL);
+                            
+          modem->gdbus_modem = MM_GDBUS_MODEM(modem->modem);
+
+          modem->modem_state_watch_id = g_signal_connect(modem-
>gdbus_modem, 
+                                                           "state-
changed", 
+                                                           G_CALLBACK(
modem_state_changed_cb), 
+                                                           NULL);
+        }
+        modem->state = mm_modem_get_state (modem->modem);
+        mmsd_mm_get_modem_state ();
+
+      }
+      break;
+    case MMSD_MM_STATE_NO_MODEM:
+      if (modem->modem_available) {
+        g_signal_handler_disconnect (modem->gdbus_modem,
+                                     modem->modem_state_watch_id);
+        mmsd_plugin_disconnect();
+        mms_error("ModemManagerPlugin(): Modem vanished, Disabling
plugin");
+
+        
+      } else {
+        mms_error("ModemManagerPlugin(): Could not connect to modem");
+      }
+      modem->modem_available = FALSE;
+      mms_error("ModemManagerPlugin(): MMSD_MM_STATE_NO_MODEM");
+      break;
+
+    case MMSD_MM_STATE_NO_MESSAGING_MODEM:
+      g_signal_handler_disconnect (modem->gdbus_modem,
+                                   modem->modem_state_watch_id);
+      mmsd_plugin_disconnect();
+      mms_error("ModemManagerPlugin(): Modem has no messaging
capabilities");
+      mms_error("ModemManagerPlugin():
MMSD_MM_STATE_NO_MESSAGING_MODEM");
+      modem->modem_available = FALSE;
+      break;
+
+    case MMSD_MM_STATE_MODEM_DISABLED:
+
+      mms_error("ModemManagerPlugin(): Modem disabled");
+      mms_error("ModemManagerPlugin(): MMSD_MM_STATE_MODEM_DISABLED");
+      mms_service_set_bearer_handler(modem->service, NULL, NULL);
+      modem->modem_available = FALSE;
+      break;
+
+    case MMSD_MM_STATE_MANAGER_FOUND:
+      if (!modem->manager_available) {
+        modem->manager_available = TRUE;
+        
+        modem->owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+                                          "org.ofono.mms.ModemManager"
,
+                                          G_BUS_NAME_OWNER_FLAGS_NONE,
+                                          on_bus_acquired,
+                                          on_name_acquired,
+                                          on_name_lost,
+                                          NULL,
+                                          NULL);
+        
+      }
+
+      mms_error("ModemManagerPlugin(): MMSD_MM_STATE_MANAGER_FOUND");
+      break;
+
+    case MMSD_MM_STATE_NO_MANAGER:
+      if (modem->manager_available) {
+        mmsd_plugin_disconnect();
+        g_clear_object (&modem->mm);
+        g_dbus_connection_unregister_object (modem->master_connection,
+                                             modem->registration_id);
+        g_bus_unown_name (modem->owner_id);
+        mms_error("ModemManagerPlugin(): ModemManager vanished");
+        modem->modem_available = FALSE;
+      } else {
+        mms_error("ModemManagerPlugin(): Could not connect to
ModemManager");
+      }
+
+      modem->manager_available = FALSE;
+      mms_error("ModemManagerPlugin(): MMSD_MM_STATE_NO_MANAGER");
+      break;
+
+    case MMSD_MM_STATE_MODEM_UNLOCK_ERROR:
+      mms_error("ModemManagerPlugin(): SIM card unlock failed");
+      mms_error("ModemManagerPlugin():
MMSD_MM_STATE_MODEM_UNLOCK_ERROR");
+      break;
+
+    case MMSD_MM_STATE_READY:
+      mms_error("ModemManagerPlugin(): MMSD_MM_STATE_READY");
+      modem->modem_available = TRUE;
+      mmsd_plugin_connect();
+      break;
+
+    default:
+      g_return_if_reached ();
+  }
+}
+
+static void
+mm_appeared_cb (GDBusConnection *connection,
+                const gchar *name,
+                const gchar *name_owner,
+                gpointer user_data)
+{
+  g_assert (G_IS_DBUS_CONNECTION (connection));
+
+  mm_manager_new (connection,
+                  G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+                  NULL,
+                  (GAsyncReadyCallback) cb_mm_manager_new,
+                  NULL);
+
+}
+
+static void
+mm_vanished_cb (GDBusConnection *connection,
+                             const gchar *name,
+                             gpointer user_data)
+{
+  g_assert (G_IS_DBUS_CONNECTION (connection));
+
+  mms_error("ModemManagerPlugin(): Modem Manager vanished");
+
+  mmsd_mm_state (MMSD_MM_STATE_NO_MANAGER);
+}
+
+static void
+mm_get_modem_manager (void)
+{
+
+  modem->mm_watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
+                                          MM_DBUS_SERVICE,
+                                          G_BUS_NAME_WATCHER_FLAGS_AUT
O_START,
+                                          (GBusNameAppearedCallback)
mm_appeared_cb,
+                                          (GBusNameVanishedCallback)
mm_vanished_cb,
+                                          NULL, NULL);
+}
+
+static void bearer_handler(mms_bool_t active, void *user_data)
+{
+       struct modem_data *modem = user_data;
+       gint32 response;
+
+       /* Check for any errors within the context */
+    response = set_context();
+    if (response != MMSD_MM_MODEM_CONTEXT_ACTIVE) {  
+      mms_error("ModemManagerPlugin(): Set MMSC: %s, Set Proxy: %s,
Set MMS APN: %s", modem->message_center, modem->MMS_proxy, modem-
>mms_apn);
+      g_dbus_connection_emit_signal (modem->master_connection,
+                                     NULL,
+                                     "/org/ofono/mms",
+                                     "org.ofono.mms.ModemManager",
+                                     "BearerHandlerError",
+                                     g_variant_new ("(h)",
+                                                    response),
+                                     NULL);
+    }
+
+       mms_error("ModemManagerPlugin(): At Bearer Handler: path %s
active %d context_active %d", modem->path, active, modem-
>context_active);
+       if (active == TRUE && modem->context_active == TRUE) {
+               mms_error("ModemManagerPlugin(): active and
context_active, bearer_notify");
+               mms_service_bearer_notify(modem->service, TRUE, modem-
>context_interface, modem->MMS_proxy);
+               return;
+       } else if (active == TRUE && modem->context_active == FALSE) {
+           mms_error("ModemManagerPlugin(): Error activating
context!");
+           mms_service_bearer_notify(modem->service, FALSE, NULL,
NULL);
+           return;
+       }
+           
+       mms_error("ModemManagerPlugin(): checking for failure");
+       if (active == FALSE && modem->context_active == FALSE) {
+           mms_error("ModemManagerPlugin(): Context not active!");
+               mms_service_bearer_notify(modem->service, FALSE, NULL,
NULL);
+               return;
+       } else {
+           mms_error("ModemManagerPlugin(): No failures");
+           mms_service_bearer_notify(modem->service, FALSE, modem-
>context_interface, modem->MMS_proxy);
+           return;
+       }
+
+}
+ 
+static int set_context (void) {
+    guint max_bearers, active_bearers;
+    GList *bearer_list, *l;
+    MMBearer *modem_bearer;
+    MMBearerProperties *modem_bearer_properties;
+    const gchar *apn;
+    gboolean interface_disconnected;
+    gboolean bearer_connected;
+    
+    mms_error("ModemManagerPlugin(): Setting Context...");
+    if (modem->context_active) {
+        g_free(modem->context_interface);
+        g_free(modem->context_path);
+    }
+    modem->context_active = FALSE;
+    interface_disconnected = FALSE;
+    mms_service_set_mmsc(modem->service, modem->message_center);
+    max_bearers = mm_modem_get_max_active_bearers (modem->modem);
+    mms_error("ModemManagerPlugin(): Max number of bearers: %d",
max_bearers);
+    bearer_list = mm_modem_list_bearers_sync (modem->modem, NULL,
NULL);
+    active_bearers = 0;
+    if (bearer_list != NULL) {
+        for (l = bearer_list; l != NULL; l = l->next)
+        {
+            active_bearers = active_bearers + 1;
+            modem_bearer = (MMBearer *) l->data;
+            modem_bearer_properties = mm_bearer_get_properties
(modem_bearer);
+            apn = mm_bearer_properties_get_apn
(modem_bearer_properties);
+            mms_error("ModemManagerPlugin(): Current Context APN: %s,
mmsd settings MMS APN: %s", apn, modem->mms_apn);
+            bearer_connected = mm_bearer_get_connected (modem_bearer);
+            if (g_strcmp0 (apn, modem->mms_apn) == 0 ) {
+                if (modem->state != MM_MODEM_STATE_CONNECTED) {
+                    mms_error("ModemManagerPlugin(): The modem
interface is reporting it is disconnected!");
+                    mms_error("ModemManagerPlugin(): Reported State:
%d", modem->state);
+                    interface_disconnected = TRUE;
+                } else if (!bearer_connected) {
+                    mms_error("ModemManagerPlugin(): The proper
context is not connected!");
+                    interface_disconnected = TRUE;
+                } else {
+                    mms_error("ModemManagerPlugin(): You are connected
to the correct APN! Enabling context...");
+                    modem->context_interface = mm_bearer_dup_interface
(modem_bearer);
+                    modem->context_path = mm_bearer_dup_path
(modem_bearer);
+                    modem->context_active = TRUE;
+                }
+            }
+        }
+        g_list_free (bearer_list);
+        g_list_free (l);
+        if (!modem->context_active) { // I did not find the right
context I wanted.
+            if(active_bearers == max_bearers) {
+                if(interface_disconnected) {
+                    return MMSD_MM_MODEM_INTERFACE_DISCONNECTED;
+                } else {
+                    mms_error("ModemManagerPlugin(): The modem is not
connected to the correct APN!");
+                    return MMSD_MM_MODEM_INCORRECT_APN_CONNECTED;
+                }
+            } else if (active_bearers == 0) {
+                mms_error("ModemManagerPlugin(): The modem bearer is
disconnected! Please enable modem data");     
+                return MMSD_MM_MODEM_NO_BEARERS_ACTIVE;
+            } 
+             else if (active_bearers < max_bearers) {
+                /*
+                 * TODO: Modem manager does not support this yet, but
this is
+                 *       where to add code when Modem manager supports
multiple
+                 *       contexts and/or a seperate MMS context.
+                 *       The Pinephone and Librem 5 only support 
+                 *       one active bearer as well
+                 */ 
+                mms_error("ModemManagerPlugin(): This is a stub for
adding a new context/bearer, but Modem Manager does not support this
yet.");         
+                return MMSD_MM_MODEM_FUTURE_CASE_DISCONNECTED;
+            }
+        }
+    } else {
+        mms_error("ModemManagerPlugin(): There are no modem bearers!
Please enable modem data");
+        return MMSD_MM_MODEM_NO_BEARERS_ACTIVE;
+    }
+    
+    if (g_strcmp0(modem->message_center, "http://mmsc.invalid") == 0)
{
+        mms_error("ModemManagerPlugin(): The MMSC is not configured!
Please configure the MMSC and restart mmsd.");
+        return MMSD_MM_MODEM_MMSC_MISCONFIGURED;
+    } 
+       
+    return MMSD_MM_MODEM_CONTEXT_ACTIVE;
+
+}
+
+static void mmsd_plugin_connect (void) {
+
+    if (modem->plugin_registered == FALSE) {
+        mms_error("ModemManagerPlugin(): Registering Modem Manager MMS
Service");
+        mms_service_register(modem->service);
+        modem-> plugin_registered = TRUE;
+    }
+    mms_error("ModemManagerPlugin(): Setting Bearer Handler");
+    mms_service_set_bearer_handler(modem->service, bearer_handler,
modem);
+        
+} 
+
+
+static void mmsd_plugin_disconnect (void) {
+    
+    mms_error("ModemManagerPlugin(): Disabling Bearer Handler");
+    mms_service_set_bearer_handler(modem->service, NULL, NULL);
+    g_object_unref(modem->sim);
+    g_free(modem->imsi);
+    g_free(modem->path);
+    g_clear_object (&modem->modem);
+    g_clear_object (&modem->modem_messaging);
+    modem->object = NULL;
+    if (modem->device_arr && modem->device_arr->len) {
+      g_ptr_array_set_size (modem->device_arr, 0);
+      g_ptr_array_unref(modem->device_arr);
+    }
+    modem->modem_available = FALSE;
+}
+ 
+static int modemmanager_init(void)
+{
+    g_autoptr(GError)  error = NULL;
+    /* Set up modem Structure to be used here */
+    modem = g_try_new0(struct modem_data, 1);
+
+    if (modem == NULL) {
+      mms_error("ModemManagerPlugin(): Could not allocate space for
modem data!");
+      return -ENOMEM;
+    }
+    modem->service = mms_service_create();
+    mms_service_set_identity(modem->service, IDENTIFIER);
+    
+    // Opening/making config file at
$HOME/.mms/modemmanager/ModemManagerSettings
+    modem->modemsettings = mms_settings_open(IDENTIFIER,
SETTINGS_STORE);
+
+    modem->message_center = g_key_file_get_string(modem-
>modemsettings, 
+                                                  SETTINGS_GROUP,
+                                                  "CarrierMMSC",
&error);
+    if (error) {
+        mms_error("ModemManagerPlugin(): No MMSC was configured!");
+        modem->message_center = g_strdup("http://mms.invalid");
+        g_key_file_set_string(modem->modemsettings, SETTINGS_GROUP,
+                              "CarrierMMSC", modem->message_center);
+        error = NULL;
+    }
+
+    modem->mms_apn = g_key_file_get_string(modem->modemsettings, 
+                                           SETTINGS_GROUP,
+                                           "MMS_APN", &error);
+    if (error) {
+        mms_error("ModemManagerPlugin(): No MMS APN was configured!");
+        modem->mms_apn = g_strdup("apn.invalid");
+        g_key_file_set_string(modem->modemsettings, SETTINGS_GROUP,
+                              "MMS_APN", modem->mms_apn);
+        error = NULL;
+    }
+
+    modem->MMS_proxy = g_key_file_get_string(modem->modemsettings, 
+                                             SETTINGS_GROUP,
+                                             "CarrierMMSProxy",
&error);
+    if (error) {
+        mms_error("ModemManagerPlugin(): No Context Proxy was
configured! Setting to NULL.");
+        modem->MMS_proxy = g_strdup("NULL");
+        g_key_file_set_string(modem->modemsettings, SETTINGS_GROUP,
+                              "CarrierMMSProxy", modem->MMS_proxy);
+        error = NULL;
+    }   
+    if (g_strcmp0 (modem->MMS_proxy, "NULL") == 0) {
+        g_free(modem->MMS_proxy);
+        modem->MMS_proxy = NULL;
+    }
+    
+    modem->auto_process_on_connection = g_key_file_get_boolean(modem-
>modemsettings, 
+                                                               SETTING
S_GROUP,
+                                                               "AutoPr
ocessOnConnection", 
+                                                               &error)
;
+    if (error) {
+        mms_error("ModemManagerPlugin(): Auto Process On Connection
was not configured! Setting to TRUE.");
+        modem->auto_process_on_connection = TRUE;
+        g_key_file_set_boolean(modem->modemsettings, SETTINGS_GROUP,
+                              "AutoProcessOnConnection", modem-
>auto_process_on_connection);
+        error = NULL;
+    }   
+
+    mms_settings_close(IDENTIFIER, SETTINGS_STORE,
+                       modem->modemsettings, TRUE);  
+    introspection_data = g_dbus_node_info_new_for_xml
(introspection_xml, NULL);
+    g_assert (introspection_data != NULL);
+    
+    modem->modem_available = FALSE;
+    modem->manager_available = FALSE;
+    modem->context_active = FALSE;
+    modem->plugin_registered = FALSE;
+    mm_get_modem_manager ();      
+                            
+    return 0;
+}
+
+static void modemmanager_exit(void)
+{
+    if (modem->plugin_registered == TRUE) {
+      mms_service_unregister(modem->service);
+    }
+    if (modem->manager_available) {
+        mmsd_plugin_disconnect();
+        g_clear_object (&modem->mm);
+        g_dbus_connection_unregister_object (modem->master_connection,
+                                             modem->registration_id);
+        g_bus_unown_name (modem->owner_id);
+    }
+    g_free(modem->message_center);
+    g_free(modem->MMS_proxy);
+    g_free(modem->mms_apn);
+    g_free(modem);
+    g_dbus_node_info_unref (introspection_data);
+    
+}
+
+MMS_PLUGIN_DEFINE(modemmanager, modemmanager_init, modemmanager_exit)
\ No newline at end of file
diff --git a/src/service.c b/src/service.c
index b0c2428..7df77da 100644
--- a/src/service.c
+++ b/src/service.c
@@ -647,7 +647,7 @@ static void process_request_queue(struct
mms_service *service);
 static void emit_message_added(const struct mms_service *service,
                                                struct mms_message
*msg);
 
-static void activate_bearer(struct mms_service *service)
+void activate_bearer(struct mms_service *service)
 {
        DBG("service %p setup %d active %d", service, service-
>bearer_setup, service->bearer_active);
 
diff --git a/src/service.h b/src/service.h
index 56c0585..586ceca 100644
--- a/src/service.h
+++ b/src/service.h
@@ -52,3 +52,5 @@ int mms_message_register(struct mms_service *service,
                                                struct mms_message
*msg);
 int mms_message_unregister(const struct mms_service *service,
                                                const char *msg_path);
+
