diff --git a/configure.ac b/configure.ac
index d784ba4..2dd8fa6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -35,6 +35,10 @@ MISSION_CONTROL_REQUIRED=4.61
 ENCHANT_REQUIRED=1.2.0
 ISO_CODES_REQUIRED=0.35
 LIBNOTIFY_REQUIRED=0.4.4
+GEOCLUE_REQUIRED=0.11
+LIBCHAMPLAIN_REQUIRED=0.2.6
+LIBCHAMPLAIN_GTK_REQUIRED=0.2.6
+CLUTTER_GTK_REQUIRED=0.8.2
 
 # Uncomment that to build with deprecated symbols disabled
 #AC_DEFINE(G_DISABLE_DEPRECATED, [], [Disable deprecated GLib symbols])
@@ -178,6 +182,68 @@ fi
 AM_CONDITIONAL(HAVE_ENCHANT, test "x$have_enchant" = "xyes")
 
 # -----------------------------------------------------------
+# Map view checks: libchamplain
+# -----------------------------------------------------------
+AC_ARG_ENABLE(map,
+              AS_HELP_STRING([--enable-map=@<:@no/yes/auto@:>@],
+                             [Enable map view]), ,
+                             enable_map=auto)
+
+if test "x$enable_map" != "xno"; then
+   PKG_CHECK_MODULES(LIBCHAMPLAIN,
+   [
+      champlain-0.2 >= $LIBCHAMPLAIN_REQUIRED,
+      champlain-gtk-0.2 >= $LIBCHAMPLAIN_GTK_REQUIRED
+      clutter-gtk-0.8 >= $CLUTTER_GTK_REQUIRED
+   ], have_libchamplain="yes", have_libchamplain="no")
+
+   if test "x$have_libchamplain" = "xyes"; then
+      AC_DEFINE(HAVE_LIBCHAMPLAIN, 1, [Define if you have libchamplain])
+   else
+       have_libchamplain="no"
+   fi
+else
+   have_libchamplain=no
+fi
+
+if test "x$enable_map" = "xyes" -a "x$have_libchamplain" != "xyes"; then
+   AC_MSG_ERROR([Couldn't find map view dependencies.])
+fi
+
+AM_CONDITIONAL(HAVE_LIBCHAMPLAIN, test "x$have_libchamplain" = "xyes")
+
+# -----------------------------------------------------------
+# location checks: geoclue
+# -----------------------------------------------------------
+AC_ARG_ENABLE(location,
+              AS_HELP_STRING([--enable-location=@<:@no/yes/auto@:>@],
+                             [Enable location awareness]), ,
+                             enable_location=auto)
+
+if test "x$enable_location" != "xno"; then
+   PKG_CHECK_MODULES(GEOCLUE,
+   [
+      geoclue >= $GEOCLUE_REQUIRED
+   ], have_geoclue="yes", have_geoclue="no")
+
+   if test "x$have_geoclue" = "xyes"; then
+      AC_DEFINE(HAVE_GEOCLUE, 1, [Define if you have geoclue])
+   else
+       have_geoclue="no"
+   fi
+else
+   have_geoclue=no
+fi
+
+if test "x$enable_map" = "xyes" -a "x$have_geoclue" != "xyes"; then
+   AC_MSG_ERROR([Couldn't find location dependencies.])
+fi
+
+AM_CONDITIONAL(HAVE_GEOCLUE, test "x$have_geoclue" = "xyes")
+AC_SUBST(GEOCLUE_CFLAGS)
+AC_SUBST(GEOCLUE_LIBS)
+
+# -----------------------------------------------------------
 # Megaphone
 # -----------------------------------------------------------
 AC_ARG_ENABLE(megaphone,
diff --git a/data/empathy.schemas.in b/data/empathy.schemas.in
index 62b462f..c0fff4a 100644
--- a/data/empathy.schemas.in
+++ b/data/empathy.schemas.in
@@ -463,5 +463,91 @@
       </locale>
     </schema>
 
-  </schemalist>  
+    <schema>
+      <key>/schemas/apps/empathy/location/publish</key>
+      <applyto>/apps/empathy/location/publish</applyto>
+      <owner>empathy</owner>
+      <type>bool</type>
+      <default>false</default>
+      <locale name="C">
+        <short>Empathy can publish the user's location</short>
+        <long>
+        Whether or not Empathy can publish the user's location to its contacts. 
+        </long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/empathy/location/method</key>
+      <applyto>/apps/empathy/location/method</applyto>
+      <owner>empathy</owner>
+      <type>string</type>
+      <default>automatic</default>
+      <locale name="C">
+        <short>How Empathy should determine the user's location</short>
+        <long>
+        How Empathy determines the user's location.  A value of "automatic" means that 
+        Empathy will try to guess the user's location, a value of "manual" 
+        means that the user has specified a location.
+        </long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/empathy/location/resource_network</key>
+      <applyto>/apps/empathy/location/resource_network</applyto>
+      <owner>empathy</owner>
+      <type>bool</type>
+      <default>true</default>
+      <locale name="C">
+        <short>Empathy can use the network to guess the location</short>
+        <long>
+        Whether or not Empathy can use the network to guess the location.
+        </long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/empathy/location/resource_cell</key>
+      <applyto>/apps/empathy/location/resource_cell</applyto>
+      <owner>empathy</owner>
+      <type>bool</type>
+      <default>true</default>
+      <locale name="C">
+        <short>Empathy can use the cellular network to guess the location</short>
+        <long>
+        Whether or not Empathy can use the cellular network to guess the location.
+        </long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/empathy/location/resource_gps</key>
+      <applyto>/apps/empathy/location/resource_gps</applyto>
+      <owner>empathy</owner>
+      <type>bool</type>
+      <default>false</default>
+      <locale name="C">
+        <short>Empathy can use the GPS to guess the location</short>
+        <long>
+        Whether or not Empathy can use the GPS to guess the location.
+        </long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/empathy/location/reduce_accuracy</key>
+      <applyto>/apps/empathy/location/reduce_accuracy</applyto>
+      <owner>empathy</owner>
+      <type>bool</type>
+      <default>false</default>
+      <locale name="C">
+        <short>Empathy should reduce the location's accuracy</short>
+        <long>
+        Whether or not Empathy should reduce the location's accuracy for privacy reasons.
+        </long>
+      </locale>
+    </schema>
+
+  </schemalist>
 </gconfschemafile>
diff --git a/extensions/Connection_Interface_Location.xml b/extensions/Connection_Interface_Location.xml
new file mode 100644
index 0000000..1e7bee4
--- /dev/null
+++ b/extensions/Connection_Interface_Location.xml
@@ -0,0 +1,330 @@
+<?xml version="1.0" ?>
+<node name="/Connection_Interface_Location"
+  xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
+  <tp:copyright>Copyright (C) 2008 Collabora Ltd.</tp:copyright>
+  <tp:copyright>Copyright (C) 2008 Nokia Corporation</tp:copyright>
+  <tp:license xmlns="http://www.w3.org/1999/xhtml">
+    <p>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.1 of the License, or (at your option) any later version.</p>
+
+<p>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.</p>
+
+<p>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.</p>
+  </tp:license>
+  <interface name="org.freedesktop.Telepathy.Connection.Interface.Location.DRAFT"
+    tp:causes-havoc='experimental'>
+    <tp:requires interface="org.freedesktop.Telepathy.Connection"/>
+
+    <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+      <p>An interface on connections to support protocols which allow users to
+        publish their current geographical location, and subscribe to the
+        current location of their contacts.</p>
+
+      <p>This interface is geared strongly towards automatic propagation and
+        use of this information, so focuses on latitude, longitude and
+        altitude which can be determined by GPS, although provision is also
+        included for an optional human-readable description of locations. All
+        co-ordinate information is required to be relative to the WGS84
+        datum.</p>
+
+      <p>The information published through this interface is intended to have
+        the same scope as presence information, so will normally be made
+        available to those individuals on the user's "publish" contact list.
+        Even so, user interfaces should not automatically publish location
+        information without the consent of the user, and it is recommended
+        that an option is made available to reduce the accuracy of the
+        reported information to allow the user to maintain their privacy.</p>
+
+      <p>Location information is represented using the terminology of XMPP's
+        <a href="http://www.xmpp.org/extensions/xep-0080.html">XEP-0080</a>
+        or the XEP-0080-derived
+        <a href="http://geoclue.freedesktop.org/">Geoclue</a> API where
+        possible.</p>
+    </tp:docstring>
+
+    <tp:enum name="Location_Accuracy_Level" type="i">
+      <tp:docstring>
+        A location accuracy level. This should be kept in sync with
+        GeoclueAccuracyLevel in the Geoclue project.
+      </tp:docstring>
+
+      <tp:enumvalue suffix="None" value="0">
+        <tp:docstring>
+          The accuracy is unspecified.
+        </tp:docstring>
+      </tp:enumvalue>
+      <tp:enumvalue suffix="Country" value="1">
+        <tp:docstring>
+          The location indicates the contact's country.
+        </tp:docstring>
+      </tp:enumvalue>
+      <tp:enumvalue suffix="Region" value="2">
+        <tp:docstring>
+          The location indicates the contact's region within a country.
+        </tp:docstring>
+      </tp:enumvalue>
+      <tp:enumvalue suffix="Locality" value="3">
+        <tp:docstring>
+          The location indicates the contact's locality within a region
+          (e.g. the correct city).
+        </tp:docstring>
+      </tp:enumvalue>
+      <tp:enumvalue suffix="Postal_Code" value="4">
+        <tp:docstring>
+          The location indicates the correct postal code.
+        </tp:docstring>
+      </tp:enumvalue>
+      <tp:enumvalue suffix="Street" value="5">
+        <tp:docstring>
+          The location indicates the correct street.
+        </tp:docstring>
+      </tp:enumvalue>
+      <tp:enumvalue suffix="Detailed" value="6">
+        <tp:docstring>
+          The location's accuracy is given by the error, horizontal-error-m
+          and/or vertical-error-m keys.
+        </tp:docstring>
+      </tp:enumvalue>
+    </tp:enum>
+
+    <tp:mapping name="Location">
+      <tp:docstring>
+        A user's location, represented as an extensible mapping.
+      </tp:docstring>
+
+      <tp:member name="Key" type="s">
+        <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+
+          <p>Civic addresses are represented by the following well-known
+            keys (all of which have string values), which should be kept in
+            sync with those used in XEP-0080 and in the Geoclue project:</p>
+
+          <ul>
+            <li>countrycode - s: an ISO-3166-1 alpha-2 (two-letter) country
+              code, e.g. "us", "gb", "fr"</li>
+            <li>country - s: a country name in unspecified locale, e.g.
+              "USA"</li>
+            <li>region - s: an administrative region of the nation, such as a
+              state or province</li>
+            <li>locality - s: a locality within the administrative region, such
+              as a town or city</li>
+            <li>area - s: a named area such as a campus or neighborhood</li>
+            <li>postalcode - s: a code used for postal delivery</li>
+            <li>street - s: a thoroughfare within the locality, or a crossing of
+              two thoroughfares</li>
+          </ul>
+
+          <p>The following address keys are defined in XEP-0080 but not by
+            Geoclue, and are also allowed:</p>
+
+          <ul>
+            <li>building - s: a specific building on a street or in an area</li>
+            <li>floor - s: a particular floor in a building</li>
+            <li>room - s: a particular room in a building</li>
+            <li>text - s: any more specific information, e.g.
+              "Northwest corner of the lobby"</li>
+            <li>description - s: A natural-language name for or description of
+              the location, e.g. "Bill's house"</li>
+            <li>uri - s: a URI representing the location or pointing to more
+              information about it</li>
+          </ul>
+
+          <p>Positions are represented by the following well-known keys:</p>
+
+          <ul>
+            <li>lat - d: latitude in decimal degrees north, -90 to +90,
+              relative to the WGS-84 datum
+              <tp:rationale>
+                This is from XEP-0080; the XEP allows use of a different
+                datum, but recommends this one. We enforce sanity by requiring
+                a consistent datum: a minimal compliant implementation of this
+                specification in terms of XEP-0080 would simply ignore the
+                &lt;lat&gt; and &lt;lon&gt; elements if &lt;datum&gt; exists
+                and has a value other than WGS-84, while an advanced
+                implementation might correct for the different datum.
+              </tp:rationale>
+            </li>
+            <li>lon - d: Longitude in decimal degrees east, -180 to +180,
+              relative to the WGS-84 datum
+              <tp:rationale>
+                Same rationale as 'lat'
+              </tp:rationale>
+            </li>
+            <li>alt - d: altitude in metres above sea level (negative
+              if below sea level)
+              <tp:rationale>
+                This is from XEP-0080
+              </tp:rationale>
+            </li>
+            <li>accuracy-level - i (<tp:type>Location_Accuracy_Level</tp:type>):
+              an indication of accuracy, which SHOULD be omitted if it would be
+              Location_Accuracy_Level_None or
+              Location_Accuracy_Level_Detailed
+              <tp:rationale>
+                This is a struct field in GeoClue; the name is new in this
+                specification, and was chosen in an attempt to avoid clashing
+                with any future XEP-0080 terminology.
+              </tp:rationale>
+            </li>
+            <li>error - d: horizontal position error in arc-minutes (1/60
+              degree) if known
+              <tp:rationale>
+                This is from XEP-0080
+              </tp:rationale>
+            </li>
+            <li>vertical-error-m - d: vertical position error in metres if
+              known
+              <tp:rationale>
+                This exists as a struct field in GeoClue; the name is new
+                in this specification.
+              </tp:rationale>
+            </li>
+            <li>horizontal-error-m - d: horizontal position error in metres if
+              known
+              <tp:rationale>
+                This exists as a struct field in GeoClue; the name is new
+                in this specification.
+              </tp:rationale>
+            </li>
+          </ul>
+
+          <p>Velocities are represented by the following well-known keys:</p>
+
+          <ul>
+            <li>speed - d: speed in metres per second
+              <tp:rationale>
+                This is from XEP-0080
+              </tp:rationale>
+            </li>
+            <li>bearing - d: direction of movement in decimal degrees,
+              where North is 0 and East is 90
+              <tp:rationale>
+                This is from XEP-0080, and is equivalent to the struct field
+                called "direction" in GeoClue
+              </tp:rationale>
+            </li>
+            <li>climb - d: rate of change of 'alt' in metres per second
+              <tp:rationale>
+                This is a struct field in GeoClue; the name is new to this
+                specification, but seems uncontroversial
+              </tp:rationale>
+            </li>
+          </ul>
+
+          <p>Other well-known keys:</p>
+
+          <ul>
+            <li>timestamp - t (<tp:type>Unix_Timestamp64</tp:type>): the time
+              that the contact was at this location, in seconds since
+              1970-01-01T00:00:00Z (i.e. the beginning of 1970 in UTC)
+              <tp:rationale>
+                XEP-0080 uses an ISO 8601 string for this, but a number of
+                seconds since the epoch is probably easier to work with.
+              </tp:rationale>
+            </li>
+          </ul>
+        </tp:docstring>
+      </tp:member>
+
+      <tp:member name="Value" type="v">
+        <tp:docstring>
+          The value corresponding to the well-known key.
+        </tp:docstring>
+      </tp:member>
+    </tp:mapping>
+
+    <tp:mapping name="Contact_Locations" type="a{ua{sv}}">
+      <tp:member name="Contact" type="u" tp:type="Contact_Handle">
+      </tp:member>
+      <tp:member name="Location" type="a{sv}" tp:type="Location">
+      </tp:member>
+    </tp:mapping>
+
+    <method name="GetLocations" tp:name-for-bindings="Get_Locations">
+      <tp:docstring>
+        Return the current locations of the given contacts, if they are
+        already known. If any of the given contacts' locations are not known,
+        request their current locations, and later emit
+        <tp:member-ref>LocationUpdated</tp:member-ref> for them; the
+        <tp:member-ref>LocationUpdated</tp:member-ref> signal for contacts
+        whose location could not be determined will have an empty Location.
+      </tp:docstring>
+
+      <arg direction="in" name="Contacts" type="au" tp:type="Contact_Handle[]">
+        <tp:docstring>
+          The contacts whose locations should be returned or signalled.
+        </tp:docstring>
+      </arg>
+
+      <arg direction="out" name="Locations" type="a{ua{sv}}"
+        tp:type="Contact_Locations">
+        <tp:docstring>
+          The contacts' locations, if already known. Contacts whose locations
+          are not already known are omitted from the mapping; contacts known
+          to have no location information appear in the mapping with an empty
+          Location dictionary.
+        </tp:docstring>
+      </arg>
+    </method>
+
+    <signal name="LocationUpdated" tp:name-for-bindings="Location_Updated">
+      <tp:docstring>
+        Emitted when a contact's location changes or becomes known.
+      </tp:docstring>
+
+      <arg name="Contact" type="u" tp:type="Contact_Handle">
+        <tp:docstring>
+          The contact
+        </tp:docstring>
+      </arg>
+      <arg name="Location" type="a{sv}" tp:type="Location">
+        <tp:docstring>
+          The contact's location, or empty to indicate that nothing is known
+          about the contact's location.
+        </tp:docstring>
+      </arg>
+    </signal>
+
+    <method name="SetLocation" tp:name-for-bindings="SetLocation">
+      <tp:docstring>
+        Set the local user's own location.
+      </tp:docstring>
+
+      <arg direction="in" name="Location" type="a{sv}">
+        <tp:docstring>
+          The location to advertise. If the user wants to obscure their
+          exact location by reducing the precision or accuracy, clients
+          MUST do this themselves, rather than relying on the connection
+          manager to do so. Clients that interact with more than one
+          connection SHOULD advertise the same reduced-accuracy location
+          to all of them, so that contacts cannot obtain an undesirably
+          accurate location by assuming that random errors have been added
+          and averaging the locations advertised on multiple connections.
+        </tp:docstring>
+      </arg>
+    </method>
+
+    <property name="LocationAccessControlTypes" type="au" access="read"
+      tp:type="Rich_Presence_Access_Control_Type[]" tp:name-for-bindings="Location_Access_Control_Types">
+      <tp:docstring>The types of access control that are supported by this
+        connection.</tp:docstring>
+    </property>
+
+    <property name="LocationAccessControl" type="(uv)" access="readwrite"
+      tp:type="Rich_Presence_Access_Control" tp:name-for-bindings="Location_Access_Control">
+      <tp:docstring>The current access control mechanism and settings
+        for this connection. Before publishing location for the first time,
+        if this has not been set by a client, implementations SHOULD
+        set it to be as restrictive as possible (an empty whitelist, if
+        supported).</tp:docstring>
+    </property>
+  </interface>
+</node>
+<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index 0a57fe3..a5ecf03 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -11,6 +11,7 @@ EXTRA_DIST = \
     generic-types.xml \
     misc.xml \
     Channel_Handler.xml \
+    Connection_Interface_Location.xml \
     Tube_Handler.xml \
     Channel_Interface_Tube.xml \
     Channel_Type_DBus_Tube.xml \
diff --git a/extensions/all.xml b/extensions/all.xml
index c9f4c0b..85d9dde 100644
--- a/extensions/all.xml
+++ b/extensions/all.xml
@@ -28,6 +28,18 @@
     from="Telepathy specification"/>
   <tp:external-type name="Tube_ID" type="u"
     from="Telepathy specification"/>
+
+  <!-- for localisation -->
+  <tp:external-type name="Rich_Presence_Access_Control_Type" type="u"
+    from="Telepathy specification"/>
+  <tp:external-type name="Rich_Presence_Access_Control" type="(uv)"
+    from="Telepathy specification"/>
+  <tp:external-type name="Unix_Timestamp64" type="t"
+    from="Telepathy specification"/>
+  <tp:external-type name="Unix_Timestamp" type="u"
+    from="Telepathy specification"/>
+  <tp:external-type name="String_String_Map" type="a{ss}"
+    from="Telepathy specification"/>
 </tp:generic-types>
 
 
diff --git a/extensions/misc.xml b/extensions/misc.xml
index 5c89ff0..a6ad1c6 100644
--- a/extensions/misc.xml
+++ b/extensions/misc.xml
@@ -9,5 +9,6 @@
 <xi:include href="Channel_Interface_Tube.xml" />
 <xi:include href="Channel_Type_DBus_Tube.xml" />
 <xi:include href="Channel_Type_Stream_Tube.xml" />
+<xi:include href="Connection_Interface_Location.xml"/>
 
 </tp:spec>
diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am
index 46d0316..6f17a07 100644
--- a/libempathy-gtk/Makefile.am
+++ b/libempathy-gtk/Makefile.am
@@ -5,6 +5,8 @@ AM_CPPFLAGS =                                           \
 	-DPKGDATADIR=\""$(pkgdatadir)"\"		\
 	$(EMPATHY_CFLAGS)				\
 	$(ENCHANT_CFLAGS)				\
+	$(GEOCLUE_CFLAGS)				\
+	$(LIBCHAMPLAIN_CFLAGS)				\
 	$(WARN_CFLAGS)
 
 BUILT_SOURCES = 					\
@@ -42,6 +44,7 @@ libempathy_gtk_la_SOURCES =             	\
 	empathy-video-src.c			\
 	empathy-video-widget.c			\
 	empathy-irc-network-dialog.c		\
+	empathy-location-manager.c		\
 	empathy-log-window.c			\
 	empathy-new-message-dialog.c		\
 	empathy-presence-chooser.c		\
@@ -62,6 +65,8 @@ nodist_libempathy_gtk_la_SOURCES =\
 libempathy_gtk_la_LIBADD =			\
 	$(EMPATHY_LIBS)				\
 	$(ENCHANT_LIBS)				\
+	$(GEOCLUE_LIBS)				\
+	$(LIBCHAMPLAIN_LIBS)			\
 	$(top_builddir)/libempathy/libempathy.la
 
 libempathy_gtk_la_LDFLAGS =                \
@@ -95,6 +100,7 @@ libempathy_gtk_headers =			\
 	empathy-video-widget.h			\
 	empathy-images.h			\
 	empathy-irc-network-dialog.h		\
+	empathy-location-manager.h		\
 	empathy-log-window.h			\
 	empathy-new-message-dialog.h		\
 	empathy-presence-chooser.h		\
diff --git a/libempathy-gtk/empathy-conf.h b/libempathy-gtk/empathy-conf.h
index 2051a7f..4536a5d 100644
--- a/libempathy-gtk/empathy-conf.h
+++ b/libempathy-gtk/empathy-conf.h
@@ -70,6 +70,7 @@ struct _EmpathyConfClass {
 #define EMPATHY_PREFS_UI_SHOW_AVATARS              EMPATHY_PREFS_PATH "/ui/show_avatars"
 #define EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST      EMPATHY_PREFS_PATH "/ui/compact_contact_list"
 #define EMPATHY_PREFS_CONTACTS_SHOW_OFFLINE        EMPATHY_PREFS_PATH "/contacts/show_offline"
+#define EMPATHY_PREFS_CONTACTS_SHOW_MAP            EMPATHY_PREFS_PATH "/contacts/show_map"
 #define EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM      EMPATHY_PREFS_PATH "/contacts/sort_criterium"
 #define EMPATHY_PREFS_HINTS_CLOSE_MAIN_WINDOW      EMPATHY_PREFS_PATH "/hints/close_main_window"
 #define EMPATHY_PREFS_SALUT_ACCOUNT_CREATED        EMPATHY_PREFS_PATH "/accounts/salut_created"
@@ -77,6 +78,12 @@ struct _EmpathyConfClass {
 #define EMPATHY_PREFS_AUTOCONNECT                  EMPATHY_PREFS_PATH "/autoconnect"
 #define EMPATHY_PREFS_IMPORT_ASKED                 EMPATHY_PREFS_PATH "/import_asked"
 #define EMPATHY_PREFS_FILE_TRANSFER_DEFAULT_FOLDER EMPATHY_PREFS_PATH "/file_transfer/default_folder"
+#define EMPATHY_PREFS_LOCATION_PUBLISH             EMPATHY_PREFS_PATH "/location/publish"
+#define EMPATHY_PREFS_LOCATION_METHOD              EMPATHY_PREFS_PATH "/location/method"
+#define EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK    EMPATHY_PREFS_PATH "/location/resource_network"
+#define EMPATHY_PREFS_LOCATION_RESOURCE_CELL       EMPATHY_PREFS_PATH "/location/resource_cell"
+#define EMPATHY_PREFS_LOCATION_RESOURCE_GPS        EMPATHY_PREFS_PATH "/location/resource_gps"
+#define EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY     EMPATHY_PREFS_PATH "/location/reduce_accuracy"
 
 typedef void (*EmpathyConfNotifyFunc) (EmpathyConf  *conf, 
 				      const gchar *key,
diff --git a/libempathy-gtk/empathy-contact-dialogs.c b/libempathy-gtk/empathy-contact-dialogs.c
index ca9277d..1f74c61 100644
--- a/libempathy-gtk/empathy-contact-dialogs.c
+++ b/libempathy-gtk/empathy-contact-dialogs.c
@@ -189,6 +189,9 @@ empathy_contact_information_dialog_show (EmpathyContact *contact,
 
 	/* Contact info widget */
 	contact_widget = empathy_contact_widget_new (contact,
+#if HAVE_LIBCHAMPLAIN
+		EMPATHY_CONTACT_WIDGET_SHOW_LOCATION |
+#endif
 		EMPATHY_CONTACT_WIDGET_EDIT_NONE);
 	gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8);
 	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
@@ -244,11 +247,11 @@ empathy_contact_edit_dialog_show (EmpathyContact *contact,
 	gtk_window_set_default (GTK_WINDOW (dialog), button);
 	gtk_widget_show (button);
 
-	/* Contact info widget */
 	contact_widget = empathy_contact_widget_new (contact,
 		EMPATHY_CONTACT_WIDGET_EDIT_ALIAS |
 		EMPATHY_CONTACT_WIDGET_EDIT_GROUPS);
 	gtk_container_set_border_width (GTK_CONTAINER (contact_widget), 8);
+
 	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
 			    contact_widget,
 			    TRUE, TRUE, 0);
diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c
index 79014f2..77963d0 100644
--- a/libempathy-gtk/empathy-contact-widget.c
+++ b/libempathy-gtk/empathy-contact-widget.c
@@ -21,19 +21,27 @@
 
 #include <config.h>
 
+#define _GNU_SOURCE
 #include <string.h>
 #include <stdlib.h>
+#include <time.h>
 
 #include <gtk/gtk.h>
 #include <glade/glade.h>
 #include <glib/gi18n-lib.h>
 
+#if HAVE_LIBCHAMPLAIN
+#include <champlain/champlain.h>
+#include <champlain-gtk/champlain-gtk.h>
+#endif
+
 #include <libmissioncontrol/mc-account.h>
 #include <telepathy-glib/util.h>
 
 #include <libempathy/empathy-tp-contact-factory.h>
 #include <libempathy/empathy-contact-manager.h>
 #include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-location.h>
 #include <libempathy/empathy-utils.h>
 
 #include "empathy-contact-widget.h"
@@ -73,6 +81,15 @@ typedef struct
   GtkWidget *table_contact;
   GtkWidget *vbox_avatar;
 
+#if HAVE_LIBCHAMPLAIN
+  /* Location */
+  GtkWidget *vbox_location;
+  GtkWidget *label_location;
+  GtkWidget *viewport_map;
+  GtkWidget *map_view_embed;
+  ClutterActor *map_view;
+#endif
+
   /* Groups */
   GtkWidget *vbox_groups;
   GtkWidget *entry_group;
@@ -144,6 +161,9 @@ static void contact_widget_details_setup (EmpathyContactWidget *information);
 static void contact_widget_details_update (EmpathyContactWidget *information);
 static void contact_widget_client_setup (EmpathyContactWidget *information);
 static void contact_widget_client_update (EmpathyContactWidget *information);
+#if HAVE_LIBCHAMPLAIN
+static void contact_widget_location_update (EmpathyContactWidget *information);
+#endif
 
 enum
 {
@@ -179,6 +199,11 @@ empathy_contact_widget_new (EmpathyContact *contact,
        "label_status", &information->label_status,
        "table_contact", &information->table_contact,
        "vbox_avatar", &information->vbox_avatar,
+#if HAVE_LIBCHAMPLAIN
+       "vbox_location", &information->vbox_location,
+       "label_location", &information->label_location,
+       "viewport_map", &information->viewport_map,
+#endif
        "vbox_groups", &information->vbox_groups,
        "entry_group", &information->entry_group,
        "button_group", &information->button_group,
@@ -331,6 +356,9 @@ contact_widget_set_contact (EmpathyContactWidget *information,
   contact_widget_groups_update (information);
   contact_widget_details_update (information);
   contact_widget_client_update (information);
+#if HAVE_LIBCHAMPLAIN
+  contact_widget_location_update (information);
+#endif
 }
 
 static gboolean
@@ -1161,3 +1189,82 @@ contact_widget_client_update (EmpathyContactWidget *information)
 {
   /* FIXME: Needs new telepathy spec */
 }
+
+#if HAVE_LIBCHAMPLAIN
+static void
+contact_widget_location_update (EmpathyContactWidget *information)
+{
+  GHashTable *location;
+  GValue *value;
+  gdouble lat, lon;
+  ClutterActor *marker;
+  ChamplainLayer *layer;
+
+  location = empathy_contact_get_location (information->contact);
+  value = g_hash_table_lookup (location, EMPATHY_LOCATION_LAT);
+  if (value == NULL)
+    {
+      gtk_widget_hide (information->vbox_location);
+      return;
+    }
+  lat = g_value_get_double (value);
+
+  value = g_hash_table_lookup (location, EMPATHY_LOCATION_LON);
+  if (value == NULL)
+    {
+      gtk_widget_hide (information->vbox_location);
+      return;
+    }
+  lon = g_value_get_double (value);
+
+  value = g_hash_table_lookup (location, EMPATHY_LOCATION_TIMESTAMP);
+  if (value == NULL)
+    gtk_label_set_markup (GTK_LABEL (information->label_location), _("<b>Location</b>"));
+  else
+    {
+      gchar user_date [100];
+      gint64 stamp;
+      struct tm *ptm;
+      time_t time;
+
+      stamp = g_value_get_int64 (value);
+      time = stamp;
+      ptm = gmtime (&time);
+
+      if (strftime (user_date, 100, _("%B %e, %Y at %R UTC"), ptm) > 0)
+        {
+          gchar *text;
+          text = g_strconcat ( _("<b>Location</b> on "), user_date, NULL);
+          gtk_label_set_markup (GTK_LABEL (information->label_location), text);
+          g_free (text);
+        }
+      else
+        gtk_label_set_markup (GTK_LABEL (information->label_location), _("<b>Location</b>"));
+    }
+
+  if (/* information->flags & EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP || */
+      information->flags & EMPATHY_CONTACT_WIDGET_SHOW_LOCATION)
+    {
+      information->map_view = champlain_view_new (CHAMPLAIN_VIEW_MODE_KINETIC);
+      information->map_view_embed = champlain_view_embed_new (
+          CHAMPLAIN_VIEW (information->map_view));
+
+      gtk_container_add (GTK_CONTAINER (information->viewport_map),
+          information->map_view_embed);
+      g_object_set (G_OBJECT (information->map_view), "show-license", FALSE,
+          NULL);
+
+      layer = champlain_layer_new ();
+      champlain_view_add_layer (CHAMPLAIN_VIEW (information->map_view), layer);
+
+      marker = champlain_marker_new_with_label (
+          empathy_contact_get_name (information->contact), NULL, NULL, NULL);
+      champlain_marker_set_position (CHAMPLAIN_MARKER (marker), lat, lon);
+      clutter_container_add (CLUTTER_CONTAINER (layer), marker, NULL);
+
+      champlain_view_center_on (CHAMPLAIN_VIEW(information->map_view), lat, lon);
+      gtk_widget_show_all (information->vbox_location);
+    }
+
+}
+#endif
diff --git a/libempathy-gtk/empathy-contact-widget.glade b/libempathy-gtk/empathy-contact-widget.glade
index 721ebe3..20fceb1 100644
--- a/libempathy-gtk/empathy-contact-widget.glade
+++ b/libempathy-gtk/empathy-contact-widget.glade
@@ -7,6 +7,7 @@
     <property name="title" translatable="yes">Contact information</property>
     <child>
       <widget class="GtkVBox" id="vbox_contact_widget">
+        <property name="border_width">5</property>
         <property name="spacing">6</property>
         <child>
           <widget class="GtkVBox" id="vbox_contact">
@@ -53,12 +54,14 @@
                               <placeholder/>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label680">
+                              <widget class="GtkLabel" id="label_alias">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Account:</property>
+                                <property name="label" translatable="yes">Alias:</property>
                               </widget>
                               <packing>
+                                <property name="top_attach">2</property>
+                                <property name="bottom_attach">3</property>
                                 <property name="x_options">GTK_FILL</property>
                                 <property name="y_options"></property>
                               </packing>
@@ -77,14 +80,12 @@
                               </packing>
                             </child>
                             <child>
-                              <widget class="GtkLabel" id="label_alias">
+                              <widget class="GtkLabel" id="label680">
                                 <property name="visible">True</property>
                                 <property name="xalign">0</property>
-                                <property name="label" translatable="yes">Alias:</property>
+                                <property name="label" translatable="yes">Account:</property>
                               </widget>
                               <packing>
-                                <property name="top_attach">2</property>
-                                <property name="bottom_attach">3</property>
                                 <property name="x_options">GTK_FILL</property>
                                 <property name="y_options"></property>
                               </packing>
@@ -153,6 +154,48 @@
           </packing>
         </child>
         <child>
+          <widget class="GtkVBox" id="vbox_location">
+            <property name="spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label_location">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;b&gt;Location&lt;/b&gt; at (date)	</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <widget class="GtkViewport" id="viewport_map">
+                    <property name="height_request">150</property>
+                    <property name="visible">True</property>
+                    <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+                    <child>
+                      <placeholder/>
+                    </child>
+                  </widget>
+                </child>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
           <widget class="GtkVBox" id="vbox_groups">
             <property name="spacing">6</property>
             <child>
@@ -250,7 +293,7 @@
             </child>
           </widget>
           <packing>
-            <property name="position">1</property>
+            <property name="position">2</property>
           </packing>
         </child>
         <child>
@@ -295,47 +338,47 @@
                           <placeholder/>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="label670">
+                          <widget class="GtkLabel" id="label652">
                             <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Fullname:</property>
+                            <property name="label" translatable="yes">Birthday:</property>
                           </widget>
                           <packing>
+                            <property name="top_attach">3</property>
+                            <property name="bottom_attach">4</property>
                             <property name="x_options">GTK_FILL</property>
                             <property name="y_options"></property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="label650">
+                          <widget class="GtkLabel" id="label651">
                             <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Email:</property>
+                            <property name="label" translatable="yes">Web site:</property>
                           </widget>
                           <packing>
-                            <property name="top_attach">1</property>
-                            <property name="bottom_attach">2</property>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
                             <property name="x_options">GTK_FILL</property>
                             <property name="y_options"></property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="label651">
+                          <widget class="GtkLabel" id="label650">
                             <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Web site:</property>
+                            <property name="label" translatable="yes">Email:</property>
                           </widget>
                           <packing>
-                            <property name="top_attach">2</property>
-                            <property name="bottom_attach">3</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
                             <property name="x_options">GTK_FILL</property>
                             <property name="y_options"></property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="label652">
+                          <widget class="GtkLabel" id="label670">
                             <property name="xalign">0</property>
-                            <property name="label" translatable="yes">Birthday:</property>
+                            <property name="label" translatable="yes">Fullname:</property>
                           </widget>
                           <packing>
-                            <property name="top_attach">3</property>
-                            <property name="bottom_attach">4</property>
                             <property name="x_options">GTK_FILL</property>
                             <property name="y_options"></property>
                           </packing>
@@ -387,7 +430,7 @@
           </widget>
           <packing>
             <property name="expand">False</property>
-            <property name="position">2</property>
+            <property name="position">3</property>
           </packing>
         </child>
         <child>
@@ -420,37 +463,35 @@
                         <property name="column_spacing">12</property>
                         <property name="row_spacing">6</property>
                         <child>
-                          <widget class="GtkLabel" id="label668">
+                          <widget class="GtkLabel" id="label_os">
+                            <property name="can_focus">True</property>
                             <property name="xalign">0</property>
-                            <property name="yalign">0</property>
-                            <property name="label" translatable="yes">OS:</property>
+                            <property name="xpad">2</property>
+                            <property name="wrap">True</property>
+                            <property name="selectable">True</property>
                           </widget>
                           <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
                             <property name="top_attach">2</property>
                             <property name="bottom_attach">3</property>
-                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options"></property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="label667">
+                          <widget class="GtkLabel" id="label_version">
+                            <property name="can_focus">True</property>
                             <property name="xalign">0</property>
-                            <property name="yalign">0</property>
-                            <property name="label" translatable="yes">Version:</property>
+                            <property name="xpad">2</property>
+                            <property name="wrap">True</property>
+                            <property name="selectable">True</property>
                           </widget>
                           <packing>
+                            <property name="left_attach">1</property>
+                            <property name="right_attach">2</property>
                             <property name="top_attach">1</property>
                             <property name="bottom_attach">2</property>
-                            <property name="x_options">GTK_FILL</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <widget class="GtkLabel" id="label666">
-                            <property name="xalign">0</property>
-                            <property name="yalign">0</property>
-                            <property name="label" translatable="yes">Client:</property>
-                          </widget>
-                          <packing>
-                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options"></property>
                           </packing>
                         </child>
                         <child>
@@ -468,35 +509,37 @@
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="label_version">
-                            <property name="can_focus">True</property>
+                          <widget class="GtkLabel" id="label666">
                             <property name="xalign">0</property>
-                            <property name="xpad">2</property>
-                            <property name="wrap">True</property>
-                            <property name="selectable">True</property>
+                            <property name="yalign">0</property>
+                            <property name="label" translatable="yes">Client:</property>
+                          </widget>
+                          <packing>
+                            <property name="x_options">GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <widget class="GtkLabel" id="label667">
+                            <property name="xalign">0</property>
+                            <property name="yalign">0</property>
+                            <property name="label" translatable="yes">Version:</property>
                           </widget>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
                             <property name="top_attach">1</property>
                             <property name="bottom_attach">2</property>
-                            <property name="y_options"></property>
+                            <property name="x_options">GTK_FILL</property>
                           </packing>
                         </child>
                         <child>
-                          <widget class="GtkLabel" id="label_os">
-                            <property name="can_focus">True</property>
+                          <widget class="GtkLabel" id="label668">
                             <property name="xalign">0</property>
-                            <property name="xpad">2</property>
-                            <property name="wrap">True</property>
-                            <property name="selectable">True</property>
+                            <property name="yalign">0</property>
+                            <property name="label" translatable="yes">OS:</property>
                           </widget>
                           <packing>
-                            <property name="left_attach">1</property>
-                            <property name="right_attach">2</property>
                             <property name="top_attach">2</property>
                             <property name="bottom_attach">3</property>
-                            <property name="y_options"></property>
+                            <property name="x_options">GTK_FILL</property>
                           </packing>
                         </child>
                       </widget>
@@ -549,7 +592,7 @@
           </widget>
           <packing>
             <property name="expand">False</property>
-            <property name="position">3</property>
+            <property name="position">4</property>
           </packing>
         </child>
       </widget>
diff --git a/libempathy-gtk/empathy-contact-widget.h b/libempathy-gtk/empathy-contact-widget.h
index 4ba75e1..b81aec2 100644
--- a/libempathy-gtk/empathy-contact-widget.h
+++ b/libempathy-gtk/empathy-contact-widget.h
@@ -38,6 +38,7 @@ typedef enum
   EMPATHY_CONTACT_WIDGET_EDIT_ID      = 1 << 3,
   EMPATHY_CONTACT_WIDGET_EDIT_GROUPS  = 1 << 4,
   EMPATHY_CONTACT_WIDGET_FOR_TOOLTIP  = 1 << 5,
+  EMPATHY_CONTACT_WIDGET_SHOW_LOCATION  = 1 << 6,
 } EmpathyContactWidgetFlags;
 
 GtkWidget * empathy_contact_widget_new (EmpathyContact *contact,
diff --git a/libempathy-gtk/empathy-location-manager.c b/libempathy-gtk/empathy-location-manager.c
new file mode 100644
index 0000000..9da3964
--- /dev/null
+++ b/libempathy-gtk/empathy-location-manager.c
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <time.h>
+
+#include <glib/gi18n.h>
+
+#include <telepathy-glib/util.h>
+
+#if HAVE_GEOCLUE
+#include <geoclue/geoclue-master.h>
+
+#include <extensions/extensions.h>
+
+#include "empathy-location-manager.h"
+#include "empathy-conf.h"
+
+#include "libempathy/empathy-account-manager.h"
+#include "libempathy/empathy-enum-types.h"
+#include "libempathy/empathy-location.h"
+#include "libempathy/empathy-tp-contact-factory.h"
+#include "libempathy/empathy-utils.h"
+
+#define DEBUG_FLAG EMPATHY_DEBUG_LOCATION
+#include "libempathy/empathy-debug.h"
+
+#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLocationManager)
+typedef struct {
+    gboolean is_setup;
+    MissionControl *mc;
+    GHashTable *location;
+    gpointer token;
+
+    GeoclueResourceFlags resources;
+    GeoclueMasterClient *gc_client;
+    GeocluePosition *gc_position;
+    GeoclueAddress *gc_address;
+
+    gboolean reduce_accuracy;
+    gdouble reduce_value;
+    EmpathyAccountManager *account_manager;
+} EmpathyLocationManagerPriv;
+
+static void location_manager_finalize (GObject *object);
+static void location_manager_get_property (GObject *object, guint param_id,
+    GValue *value, GParamSpec *pspec);
+static void location_manager_set_property (GObject *object, guint param_id,
+    const GValue *value, GParamSpec *pspec);
+static void position_changed_cb (GeocluePosition *position,
+    GeocluePositionFields fields, int timestamp, double latitude,
+    double longitude, double altitude, GeoclueAccuracy *accuracy,
+    gpointer user_data);
+static void address_changed_cb (GeoclueAddress *address, int timestamp,
+    GHashTable *details, GeoclueAccuracy *accuracy, gpointer user_data);
+static void setup_geoclue (EmpathyLocationManager *location_manager);
+static void publish_cb (EmpathyConf  *conf, const gchar *key,
+    gpointer user_data);
+static void update_resources (EmpathyLocationManager *location_manager);
+static void resource_cb (EmpathyConf  *conf, const gchar *key,
+    gpointer user_data);
+static void accuracy_cb (EmpathyConf  *conf, const gchar *key,
+    gpointer user_data);
+static void account_connection_changed_cb (EmpathyAccountManager *manager,
+    McAccount *account, TpConnectionStatusReason reason,
+    TpConnectionStatus current, TpConnectionStatus previous,
+    gpointer *location_manager);
+
+G_DEFINE_TYPE (EmpathyLocationManager, empathy_location_manager, G_TYPE_OBJECT);
+
+enum
+{
+  PROP_0,
+};
+
+static void
+empathy_location_manager_class_init (EmpathyLocationManagerClass *class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (class);
+
+  object_class->finalize = location_manager_finalize;
+  object_class->get_property = location_manager_get_property;
+  object_class->set_property = location_manager_set_property;
+
+  g_type_class_add_private (object_class, sizeof (EmpathyLocationManagerPriv));
+}
+
+static void
+publish_location (EmpathyLocationManager *location_manager,
+                  McAccount *account,
+                  gboolean force_publication)
+{
+  EmpathyLocationManagerPriv *priv;
+  guint connection_status = -1;
+  gboolean can_publish;
+  EmpathyConf *conf = empathy_conf_get ();
+  TpConnection *conn;
+  EmpathyTpContactFactory *factory;
+
+  priv = GET_PRIV (location_manager);
+
+  conn = mission_control_get_tpconnection (priv->mc, account, NULL);
+  if (!conn)
+    return;
+
+  factory = empathy_tp_contact_factory_dup_singleton (conn);
+
+  if (force_publication == FALSE)
+    {
+      if (!empathy_conf_get_bool (conf, EMPATHY_PREFS_LOCATION_PUBLISH,
+            &can_publish))
+        return;
+
+      if (can_publish == FALSE)
+        return;
+    }
+
+  connection_status = mission_control_get_connection_status (priv->mc,
+      account, NULL);
+
+  if (connection_status != TP_CONNECTION_STATUS_CONNECTED)
+    return;
+
+  DEBUG ("Publishing location to account %s",
+      mc_account_get_display_name (account));
+
+  empathy_tp_contact_factory_set_location (factory, priv->location);
+  g_object_unref (factory);
+}
+
+static void
+publish_location_to_all_accounts (EmpathyLocationManager *location_manager,
+                                  gboolean force_publication)
+{
+  GList *accounts = NULL, *l;
+
+  accounts = mc_accounts_list_by_enabled (TRUE);
+  for (l = accounts; l; l = l->next)
+    {
+      publish_location (location_manager, l->data, force_publication);
+    }
+
+  mc_accounts_list_free (accounts);
+}
+
+static void
+account_connection_changed_cb (EmpathyAccountManager *manager,
+                               McAccount *account,
+                               TpConnectionStatusReason reason,
+                               TpConnectionStatus current,
+                               TpConnectionStatus previous,
+                               gpointer *location_manager)
+{
+  DEBUG ("Account %s changed status from %d to %d", mc_account_get_display_name (account),
+      previous, current);
+
+  if (account && current == TP_CONNECTION_STATUS_CONNECTED)
+    publish_location (EMPATHY_LOCATION_MANAGER (location_manager), account,
+        FALSE);
+}
+
+static void
+empathy_location_manager_init (EmpathyLocationManager *location_manager)
+{
+  EmpathyConf               *conf;
+  EmpathyLocationManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (location_manager,
+      EMPATHY_TYPE_LOCATION_MANAGER, EmpathyLocationManagerPriv);
+
+  location_manager->priv = priv;
+  priv->is_setup = FALSE;
+  priv->mc = empathy_mission_control_dup_singleton ();
+  priv->location = g_hash_table_new_full (g_direct_hash, g_direct_equal,
+      g_free, (GDestroyNotify) tp_g_value_slice_free);
+
+  // Setup settings status callbacks
+  conf = empathy_conf_get ();
+  empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_PUBLISH, publish_cb,
+      location_manager);
+  empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
+      resource_cb, location_manager);
+  empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_RESOURCE_CELL,
+      resource_cb, location_manager);
+  empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_RESOURCE_GPS,
+      resource_cb, location_manager);
+  empathy_conf_notify_add (conf, EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
+      accuracy_cb, location_manager);
+
+  resource_cb (conf, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK, location_manager);
+  resource_cb (conf, EMPATHY_PREFS_LOCATION_RESOURCE_CELL, location_manager);
+  resource_cb (conf, EMPATHY_PREFS_LOCATION_RESOURCE_GPS, location_manager);
+  accuracy_cb (conf, EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY, location_manager);
+  publish_cb (conf, EMPATHY_PREFS_LOCATION_PUBLISH, location_manager);
+
+  // Setup account status callbacks
+  priv->account_manager = empathy_account_manager_dup_singleton ();
+  g_signal_connect (priv->account_manager,
+    "account-connection-changed",
+    G_CALLBACK (account_connection_changed_cb), location_manager);
+}
+
+
+static void
+location_manager_finalize (GObject *object)
+{
+  EmpathyLocationManagerPriv *priv;
+
+  priv = GET_PRIV (object);
+
+  DEBUG ("finalize: %p", object);
+  g_object_unref (priv->account_manager);
+
+  G_OBJECT_CLASS (empathy_location_manager_parent_class)->finalize (object);
+}
+
+
+static void
+location_manager_get_property (GObject *object,
+                      guint param_id,
+                      GValue *value,
+                      GParamSpec *pspec)
+{
+  EmpathyLocationManagerPriv *priv;
+
+  priv = GET_PRIV (object);
+
+  switch (param_id)
+    {
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    };
+}
+
+
+static void
+location_manager_set_property (GObject *object,
+                      guint param_id,
+                      const GValue *value,
+                      GParamSpec *pspec)
+{
+  EmpathyLocationManagerPriv *priv;
+
+  priv = GET_PRIV (object);
+
+  switch (param_id)
+    {
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+        break;
+    };
+}
+
+
+EmpathyLocationManager *
+empathy_location_manager_get_default (void)
+{
+  static EmpathyLocationManager *singleton = NULL;
+  if (singleton == NULL)
+    singleton = g_object_new (EMPATHY_TYPE_LOCATION_MANAGER, NULL);
+  return singleton;
+}
+
+static void
+update_timestamp (EmpathyLocationManager *location_manager,
+                  int timestamp)
+{
+  EmpathyLocationManagerPriv *priv;
+  priv = GET_PRIV (location_manager);
+  GValue *new_value;
+  gint64 stamp64 = (gint64) timestamp;
+
+  new_value = tp_g_value_slice_new (G_TYPE_INT64);
+  g_value_set_int64 (new_value, stamp64);
+  g_hash_table_insert (priv->location, g_strdup (EMPATHY_LOCATION_TIMESTAMP),
+      new_value);
+  DEBUG ("\t - Timestamp: %" G_GINT64_FORMAT, stamp64);
+}
+
+static void
+initial_position_cb (GeocluePosition *position,
+                     GeocluePositionFields fields,
+                     int timestamp,
+                     double latitude,
+                     double longitude,
+                     double altitude,
+                     GeoclueAccuracy *accuracy,
+                     GError *error,
+                     gpointer location_manager)
+{
+  if (error)
+    {
+      DEBUG ("Error: %s", error->message);
+      g_error_free (error);
+    }
+  else
+    position_changed_cb (position, fields, timestamp, latitude, longitude,
+      altitude, accuracy, location_manager);
+}
+
+static void
+position_changed_cb (GeocluePosition *position,
+                     GeocluePositionFields fields,
+                     int timestamp,
+                     double latitude,
+                     double longitude,
+                     double altitude,
+                     GeoclueAccuracy *accuracy,
+                     gpointer location_manager)
+{
+  EmpathyLocationManagerPriv *priv;
+  priv = GET_PRIV (location_manager);
+  GeoclueAccuracyLevel level;
+  gdouble mean, horizontal, vertical;
+  GValue *new_value;
+
+  geoclue_accuracy_get_details (accuracy, &level, &horizontal, &vertical);
+  DEBUG ("New position (accuracy level %d)", level);
+  if (level == GEOCLUE_ACCURACY_LEVEL_NONE)
+    return;
+
+  if (fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)
+    {
+      longitude += priv->reduce_value;
+      new_value = tp_g_value_slice_new (G_TYPE_DOUBLE);
+      g_value_set_double (new_value, longitude);
+      g_hash_table_insert (priv->location, g_strdup (EMPATHY_LOCATION_LON),
+          new_value);
+      DEBUG ("\t - Longitude: %f", longitude);
+    }
+  if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE)
+    {
+      latitude += priv->reduce_value;
+      new_value = tp_g_value_slice_new (G_TYPE_DOUBLE);
+      g_value_set_double (new_value, latitude);
+      g_hash_table_insert (priv->location, g_strdup (EMPATHY_LOCATION_LAT),
+          new_value);
+      DEBUG ("\t - Latitude: %f", latitude);
+    }
+  if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE)
+    {
+      new_value = tp_g_value_slice_new (G_TYPE_DOUBLE);
+      g_value_set_double (new_value, altitude);
+      g_hash_table_insert (priv->location, g_strdup (EMPATHY_LOCATION_ALT),
+          new_value);
+      DEBUG ("\t - Altitude: %f", altitude);
+    }
+
+  if (level == GEOCLUE_ACCURACY_LEVEL_DETAILED)
+    {
+      mean = (horizontal + vertical) / 2.0;
+      new_value = tp_g_value_slice_new (G_TYPE_DOUBLE);
+      g_value_set_double (new_value, mean);
+      g_hash_table_insert (priv->location,
+          g_strdup (EMPATHY_LOCATION_ACCURACY), new_value);
+      DEBUG ("\t - Accuracy: %f", mean);
+    }
+
+  update_timestamp (location_manager, timestamp);
+  publish_location_to_all_accounts (EMPATHY_LOCATION_MANAGER (location_manager),
+      FALSE);
+}
+
+
+static void
+address_foreach_cb (gpointer key,
+                    gpointer value,
+                    gpointer location_manager)
+{
+  if (location_manager == NULL)
+    return;
+
+  EmpathyLocationManagerPriv *priv;
+  priv = GET_PRIV (location_manager);
+
+  // Discard street information if reduced accuracy is on
+  if (priv->reduce_accuracy && strcmp (key, EMPATHY_LOCATION_STREET) == 0)
+    return;
+
+  GValue *new_value = tp_g_value_slice_new (G_TYPE_STRING);
+  g_value_set_string (new_value, value);
+
+  g_hash_table_insert (priv->location, g_strdup (key), new_value);
+  DEBUG ("\t - %s: %s", (char*) key, (char*) value);
+}
+
+static void
+initial_address_cb (GeoclueAddress *address,
+                    int timestamp,
+                    GHashTable *details,
+                    GeoclueAccuracy *accuracy,
+                    GError *error,
+                    gpointer location_manager)
+{
+  if (error)
+    {
+      DEBUG ("Error: %s", error->message);
+      g_error_free (error);
+    }
+  else
+    address_changed_cb (address, timestamp, details, accuracy, location_manager);
+}
+
+static void
+address_changed_cb (GeoclueAddress *address,
+                    int timestamp,
+                    GHashTable *details,
+                    GeoclueAccuracy *accuracy,
+                    gpointer location_manager)
+{
+  GeoclueAccuracyLevel level;
+  geoclue_accuracy_get_details (accuracy, &level, NULL, NULL);
+  EmpathyLocationManagerPriv *priv;
+
+  DEBUG ("New address (accuracy level %d):", level);
+
+  priv = GET_PRIV (location_manager);
+  g_hash_table_remove_all (priv->location);
+
+  g_hash_table_foreach (details, address_foreach_cb, (gpointer)location_manager);
+
+  update_timestamp (location_manager, timestamp);
+  publish_location_to_all_accounts (EMPATHY_LOCATION_MANAGER (location_manager),
+      FALSE);
+}
+
+
+static void
+update_resources (EmpathyLocationManager *location_manager)
+{
+  EmpathyLocationManagerPriv *priv;
+
+  priv = GET_PRIV (location_manager);
+
+  DEBUG ("Updating resources");
+
+  if (!geoclue_master_client_set_requirements (priv->gc_client,
+          GEOCLUE_ACCURACY_LEVEL_LOCALITY, 0, TRUE, priv->resources,
+          NULL))
+    {
+      g_printerr ("set_requirements failed");
+      return;
+    }
+
+  if (!priv->is_setup)
+    return;
+
+  geoclue_address_get_address_async (priv->gc_address,
+      initial_address_cb, location_manager);
+  geoclue_position_get_position_async (priv->gc_position,
+      initial_position_cb, location_manager);
+
+}
+
+
+static void
+setup_geoclue (EmpathyLocationManager *location_manager)
+{
+  EmpathyLocationManagerPriv *priv;
+
+  priv = GET_PRIV (location_manager);
+
+  GeoclueMaster *master;
+  GError *error = NULL;
+
+  DEBUG ("Setting up Geoclue");
+  master = geoclue_master_get_default ();
+  priv->gc_client = geoclue_master_create_client (master, NULL, NULL);
+  g_object_unref (master);
+
+  update_resources (location_manager);
+
+  /* Get updated when the position is changes */
+  priv->gc_position = geoclue_master_client_create_position (
+      priv->gc_client, &error);
+  if (priv->gc_position == NULL)
+    {
+      g_printerr ("Failed to create GeocluePosition: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+
+  g_signal_connect (G_OBJECT (priv->gc_position), "position-changed",
+      G_CALLBACK (position_changed_cb), location_manager);
+
+  /* Get updated when the address changes */
+  priv->gc_address = geoclue_master_client_create_address (
+      priv->gc_client, &error);
+  if (priv->gc_address == NULL)
+    {
+      g_printerr ("Failed to create GeoclueAddress: %s", error->message);
+      g_error_free (error);
+      return;
+    }
+
+  g_signal_connect (G_OBJECT (priv->gc_address), "address-changed",
+      G_CALLBACK (address_changed_cb), location_manager);
+
+  priv->is_setup = TRUE;
+}
+
+static void
+publish_cb (EmpathyConf *conf,
+            const gchar *key,
+            gpointer user_data)
+{
+  EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
+  EmpathyLocationManagerPriv *priv;
+  gboolean can_publish;
+
+  DEBUG ("Publish Conf changed");
+  priv = GET_PRIV (manager);
+  if (!empathy_conf_get_bool (conf, key, &can_publish))
+    return;
+
+  if (can_publish)
+    {
+      if (!priv->is_setup)
+        setup_geoclue (manager);
+      geoclue_address_get_address_async (priv->gc_address,
+          initial_address_cb, manager);
+      geoclue_position_get_position_async (priv->gc_position,
+          initial_position_cb, manager);
+      publish_location_to_all_accounts (manager, FALSE);
+    }
+  else
+    {
+      /* As per XEP-0080: send an empty location to have remove current
+       * location from the servers
+       */
+      g_hash_table_remove_all (priv->location);
+      publish_location_to_all_accounts (manager, TRUE);
+    }
+
+}
+
+
+static void
+accuracy_cb (EmpathyConf  *conf,
+             const gchar *key,
+             gpointer user_data)
+{
+  EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
+  EmpathyLocationManagerPriv *priv;
+
+  gboolean enabled;
+
+  priv = GET_PRIV (manager);
+  DEBUG ("%s changed", key);
+
+  if (!empathy_conf_get_bool (conf, key, &enabled))
+    return;
+  priv->reduce_accuracy = enabled;
+
+  if (enabled)
+    {
+      GRand *rand = g_rand_new_with_seed (time (NULL));
+      priv->reduce_value = g_rand_double_range (rand, -0.25, 0.25);
+      g_rand_free (rand);
+    }
+  else
+    priv->reduce_value = 0.0;
+
+  if (!priv->is_setup)
+    return;
+
+  geoclue_address_get_address_async (priv->gc_address,
+      initial_address_cb, manager);
+  geoclue_position_get_position_async (priv->gc_position,
+      initial_position_cb, manager);
+}
+
+static void
+resource_cb (EmpathyConf  *conf,
+             const gchar *key,
+             gpointer user_data)
+{
+  EmpathyLocationManager *manager = EMPATHY_LOCATION_MANAGER (user_data);
+  EmpathyLocationManagerPriv *priv;
+  GeoclueResourceFlags resource = 0;
+  gboolean resource_enabled;
+
+  priv = GET_PRIV (manager);
+  DEBUG ("%s changed", key);
+
+  if (!empathy_conf_get_bool (conf, key, &resource_enabled))
+    return;
+
+  if (strcmp (key, EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK) == 0)
+    resource = GEOCLUE_RESOURCE_NETWORK;
+  if (strcmp (key, EMPATHY_PREFS_LOCATION_RESOURCE_CELL) == 0)
+    resource = GEOCLUE_RESOURCE_CELL;
+  if (strcmp (key, EMPATHY_PREFS_LOCATION_RESOURCE_GPS) == 0)
+    resource = GEOCLUE_RESOURCE_GPS;
+
+  if (resource_enabled)
+    priv->resources |= resource;
+  else
+    priv->resources &= ~resource;
+
+  if (priv->is_setup)
+    update_resources (manager);
+}
+
+#endif
diff --git a/libempathy-gtk/empathy-location-manager.h b/libempathy-gtk/empathy-location-manager.h
new file mode 100644
index 0000000..937e268
--- /dev/null
+++ b/libempathy-gtk/empathy-location-manager.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
+ */
+
+#ifndef __EMPATHY_LOCATION_MANAGER_H__
+#define __EMPATHY_LOCATION_MANAGER_H__
+
+#include <glib-object.h>
+
+
+G_BEGIN_DECLS
+
+#define EMPATHY_TYPE_LOCATION_MANAGER         (empathy_location_manager_get_type ())
+#define EMPATHY_LOCATION_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_LOCATION_MANAGER, EmpathyLocationManager))
+#define EMPATHY_LOCATION_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_LOCATION_MANAGER, EmpathyLocationManagerClass))
+#define EMPATHY_IS_LOCATION_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_LOCATION_MANAGER))
+#define EMPATHY_IS_LOCATION_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_LOCATION_MANAGER))
+#define EMPATHY_LOCATION_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_LOCATION_MANAGER, EmpathyLocationManagerClass))
+
+typedef struct _EmpathyLocationManager      EmpathyLocationManager;
+typedef struct _EmpathyLocationManagerClass EmpathyLocationManagerClass;
+
+typedef enum {
+	EMPATHY_LOCATION_MANAGER_METHOD_MANUAL,
+	EMPATHY_LOCATION_MANAGER_METHOD_AUTOMATIC
+} EmpathyLocationManagerMethod;
+
+struct _EmpathyLocationManager
+{
+  GObject parent;
+  gpointer priv;
+};
+
+struct _EmpathyLocationManagerClass
+{
+  GObjectClass parent_class;
+};
+
+GType empathy_location_manager_get_type (void) G_GNUC_CONST;
+EmpathyLocationManager * empathy_location_manager_get_default (void);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_LOCATION_MANAGER_H__ */
diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am
index ffd1b82..006996f 100644
--- a/libempathy/Makefile.am
+++ b/libempathy/Makefile.am
@@ -80,6 +80,7 @@ libempathy_headers =				\
 	empathy-irc-network.h			\
 	empathy-irc-network-manager.h		\
 	empathy-irc-server.h			\
+	empathy-location.h			\
 	empathy-log-manager.h			\
 	empathy-log-store.h			\
 	empathy-log-store-empathy.h		\
diff --git a/libempathy/empathy-contact.c b/libempathy/empathy-contact.c
index 51259bd..1c47d32 100644
--- a/libempathy/empathy-contact.c
+++ b/libempathy/empathy-contact.c
@@ -51,6 +51,7 @@ typedef struct {
   EmpathyCapabilities capabilities;
   gboolean is_user;
   guint hash;
+  GHashTable *location;
 } EmpathyContactPriv;
 
 static void contact_finalize (GObject *object);
@@ -74,6 +75,7 @@ enum
   PROP_HANDLE,
   PROP_CAPABILITIES,
   PROP_IS_USER,
+  PROP_LOCATION
 };
 
 enum {
@@ -226,6 +228,15 @@ empathy_contact_class_init (EmpathyContactClass *class)
         FALSE,
         G_PARAM_READWRITE));
 
+
+  g_object_class_install_property (object_class,
+      PROP_LOCATION,
+      g_param_spec_boxed ("location",
+        "Contact location",
+        "Physical location of the contact",
+        G_TYPE_HASH_TABLE,
+        G_PARAM_READABLE));
+
   signals[PRESENCE_CHANGED] =
     g_signal_new ("presence-changed",
                   G_TYPE_FROM_CLASS (class),
@@ -247,6 +258,10 @@ empathy_contact_init (EmpathyContact *contact)
     EMPATHY_TYPE_CONTACT, EmpathyContactPriv);
 
   contact->priv = priv;
+
+  priv->location = g_hash_table_new_full (g_str_hash, g_str_equal,
+                       (GDestroyNotify) g_free,
+                       (GDestroyNotify) tp_g_value_slice_free);
 }
 
 static void
@@ -985,3 +1000,48 @@ empathy_avatar_save_to_file (EmpathyAvatar *self,
   return g_file_set_contents (filename, self->data, self->len, error);
 }
 
+/**
+ * empathy_contact_get_location:
+ * @contact: the contact
+ *
+ * Returns the user's location if available.  The keys are defined in
+ * empathy-location.h. If the contact doesn't have location
+ * information, the GHashTable will be empthy.
+ *
+ * Returns: a #GHashTable of location values
+ */
+GHashTable *
+empathy_contact_get_location (EmpathyContact *contact)
+{
+  EmpathyContactPriv *priv;
+
+  g_return_val_if_fail (EMPATHY_CONTACT (contact), NULL);
+
+  priv = GET_PRIV (contact);
+
+  return priv->location;
+}
+
+/**
+ * empathy_contact_set_location:
+ * @contact: the contact
+ * @location: the location
+ *
+ * Sets the user's location based on the location #GHashTable passed.
+ */
+void 
+empathy_contact_set_location (EmpathyContact *contact,
+                              GHashTable *location)
+{
+  EmpathyContactPriv *priv;
+
+  g_return_if_fail (EMPATHY_CONTACT (contact));
+  g_return_if_fail (location != NULL);
+
+  priv = GET_PRIV (contact);
+
+  g_hash_table_unref (priv->location);
+
+  priv->location = g_hash_table_ref (location);
+  g_object_notify (G_OBJECT (contact), "location");
+}
diff --git a/libempathy/empathy-contact.h b/libempathy/empathy-contact.h
index 8b89b39..afc6b18 100644
--- a/libempathy/empathy-contact.h
+++ b/libempathy/empathy-contact.h
@@ -119,6 +119,10 @@ void empathy_avatar_unref (EmpathyAvatar *avatar);
 gboolean empathy_avatar_save_to_file (EmpathyAvatar *avatar,
     const gchar *filename, GError **error);
 
+GHashTable * empathy_contact_get_location (EmpathyContact *contact);
+void empathy_contact_set_location (EmpathyContact *contact,
+  GHashTable *location);
+
 G_END_DECLS
 
 #endif /* __EMPATHY_CONTACT_H__ */
diff --git a/libempathy/empathy-debug.c b/libempathy/empathy-debug.c
index ec72bfc..bcfa25d 100644
--- a/libempathy/empathy-debug.c
+++ b/libempathy/empathy-debug.c
@@ -45,6 +45,7 @@ static GDebugKey keys[] = {
   { "Irc", EMPATHY_DEBUG_IRC },
   { "Dispatcher", EMPATHY_DEBUG_DISPATCHER },
   { "Ft", EMPATHY_DEBUG_FT },
+  { "Location", EMPATHY_DEBUG_LOCATION },
   { "Other", EMPATHY_DEBUG_OTHER },
   { 0, }
 };
diff --git a/libempathy/empathy-debug.h b/libempathy/empathy-debug.h
index 8b68fd2..787264d 100644
--- a/libempathy/empathy-debug.h
+++ b/libempathy/empathy-debug.h
@@ -39,7 +39,8 @@ typedef enum
   EMPATHY_DEBUG_IRC = 1 << 5,
   EMPATHY_DEBUG_DISPATCHER = 1 << 6,
   EMPATHY_DEBUG_FT = 1 << 7,
-  EMPATHY_DEBUG_OTHER = 1 << 8,
+  EMPATHY_DEBUG_LOCATION = 1 << 8,
+  EMPATHY_DEBUG_OTHER = 1 << 9,
 } EmpathyDebugFlags;
 
 gboolean empathy_debug_flag_is_set (EmpathyDebugFlags flag);
diff --git a/libempathy/empathy-location.h b/libempathy/empathy-location.h
new file mode 100644
index 0000000..17b9704
--- /dev/null
+++ b/libempathy/empathy-location.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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.1 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Authors: Pierre-Luc Beaudoin <pierre-luc.beaudoin@collabora.co.uk>
+ */
+
+#ifndef __EMPATHY_LOCATION_H__
+#define __EMPATHY_LOCATION_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define EMPATHY_LOCATION_COUNTRY_CODE "countrycode"
+#define EMPATHY_LOCATION_COUNTRY "country"
+#define EMPATHY_LOCATION_REGION "region"
+#define EMPATHY_LOCATION_LOCALITY "locality"
+#define EMPATHY_LOCATION_AREA "area"
+#define EMPATHY_LOCATION_POSTAL_CODE "postalcode"
+#define EMPATHY_LOCATION_STREET "street"
+#define EMPATHY_LOCATION_BUILDING "building"
+#define EMPATHY_LOCATION_FLOOR "floor"
+#define EMPATHY_LOCATION_ROOM "room"
+#define EMPATHY_LOCATION_TEXT "text"
+#define EMPATHY_LOCATION_DESCRIPTION "description"
+#define EMPATHY_LOCATION_URI "uri"
+#define EMPATHY_LOCATION_LAT "lat"
+#define EMPATHY_LOCATION_LON "lon"
+#define EMPATHY_LOCATION_ALT "alt"
+#define EMPATHY_LOCATION_ACCURACY "accuracy"
+#define EMPATHY_LOCATION_ACCURACY_LEVEL "accuracy-level"
+#define EMPATHY_LOCATION_ERROR "error"
+#define EMPATHY_LOCATION_VERTICAL_ERROR_M "vertical-error-m"
+#define EMPATHY_LOCATION_HORIZONTAL_ERROR_M "horizontal-error-m"
+#define EMPATHY_LOCATION_SPEED "speed"
+#define EMPATHY_LOCATION_BEARING "bearing"
+#define EMPATHY_LOCATION_CLIMB "climb"
+#define EMPATHY_LOCATION_TIMESTAMP "timestamp"
+
+G_END_DECLS
+
+#endif /* __EMPATHY_LOCATION_H__ */
diff --git a/libempathy/empathy-tp-contact-factory.c b/libempathy/empathy-tp-contact-factory.c
index 7735b0f..fad4625 100644
--- a/libempathy/empathy-tp-contact-factory.c
+++ b/libempathy/empathy-tp-contact-factory.c
@@ -122,6 +122,17 @@ tp_contact_factory_set_aliases_cb (TpConnection *connection,
 }
 
 static void
+tp_contact_factory_set_location_cb (TpProxy *proxy,
+				    const GError *error,
+				    gpointer user_data,
+				    GObject *weak_object)
+{
+	if (error) {
+		DEBUG ("Error setting location: %s", error->message);
+	}
+}
+
+static void
 tp_contact_factory_set_avatar_cb (TpConnection *connection,
 				  const gchar  *token,
 				  const GError *error,
@@ -304,6 +315,21 @@ tp_contact_factory_avatar_updated_cb (TpConnection *connection,
 }
 
 static void
+tp_contact_factory_update_location (EmpathyTpContactFactory *tp_factory,
+				    guint                    handle,
+				    GHashTable              *location)
+{
+	EmpathyContact      *contact;
+
+	contact = tp_contact_factory_find_by_handle (tp_factory, handle);
+	if (!contact) {
+		return;
+	}
+
+	empathy_contact_set_location (contact, location);
+}
+
+static void
 tp_contact_factory_update_capabilities (EmpathyTpContactFactory *tp_factory,
 					guint                    handle,
 					const gchar             *channel_type,
@@ -380,6 +406,35 @@ tp_contact_factory_got_capabilities (EmpathyTpContactFactory *tp_factory,
 }
 
 static void
+tp_contact_factory_got_locations (EmpathyTpContactFactory *tp_factory,
+				  GHashTable              *locations,
+				  const GError            *error)
+{
+	GHashTableIter iter;
+	gpointer key, value;
+
+	if (error) {
+		DEBUG ("Error: %s", error->message);
+		/* FIXME Should set the capabilities of the contacts for which this request
+		 * originated to NONE */
+		return;
+	}
+
+	g_hash_table_iter_init (&iter, locations);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		/* do something with key and value */
+		guint        handle = GPOINTER_TO_INT (key);
+		GHashTable  *location = value;
+
+		tp_contact_factory_update_location (tp_factory,
+						    handle,
+						    location);
+	}
+
+	g_hash_table_unref (locations);
+}
+
+static void
 tp_contact_factory_capabilities_changed_cb (TpConnection    *connection,
 					    const GPtrArray *capabilities,
 					    gpointer         user_data,
@@ -409,6 +464,36 @@ tp_contact_factory_capabilities_changed_cb (TpConnection    *connection,
 	}
 }
 
+static void 
+update_location_for_each (gpointer key,
+			  gpointer value,
+			  gpointer user_data)
+{
+	GHashTable *location = (GHashTable*) user_data;
+	g_hash_table_insert (location, g_strdup(key), tp_g_value_slice_dup (value));
+}
+
+static void
+tp_contact_factory_location_updated_cb (TpProxy      *proxy,
+					guint         handle,
+					GHashTable   *location,
+					gpointer      user_data,
+					GObject      *weak_object)
+{
+	EmpathyTpContactFactory *tp_factory = EMPATHY_TP_CONTACT_FACTORY (weak_object);
+	EmpathyContact          *contact;
+	GHashTable              *new_location;
+
+	new_location = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+		(GDestroyNotify) tp_g_value_slice_free);
+
+	// Copy keys
+	g_hash_table_foreach (location, update_location_for_each, new_location);
+
+	contact = tp_contact_factory_find_by_handle (tp_factory, handle);
+	empathy_contact_set_location (contact, new_location);
+}
+
 static void
 get_requestable_channel_classes_cb (TpProxy *connection,
 				    const GValue *value,
@@ -507,6 +592,7 @@ tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
 	GArray handles = {(gchar*) &handle, 1};
 	GHashTable *tokens;
 	GPtrArray *capabilities;
+	GHashTable *locations;
 	GError *error = NULL;
 
 	/* Keep a weak ref to that contact */
@@ -554,6 +640,14 @@ tp_contact_factory_add_contact (EmpathyTpContactFactory *tp_factory,
 									&error,
 									NULL);
 	tp_contact_factory_got_capabilities (tp_factory, capabilities, error);
+
+	emp_cli_connection_interface_location_run_get_locations (TP_PROXY (priv->connection),
+								 -1,
+								 &handles,
+								 &locations,
+								 &error,
+								 NULL);
+	tp_contact_factory_got_locations (tp_factory, locations, error);
 	g_clear_error (&error);
 
 	DEBUG ("Contact added: %s (%d)",
@@ -943,6 +1037,24 @@ empathy_tp_contact_factory_set_avatar (EmpathyTpContactFactory *tp_factory,
 	}
 }
 
+void
+empathy_tp_contact_factory_set_location (EmpathyTpContactFactory *tp_factory,
+					 GHashTable              *location)
+{
+	EmpathyTpContactFactoryPriv *priv = GET_PRIV (tp_factory);
+
+	g_return_if_fail (EMPATHY_IS_TP_CONTACT_FACTORY (tp_factory));
+
+	DEBUG ("Setting location");
+
+	emp_cli_connection_interface_location_call_set_location (TP_PROXY (priv->connection),
+								 -1,
+								 location,
+								 tp_contact_factory_set_location_cb,
+								 NULL, NULL,
+								 G_OBJECT (tp_factory));
+}
+
 static void
 tp_contact_factory_get_property (GObject    *object,
 				 guint       param_id,
@@ -1047,7 +1159,11 @@ tp_contact_factory_constructor (GType                  type,
 										  NULL, NULL,
 										  tp_factory,
 										  NULL);
-
+	emp_cli_connection_interface_location_connect_to_location_updated (TP_PROXY (priv->connection),
+									   tp_contact_factory_location_updated_cb,
+									   NULL, NULL,
+									   G_OBJECT (tp_factory),
+									   NULL);
 
 	/* FIXME: This should be moved to TpConnection */
 	tp_cli_connection_interface_avatars_call_get_avatar_requirements (priv->connection,
diff --git a/libempathy/empathy-tp-contact-factory.h b/libempathy/empathy-tp-contact-factory.h
index 91ff2f9..ed11bf7 100644
--- a/libempathy/empathy-tp-contact-factory.h
+++ b/libempathy/empathy-tp-contact-factory.h
@@ -108,7 +108,8 @@ void                     empathy_tp_contact_factory_set_avatar       (EmpathyTpC
 								      const gchar             *data,
 								      gsize                    size,
 								      const gchar             *mime_type);
-
+void                     empathy_tp_contact_factory_set_location     (EmpathyTpContactFactory *tp_factory,
+								      GHashTable              *location);
 G_END_DECLS
 
 #endif /* __EMPATHY_TP_CONTACT_FACTORY_H__ */
diff --git a/src/Makefile.am b/src/Makefile.am
index a49bfc5..2f019b2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,6 +2,8 @@ AM_CPPFLAGS =						\
 	-I$(top_srcdir)                          	\
 	$(EMPATHY_CFLAGS)				\
 	$(LIBNOTIFY_CFLAGS)				\
+	$(LIBCHAMPLAIN_CFLAGS)				\
+	$(GEOCLUE_CFLAGS)				\
 	$(WARN_CFLAGS)
 
 LDADD =								\
@@ -9,7 +11,9 @@ LDADD =								\
 	$(top_builddir)/libempathy/libempathy.la		\
 	$(top_builddir)/extensions/libemp-extensions.la		\
 	$(LIBNOTIFY_LIBS)					\
-	$(EMPATHY_LIBS)
+	$(EMPATHY_LIBS)						\
+	$(LIBCHAMPLAIN_LIBS)					\
+	$(GEOCLUE_LIBS)
 
 bin_PROGRAMS =			\
 	empathy			\
@@ -57,6 +61,18 @@ glade_DATA = 					\
 	empathy-preferences.glade		\
 	empathy-status-icon.glade
 
+if HAVE_LIBCHAMPLAIN
+icondir = $(datadir)/empathy
+icon_DATA = 					\
+	empathy-map-view-marker.svg
+
+empathy_SOURCES += 				\
+	empathy-map-view.c empathy-map-view.h
+
+glade_DATA += 					\
+	empathy-map-view.glade
+endif 
+
 dist_man_MANS =			\
 	empathy.1
 
@@ -80,7 +96,8 @@ dist_man_MANS =			\
 
 EXTRA_DIST =			\
 	$(autostart_DATA)	\
-	$(glade_DATA)
+	$(glade_DATA)		\
+	$(icon_DATA)
 
 CLEANFILES = $(BUILT_SOURCES)
 
diff --git a/src/empathy-main-window.c b/src/empathy-main-window.c
index d37f1a8..db62c6d 100644
--- a/src/empathy-main-window.c
+++ b/src/empathy-main-window.c
@@ -53,6 +53,7 @@
 
 #include "empathy-accounts-dialog.h"
 #include "empathy-main-window.h"
+#include "empathy-map-view.h"
 #include "ephy-spinner.h"
 #include "empathy-preferences.h"
 #include "empathy-about-dialog.h"
@@ -184,6 +185,10 @@ static void     main_window_notify_sort_criterium_cb           (EmpathyConf
 static void     main_window_account_created_or_deleted_cb      (EmpathyAccountManager    *manager,
 								McAccount                *account,
 								EmpathyMainWindow        *window);
+#if HAVE_LIBCHAMPLAIN
+static void     main_window_chat_show_map_cb                   (GtkCheckMenuItem         *item,
+								EmpathyMainWindow        *window);
+#endif
 
 static void
 main_window_flash_stop (EmpathyMainWindow *window)
@@ -500,6 +505,7 @@ empathy_main_window_show (void)
 	GtkWidget                *sw;
 	GtkWidget                *show_offline_widget;
 	GtkWidget                *ebox;
+	GtkWidget                *show_map_widget;
 	GtkToolItem              *item;
 	gboolean                  show_offline;
 	gboolean                  show_avatars;
@@ -524,6 +530,7 @@ empathy_main_window_show (void)
 				       "main_vbox", &window->main_vbox,
 				       "errors_vbox", &window->errors_vbox,
 				       "chat_show_offline", &show_offline_widget,
+				       "chat_show_map", &show_map_widget,
 				       "room", &window->room,
 				       "room_sep", &window->room_sep,
 				       "room_join_favorites", &window->room_join_favorites,
@@ -547,6 +554,9 @@ empathy_main_window_show (void)
 			      "room_manage_favorites", "activate", main_window_room_manage_favorites_cb,
 			      "chat_add_contact", "activate", main_window_chat_add_contact_cb,
 			      "chat_show_offline", "toggled", main_window_chat_show_offline_cb,
+#if HAVE_LIBCHAMPLAIN
+			      "chat_show_map", "activate", main_window_chat_show_map_cb,
+#endif
 			      "edit", "button-press-event", main_window_edit_button_press_event_cb,
 			      "edit_accounts", "activate", main_window_edit_accounts_cb,
 			      "edit_personal_information", "activate", main_window_edit_personal_information_cb,
@@ -577,6 +587,9 @@ empathy_main_window_show (void)
 	gtk_widget_hide (window->edit_context);
 	gtk_widget_hide (window->edit_context_separator);
 
+#if !HAVE_LIBCHAMPLAIN
+	gtk_widget_hide (show_map_widget);
+#endif 
 	/* Set up presence chooser */
 	window->presence_chooser = empathy_presence_chooser_new ();
 	gtk_widget_show (window->presence_chooser);
@@ -950,6 +963,15 @@ main_window_chat_show_offline_cb (GtkCheckMenuItem  *item,
 	//empathy_sound_set_enabled (TRUE);
 }
 
+#if HAVE_LIBCHAMPLAIN
+static void
+main_window_chat_show_map_cb (GtkCheckMenuItem  *item,
+			      EmpathyMainWindow *window)
+{
+	empathy_map_view_show ();
+}
+#endif 
+
 static gboolean
 main_window_edit_button_press_event_cb (GtkWidget         *widget,
 					GdkEventButton    *event,
diff --git a/src/empathy-main-window.glade b/src/empathy-main-window.glade
index 737105d..0097767 100644
--- a/src/empathy-main-window.glade
+++ b/src/empathy-main-window.glade
@@ -51,6 +51,14 @@
                       </widget>
                     </child>
                     <child>
+                      <widget class="GtkImageMenuItem" id="chat_show_map">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">Show Contacts _Map</property>
+                        <property name="use_underline">True</property>
+                        <accelerator key="M" modifiers="GDK_CONTROL_MASK" signal="activate"/>
+                      </widget>
+                    </child>
+                    <child>
                       <widget class="GtkSeparatorMenuItem" id="separator5">
                         <property name="visible">True</property>
                       </widget>
diff --git a/src/empathy-map-view-marker.svg b/src/empathy-map-view-marker.svg
new file mode 100644
index 0000000..8a22432
--- /dev/null
+++ b/src/empathy-map-view-marker.svg
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="75"
+   height="50"
+   id="svg2"
+   sodipodi:version="0.32"
+   inkscape:version="0.46"
+   version="1.0"
+   sodipodi:docname="empathy-map-view-marker.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape">
+  <defs
+     id="defs4">
+    <linearGradient
+       inkscape:collect="always"
+       id="linearGradient3153">
+      <stop
+         style="stop-color:#6c6c6c;stop-opacity:1"
+         offset="0"
+         id="stop3155" />
+      <stop
+         style="stop-color:#bdbdbd;stop-opacity:1"
+         offset="1"
+         id="stop3157" />
+    </linearGradient>
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <filter
+       inkscape:collect="always"
+       id="filter3208"
+       x="-0.05052691"
+       width="1.1010538"
+       y="-0.14783885"
+       height="1.2956777">
+      <feGaussianBlur
+         inkscape:collect="always"
+         stdDeviation="8.6187787"
+         id="feGaussianBlur3210" />
+    </filter>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#linearGradient3153"
+       id="linearGradient3159"
+       x1="35.099094"
+       y1="41.50539"
+       x2="3.8490961"
+       y2="2.2553883"
+       gradientUnits="userSpaceOnUse" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     gridtolerance="10000"
+     guidetolerance="10"
+     objecttolerance="10"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.4142136"
+     inkscape:cx="23.050276"
+     inkscape:cy="0.071432203"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="false"
+     inkscape:window-width="1440"
+     inkscape:window-height="827"
+     inkscape:window-x="0"
+     inkscape:window-y="25" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <path
+       style="fill:url(#linearGradient3159);fill-opacity:1;stroke:#6c6c6c;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="M 4.09476,1.124408 C 2.473741,1.124408 1.171355,2.426796 1.171355,4.047814 L 1.171355,37.702134 C 1.171355,39.323154 2.473742,40.630163 4.09476,40.630158 L 11.502568,40.630158 L 20.893471,48.802311 C 21.451193,49.360033 22.195233,49.3359 22.697572,48.833561 L 31.744726,40.630158 L 39.147916,40.630158 C 40.768934,40.630158 42.075943,39.323152 42.075939,37.702134 L 42.075939,4.047814 C 42.075939,2.426795 40.768933,1.124408 39.147916,1.124408 L 4.09476,1.124408 z"
+       id="rect2383"
+       sodipodi:nodetypes="ccccccccccccc" />
+    <path
+       style="fill:#787878;fill-opacity:0.20276495;filter:url(#filter3208)"
+       d="M 222.78161,195.28963 C 211.81297,194.95482 197.91239,198.42398 191.57965,203.07667 L 65.13994,295.97236 C 58.8072,300.62505 62.51379,304.64546 73.48244,304.98025 L 123.60744,306.51027 L 148.31924,333.09631 C 150.6655,335.62052 159.59415,335.89306 168.35049,333.70774 L 260.57619,310.69109 L 310.66994,312.22015 C 321.63858,312.55496 335.58848,309.07351 341.92119,304.42082 L 468.3609,211.52512 C 474.69365,206.87243 470.93774,202.86434 459.96911,202.52953 L 222.78161,195.28963 z"
+       id="path3186"
+       transform="matrix(0.1477867,0,0,0.1477867,-0.980789,0.501454)" />
+  </g>
+</svg>
diff --git a/src/empathy-map-view.c b/src/empathy-map-view.c
new file mode 100644
index 0000000..968f1f2
--- /dev/null
+++ b/src/empathy-map-view.c
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
+ */
+
+#include <config.h>
+
+#include <sys/stat.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+#include <glib/gi18n.h>
+
+#include <champlain/champlain.h>
+#include <champlain-gtk/champlain-gtk.h>
+#include <clutter-gtk/gtk-clutter-embed.h>
+#include <geoclue/geoclue-geocode.h>
+#include <telepathy-glib/util.h>
+
+#include <libempathy/empathy-contact.h>
+#include <libempathy/empathy-utils.h>
+#include <libempathy/empathy-chatroom-manager.h>
+#include <libempathy/empathy-chatroom.h>
+#include <libempathy/empathy-contact-list.h>
+#include <libempathy/empathy-contact-manager.h>
+#include <libempathy/empathy-contact-factory.h>
+#include <libempathy/empathy-location.h>
+#include <libempathy/empathy-status-presets.h>
+
+#include <libempathy-gtk/empathy-contact-dialogs.h>
+#include <libempathy-gtk/empathy-contact-list-store.h>
+#include <libempathy-gtk/empathy-contact-list-view.h>
+#include <libempathy-gtk/empathy-presence-chooser.h>
+#include <libempathy-gtk/empathy-ui-utils.h>
+#include <libempathy-gtk/empathy-geometry.h>
+#include <libempathy-gtk/empathy-conf.h>
+#include <libempathy-gtk/empathy-log-window.h>
+#include <libempathy-gtk/empathy-new-message-dialog.h>
+#include <libempathy-gtk/empathy-gtk-enum-types.h>
+
+#include "empathy-accounts-dialog.h"
+#include "empathy-map-view.h"
+#include "ephy-spinner.h"
+#include "empathy-preferences.h"
+#include "empathy-about-dialog.h"
+#include "empathy-new-chatroom-dialog.h"
+#include "empathy-chatrooms-window.h"
+#include "empathy-event-manager.h"
+
+#define DEBUG_FLAG EMPATHY_DEBUG_LOCATION
+#include <libempathy/empathy-debug.h>
+
+typedef struct {
+  EmpathyContactListStore *list_store;
+
+  GtkWidget *window;
+  GtkWidget *zoom_in;
+  GtkWidget *zoom_out;
+  ChamplainView *map_view;
+  ChamplainLayer *layer;
+
+} EmpathyMapView;
+
+static void map_view_destroy_cb (GtkWidget *widget,
+    EmpathyMapView *window);
+static gboolean map_view_contacts_foreach (GtkTreeModel *model,
+    GtkTreePath *path, GtkTreeIter *iter, gpointer user_data);
+static gboolean map_view_contacts_foreach_disconnect (GtkTreeModel *model,
+    GtkTreePath *path, GtkTreeIter *iter, gpointer user_data);
+static void map_view_zoom_in_cb (GtkWidget *widget, EmpathyMapView *window);
+static void map_view_zoom_out_cb (GtkWidget *widget, EmpathyMapView *window);
+static void map_view_contact_location_notify (GObject *gobject,
+    GParamSpec *arg1, gpointer user_data);
+static gchar * get_dup_string (GHashTable *location, gchar *key);
+
+// FIXME: Make it so that only one window can be shown
+GtkWidget *
+empathy_map_view_show ()
+{
+  static EmpathyMapView *window = NULL;
+  GladeXML *glade;
+  GtkWidget *sw;
+  GtkWidget *embed;
+  gchar *filename;
+  GtkTreeModel *model;
+  EmpathyContactList *list_iface;
+  EmpathyContactListStore *list_store;
+
+  /*
+  if (window)
+    {
+      empathy_window_present (GTK_WINDOW (window->window), TRUE);
+      return window->window;
+    }
+  */
+
+  window = g_new0 (EmpathyMapView, 1);
+
+  /* Set up interface */
+  filename = empathy_file_lookup ("empathy-map-view.glade", "src");
+  glade = empathy_glade_get_file (filename, "map_view", NULL, "map_view",
+      &window->window, "zoom_in", &window->zoom_in, "zoom_out",
+      &window->zoom_out, "map_scrolledwindow", &sw, NULL);
+  g_free (filename);
+
+  empathy_glade_connect (glade, window, "map_view", "destroy",
+      map_view_destroy_cb, "zoom_in", "clicked", map_view_zoom_in_cb,
+      "zoom_out", "clicked", map_view_zoom_out_cb, NULL);
+
+  g_object_unref (glade);
+
+  list_iface = EMPATHY_CONTACT_LIST (empathy_contact_manager_dup_singleton ());
+  list_store = empathy_contact_list_store_new (list_iface);
+  g_object_unref (list_iface);
+
+  window->list_store = list_store;
+
+  /* Set up map view */
+  window->map_view = CHAMPLAIN_VIEW (champlain_view_new (
+      CHAMPLAIN_VIEW_MODE_KINETIC));
+  g_object_set (G_OBJECT (window->map_view), "zoom-level", 1, NULL);
+  champlain_view_center_on (window->map_view, 36, 0);
+
+  embed = champlain_view_embed_new (window->map_view);
+  gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw),
+     GTK_WIDGET (embed));
+  gtk_widget_show_all (embed);
+
+  window->layer = champlain_layer_new ();
+  champlain_view_add_layer (CHAMPLAIN_VIEW (window->map_view), window->layer);
+
+  /* Set up contact list. */
+  model = GTK_TREE_MODEL (window->list_store);
+  gtk_tree_model_foreach (model, map_view_contacts_foreach, window);
+
+  empathy_window_present (GTK_WINDOW (window->window), TRUE);
+  return window->window;
+}
+
+static gboolean
+map_view_contacts_foreach_disconnect (GtkTreeModel *model,
+                                      GtkTreePath *path,
+                                      GtkTreeIter *iter,
+                                      gpointer user_data)
+{
+  EmpathyContact *contact;
+  guint handle_id;
+
+  gtk_tree_model_get (model, iter, EMPATHY_CONTACT_LIST_STORE_COL_CONTACT,
+     &contact, -1);
+  if (!contact)
+    return FALSE;
+
+  handle_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (contact), "map-view-handle"));
+  if (handle_id > 0)
+    g_signal_handler_disconnect (contact, handle_id);
+
+  return FALSE;
+}
+
+static void
+map_view_destroy_cb (GtkWidget *widget,
+                     EmpathyMapView *window)
+{
+  GtkTreeModel *model;
+
+  /* Set up contact list. */
+  model = GTK_TREE_MODEL (window->list_store);
+  gtk_tree_model_foreach (model, map_view_contacts_foreach_disconnect, window);
+  g_object_unref (window->list_store);
+  g_free (window);
+}
+
+#define GEOCODE_SERVICE "org.freedesktop.Geoclue.Providers.Yahoo"
+#define GEOCODE_PATH "/org/freedesktop/Geoclue/Providers/Yahoo"
+
+static void
+map_view_geocode_cb (GeoclueGeocode *geocode,
+                     GeocluePositionFields fields,
+                     double latitude,
+                     double longitude,
+                     double altitude,
+                     GeoclueAccuracy *accuracy,
+                     GError *error,
+                     gpointer userdata)
+{
+  GValue *new_value;
+  gboolean found = FALSE;
+  GHashTable *location = empathy_contact_get_location (EMPATHY_CONTACT (userdata));
+  g_hash_table_ref (location);
+
+  if (error)
+  {
+      return;
+  }
+
+  if (fields & GEOCLUE_POSITION_FIELDS_LONGITUDE)
+    {
+      new_value = tp_g_value_slice_new (G_TYPE_DOUBLE);
+      g_value_set_double (new_value, longitude);
+      g_hash_table_replace (location, EMPATHY_LOCATION_LON, new_value);
+      DEBUG ("\t - Longitude: %f", longitude);
+    }
+  if (fields & GEOCLUE_POSITION_FIELDS_LATITUDE)
+    {
+      new_value = tp_g_value_slice_new (G_TYPE_DOUBLE);
+      g_value_set_double (new_value, latitude);
+      g_hash_table_replace (location, EMPATHY_LOCATION_LAT, new_value);
+      DEBUG ("\t - Latitude: %f", latitude);
+      found = TRUE;
+    }
+  if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE)
+    {
+      new_value = tp_g_value_slice_new (G_TYPE_DOUBLE);
+      g_value_set_double (new_value, altitude);
+      g_hash_table_replace (location, EMPATHY_LOCATION_ALT, new_value);
+      DEBUG ("\t - Altitude: %f", altitude);
+    }
+
+  //Don't change the accuracy as we used an address to get this position
+  if (found)
+    empathy_contact_set_location (EMPATHY_CONTACT (userdata), location);
+  g_hash_table_unref (location);
+}
+
+
+static gchar *
+get_dup_string (GHashTable *location, gchar *key)
+{
+  GValue *value;
+
+  value = g_hash_table_lookup (location, key);
+  if (value)
+  {
+      return g_value_dup_string (value);
+  }
+  return NULL;
+
+}
+
+static void
+map_view_marker_update (ChamplainMarker *marker,
+                        EmpathyContact *contact)
+{
+  gdouble lon, lat;
+  GValue *value;
+  GHashTable *location = empathy_contact_get_location (contact);
+
+  if (g_hash_table_size (location) == 0)
+  {
+    clutter_actor_hide (CLUTTER_ACTOR (marker));
+    return;
+  }
+
+  value = g_hash_table_lookup (location, EMPATHY_LOCATION_LAT);
+  if (value == NULL)
+    {
+      GeoclueGeocode * geocode = geoclue_geocode_new (GEOCODE_SERVICE,
+          GEOCODE_PATH);
+      gchar *str;
+
+      GHashTable *address = geoclue_address_details_new();
+      str = get_dup_string (location, EMPATHY_LOCATION_COUNTRY);
+      if (str != NULL)
+        g_hash_table_insert (address, g_strdup ("country"), str);
+
+      str = get_dup_string (location, EMPATHY_LOCATION_POSTAL_CODE);
+      if (str != NULL)
+        g_hash_table_insert (address, g_strdup ("postalcode"), str);
+
+      str = get_dup_string (location, EMPATHY_LOCATION_LOCALITY);
+      if (str != NULL)
+        g_hash_table_insert (address, g_strdup ("locality"), str);
+
+      str = get_dup_string (location, EMPATHY_LOCATION_STREET);
+      if (str != NULL)
+        g_hash_table_insert (address, g_strdup ("street"), str);
+
+      geoclue_geocode_address_to_position_async (geocode, address,
+          map_view_geocode_cb, contact);
+      clutter_actor_hide (CLUTTER_ACTOR (marker));
+      return;
+    }
+  lat = g_value_get_double (value);
+
+  value = g_hash_table_lookup (location, EMPATHY_LOCATION_LON);
+  if (value == NULL)
+    return;
+  lon = g_value_get_double (value);
+
+  clutter_actor_show (CLUTTER_ACTOR (marker));
+  champlain_marker_set_position (marker, lat, lon);
+}
+
+
+static void
+map_view_contact_location_notify (GObject *gobject,
+                                  GParamSpec *arg1,
+                                  gpointer user_data)
+{
+  ChamplainMarker *marker = CHAMPLAIN_MARKER (user_data);
+  EmpathyContact *contact = EMPATHY_CONTACT (gobject);
+  map_view_marker_update (marker, contact);
+}
+
+
+static gboolean
+map_view_contacts_foreach (GtkTreeModel *model,
+                           GtkTreePath *path,
+                           GtkTreeIter *iter,
+                           gpointer user_data)
+{
+  EmpathyMapView *window = (EmpathyMapView*) user_data;
+  EmpathyContact *contact;
+  ClutterActor *marker;
+  ClutterActor *texture;
+  ClutterActor *background;
+  GdkPixbuf *avatar;
+  gchar *filename;
+  guint handle_id;
+
+  gtk_tree_model_get (model, iter, EMPATHY_CONTACT_LIST_STORE_COL_CONTACT,
+     &contact, -1);
+  if (!contact)
+    return FALSE;
+
+  marker = champlain_marker_new ();
+
+  handle_id = g_signal_connect (contact, "notify::location",
+      G_CALLBACK (map_view_contact_location_notify), marker);
+  g_object_set_data (G_OBJECT (contact), "map-view-handle",
+      GINT_TO_POINTER (handle_id));
+
+
+  filename = empathy_file_lookup ("empathy-map-view-marker.svg", "src");
+  background = clutter_texture_new_from_file (filename, NULL);
+  clutter_container_add (CLUTTER_CONTAINER (marker), background, NULL);
+
+  avatar = empathy_pixbuf_avatar_from_contact_scaled (contact, 32, 32);
+  if (avatar)
+    {
+      texture = clutter_texture_new ();
+      gtk_clutter_texture_set_from_pixbuf (CLUTTER_TEXTURE (texture), avatar);
+      clutter_actor_set_position (CLUTTER_ACTOR (texture), 5, 5);
+      clutter_container_add (CLUTTER_CONTAINER (marker), texture, NULL);
+    }
+
+  clutter_actor_set_anchor_point (marker, 25, 50);
+  map_view_marker_update (CHAMPLAIN_MARKER (marker), contact);
+
+  clutter_container_add (CLUTTER_CONTAINER (window->layer), marker, NULL);
+
+  g_object_unref (contact);
+  return FALSE;
+}
+
+
+static void
+map_view_zoom_in_cb (GtkWidget *widget,
+                     EmpathyMapView *window)
+{
+  champlain_view_zoom_in (window->map_view);
+}
+
+
+static void
+map_view_zoom_out_cb (GtkWidget *widget,
+                      EmpathyMapView *window)
+{
+  champlain_view_zoom_out (window->map_view);
+}
diff --git a/src/empathy-map-view.glade b/src/empathy-map-view.glade
new file mode 100644
index 0000000..572d1ac
--- /dev/null
+++ b/src/empathy-map-view.glade
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+  <widget class="GtkWindow" id="map_view">
+    <property name="title" translatable="yes">Contact Map View</property>
+    <property name="role">map_view</property>
+    <property name="window_position">GTK_WIN_POS_CENTER</property>
+    <property name="default_width">512</property>
+    <property name="default_height">384</property>
+    <child>
+      <widget class="GtkVBox" id="main_vbox">
+        <property name="visible">True</property>
+        <child>
+          <widget class="GtkToolbar" id="toolbar">
+            <property name="visible">True</property>
+            <child>
+              <widget class="GtkToolButton" id="zoom_in">
+                <property name="visible">True</property>
+                <property name="stock_id">gtk-zoom-in</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkToolButton" id="zoom_out">
+                <property name="visible">True</property>
+                <property name="stock_id">gtk-zoom-out</property>
+              </widget>
+              <packing>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkScrolledWindow" id="map_scrolledwindow">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="has_focus">True</property>
+            <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+            <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+            <property name="shadow_type">GTK_SHADOW_IN</property>
+            <child>
+              <placeholder/>
+            </child>
+          </widget>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>
diff --git a/src/empathy-map-view.h b/src/empathy-map-view.h
new file mode 100644
index 0000000..45ecbdd
--- /dev/null
+++ b/src/empathy-map-view.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 Collabora Ltd.
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors: Pierre-Luc Beaudoin <pierre-luc@pierlux.com>
+ */
+
+#ifndef __EMPATHY_MAP_VIEW_H__
+#define __EMPATHY_MAP_VIEW_H__
+
+#include <gtk/gtkwidget.h>
+
+G_BEGIN_DECLS
+
+GtkWidget *empathy_map_view_show (void);
+
+G_END_DECLS
+
+#endif /* __EMPATHY_MAP_VIEW_H__ */
diff --git a/src/empathy-preferences.c b/src/empathy-preferences.c
index 0ad8e9b..95a84ff 100644
--- a/src/empathy-preferences.c
+++ b/src/empathy-preferences.c
@@ -65,6 +65,15 @@ typedef struct {
 
 	GtkWidget *treeview_spell_checker;
 
+	GtkWidget *checkbutton_publish_location;
+	GtkWidget *radiobutton_location_method_automatic;
+	GtkWidget *radiobutton_location_method_manual;
+	GtkWidget *checkbutton_location_method_automatic_network;
+	GtkWidget *checkbutton_location_method_automatic_cell;
+	GtkWidget *checkbutton_location_method_automatic_gps;
+	GtkWidget *button_location_method_manual;
+	GtkWidget *checkbutton_location_reduce_accuracy;
+
 	GList     *notify_ids;
 } EmpathyPreferences;
 
@@ -248,6 +257,49 @@ preferences_setup_widgets (EmpathyPreferences *preferences)
 					  EMPATHY_PREFS_AUTOCONNECT,
 					  preferences->checkbutton_autoconnect);
 
+	preferences_hookup_toggle_button (preferences,
+					  EMPATHY_PREFS_LOCATION_PUBLISH,
+					  preferences->checkbutton_publish_location);
+
+	preferences_hookup_radio_button (preferences,
+					 EMPATHY_PREFS_LOCATION_METHOD,
+					 preferences->radiobutton_location_method_automatic);
+	preferences_hookup_sensitivity (preferences,
+					EMPATHY_PREFS_LOCATION_PUBLISH,
+					preferences->radiobutton_location_method_automatic);
+
+	preferences_hookup_toggle_button (preferences,
+					  EMPATHY_PREFS_LOCATION_RESOURCE_NETWORK,
+					  preferences->checkbutton_location_method_automatic_network);
+	preferences_hookup_sensitivity (preferences,
+					EMPATHY_PREFS_LOCATION_PUBLISH,
+					preferences->checkbutton_location_method_automatic_network);
+
+	preferences_hookup_toggle_button (preferences,
+					  EMPATHY_PREFS_LOCATION_RESOURCE_CELL,
+					  preferences->checkbutton_location_method_automatic_cell);
+	preferences_hookup_sensitivity (preferences,
+					EMPATHY_PREFS_LOCATION_PUBLISH,
+					preferences->checkbutton_location_method_automatic_cell);
+
+	preferences_hookup_toggle_button (preferences,
+					  EMPATHY_PREFS_LOCATION_RESOURCE_GPS,
+					  preferences->checkbutton_location_method_automatic_gps);
+	preferences_hookup_sensitivity (preferences,
+					EMPATHY_PREFS_LOCATION_PUBLISH,
+					preferences->checkbutton_location_method_automatic_gps);
+
+	preferences_hookup_toggle_button (preferences,
+					  EMPATHY_PREFS_LOCATION_REDUCE_ACCURACY,
+					  preferences->checkbutton_location_reduce_accuracy);
+	preferences_hookup_sensitivity (preferences,
+					EMPATHY_PREFS_LOCATION_PUBLISH,
+					preferences->checkbutton_location_reduce_accuracy);
+
+	preferences_hookup_sensitivity (preferences,
+					EMPATHY_PREFS_LOCATION_PUBLISH,
+					preferences->radiobutton_location_method_manual);
+	
 	id = empathy_conf_notify_add (empathy_conf_get (),
 				      EMPATHY_PREFS_UI_COMPACT_CONTACT_LIST,
 				      preferences_compact_contact_list_changed_cb,
@@ -646,25 +698,33 @@ preferences_widget_sync_string (const gchar *key, GtkWidget *widget)
 		if (GTK_IS_ENTRY (widget)) {
 			gtk_entry_set_text (GTK_ENTRY (widget), value);
 		} else if (GTK_IS_RADIO_BUTTON (widget)) {
-			if (strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
-				GType        type;
-				GEnumClass  *enum_class;
-				GEnumValue  *enum_value;
-				GSList      *list;
-				GtkWidget   *toggle_widget;
-				
-				/* Get index from new string */
+			GType        type;
+			GTypeClass  *type_class;
+			GEnumClass  *enum_class;
+			GEnumValue  *enum_value;
+			GSList      *list;
+			GtkWidget   *toggle_widget;
+
+			if (strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0)
 				type = empathy_contact_list_store_sort_get_type ();
-				enum_class = G_ENUM_CLASS (g_type_class_peek (type));
-				enum_value = g_enum_get_value_by_nick (enum_class, value);
-				
-				if (enum_value) { 
-					list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
-					toggle_widget = g_slist_nth_data (list, enum_value->value);
-					gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_widget), TRUE);
-				}
-			} else {
+			else if (strcmp (key, EMPATHY_PREFS_LOCATION_METHOD) == 0)
+				type = EMPATHY_TYPE_LOCATION_MANAGER_METHOD;
+			else {
 				g_warning ("Unhandled key:'%s' just had string change", key);
+				g_free (value);
+				return;
+			}
+
+			/* Get index from new string */
+			type_class = g_type_class_ref (type);
+			enum_class = G_ENUM_CLASS (type_class);
+			enum_value = g_enum_get_value_by_nick (enum_class, value);
+			g_type_class_unref (type_class);
+
+			if (enum_value) {
+				list = gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget));
+				toggle_widget = g_slist_nth_data (list, enum_value->value);
+				gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle_widget), TRUE);
 			}
 		}
 
@@ -975,35 +1035,42 @@ preferences_radio_button_toggled_cb (GtkWidget *button,
 {
 	const gchar *key;
 	const gchar *value = NULL;
+	GSList      *group;
+	GType        type;
+	GTypeClass  *type_class;
+	GEnumClass  *enum_class;
+	GEnumValue  *enum_value;
 
-	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
+	if (!gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
 		return;
-	}
 
 	key = g_object_get_data (G_OBJECT (button), "key");
 
-	if (key && strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0) {
-		GSList      *group;
-		GType        type;
-		GEnumClass  *enum_class;
-		GEnumValue  *enum_value;
-		
-		group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
-		
-		/* Get string from index */
+	if (key && strcmp (key, EMPATHY_PREFS_CONTACTS_SORT_CRITERIUM) == 0)
 		type = empathy_contact_list_store_sort_get_type ();
-		enum_class = G_ENUM_CLASS (g_type_class_peek (type));
-		enum_value = g_enum_get_value (enum_class, g_slist_index (group, button));
-		
-		if (!enum_value) {
-			g_warning ("No GEnumValue for EmpathyContactListSort with GtkRadioButton index:%d", 
-				   g_slist_index (group, button));
-			return;
-		}
+	else if (key && strcmp (key, EMPATHY_PREFS_LOCATION_METHOD) == 0)
+		type = EMPATHY_TYPE_LOCATION_MANAGER_METHOD;
+	else {
+		g_warning ("Unsupported type");
+		return;
+	}
 
-		value = enum_value->value_nick;
+	group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
+
+	/* Get string from index */
+	type_class = g_type_class_ref (type);
+	enum_class = G_ENUM_CLASS (type_class);
+	enum_value = g_enum_get_value (enum_class, g_slist_index (group, button));
+	g_type_class_unref (type_class);
+	
+	if (!enum_value) {
+		g_warning ("No GEnumValue with index:%d",
+			   g_slist_index (group, button));
+		return;
 	}
 
+	value = enum_value->value_nick;
+
 	empathy_conf_set_string (empathy_conf_get (), key, value);
 }
 
@@ -1089,6 +1156,14 @@ empathy_preferences_show (GtkWindow *parent)
 		"checkbutton_sounds_disabled_away", &preferences->checkbutton_sounds_disabled_away,
 		"treeview_sounds", &preferences->treeview_sounds,
 		"treeview_spell_checker", &preferences->treeview_spell_checker,
+		"checkbutton_publish_location", &preferences->checkbutton_publish_location,
+		"radiobutton_location_method_automatic", &preferences->radiobutton_location_method_automatic,
+		"radiobutton_location_method_manual", &preferences->radiobutton_location_method_manual,
+		"checkbutton_location_method_automatic_network", &preferences->checkbutton_location_method_automatic_network,
+		"checkbutton_location_method_automatic_cell", &preferences->checkbutton_location_method_automatic_cell,
+		"checkbutton_location_method_automatic_gps", &preferences->checkbutton_location_method_automatic_gps,
+		"button_location_method_manual", &preferences->button_location_method_manual,
+		"checkbutton_location_reduce_accuracy", &preferences->checkbutton_location_reduce_accuracy,
 		NULL);
 	g_free (filename);
 
@@ -1120,6 +1195,15 @@ empathy_preferences_show (GtkWindow *parent)
 		gtk_widget_show (page);
 	}
 
+#if HAVE_GEOCLUE
+	{
+		GtkWidget *page;
+
+		page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (preferences->notebook), 5);
+		gtk_widget_show (page);
+	}
+#endif
+
 	if (parent) {
 		gtk_window_set_transient_for (GTK_WINDOW (preferences->dialog),
 					      GTK_WINDOW (parent));
diff --git a/src/empathy-preferences.glade b/src/empathy-preferences.glade
index c7c5ace..fe483a7 100644
--- a/src/empathy-preferences.glade
+++ b/src/empathy-preferences.glade
@@ -621,6 +621,258 @@
                 <property name="tab_fill">False</property>
               </packing>
             </child>
+            <child>
+              <widget class="GtkVBox" id="vbox1">
+                <property name="border_width">12</property>
+                <property name="spacing">18</property>
+                <child>
+                  <widget class="GtkFrame" id="frame1">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_NONE</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment1">
+                        <property name="visible">True</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkCheckButton" id="checkbutton_publish_location">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="label" translatable="yes">_Publish location to contacts</property>
+                            <property name="use_underline">True</property>
+                            <property name="response_id">0</property>
+                            <property name="draw_indicator">True</property>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label1">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Location&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkFrame" id="frame8">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_NONE</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment3">
+                        <property name="visible">True</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox4">
+                            <property name="visible">True</property>
+                            <child>
+                              <widget class="GtkRadioButton" id="radiobutton_location_method_automatic">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">_Automatic</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="active">True</property>
+                                <property name="draw_indicator">True</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkAlignment" id="alignment4">
+                                <property name="visible">True</property>
+                                <property name="left_padding">18</property>
+                                <child>
+                                  <widget class="GtkVBox" id="vbox5">
+                                    <property name="visible">True</property>
+                                    <child>
+                                      <widget class="GtkCheckButton" id="checkbutton_location_method_automatic_network">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="label" translatable="yes">Use network</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="response_id">0</property>
+                                        <property name="active">True</property>
+                                        <property name="draw_indicator">True</property>
+                                      </widget>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <widget class="GtkCheckButton" id="checkbutton_location_method_automatic_cell">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="label" translatable="yes">Use cellphone (if available)</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="response_id">0</property>
+                                        <property name="active">True</property>
+                                        <property name="draw_indicator">True</property>
+                                      </widget>
+                                      <packing>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <widget class="GtkCheckButton" id="checkbutton_location_method_automatic_gps">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="label" translatable="yes">Use GPS (if available)</property>
+                                        <property name="use_underline">True</property>
+                                        <property name="response_id">0</property>
+                                        <property name="active">True</property>
+                                        <property name="draw_indicator">True</property>
+                                      </widget>
+                                      <packing>
+                                        <property name="position">2</property>
+                                      </packing>
+                                    </child>
+                                  </widget>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <widget class="GtkHBox" id="hbox1">
+                                <property name="spacing">12</property>
+                                <child>
+                                  <widget class="GtkRadioButton" id="radiobutton_location_method_manual">
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="label" translatable="yes">_Manual</property>
+                                    <property name="use_underline">True</property>
+                                    <property name="response_id">0</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">radiobutton_location_method_automatic</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <widget class="GtkButton" id="button_location_method_manual">
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="label" translatable="yes">gtk-edit</property>
+                                    <property name="use_stock">True</property>
+                                    <property name="response_id">0</property>
+                                  </widget>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </widget>
+                              <packing>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Location Determination Method&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkFrame" id="frame2">
+                    <property name="visible">True</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">GTK_SHADOW_NONE</property>
+                    <child>
+                      <widget class="GtkAlignment" id="alignment2">
+                        <property name="visible">True</property>
+                        <property name="top_padding">6</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <widget class="GtkVBox" id="vbox3">
+                            <property name="visible">True</property>
+                            <child>
+                              <widget class="GtkCheckButton" id="checkbutton_location_reduce_accuracy">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="label" translatable="yes">Reduce location accuracy</property>
+                                <property name="use_underline">True</property>
+                                <property name="response_id">0</property>
+                                <property name="draw_indicator">True</property>
+                              </widget>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                              </packing>
+                            </child>
+                          </widget>
+                        </child>
+                      </widget>
+                    </child>
+                    <child>
+                      <widget class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Privacy&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </widget>
+                      <packing>
+                        <property name="type">label_item</property>
+                      </packing>
+                    </child>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+              </widget>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Location</property>
+              </widget>
+              <packing>
+                <property name="type">tab</property>
+                <property name="position">4</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
           </widget>
           <packing>
             <property name="position">1</property>
diff --git a/src/empathy.c b/src/empathy.c
index 817b9bc..588fe1b 100644
--- a/src/empathy.c
+++ b/src/empathy.c
@@ -31,6 +31,10 @@
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 
+#if HAVE_LIBCHAMPLAIN
+#include <clutter-gtk/gtk-clutter-embed.h>
+#endif
+
 #include <libebook/e-book.h>
 #include <libnotify/notify.h>
 
@@ -51,6 +55,7 @@
 
 #include <libempathy-gtk/empathy-conf.h>
 #include <libempathy-gtk/empathy-ui-utils.h>
+#include <libempathy-gtk/empathy-location-manager.h>
 
 #include "empathy-accounts-dialog.h"
 #include "empathy-main-window.h"
@@ -417,6 +422,9 @@ int
 main (int argc, char *argv[])
 {
 	guint32            startup_timestamp;
+#if HAVE_GEOCLUE
+	EmpathyLocationManager *location_manager = NULL;
+#endif
 	EmpathyStatusIcon *icon;
 	EmpathyDispatcher *dispatcher;
 	EmpathyLogManager *log_manager;
@@ -466,6 +474,10 @@ main (int argc, char *argv[])
 
 	gst_init (&argc, &argv);
 
+#if HAVE_LIBCHAMPLAIN
+	gtk_clutter_init(&argc, &argv);
+#endif
+
 	gtk_window_set_default_icon_name ("empathy");
 	textdomain (GETTEXT_PACKAGE);
 
@@ -573,6 +585,11 @@ main (int argc, char *argv[])
 	g_signal_connect (G_OBJECT (call_factory), "new-call-handler",
 		G_CALLBACK (new_call_handler_cb), NULL);
 
+	/* Location mananger */
+#if HAVE_GEOCLUE
+	location_manager = empathy_location_manager_get_default ();
+#endif
+
 	gtk_main ();
 
 	empathy_idle_set_state (idle, MC_PRESENCE_OFFLINE);
@@ -584,6 +601,9 @@ main (int argc, char *argv[])
 	g_object_unref (dispatcher);
 	g_object_unref (chatroom_manager);
 	g_object_unref (ft_manager);
+#if HAVE_GEOCLUE
+	g_object_unref (location_manager);
+#endif
 
 	notify_uninit ();
 
