diff --git a/include/NetworkManager.h b/include/NetworkManager.h
index d61a89c..1a09e6c 100644
--- a/include/NetworkManager.h
+++ b/include/NetworkManager.h
@@ -35,6 +35,7 @@
 #define NM_DBUS_PATH_ACCESS_POINT           NM_DBUS_PATH "/AccessPoint"
 #define NM_DBUS_INTERFACE_ACCESS_POINT      NM_DBUS_INTERFACE ".AccessPoint"
 #define NM_DBUS_INTERFACE_SERIAL_DEVICE     NM_DBUS_INTERFACE_DEVICE ".Serial"
+#define NM_DBUS_INTERFACE_MODEM_DEVICE      NM_DBUS_INTERFACE_DEVICE ".Modem"
 #define NM_DBUS_INTERFACE_GSM_DEVICE        NM_DBUS_INTERFACE_DEVICE ".Gsm"
 #define NM_DBUS_INTERFACE_CDMA_DEVICE       NM_DBUS_INTERFACE_DEVICE ".Cdma"
 #define NM_DBUS_INTERFACE_ACTIVE_CONNECTION NM_DBUS_INTERFACE ".Connection.Active"
@@ -75,7 +76,10 @@ typedef enum NMDeviceType
 	NM_DEVICE_TYPE_ETHERNET,
 	NM_DEVICE_TYPE_WIFI,
 	NM_DEVICE_TYPE_GSM,
-	NM_DEVICE_TYPE_CDMA
+	NM_DEVICE_TYPE_CDMA,
+	NM_DEVICE_TYPE_BT,
+	NM_DEVICE_TYPE_OLPC_MESH,
+        NM_DEVICE_TYPE_MODEM
 } NMDeviceType;
 
 /* DEPRECATED TYPE NAMES */
@@ -84,6 +88,9 @@ typedef enum NMDeviceType
 #define DEVICE_TYPE_802_11_WIRELESS  NM_DEVICE_TYPE_WIFI
 #define DEVICE_TYPE_GSM              NM_DEVICE_TYPE_GSM
 #define DEVICE_TYPE_CDMA             NM_DEVICE_TYPE_CDMA
+#define DEVICE_TYPE_BT               NM_DEVICE_TYPE_BT
+#define DEVICE_TYPE_OLPC_MESH        NM_DEVICE_TYPE_OLPC_MESH
+#define DEVICE_TYPE_MODEM            NM_DEVICE_TYPE_MODEM
 
 
 /*
diff --git a/introspection/Makefile.am b/introspection/Makefile.am
index a77dba1..ebfd885 100644
--- a/introspection/Makefile.am
+++ b/introspection/Makefile.am
@@ -8,6 +8,7 @@ EXTRA_DIST = \
 	nm-device-ethernet.xml \
 	nm-device-cdma.xml \
 	nm-device-gsm.xml \
+	nm-device-analog-modem.xml \
 	nm-device-serial.xml \
 	nm-device.xml \
 	nm-ip4-config.xml \
diff --git a/introspection/nm-device-analog-modem.xml b/introspection/nm-device-analog-modem.xml
new file mode 100644
index 0000000..cb55816
--- /dev/null
+++ b/introspection/nm-device-analog-modem.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+  <interface name="org.freedesktop.NetworkManager.Device.Modem">
+
+    <signal name="PropertiesChanged">
+        <arg name="properties" type="a{sv}" tp:type="String_Variant_Map">
+            <tp:docstring>
+                A dictionary mapping property names to variant boxed values
+            </tp:docstring>
+        </arg>
+    </signal>
+
+  </interface>
+</node>
diff --git a/libnm-glib/Makefile.am b/libnm-glib/Makefile.am
index dabf941..cd72ffb 100644
--- a/libnm-glib/Makefile.am
+++ b/libnm-glib/Makefile.am
@@ -9,6 +9,7 @@ BUILT_SOURCES = \
 	nm-device-bindings.h \
 	nm-device-ethernet-bindings.h \
 	nm-device-wifi-bindings.h \
+	nm-device-analog-modem-bindings.h \
 	nm-exported-connection-glue.h \
 	nm-exported-connection-bindings.h \
 	nm-settings-glue.h \
@@ -37,6 +38,7 @@ libnminclude_HEADERS = \
 	nm-device.h		\
 	nm-device-ethernet.h \
 	nm-device-wifi.h \
+	nm-device-analog-modem.h \
 	nm-access-point.h \
 	nm-ip4-config.h \
 	nm-settings.h \
@@ -64,6 +66,7 @@ libnm_glib_la_SOURCES = \
 	nm-device-private.h	\
 	nm-device-ethernet.c \
 	nm-device-wifi.c \
+	nm-device-analog-modem.c \
 	nm-access-point.c	\
 	nm-ip4-config.c		\
 	nm-settings.c		\
@@ -118,6 +121,9 @@ nm-device-ethernet-bindings.h: $(top_srcdir)/introspection/nm-device-ethernet.xm
 nm-device-wifi-bindings.h: $(top_srcdir)/introspection/nm-device-wifi.xml
 	dbus-binding-tool --prefix=nm_device_wifi --mode=glib-client --output=$@ $<
 
+nm-device-analog-modem-bindings.h: $(top_srcdir)/introspection/nm-device-analog-modem.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_analog_modem --mode=glib-client --output=$@ $<
+
 nm-access-point-bindings.h: $(top_srcdir)/introspection/nm-access-point.xml
 	dbus-binding-tool --prefix=nm_access_point --mode=glib-client --output=$@ $<
 
diff --git a/libnm-glib/libnm_glib.ver b/libnm-glib/libnm_glib.ver
index 6336c86..3ba54d6 100644
--- a/libnm-glib/libnm_glib.ver
+++ b/libnm-glib/libnm_glib.ver
@@ -50,6 +50,10 @@ global:
 	nm_dbus_settings_system_get_type;
 	nm_dbus_settings_system_get_unmanaged_devices;
 	nm_dbus_settings_system_new;
+	nm_device_analog_modem_get_type;
+	nm_device_analog_modem_new;
+	nm_device_analog_modem_number;
+	nm_device_analog_modem_username;
 	nm_device_ethernet_get_carrier;
 	nm_device_ethernet_get_hw_address;
 	nm_device_ethernet_get_speed;
diff --git a/libnm-glib/nm-device-analog-modem.c b/libnm-glib/nm-device-analog-modem.c
new file mode 100644
index 0000000..33d746d
--- /dev/null
+++ b/libnm-glib/nm-device-analog-modem.c
@@ -0,0 +1,270 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * libnm_glib -- Access network status & information from glib applications
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2007 - 2008 Novell, Inc.
+ * Copyright (C) 2007 - 2010 Red Hat, Inc.
+ */
+
+#include <string.h>
+
+#include "nm-device-analog-modem.h"
+#include "nm-device-private.h"
+#include "nm-object-private.h"
+#include "nm-object-cache.h"
+#include "nm-dbus-glib-types.h"
+#include "nm-types-private.h"
+
+#include "nm-device-analog-modem-bindings.h"
+
+G_DEFINE_TYPE (NMDeviceAnalogModem, nm_device_analog_modem, NM_TYPE_DEVICE)
+
+#define NM_DEVICE_ANALOG_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_ANALOG_MODEM, NMDeviceAnalogModemPrivate))
+
+typedef struct {
+	gboolean disposed;
+	DBusGProxy *proxy;
+
+	char *number;
+	char *username;
+} NMDeviceAnalogModemPrivate;
+
+enum {
+	PROP_0,
+	PROP_NUMBER,
+	PROP_USERNAME,
+
+	LAST_PROP
+};
+
+#define DBUS_PROP_NUMBER "Number"
+#define DBUS_PROP_USERNAME "UserName"
+
+/**
+ * nm_device_analog_modem_new:
+ * @connection: the #DBusGConnection
+ * @path: the DBus object path of the device
+ *
+ * Creates a new #NMDeviceAnalogModem.
+ *
+ * Returns: a new device
+ **/
+GObject *
+nm_device_analog_modem_new (DBusGConnection *connection, const char *path)
+{
+	g_return_val_if_fail (connection != NULL, NULL);
+	g_return_val_if_fail (path != NULL, NULL);
+
+	return g_object_new (NM_TYPE_DEVICE_ANALOG_MODEM,
+	                     NM_OBJECT_DBUS_CONNECTION, connection,
+	                     NM_OBJECT_DBUS_PATH, path,
+	                     NULL);
+}
+
+/**
+ * nm_device_analog_modem_get_hw_address:
+ * @device: a #NMDeviceAnalogModem
+ *
+ * Gets the actual hardware (MAC) address of the #NMDeviceAnalogModem
+ *
+ * Returns: the actual hardware address. This is the internal string used by the
+ * device, and must not be modified.
+ **/
+const char *
+nm_device_analog_modem_get_number (NMDeviceAnalogModem *device)
+{
+	NMDeviceAnalogModemPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DEVICE_ANALOG_MODEM (device), NULL);
+
+	priv = NM_DEVICE_ANALOG_MODEM_GET_PRIVATE (device);
+	if (!priv->number) {
+		priv->number = _nm_object_get_string_property (NM_OBJECT (device),
+													   NM_DBUS_INTERFACE_MODEM_DEVICE,
+													   DBUS_PROP_NUMBER);
+	}
+
+	return priv->number;
+}
+
+/**
+ * nm_device_analog_modem_get_permanent_hw_address:
+ * @device: a #NMDeviceAnalogModem
+ *
+ * Gets the permanent hardware (MAC) address of the #NMDeviceAnalogModem
+ *
+ * Returns: the permanent hardware address. This is the internal string used by the
+ * device, and must not be modified.
+ **/
+const char *
+nm_device_analog_modem_get_username (NMDeviceAnalogModem *device)
+{
+	NMDeviceAnalogModemPrivate *priv;
+
+	g_return_val_if_fail (NM_IS_DEVICE_ANALOG_MODEM (device), NULL);
+
+	priv = NM_DEVICE_ANALOG_MODEM_GET_PRIVATE (device);
+	if (!priv->username) {
+		priv->username = _nm_object_get_string_property (NM_OBJECT (device),
+														 NM_DBUS_INTERFACE_MODEM_DEVICE,
+														 DBUS_PROP_USERNAME);
+	}
+
+	return priv->username;
+}
+
+/**************************************************************/
+
+static void
+nm_device_analog_modem_init (NMDeviceAnalogModem *device)
+{
+	NMDeviceAnalogModemPrivate *priv = NM_DEVICE_ANALOG_MODEM_GET_PRIVATE (device);
+
+	priv->disposed = FALSE;
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+	NMDeviceAnalogModem *self = NM_DEVICE_ANALOG_MODEM (object);
+
+	switch (prop_id) {
+	case PROP_NUMBER:
+		g_value_set_string (value, nm_device_analog_modem_get_number (self));
+		break;
+	case PROP_USERNAME:
+		g_value_set_string (value, nm_device_analog_modem_get_username (self));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+register_for_property_changed (NMDeviceAnalogModem *device)
+{
+	NMDeviceAnalogModemPrivate *priv = NM_DEVICE_ANALOG_MODEM_GET_PRIVATE (device);
+	const NMPropertiesChangedInfo property_changed_info[] = {
+		{ NM_DEVICE_ANALOG_MODEM_NUMBER,               _nm_object_demarshal_generic, &priv->number },
+		{ NM_DEVICE_ANALOG_MODEM_USERNAME,             _nm_object_demarshal_generic, &priv->username },
+		{ NULL },
+	};
+
+	_nm_object_handle_properties_changed (NM_OBJECT (device),
+	                                     priv->proxy,
+	                                     property_changed_info);
+}
+
+static GObject*
+constructor (GType type,
+		   guint n_construct_params,
+		   GObjectConstructParam *construct_params)
+{
+	GObject *object;
+	NMDeviceAnalogModemPrivate *priv;
+
+	object = G_OBJECT_CLASS (nm_device_analog_modem_parent_class)->constructor (type,
+																    n_construct_params,
+																    construct_params);
+	if (!object)
+		return NULL;
+
+	priv = NM_DEVICE_ANALOG_MODEM_GET_PRIVATE (object);
+
+	priv->proxy = dbus_g_proxy_new_for_name (nm_object_get_connection (NM_OBJECT (object)),
+											 NM_DBUS_SERVICE,
+											 nm_object_get_path (NM_OBJECT (object)),
+											 NM_DBUS_INTERFACE_MODEM_DEVICE);
+
+	register_for_property_changed (NM_DEVICE_ANALOG_MODEM (object));
+
+	return object;
+}
+
+static void
+dispose (GObject *object)
+{
+	NMDeviceAnalogModemPrivate *priv = NM_DEVICE_ANALOG_MODEM_GET_PRIVATE (object);
+
+	if (priv->disposed) {
+		G_OBJECT_CLASS (nm_device_analog_modem_parent_class)->dispose (object);
+		return;
+	}
+
+	priv->disposed = TRUE;
+	g_object_unref (priv->proxy);
+
+	G_OBJECT_CLASS (nm_device_analog_modem_parent_class)->dispose (object);
+}
+
+static void
+finalize (GObject *object)
+{
+	NMDeviceAnalogModemPrivate *priv = NM_DEVICE_ANALOG_MODEM_GET_PRIVATE (object);
+
+	g_free (priv->number);
+	g_free (priv->username);
+
+	G_OBJECT_CLASS (nm_device_analog_modem_parent_class)->finalize (object);
+}
+
+static void
+nm_device_analog_modem_class_init (NMDeviceAnalogModemClass *device_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (device_class);
+
+	g_type_class_add_private (device_class, sizeof (NMDeviceAnalogModemPrivate));
+
+	/* virtual methods */
+	object_class->constructor = constructor;
+	object_class->get_property = get_property;
+	object_class->dispose = dispose;
+	object_class->finalize = finalize;
+
+	/* properties */
+
+	/**
+	 * NMDeviceAnalogModem:number:
+	 *
+	 * The number dialed.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_NUMBER,
+		 g_param_spec_string (NM_DEVICE_ANALOG_MODEM_NUMBER,
+						  "Number",
+						  "Number dialed",
+						  NULL,
+						  G_PARAM_READABLE));
+
+	/**
+	 * NMDeviceAnalogModem:username:
+	 *
+	 * The user name to log in with.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_USERNAME,
+		 g_param_spec_string (NM_DEVICE_ANALOG_MODEM_USERNAME,
+						  "Username",
+						  "Username to log in with",
+						  NULL,
+						  G_PARAM_READABLE));
+}
diff --git a/libnm-glib/nm-device-analog-modem.h b/libnm-glib/nm-device-analog-modem.h
new file mode 100644
index 0000000..ee38148
--- /dev/null
+++ b/libnm-glib/nm-device-analog-modem.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/*
+ * libnm_glib -- Access network status & information from glib applications
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2007 - 2008 Novell, Inc.
+ * Copyright (C) 2007 - 2010 Red Hat, Inc.
+ */
+
+#ifndef NM_DEVICE_ANALOG_MODEM_H
+#define NM_DEVICE_ANALOG_MODEM_H
+
+#include "nm-device.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_ANALOG_MODEM            (nm_device_analog_modem_get_type ())
+#define NM_DEVICE_ANALOG_MODEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ANALOG_MODEM, NMDeviceAnalogModem))
+#define NM_DEVICE_ANALOG_MODEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_ANALOG_MODEM, NMDeviceAnalogModemClass))
+#define NM_IS_DEVICE_ANALOG_MODEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ANALOG_MODEM))
+#define NM_IS_DEVICE_ANALOG_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_DEVICE_ANALOG_MODEM))
+#define NM_DEVICE_ANALOG_MODEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_ANALOG_MODEM, NMDeviceAnalogModemClass))
+
+#define NM_DEVICE_ANALOG_MODEM_NUMBER          "number"
+#define NM_DEVICE_ANALOG_MODEM_USERNAME        "username"
+
+typedef struct {
+	NMDevice parent;
+} NMDeviceAnalogModem;
+
+typedef struct {
+	NMDeviceClass parent;
+
+	/* Signals */
+
+	/* Padding for future expansion */
+	void (*_reserved1) (void);
+	void (*_reserved2) (void);
+	void (*_reserved3) (void);
+	void (*_reserved4) (void);
+	void (*_reserved5) (void);
+	void (*_reserved6) (void);
+} NMDeviceAnalogModemClass;
+
+GType nm_device_analog_modem_get_type (void);
+
+GObject *nm_device_analog_modem_new (DBusGConnection *connection, const char *path);
+
+const char *    nm_device_analog_modem_get_number           (NMDeviceAnalogModem *device);
+const char *    nm_device_analog_modem_get_username         (NMDeviceAnalogModem *device);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_ANALOG_MODEM_H */
diff --git a/libnm-glib/nm-device.c b/libnm-glib/nm-device.c
index 84cabce..1b9fe20 100644
--- a/libnm-glib/nm-device.c
+++ b/libnm-glib/nm-device.c
@@ -25,6 +25,7 @@
 
 #include "NetworkManager.h"
 #include "nm-device-ethernet.h"
+#include "nm-device-analog-modem.h"
 #include "nm-device-wifi.h"
 #include "nm-gsm-device.h"
 #include "nm-cdma-device.h"
@@ -549,6 +550,9 @@ nm_device_new (DBusGConnection *connection, const char *path)
 	case NM_DEVICE_TYPE_CDMA:
 		dtype = NM_TYPE_CDMA_DEVICE;
 		break;
+	case NM_DEVICE_TYPE_MODEM:
+		dtype = NM_TYPE_DEVICE_ANALOG_MODEM;
+		break;
 	default:
 		g_warning ("Unknown device type %d", g_value_get_uint (&value));
 		break;
diff --git a/libnm-util/Makefile.am b/libnm-util/Makefile.am
index 225d4b5..1e66389 100644
--- a/libnm-util/Makefile.am
+++ b/libnm-util/Makefile.am
@@ -14,6 +14,7 @@ libnm_util_include_HEADERS = 		\
 	nm-connection.h			\
 	nm-setting.h			\
 	nm-setting-8021x.h		\
+	nm-setting-analog-modem.h	\
 	nm-setting-connection.h		\
 	nm-setting-ip4-config.h		\
 	nm-setting-ppp.h		\
@@ -35,6 +36,7 @@ libnm_util_la_SOURCES=			\
 	nm-param-spec-specialized.h \
 	nm-setting.c			\
 	nm-setting-8021x.c		\
+	nm-setting-analog-modem.c	\
 	nm-setting-connection.c		\
 	nm-setting-ip4-config.c		\
 	nm-setting-ip6-config.c		\
diff --git a/libnm-util/libnm-util.ver b/libnm-util/libnm-util.ver
index b8cf0b6..d57fb4a 100644
--- a/libnm-util/libnm-util.ver
+++ b/libnm-util/libnm-util.ver
@@ -75,6 +75,16 @@ global:
 	nm_setting_cdma_get_number;
 	nm_setting_cdma_get_username;
 	nm_setting_cdma_get_password;
+	nm_setting_analog_modem_error_get_type;
+	nm_setting_analog_modem_error_quark;
+	nm_setting_analog_modem_get_type;
+	nm_setting_analog_modem_new;
+	nm_setting_analog_modem_get_prefix;
+	nm_setting_analog_modem_get_number;
+	nm_setting_analog_modem_get_username;
+	nm_setting_analog_modem_get_password;
+	nm_setting_analog_modem_get_enable_speaker;
+	nm_setting_analog_modem_get_detect_dialtone;
 	nm_setting_clear_secrets;
 	nm_setting_compare;
 	nm_setting_connection_error_get_type;
diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c
index ba1685a..0e10c29 100644
--- a/libnm-util/nm-connection.c
+++ b/libnm-util/nm-connection.c
@@ -44,6 +44,7 @@
 #include "nm-setting-serial.h"
 #include "nm-setting-gsm.h"
 #include "nm-setting-cdma.h"
+#include "nm-setting-analog-modem.h"
 
 /**
  * SECTION:nm-connection
@@ -139,7 +140,7 @@ static guint signals[LAST_SIGNAL] = { 0 };
 
 static GHashTable *registered_settings = NULL;
 
-#define DEFAULT_MAP_SIZE 13
+#define DEFAULT_MAP_SIZE 14
 
 static struct SettingInfo {
 	const char *name;
@@ -225,6 +226,11 @@ register_default_settings (void)
 	                      NM_SETTING_CDMA_ERROR,
 	                      1);
 
+	register_one_setting (NM_SETTING_ANALOG_MODEM_SETTING_NAME,
+	                      NM_TYPE_SETTING_ANALOG_MODEM,
+	                      NM_SETTING_ANALOG_MODEM_ERROR,
+	                      1);
+
 	register_one_setting (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME,
 	                      NM_TYPE_SETTING_WIRELESS_SECURITY,
 	                      NM_SETTING_WIRELESS_SECURITY_ERROR,
diff --git a/libnm-util/nm-setting-analog-modem.c b/libnm-util/nm-setting-analog-modem.c
new file mode 100644
index 0000000..b71e02e
--- /dev/null
+++ b/libnm-util/nm-setting-analog-modem.c
@@ -0,0 +1,408 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * Dan Williams <dcbw@redhat.com>
+ * Tambet Ingo <tambet@gmail.com>
+ * Hans Petter Jansson <hpj@novell.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2007 - 2010 Red Hat, Inc.
+ * (C) Copyright 2007 - 2008 Novell, Inc.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include "nm-setting-analog-modem.h"
+#include "nm-setting-serial.h"
+#include "nm-utils.h"
+
+GQuark
+nm_setting_analog_modem_error_quark (void)
+{
+	static GQuark quark;
+
+	if (G_UNLIKELY (!quark))
+		quark = g_quark_from_static_string ("nm-setting-analog-modem-error-quark");
+	return quark;
+}
+
+/* This should really be standard. */
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+nm_setting_analog_modem_error_get_type (void)
+{
+	static GType etype = 0;
+
+	if (etype == 0) {
+		static const GEnumValue values[] = {
+			/* Unknown error. */
+			ENUM_ENTRY (NM_SETTING_ANALOG_MODEM_ERROR_UNKNOWN, "UnknownError"),
+			/* The specified property was invalid. */
+			ENUM_ENTRY (NM_SETTING_ANALOG_MODEM_ERROR_INVALID_PROPERTY, "InvalidProperty"),
+			/* The specified property was missing and is required. */
+			ENUM_ENTRY (NM_SETTING_ANALOG_MODEM_ERROR_MISSING_PROPERTY, "MissingProperty"),
+			/* The required serial setting is missing */
+			ENUM_ENTRY (NM_SETTING_ANALOG_MODEM_ERROR_MISSING_SERIAL_SETTING, "MissingSerialSetting"),
+			{ 0, 0, 0 }
+		};
+		etype = g_enum_register_static ("NMSettingAnalogModemError", values);
+	}
+	return etype;
+}
+
+
+G_DEFINE_TYPE (NMSettingAnalogModem, nm_setting_analog_modem, NM_TYPE_SETTING)
+
+#define NM_SETTING_ANALOG_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_ANALOG_MODEM, NMSettingAnalogModemPrivate))
+
+typedef struct {
+	char *prefix; /* For dialing */
+	char *number; /* For dialing */
+	char *username;
+	char *password;
+	gboolean enable_speaker;
+	gboolean detect_dialtone;
+} NMSettingAnalogModemPrivate;
+
+enum {
+	PROP_0,
+	PROP_PREFIX,
+	PROP_NUMBER,
+	PROP_USERNAME,
+	PROP_PASSWORD,
+	PROP_ENABLE_SPEAKER,
+	PROP_DETECT_DIALTONE,
+
+	LAST_PROP
+};
+
+NMSetting *
+nm_setting_analog_modem_new (void)
+{
+	return (NMSetting *) g_object_new (NM_TYPE_SETTING_ANALOG_MODEM, NULL);
+}
+
+static gint
+find_setting_by_name (gconstpointer a, gconstpointer b)
+{
+	NMSetting *setting = NM_SETTING (a);
+	const char *str = (const char *) b;
+
+	return strcmp (nm_setting_get_name (setting), str);
+}
+
+const char *
+nm_setting_analog_modem_get_prefix (NMSettingAnalogModem *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_ANALOG_MODEM (setting), NULL);
+
+	return NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting)->prefix;
+}
+
+const char *
+nm_setting_analog_modem_get_number (NMSettingAnalogModem *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_ANALOG_MODEM (setting), NULL);
+
+	return NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting)->number;
+}
+
+const char *
+nm_setting_analog_modem_get_username (NMSettingAnalogModem *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_ANALOG_MODEM (setting), NULL);
+
+	return NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting)->username;
+}
+
+const char *
+nm_setting_analog_modem_get_password (NMSettingAnalogModem *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_ANALOG_MODEM (setting), NULL);
+
+	return NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting)->password;
+}
+
+gboolean
+nm_setting_analog_modem_get_enable_speaker (NMSettingAnalogModem *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_ANALOG_MODEM (setting), NULL);
+
+	return NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting)->enable_speaker;
+}
+
+gboolean
+nm_setting_analog_modem_get_detect_dialtone (NMSettingAnalogModem *setting)
+{
+	g_return_val_if_fail (NM_IS_SETTING_ANALOG_MODEM (setting), NULL);
+
+	return NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting)->detect_dialtone;
+}
+
+static gboolean
+verify (NMSetting *setting, GSList *all_settings, GError **error)
+{
+	NMSettingAnalogModemPrivate *priv = NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting);
+
+	/* Serial connections require a PPP setting */
+	if (all_settings && 
+	    !g_slist_find_custom (all_settings, NM_SETTING_SERIAL_SETTING_NAME, find_setting_by_name)) {
+		g_set_error (error,
+		             NM_SETTING_ANALOG_MODEM_ERROR,
+		             NM_SETTING_ANALOG_MODEM_ERROR_MISSING_SERIAL_SETTING,
+		             NULL);
+		return FALSE;
+	}
+
+	if (!priv->number) {
+		g_set_error (error,
+		             NM_SETTING_ANALOG_MODEM_ERROR,
+		             NM_SETTING_ANALOG_MODEM_ERROR_MISSING_PROPERTY,
+		             NM_SETTING_ANALOG_MODEM_NUMBER);
+		return FALSE;
+	} else if (!strlen (priv->number)) {
+		g_set_error (error,
+		             NM_SETTING_ANALOG_MODEM_ERROR,
+		             NM_SETTING_ANALOG_MODEM_ERROR_INVALID_PROPERTY,
+		             NM_SETTING_ANALOG_MODEM_NUMBER);
+		return FALSE;
+	}
+
+	if (priv->username && !strlen (priv->username)) {
+		g_set_error (error,
+		             NM_SETTING_ANALOG_MODEM_ERROR,
+		             NM_SETTING_ANALOG_MODEM_ERROR_INVALID_PROPERTY,
+		             NM_SETTING_ANALOG_MODEM_USERNAME);
+		return FALSE;
+	}
+
+	if (priv->password && !strlen (priv->password)) {
+		g_set_error (error,
+		             NM_SETTING_ANALOG_MODEM_ERROR,
+		             NM_SETTING_ANALOG_MODEM_ERROR_INVALID_PROPERTY,
+		             NM_SETTING_ANALOG_MODEM_USERNAME);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static GPtrArray *
+need_secrets (NMSetting *setting)
+{
+	NMSettingAnalogModemPrivate *priv = NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting);
+	GPtrArray *secrets = NULL;
+
+	if (priv->password)
+		return NULL;
+
+	if (priv->username) {
+		secrets = g_ptr_array_sized_new (1);
+		g_ptr_array_add (secrets, NM_SETTING_ANALOG_MODEM_PASSWORD);
+	}
+
+	return secrets;
+}
+
+static void
+nm_setting_analog_modem_init (NMSettingAnalogModem *setting)
+{
+	NMSettingAnalogModemPrivate *priv = NM_SETTING_ANALOG_MODEM_GET_PRIVATE (setting);
+
+	g_object_set (setting, NM_SETTING_NAME, NM_SETTING_ANALOG_MODEM_SETTING_NAME, NULL);
+	priv->enable_speaker = TRUE;
+	priv->detect_dialtone = TRUE;
+}
+
+static void
+finalize (GObject *object)
+{
+	NMSettingAnalogModemPrivate *priv = NM_SETTING_ANALOG_MODEM_GET_PRIVATE (object);
+
+	g_free (priv->number);
+	g_free (priv->username);
+	g_free (priv->password);
+
+	G_OBJECT_CLASS (nm_setting_analog_modem_parent_class)->finalize (object);
+}
+
+static void
+set_property (GObject *object, guint prop_id,
+		    const GValue *value, GParamSpec *pspec)
+{
+	NMSettingAnalogModemPrivate *priv = NM_SETTING_ANALOG_MODEM_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_PREFIX:
+		g_free (priv->prefix);
+		priv->prefix = g_value_dup_string (value);
+		break;
+	case PROP_NUMBER:
+		g_free (priv->number);
+		priv->number = g_value_dup_string (value);
+		break;
+	case PROP_USERNAME:
+		g_free (priv->username);
+		priv->username = g_value_dup_string (value);
+		break;
+	case PROP_PASSWORD:
+		g_free (priv->password);
+		priv->password = g_value_dup_string (value);
+		break;
+	case PROP_ENABLE_SPEAKER:
+		priv->enable_speaker = g_value_get_boolean (value);
+		break;
+	case PROP_DETECT_DIALTONE:
+		priv->detect_dialtone = g_value_get_boolean (value);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+		    GValue *value, GParamSpec *pspec)
+{
+	NMSettingAnalogModem *setting = NM_SETTING_ANALOG_MODEM (object);
+
+	switch (prop_id) {
+	case PROP_PREFIX:
+		g_value_set_string (value, nm_setting_analog_modem_get_prefix (setting));
+		break;
+	case PROP_NUMBER:
+		g_value_set_string (value, nm_setting_analog_modem_get_number (setting));
+		break;
+	case PROP_USERNAME:
+		g_value_set_string (value, nm_setting_analog_modem_get_username (setting));
+		break;
+	case PROP_PASSWORD:
+		g_value_set_string (value, nm_setting_analog_modem_get_password (setting));
+		break;
+	case PROP_ENABLE_SPEAKER:
+		g_value_set_boolean (value, nm_setting_analog_modem_get_enable_speaker (setting));
+		break;
+	case PROP_DETECT_DIALTONE:
+		g_value_set_boolean (value, nm_setting_analog_modem_get_detect_dialtone (setting));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+nm_setting_analog_modem_class_init (NMSettingAnalogModemClass *setting_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
+	NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
+
+	g_type_class_add_private (setting_class, sizeof (NMSettingAnalogModemPrivate));
+
+	/* virtual methods */
+	object_class->set_property = set_property;
+	object_class->get_property = get_property;
+	object_class->finalize     = finalize;
+	parent_class->verify       = verify;
+	parent_class->need_secrets = need_secrets;
+
+	/* Properties */
+
+	/**
+	 * NMSettingAnalogModem:prefix:
+	 *
+	 * Prefix to dial when establishing a PPP data session with the dial-up
+	 * network provider.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_PREFIX,
+		 g_param_spec_string (NM_SETTING_ANALOG_MODEM_PREFIX,
+						  "Prefix",
+						  "Prefix to dial when establishing a PPP data session "
+						  "with the dial-up network provider.",
+						  NULL,
+						  G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+
+	/**
+	 * NMSettingAnalogModem:number:
+	 *
+	 * Number to dial when establishing a PPP data session with the dial-up
+	 * network provider.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_NUMBER,
+		 g_param_spec_string (NM_SETTING_ANALOG_MODEM_NUMBER,
+						  "Number",
+						  "Number to dial when establishing a PPP data session "
+						  "with the dial-up network provider.",
+						  NULL,
+						  G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+
+	/**
+	 * NMSettingAnalogModem:username:
+	 *
+	 * The username used to authenticate with the network.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_USERNAME,
+		 g_param_spec_string (NM_SETTING_ANALOG_MODEM_USERNAME,
+						  "Username",
+						  "Username used to authenticate with the network.",
+						  NULL,
+						  G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+
+	/**
+	 * NMSettingAnalogModem:password:
+	 *
+	 * The password used to authenticate with the network.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_PASSWORD,
+		 g_param_spec_string (NM_SETTING_ANALOG_MODEM_PASSWORD,
+						  "Password",
+						  "Password used to authenticate with the network.",
+						  NULL,
+						  G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
+
+	/**
+	 * NMSettingAnalogModem:enable-speaker:
+	 *
+	 * If the modem's speaker should be enabled when dialing.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_ENABLE_SPEAKER,
+		 g_param_spec_boolean (NM_SETTING_ANALOG_MODEM_ENABLE_SPEAKER,
+							   "Enable speaker",
+							   "If the modem's speaker should be enabled when dialing.",
+							   TRUE,
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+
+	/**
+	 * NMSettingAnalogModem:detect-dialtone:
+	 *
+	 * If the modem should wait for a dial tone before dialing.
+	 **/
+	g_object_class_install_property
+		(object_class, PROP_DETECT_DIALTONE,
+		 g_param_spec_boolean (NM_SETTING_ANALOG_MODEM_DETECT_DIALTONE,
+							   "Detect dial tone",
+							   "If the modem should wait for a dial tone before dialing.",
+							   TRUE,
+							   G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
+}
diff --git a/libnm-util/nm-setting-analog-modem.h b/libnm-util/nm-setting-analog-modem.h
new file mode 100644
index 0000000..2e5e16a
--- /dev/null
+++ b/libnm-util/nm-setting-analog-modem.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * Dan Williams <dcbw@redhat.com>
+ * Tambet Ingo <tambet@gmail.com>
+ * Hans Petter Jansson <hpj@novell.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2007 - 2010 Red Hat, Inc.
+ * (C) Copyright 2007 - 2008 Novell, Inc.
+ */
+
+#ifndef NM_SETTING_ANALOG_MODEM_H
+#define NM_SETTING_ANALOG_MODEM_H
+
+#include <nm-setting.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_SETTING_ANALOG_MODEM            (nm_setting_analog_modem_get_type ())
+#define NM_SETTING_ANALOG_MODEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_ANALOG_MODEM, NMSettingAnalogModem))
+#define NM_SETTING_ANALOG_MODEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_ANALOG_MODEM, NMSettingAnalogModemClass))
+#define NM_IS_SETTING_ANALOG_MODEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_ANALOG_MODEM))
+#define NM_IS_SETTING_ANALOG_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SETTING_ANALOG_MODEM))
+#define NM_SETTING_ANALOG_MODEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_ANALOG_MODEM, NMSettingAnalogModemClass))
+
+#define NM_SETTING_ANALOG_MODEM_SETTING_NAME "analog-modem"
+
+typedef enum
+{
+	NM_SETTING_ANALOG_MODEM_ERROR_UNKNOWN = 0,
+	NM_SETTING_ANALOG_MODEM_ERROR_INVALID_PROPERTY,
+	NM_SETTING_ANALOG_MODEM_ERROR_MISSING_PROPERTY,
+	NM_SETTING_ANALOG_MODEM_ERROR_MISSING_SERIAL_SETTING
+} NMSettingAnalogModemError;
+
+#define NM_TYPE_SETTING_ANALOG_MODEM_ERROR (nm_setting_analog_modem_error_get_type ()) 
+GType nm_setting_analog_modem_error_get_type (void);
+
+#define NM_SETTING_ANALOG_MODEM_ERROR nm_setting_analog_modem_error_quark ()
+GQuark nm_setting_analog_modem_error_quark (void);
+
+#define NM_SETTING_ANALOG_MODEM_PREFIX          "prefix"
+#define NM_SETTING_ANALOG_MODEM_NUMBER          "number"
+#define NM_SETTING_ANALOG_MODEM_USERNAME        "username"
+#define NM_SETTING_ANALOG_MODEM_PASSWORD        "password"
+#define NM_SETTING_ANALOG_MODEM_ENABLE_SPEAKER  "enable-speaker"
+#define NM_SETTING_ANALOG_MODEM_DETECT_DIALTONE "detect-dialtone"
+
+typedef struct {
+	NMSetting parent;
+} NMSettingAnalogModem;
+
+typedef struct {
+	NMSettingClass parent;
+
+	/* Padding for future expansion */
+	void (*_reserved1) (void);
+	void (*_reserved2) (void);
+	void (*_reserved3) (void);
+	void (*_reserved4) (void);
+} NMSettingAnalogModemClass;
+
+GType nm_setting_analog_modem_get_type (void);
+
+NMSetting *nm_setting_analog_modem_new                (void);
+const char *nm_setting_analog_modem_get_prefix        (NMSettingAnalogModem *setting);
+const char *nm_setting_analog_modem_get_number        (NMSettingAnalogModem *setting);
+const char *nm_setting_analog_modem_get_username      (NMSettingAnalogModem *setting);
+const char *nm_setting_analog_modem_get_password      (NMSettingAnalogModem *setting);
+gboolean nm_setting_analog_modem_get_enable_speaker  (NMSettingAnalogModem *setting);
+gboolean nm_setting_analog_modem_get_detect_dialtone (NMSettingAnalogModem *setting);
+
+G_END_DECLS
+
+#endif /* NM_SETTING_ANALOG_MODEM_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index b038e7e..56e631c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -113,6 +113,9 @@ nm-device-ethernet-glue.h: $(top_srcdir)/introspection/nm-device-ethernet.xml
 nm-device-wifi-glue.h: $(top_srcdir)/introspection/nm-device-wifi.xml
 	dbus-binding-tool --prefix=nm_device_wifi --mode=glib-server --output=$@ $<
 
+nm-device-analog-modem-glue.h: $(top_srcdir)/introspection/nm-device-analog-modem.xml
+	$(AM_V_GEN) dbus-binding-tool --prefix=nm_device_analog_modem --mode=glib-server --output=$@ $<
+
 nm-ip4-config-glue.h: $(top_srcdir)/introspection/nm-ip4-config.xml
 	dbus-binding-tool --prefix=nm_ip4_config --mode=glib-server --output=$@ $<
 
@@ -128,6 +131,7 @@ BUILT_SOURCES = 					\
 	nm-device-interface-glue.h			\
 	nm-device-ethernet-glue.h			\
 	nm-device-wifi-glue.h		\
+	nm-device-analog-modem-glue.h		\
 	nm-ip4-config-glue.h				\
 	nm-active-connection-glue.h \
 	nm-dhcp4-config-glue.h
diff --git a/src/modem-manager/Makefile.am b/src/modem-manager/Makefile.am
index 5b660d0..6b22c2b 100644
--- a/src/modem-manager/Makefile.am
+++ b/src/modem-manager/Makefile.am
@@ -11,6 +11,8 @@ libmodem_manager_la_SOURCES = \
 	nm-modem-cdma.h \
 	nm-modem-gsm.c \
 	nm-modem-gsm.h \
+	nm-modem-analog.c \
+	nm-modem-analog.h \
 	nm-modem.c \
 	nm-modem.h \
 	nm-modem-manager.h \
@@ -30,12 +32,16 @@ nm-device-cdma-glue.h: $(top_srcdir)/introspection/nm-device-cdma.xml
 nm-device-gsm-glue.h: $(top_srcdir)/introspection/nm-device-gsm.xml
 	dbus-binding-tool --prefix=nm_device_gsm --mode=glib-server --output=$@ $<
 
+nm-device-analog-modem-glue.h: $(top_srcdir)/introspection/nm-device-analog-modem.xml
+	dbus-binding-tool --prefix=nm_device_analog_modem --mode=glib-server --output=$@ $<
+
 nm-serial-device-glue.h: $(top_srcdir)/introspection/nm-device-serial.xml
 	dbus-binding-tool --prefix=nm_serial_device --mode=glib-server --output=$@ $<
 
 BUILT_SOURCES = \
 	nm-device-cdma-glue.h \
 	nm-device-gsm-glue.h \
+	nm-device-analog-modem-glue.h \
 	nm-serial-device-glue.h
 
 CLEANFILES = $(BUILT_SOURCES)
diff --git a/src/modem-manager/nm-modem-analog.c b/src/modem-manager/nm-modem-analog.c
new file mode 100644
index 0000000..040c139
--- /dev/null
+++ b/src/modem-manager/nm-modem-analog.c
@@ -0,0 +1,217 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#include <string.h>
+
+#include "nm-dbus-glib-types.h"
+#include "nm-modem-analog.h"
+#include "nm-modem-types.h"
+#include "nm-device-interface.h"
+#include "nm-device-private.h"
+#include "nm-dbus-manager.h"
+#include "nm-setting-connection.h"
+#include "nm-setting-analog-modem.h"
+#include "nm-utils.h"
+#include "NetworkManagerUtils.h"
+
+#include "nm-device-analog-modem-glue.h"
+
+G_DEFINE_TYPE (NMModemAnalog, nm_modem_analog, NM_TYPE_MODEM)
+
+NMDevice *
+nm_modem_analog_new (const char *path,
+				   const char *data_device,
+				   const char *driver)
+{
+	g_return_val_if_fail (path != NULL, NULL);
+	g_return_val_if_fail (data_device != NULL, NULL);
+	g_return_val_if_fail (driver != NULL, NULL);
+
+	return (NMDevice *) g_object_new (NM_TYPE_MODEM_ANALOG,
+									  NM_DEVICE_INTERFACE_UDI, path,
+									  NM_DEVICE_INTERFACE_IFACE, data_device,
+									  NM_DEVICE_INTERFACE_DRIVER, driver,
+									  NM_DEVICE_INTERFACE_MANAGED, TRUE,
+									  NM_MODEM_PATH, path,
+									  NULL);
+}
+
+static void
+stage1_prepare_done (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+{
+	NMDevice *device = NM_DEVICE (user_data);
+	GError *error = NULL;
+
+	dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID);
+	if (!error)
+		nm_device_activate_schedule_stage2_device_config (device);
+	else {
+		nm_warning ("Analog modem connection failed: %s", error->message);
+		g_error_free (error);
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_NONE);
+	}
+}
+
+static GHashTable *
+create_connect_properties (NMConnection *connection)
+{
+	NMSettingAnalogModem *setting;
+	GHashTable *properties;
+	const char *str;
+	gboolean b;
+
+	setting = NM_SETTING_ANALOG_MODEM (nm_connection_get_setting (connection, NM_TYPE_SETTING_ANALOG_MODEM));
+	properties = value_hash_create ();
+
+	str = nm_setting_analog_modem_get_prefix (setting);
+	if (str)
+		value_hash_add_str (properties, "prefix", str);
+	str = nm_setting_analog_modem_get_number (setting);
+	if (str)
+		value_hash_add_str (properties, "number", str);
+	b = nm_setting_analog_modem_get_enable_speaker (setting);
+	value_hash_add_uint (properties, "enable-speaker", b);
+	b = nm_setting_analog_modem_get_detect_dialtone (setting);
+	value_hash_add_uint (properties, "detect-dialtone", b);
+
+	return properties;
+}
+
+static NMActStageReturn
+real_act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
+{
+	NMConnection *connection;
+	GHashTable *properties;
+
+	connection = nm_act_request_get_connection (nm_device_get_act_request (device));
+	g_assert (connection);
+
+	properties = create_connect_properties (connection);
+	dbus_g_proxy_begin_call_with_timeout (nm_modem_get_proxy (NM_MODEM (device), MM_DBUS_INTERFACE_MODEM_SIMPLE),
+										  "Connect", stage1_prepare_done,
+										  device, NULL, 120000,
+										  DBUS_TYPE_G_MAP_OF_VARIANT, properties,
+										  G_TYPE_INVALID);
+
+	return NM_ACT_STAGE_RETURN_POSTPONE;
+}
+
+static NMConnection *
+real_get_best_auto_connection (NMDevice *dev,
+							   GSList *connections,
+							   char **specific_object)
+{
+	GSList *iter;
+
+	for (iter = connections; iter; iter = g_slist_next (iter)) {
+		NMConnection *connection = NM_CONNECTION (iter->data);
+		NMSettingConnection *s_con;
+
+		s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION);
+		g_assert (s_con);
+
+		if (!nm_setting_connection_get_autoconnect (s_con))
+			continue;
+
+		if (strcmp (nm_setting_connection_get_connection_type (s_con), NM_SETTING_ANALOG_MODEM_SETTING_NAME))
+			continue;
+
+		return connection;
+	}
+	return NULL;
+}
+
+static void
+real_connection_secrets_updated (NMDevice *dev,
+								 NMConnection *connection,
+								 GSList *updated_settings,
+								 RequestSecretsCaller caller)
+{
+	NMActRequest *req;
+	gboolean found = FALSE;
+	GSList *iter;
+
+	if (caller == SECRETS_CALLER_PPP) {
+		NMPPPManager *ppp_manager;
+		NMSettingAnalogModem *s_analog = NULL;
+
+		ppp_manager = nm_modem_get_ppp_manager (NM_MODEM (dev));
+		g_return_if_fail (ppp_manager != NULL);
+
+		s_analog = (NMSettingAnalogModem *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ANALOG_MODEM);
+		if (!s_analog) {
+			/* Shouldn't ever happen */
+			nm_ppp_manager_update_secrets (ppp_manager,
+										   nm_device_get_iface (dev),
+										   NULL,
+										   NULL,
+										   "missing analog setting; no secrets could be found.");
+		} else {
+			const char *username = nm_setting_analog_modem_get_username (s_analog);
+			const char *password = nm_setting_analog_modem_get_password (s_analog);
+
+			nm_ppp_manager_update_secrets (ppp_manager,
+										   nm_device_get_iface (dev),
+										   username ? username : "",
+										   password ? password : "",
+										   NULL);
+		}
+		return;
+	}
+
+	g_return_if_fail (caller == SECRETS_CALLER_MODEM);
+	g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH);
+
+	for (iter = updated_settings; iter; iter = g_slist_next (iter)) {
+		const char *setting_name = (const char *) iter->data;
+
+		if (!strcmp (setting_name, NM_SETTING_ANALOG_MODEM_SETTING_NAME))
+			found = TRUE;
+		else
+			nm_warning ("Ignoring updated secrets for setting '%s'.", setting_name);
+	}
+
+	if (!found)
+		return;
+
+	req = nm_device_get_act_request (dev);
+	g_assert (req);
+
+	g_return_if_fail (nm_act_request_get_connection (req) == connection);
+
+	nm_device_activate_schedule_stage1_device_prepare (dev);
+}
+
+static const char *
+real_get_ppp_name (NMModem *device, NMConnection *connection)
+{
+	NMSettingAnalogModem *s_analog;
+
+	s_analog = (NMSettingAnalogModem *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ANALOG_MODEM);
+	g_assert (s_analog);
+
+	return nm_setting_analog_modem_get_username (s_analog);
+}
+
+/*****************************************************************************/
+
+static void
+nm_modem_analog_init (NMModemAnalog *self)
+{
+	nm_device_set_device_type (NM_DEVICE (self), NM_DEVICE_TYPE_MODEM);
+}
+
+static void
+nm_modem_analog_class_init (NMModemAnalogClass *klass)
+{
+	NMDeviceClass *device_class = NM_DEVICE_CLASS (klass);
+	NMModemClass *modem_class = NM_MODEM_CLASS (klass);
+
+	/* Virtual methods */
+	device_class->get_best_auto_connection = real_get_best_auto_connection;
+	device_class->connection_secrets_updated = real_connection_secrets_updated;
+	device_class->act_stage1_prepare = real_act_stage1_prepare;
+	modem_class->get_ppp_name = real_get_ppp_name;
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+									 &dbus_glib_nm_device_analog_modem_object_info);
+}
diff --git a/src/modem-manager/nm-modem-analog.h b/src/modem-manager/nm-modem-analog.h
new file mode 100644
index 0000000..8c2b831
--- /dev/null
+++ b/src/modem-manager/nm-modem-analog.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#ifndef NM_MODEM_ANALOG_H
+#define NM_MODEM_ANALOG_H
+
+#include <nm-modem.h>
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_MODEM_ANALOG			  (nm_modem_analog_get_type ())
+#define NM_MODEM_ANALOG(obj)			  (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MODEM_ANALOG, NMModemAnalog))
+#define NM_MODEM_ANALOG_CLASS(klass)	  (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_MODEM_ANALOG, NMModemAnalogClass))
+#define NM_IS_MODEM_ANALOG(obj)		      (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_MODEM_ANALOG))
+#define NM_IS_MODEM_ANALOG_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_MODEM_ANALOG))
+#define NM_MODEM_ANALOG_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_MODEM_ANALOG, NMModemAnalogClass))
+
+typedef struct {
+	NMModem parent;
+} NMModemAnalog;
+
+typedef struct {
+	NMModemClass parent;
+} NMModemAnalogClass;
+
+GType nm_modem_analog_get_type (void);
+
+NMDevice *nm_modem_analog_new (const char *path,
+							   const char *data_device,
+							   const char *driver);
+
+G_END_DECLS
+
+#endif /* NM_MODEM_ANALOG_H */
diff --git a/src/modem-manager/nm-modem-manager.c b/src/modem-manager/nm-modem-manager.c
index 84cf53f..ebb30c8 100644
--- a/src/modem-manager/nm-modem-manager.c
+++ b/src/modem-manager/nm-modem-manager.c
@@ -5,6 +5,7 @@
 #include "nm-modem.h"
 #include "nm-modem-gsm.h"
 #include "nm-modem-cdma.h"
+#include "nm-modem-analog.h"
 #include "nm-dbus-manager.h"
 #include "nm-utils.h"
 #include "nm-modem-types.h"
@@ -163,6 +164,8 @@ create_modem (NMModemManager *manager, const char *path)
 		device = nm_modem_gsm_new (path, data_device, driver, ip_method);
 	else if (modem_type == MM_MODEM_TYPE_CDMA)
 		device = nm_modem_cdma_new (path, data_device, driver);
+	else if (modem_type == MM_MODEM_TYPE_ANALOG)
+		device = nm_modem_analog_new (path, data_device, driver);
 	else
 		g_error ("Invalid modem type");
 
diff --git a/src/modem-manager/nm-modem-types.h b/src/modem-manager/nm-modem-types.h
index a251d2a..136721b 100644
--- a/src/modem-manager/nm-modem-types.h
+++ b/src/modem-manager/nm-modem-types.h
@@ -16,6 +16,7 @@
 #define MM_MODEM_TYPE_UNKNOWN  0
 #define MM_MODEM_TYPE_GSM      1
 #define MM_MODEM_TYPE_CDMA     2
+#define MM_MODEM_TYPE_ANALOG   3
 
 #define MM_MODEM_IP_METHOD_PPP    0
 #define MM_MODEM_IP_METHOD_STATIC 1
diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h
index bce0dfc..d72327b 100644
--- a/src/nm-activation-request.h
+++ b/src/nm-activation-request.h
@@ -44,7 +44,8 @@ typedef enum {
 	SECRETS_CALLER_GSM,
 	SECRETS_CALLER_CDMA,
 	SECRETS_CALLER_PPP,
-	SECRETS_CALLER_HSO_GSM
+	SECRETS_CALLER_HSO_GSM,
+	SECRETS_CALLER_MODEM
 } RequestSecretsCaller;
 
 typedef struct {
diff --git a/src/nm-device-analog-modem.c b/src/nm-device-analog-modem.c
new file mode 100644
index 0000000..e12bc34
--- /dev/null
+++ b/src/nm-device-analog-modem.c
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2009 - 2010 Red Hat, Inc.
+ */
+
+#include <string.h>
+
+#include "nm-modem-analog.h"
+#include "nm-device-interface.h"
+#include "nm-device-analog-modem.h"
+#include "nm-properties-changed-signal.h"
+
+#include "nm-device-analog-modem-glue.h"
+
+G_DEFINE_TYPE (NMDeviceAnalogModem, nm_device_analog_modem, NM_TYPE_DEVICE_MODEM)
+
+enum {
+	PROPERTIES_CHANGED,
+	LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+NMDevice *
+nm_device_analog_modem_new (NMModemAnalog *modem, const char *driver)
+{
+	g_return_val_if_fail (modem != NULL, NULL);
+	g_return_val_if_fail (NM_IS_MODEM_ANALOG (modem), NULL);
+	g_return_val_if_fail (driver != NULL, NULL);
+
+	return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ANALOG_MODEM,
+	                                  NM_DEVICE_INTERFACE_UDI, nm_modem_get_path (NM_MODEM (modem)),
+	                                  NM_DEVICE_INTERFACE_IFACE, nm_modem_get_iface (NM_MODEM (modem)),
+	                                  NM_DEVICE_INTERFACE_DRIVER, driver,
+	                                  NM_DEVICE_INTERFACE_TYPE_DESC, "Modem",
+	                                  NM_DEVICE_INTERFACE_DEVICE_TYPE, NM_DEVICE_TYPE_MODEM,
+	                                  NM_DEVICE_MODEM_MODEM, modem,
+	                                  NULL);
+}
+
+static void
+nm_device_analog_modem_init (NMDeviceAnalogModem *self)
+{
+}
+
+static void
+nm_device_analog_modem_class_init (NMDeviceAnalogModemClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	/* Signals */
+	signals[PROPERTIES_CHANGED] = 
+		nm_properties_changed_signal_new (object_class,
+		                                  G_STRUCT_OFFSET (NMDeviceAnalogModemClass, properties_changed));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass),
+	                                 &dbus_glib_nm_device_analog_modem_object_info);
+}
+
diff --git a/src/nm-device-analog-modem.h b/src/nm-device-analog-modem.h
new file mode 100644
index 0000000..7575114
--- /dev/null
+++ b/src/nm-device-analog-modem.h
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ */
+
+#ifndef NM_DEVICE_ANALOG_MODEM_H
+#define NM_DEVICE_ANALOG_MODEM_H
+
+#include "nm-device-modem.h"
+#include "nm-modem-analog.h"
+
+G_BEGIN_DECLS
+
+#define NM_TYPE_DEVICE_ANALOG_MODEM   (nm_device_analog_modem_get_type ())
+#define NM_DEVICE_ANALOG_MODEM(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_ANALOG_MODEM, NMDeviceAnalogModem))
+#define NM_DEVICE_ANALOG_MODEM_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  NM_TYPE_DEVICE_ANALOG_MODEM, NMDeviceAnalogModemClass))
+#define NM_IS_DEVICE_ANALOG_MODEM(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_ANALOG_MODEM))
+#define NM_IS_DEVICE_ANALOG_MODEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  NM_TYPE_DEVICE_ANALOG_MODEM))
+#define NM_DEVICE_ANALOG_MODEM_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  NM_TYPE_DEVICE_ANALOG_MODEM, NMDeviceAnalogModemClass))
+
+typedef struct {
+	NMDeviceModem parent;
+} NMDeviceAnalogModem;
+
+typedef struct {
+	NMDeviceModemClass parent;
+
+	/* Signals */
+	void (*properties_changed) (NMDeviceAnalogModem *self, GHashTable *properties);
+} NMDeviceAnalogModemClass;
+
+GType nm_device_analog_modem_get_type (void);
+
+NMDevice *nm_device_analog_modem_new (NMModemAnalogModem *modem, const char *driver);
+
+G_END_DECLS
+
+#endif /* NM_DEVICE_ANALOG_MODEM_H */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 59e9733..370cb23 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -39,6 +39,7 @@
 #include "nm-properties-changed-signal.h"
 #include "nm-setting-connection.h"
 #include "nm-setting-cdma.h"
+#include "nm-setting-analog-modem.h"
 #include "nm-setting-wired.h"
 #include "nm-setting-gsm.h"
 #include "nm-setting-ppp.h"
@@ -272,6 +273,8 @@ modem_added (NMModemManager *modem_manager,
 		type_name = "GSM modem";
 	else if (type == NM_DEVICE_TYPE_CDMA)
 		type_name = "CDMA modem";
+	else if (type == NM_DEVICE_TYPE_MODEM)
+		type_name = "Voiceband modem";
 	else
 		type_name = "Unknown modem";
 
@@ -1992,7 +1995,8 @@ is_user_request_connection_type_authorized(NMManager *manager, const char *dbus_
             action_id = NM_POLICY_ACTION_USER_DSL_APPLY;
         }
     } else if (!strcmp(connection_type, NM_SETTING_CDMA_SETTING_NAME)
-            || !strcmp(connection_type, NM_SETTING_GSM_SETTING_NAME)) {
+            || !strcmp(connection_type, NM_SETTING_GSM_SETTING_NAME)
+			|| !strcmp(connection_type, NM_SETTING_ANALOG_MODEM_SETTING_NAME)) {
         if (is_shared) {
             action_id = NM_POLICY_ACTION_USER_MOBILE_APPLY_WITH_SHARE;
         } else {
