diff --git a/apps/contacts/ajax/contact/addproperty.php b/apps/contacts/ajax/contact/addproperty.php
index 1412cad1cbc53b5c3f80874339e4eb1b2eb819e8..0447950fbddba573964357e586e9b76e16cde6be 100644
--- a/apps/contacts/ajax/contact/addproperty.php
+++ b/apps/contacts/ajax/contact/addproperty.php
@@ -108,7 +108,17 @@ switch($name) {
 		$value = strtolower($value);
 		break;
 	case 'TEL':
-	case 'ADR': // should I delete the property if empty or throw an error?
+	case 'ADR':
+		break;
+	case 'IMPP':
+		if(is_null($parameters) || !isset($parameters['X-SERVICE-TYPE'])) {
+			bailOut(OC_Contacts_App::$l10n->t('Missing IM parameter.'));
+		}
+		$impp = OC_Contacts_App::getIMOptions($parameters['X-SERVICE-TYPE']);
+		if(is_null($impp)) {
+			bailOut(OC_Contacts_App::$l10n->t('Unknown IM: '.$parameters['X-SERVICE-TYPE']));
+		}
+		$value = $impp['protocol'] . ':' . $value;
 		break;
 }
 
@@ -126,7 +136,7 @@ $line = count($vcard->children) - 1;
 // Apparently Sabre_VObject_Parameter doesn't do well with
 // multiple values or I don't know how to do it. Tanghus.
 foreach ($parameters as $key=>$element) {
-	if(is_array($element) && strtoupper($key) == 'TYPE') {
+	if(is_array($element) /*&& strtoupper($key) == 'TYPE'*/) {
 		// NOTE: Maybe this doesn't only apply for TYPE?
 		// And it probably shouldn't be done here anyways :-/
 		foreach($element as $e) {
diff --git a/apps/contacts/ajax/contact/saveproperty.php b/apps/contacts/ajax/contact/saveproperty.php
index fd541b7361efb445e759c0c8abfaa0932f55313a..9556c4a44c3b7b794efc8d2541236781623101b2 100644
--- a/apps/contacts/ajax/contact/saveproperty.php
+++ b/apps/contacts/ajax/contact/saveproperty.php
@@ -88,6 +88,16 @@ switch($element) {
 	case 'EMAIL':
 		$value = strtolower($value);
 		break;
+	case 'IMPP':
+		if(is_null($parameters) || !isset($parameters['X-SERVICE-TYPE'])) {
+			bailOut(OC_Contacts_App::$l10n->t('Missing IM parameter.'));
+		}
+		$impp = OC_Contacts_App::getIMOptions($parameters['X-SERVICE-TYPE']);
+		if(is_null($impp)) {
+			bailOut(OC_Contacts_App::$l10n->t('Unknown IM: '.$parameters['X-SERVICE-TYPE']));
+		}
+		$value = $impp['protocol'] . ':' . $value;
+		break;
 }
 
 if(!$value) {
@@ -112,7 +122,8 @@ if(!$value) {
 			break;
 		case 'EMAIL':
 		case 'TEL':
-		case 'ADR': // should I delete the property if empty or throw an error?
+		case 'ADR':
+		case 'IMPP':
 			debug('Setting element: (EMAIL/TEL/ADR)'.$element);
 			$vcard->children[$line]->setValue($value);
 			$vcard->children[$line]->parameters = array();
@@ -120,11 +131,18 @@ if(!$value) {
 				debug('Setting parameters: '.$parameters);
 				foreach($parameters as $key => $parameter) {
 					debug('Adding parameter: '.$key);
-					foreach($parameter as $val) {
-						debug('Adding parameter: '.$key.'=>'.$val);
+					if(is_array($parameter)) {
+						foreach($parameter as $val) {
+							debug('Adding parameter: '.$key.'=>'.$val);
+							$vcard->children[$line]->add(new Sabre_VObject_Parameter(
+								$key,
+								strtoupper(strip_tags($val)))
+							);
+						}
+					} else {
 						$vcard->children[$line]->add(new Sabre_VObject_Parameter(
 							$key,
-							strtoupper(strip_tags($val)))
+							strtoupper(strip_tags($parameter)))
 						);
 					}
 				}
diff --git a/apps/contacts/css/contacts.css b/apps/contacts/css/contacts.css
index 483df2196a38dfa6d35e643538e82d617fb17cbb..ef48d020d0f935ccc1ae9846150433cdc373b00d 100644
--- a/apps/contacts/css/contacts.css
+++ b/apps/contacts/css/contacts.css
@@ -33,7 +33,7 @@
 #card input[type="text"].contacts_property,input[type="email"].contacts_property,input[type="url"].contacts_property { width: 14em; float: left; font-weight: bold; }
 .categories { float: left; width: 16em; }
 #card input[type="checkbox"].contacts_property,input[type="text"],input[type="email"],input[type="url"],input[type="tel"],input[type="date"], select, textarea { background-color: #fefefe; border: 0 !important; -moz-appearance:none  !important; -webkit-box-sizing:none !important; -moz-box-sizing:none !important; box-sizing:none !important; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; -moz-border-radius: 0px; -webkit-border-radius: 0px; border-radius: 0px; float: left; }
-#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="url"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="url"]:active,input[type="tel"]:active, select:hover, select:focus, select:active, textarea:focus, textarea:hover { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #ddd, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; }
+#card input[type="text"]:hover, input[type="text"]:focus, input[type="text"]:active,input[type="email"]:hover,input[type="url"]:hover,input[type="tel"]:hover,input[type="date"]:hover,input[type="date"],input[type="date"]:hover,input[type="date"]:active,input[type="date"]:active,input[type="date"]:active,input[type="email"]:active,input[type="url"]:active,input[type="tel"]:active, textarea:focus, textarea:hover { border: 0 !important; -webkit-appearance:textfield; -moz-appearance:textfield; -webkit-box-sizing:content-box; -moz-box-sizing:content-box; box-sizing:content-box; background:#fff; color:#333; border:1px solid #ddd; -moz-box-shadow:0 1px 1px #ddd, 0 2px 0 #bbb inset; -webkit-box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; box-shadow:0 1px 1px #ddd, 0 1px 0 #bbb inset; -moz-border-radius:.5em; -webkit-border-radius:.5em; border-radius:.5em; outline:none; float: left; }
 textarea { width: 80%; min-height: 5em; min-width: 30em; margin: 0 !important; padding: 0 !important; outline: 0 !important;}
 dl.form { width: 100%; float: left; clear: right; margin: 0; padding: 0; cursor: normal; }
 .form dt { display: table-cell; clear: left; float: left; width: 7em; margin: 0; padding: 0.8em 0.5em 0 0; text-align:right; text-overflow:ellipsis; o-text-overflow: ellipsis; vertical-align: text-bottom; color: #bbb;/* white-space: pre-wrap; white-space: -moz-pre-wrap !important; white-space: -pre-wrap; white-space: -o-pre-wrap;*/ }
@@ -117,13 +117,21 @@ input[type="checkbox"] { width: 20px; height: 20px; vertical-align: bottom; }
 .big { font-weight:bold; font-size:1.2em; }
 .huge { font-weight:bold; font-size:1.5em; }
 .propertycontainer dd { float: left; width: 25em; }
-.propertylist { clear: none; max-width: 28em; }
-.propertylist li.propertycontainer { white-space: nowrap; min-width: 35em; /*max-width: 30em;*/ display: block; clear: right; }
+/*.propertylist { clear: none; max-width: 33em; }*/
+.propertylist li.propertycontainer { white-space: nowrap; min-width: 35em; display: block; clear: both; }
 .propertycontainer[data-element="EMAIL"] > input[type="email"],.propertycontainer[data-element="TEL"] > input[type="text"] { min-width: 12em !important; float: left; }
 .propertylist li > input[type="checkbox"],input[type="radio"] { float: left; clear: left; width: 16px; height: 16px; vertical-align: middle; padding: 0; }
 .propertylist li > select { float: left; max-width: 8em; }
+.propertylist li > .select_wrapper { float: left; overflow: hidden; color: #bbb; font-size: 0.8em; }
+.propertylist li > .select_wrapper select { float: left; overflow: hidden; color: #bbb; }
+.propertylist li > .select_wrapper select option { color: #777; }
+.propertylist li > .select_wrapper select:hover,.propertylist li > select:focus,.propertylist li > select:active { color: #777; }
+.propertylist li > .select_wrapper select.impp { margin-left: -2.3em; direction: rtl; }
+.propertylist li > .select_wrapper select.types { margin-right: -2em; }
+.propertylist li > input[type="checkbox"].impp { clear: none; }
 .propertylist li > label.xab { display: block; color: #bbb; float:left; clear: both; padding: 0.5em 0 0 2.5em; }
-.typelist[type="button"] { float: left; max-width: 10em; border: 0; background-color: #fff; color: #bbb; box-shadow: none; } /* for multiselect */
+.propertylist li > label.xab:hover { color: #777; }
+.typelist[type="button"] { float: left; max-width: 8em; border: 0; background-color: #fff; color: #bbb; box-shadow: none; } /* for multiselect */
 .typelist[type="button"]:hover { color: #777; } /* for multiselect */
 .addresslist { clear: both; font-weight: bold; }
 #ninjahelp { position: absolute; bottom: 0; left: 0; right: 0; padding: 1em; margin: 1em; opacity: 0.9; }
diff --git a/apps/contacts/index.php b/apps/contacts/index.php
index 5cd58c5c43ca74555c0e960053cba3f764296f81..f16d6f5641f8606355226ae656e99a980eb1aa91 100644
--- a/apps/contacts/index.php
+++ b/apps/contacts/index.php
@@ -28,8 +28,14 @@ OCP\App::setActiveNavigationEntry('contacts_index');
 
 // Load a specific user?
 $id = isset( $_GET['id'] ) ? $_GET['id'] : null;
+$impp_types = OC_Contacts_App::getTypesOfProperty('IMPP');
 $phone_types = OC_Contacts_App::getTypesOfProperty('TEL');
 $email_types = OC_Contacts_App::getTypesOfProperty('EMAIL');
+$ims = OC_Contacts_App::getIMOptions();
+$im_protocols = array();
+foreach($ims as $name => $values) {
+	$im_protocols[$name] = $values['displayname'];
+}
 $categories = OC_Contacts_App::getCategories();
 
 $upload_max_filesize = OCP\Util::computerFileSize(ini_get('upload_max_filesize'));
@@ -60,7 +66,9 @@ $tmpl->assign('uploadMaxHumanFilesize',
 	OCP\Util::humanFileSize($maxUploadFilesize), false);
 $tmpl->assign('phone_types', $phone_types, false);
 $tmpl->assign('email_types', $email_types, false);
+$tmpl->assign('impp_types', $impp_types, false);
 $tmpl->assign('categories', $categories, false);
+$tmpl->assign('im_protocols', $im_protocols, false);
 $tmpl->assign('has_contacts', $has_contacts, false);
 $tmpl->assign('id', $id, false);
 $tmpl->printPage();
diff --git a/apps/contacts/js/contacts.js b/apps/contacts/js/contacts.js
index 033c62b1363f040e0fbd9afd05ca9f4885ef66e8..e5daadb6d1d1e22525fceba010141117ba6d01a4 100644
--- a/apps/contacts/js/contacts.js
+++ b/apps/contacts/js/contacts.js
@@ -533,6 +533,7 @@ OC.Contacts={
 			this.loadPhoto();
 			this.loadMails();
 			this.loadPhones();
+			this.loadIMs();
 			this.loadAddresses();
 			this.loadSingleProperties();
 			OC.Contacts.loadListHandlers();
@@ -802,6 +803,12 @@ OC.Contacts={
 					}
 					OC.Contacts.Card.addPhone();
 					break;
+				case 'IMPP':
+					if($('#imlist>li').length == 1) {
+						$('#ims').show();
+					}
+					OC.Contacts.Card.addIM();
+					break;
 				case 'ADR':
 					if($('addresses>dl').length == 1) {
 						$('#addresses').show();
@@ -1289,8 +1296,72 @@ OC.Contacts={
 			});
 			OC.Contacts.Contacts.refreshThumbnail(this.id);
 		},
+		addIM:function() {
+			//alert('addMail');
+			var imlist = $('#imlist');
+			imlist.find('li.template:first-child').clone(true).appendTo(imlist).show().find('a .tip').tipsy();
+			imlist.find('li.template:last-child').find('select').addClass('contacts_property');
+			imlist.find('li.template:last-child').removeClass('template').addClass('propertycontainer');
+			imlist.find('li:last-child').find('input[type="text"]').focus();
+			return false;
+		},
+		loadIMs:function() {
+			//console.log('loadIMs');
+			$('#ims').hide();
+			$('#imlist li.propertycontainer').remove();
+			var imlist = $('#imlist');
+			for(var im in this.data.IMPP) {
+				this.addIM();
+				var curim = imlist.find('li.propertycontainer:last-child');
+				if(typeof this.data.IMPP[im].label != 'undefined') {
+					curim.prepend('<label class="xab">'+this.data.IMPP[im].label+'</label>');
+				}
+				curim.data('checksum', this.data.IMPP[im]['checksum'])
+				curim.find('input[type="text"]').val(this.data.IMPP[im]['value'].split(':').pop());
+				for(var param in this.data.IMPP[im]['parameters']) {
+					if(param.toUpperCase() == 'PREF') {
+						curim.find('input[type="checkbox"]').attr('checked', 'checked')
+					}
+					else if(param.toUpperCase() == 'TYPE') {
+						if(typeof this.data.IMPP[im]['parameters'][param] == 'string') {
+							var found = false;
+							var imt = this.data.IMPP[im]['parameters'][param];
+							curim.find('select.types option').each(function(){
+								if($(this).val().toUpperCase() == imt.toUpperCase()) {
+									$(this).attr('selected', 'selected');
+									found = true;
+								}
+							});
+							if(!found) {
+								curim.find('select.type option:last-child').after('<option value="'+imt+'" selected="selected">'+imt+'</option>');
+							}
+						} else if(typeof this.data.IMPP[im]['parameters'][param] == 'object') {
+							for(imtype in this.data.IMPP[im]['parameters'][param]) {
+								var found = false;
+								var imt = this.data.IMPP[im]['parameters'][param][imtype];
+								curim.find('select.types option').each(function(){
+									if($(this).val().toUpperCase() == imt.toUpperCase().split(',')) {
+										$(this).attr('selected', 'selected');
+										found = true;
+									}
+								});
+								if(!found) {
+									curim.find('select.type option:last-child').after('<option value="'+imt+'" selected="selected">'+imt+'</option>');
+								}
+							}
+						}
+					}
+					else if(param.toUpperCase() == 'X-SERVICE-TYPE') {
+						curim.find('select.impp').val(this.data.IMPP[im]['parameters'][param].toLowerCase());
+					}
+				}
+			}
+			if($('#imlist li').length > 1) {
+				$('#ims').show();
+			}
+			return false;
+		},
 		addMail:function() {
-			console.log('addMail');
 			var emaillist = $('#emaillist');
 			emaillist.find('li.template:first-child').clone(true).appendTo(emaillist).show().find('a .tip').tipsy();
 			emaillist.find('li.template:last-child').find('select').addClass('contacts_property');
diff --git a/apps/contacts/lib/app.php b/apps/contacts/lib/app.php
index e222c608de910965d5d68454b1f2db8cc2ba7873..e8e1937404fc2a596b1c6a96a13e644f92a82def 100644
--- a/apps/contacts/lib/app.php
+++ b/apps/contacts/lib/app.php
@@ -109,14 +109,77 @@ class OC_Contacts_App {
 	/**
 	 * @return array of vcard prop => label
 	 */
-	public static function getAddPropertyOptions() {
+	public static function getIMOptions($im = null) {
 		$l10n = self::$l10n;
-		return array(
-				'ADR'   => $l10n->t('Address'),
-				'TEL'   => $l10n->t('Telephone'),
-				'EMAIL' => $l10n->t('Email'),
-				'ORG'   => $l10n->t('Organization'),
-		     );
+		$ims = array(
+				'jabber' => array(
+					'displayname' => (string)$l10n->t('Jabber'),
+					'xname' => 'X-JABBER',
+					'protocol' => 'xmpp',
+				),
+				'aim' => array(
+					'displayname' => (string)$l10n->t('AIM'),
+					'xname' => 'X-AIM',
+					'protocol' => 'aim',
+				),
+				'msn' => array(
+					'displayname' => (string)$l10n->t('MSN'),
+					'xname' => 'X-MSN',
+					'protocol' => 'msn',
+				),
+				'twitter' => array(
+					'displayname' => (string)$l10n->t('Twitter'),
+					'xname' => 'X-TWITTER',
+					'protocol' => null,
+				),
+				'googletalk' => array(
+					'displayname' => (string)$l10n->t('GoogleTalk'),
+					'xname' => null,
+					'protocol' => 'xmpp',
+				),
+				'facebook' => array(
+					'displayname' => (string)$l10n->t('Facebook'),
+					'xname' => null,
+					'protocol' => 'xmpp',
+				),
+				'xmpp' => array(
+					'displayname' => (string)$l10n->t('XMPP'),
+					'xname' => null,
+					'protocol' => 'xmpp',
+				),
+				'icq' => array(
+					'displayname' => (string)$l10n->t('ICQ'),
+					'xname' => 'X-ICQ',
+					'protocol' => 'icq',
+				),
+				'yahoo' => array(
+					'displayname' => (string)$l10n->t('Yahoo'),
+					'xname' => 'X-YAHOO',
+					'protocol' => 'ymsgr',
+				),
+				'skype' => array(
+					'displayname' => (string)$l10n->t('Skype'),
+					'xname' => 'X-SKYPE',
+					'protocol' => 'skype',
+				),
+				'qq' => array(
+					'displayname' => (string)$l10n->t('QQ'),
+					'xname' => 'X-SKYPE',
+					'protocol' => 'x-apple',
+				),
+				'gadugadu' => array(
+					'displayname' => (string)$l10n->t('GaduGadu'),
+					'xname' => 'X-SKYPE',
+					'protocol' => 'x-apple',
+				),
+		);
+		if(is_null($im)) {
+			return $ims;
+		} else {
+			$ims['ymsgr'] = $ims['yahoo'];
+			$ims['gtalk'] = $ims['googletalk'];
+			return isset($ims[$im]) ? $ims[$im] : null;
+		}
 	}
 
 	/**
@@ -126,6 +189,7 @@ class OC_Contacts_App {
 		$l = self::$l10n;
 		switch($prop) {
 			case 'ADR':
+			case 'IMPP':
 				return array(
 					'WORK' => $l->t('Work'),
 					'HOME' => $l->t('Home'),
diff --git a/apps/contacts/lib/vcard.php b/apps/contacts/lib/vcard.php
index 5bc3d04b468f33ada0d1bf297ead34fe985aef40..a349449a99fc7ebcbacbd2f255750b4af5d7ec61 100644
--- a/apps/contacts/lib/vcard.php
+++ b/apps/contacts/lib/vcard.php
@@ -559,20 +559,36 @@ class OC_Contacts_VCard{
 	 */
 	public static function structureContact($object) {
 		$details = array();
-		foreach($object->children as $property){
+
+		$addIM = function($name, $temp, &$details) {
+			if(!array_key_exists('IMPP', $details)) {
+				$details['IMPP'] = array();
+			}
+
+			foreach($details['IMPP'] as $im) {
+				if(strtolower($im['value']) == strtolower($temp['value']) && $im['name'] == $name) {
+					return;
+				}
+			}
+			$details['IMPP'][] = $temp;
+		};
+
+		foreach($object->children as $property) {
+			$pname = $property->name;
 			$temp = self::structureProperty($property);
 			if(!is_null($temp)) {
+				// Get Apple X-ABLabels
 				if(isset($object->{$property->group . '.X-ABLABEL'})) {
 					$temp['label'] = $object->{$property->group . '.X-ABLABEL'}->value;
 					if($temp['label'] == '_$!<Other>!$_') {
 						$temp['label'] = OC_Contacts_App::$l10n->t('Other');
 					}
 				}
-				if(array_key_exists($property->name, $details)) {
-					$details[$property->name][] = $temp;
+				if(array_key_exists($pname, $details)) {
+					$details[$pname][] = $temp;
 				}
 				else{
-					$details[$property->name] = array($temp);
+					$details[$pname] = array($temp);
 				}
 			}
 		}
diff --git a/apps/contacts/templates/part.contact.php b/apps/contacts/templates/part.contact.php
index 491b4400ff4baf9bf64c34b04910fd1a3e70c983..87ed07c0ec8945f7b829b204bb5073c9fce9ecef 100644
--- a/apps/contacts/templates/part.contact.php
+++ b/apps/contacts/templates/part.contact.php
@@ -71,7 +71,8 @@ $id = isset($_['id']) ? $_['id'] : '';
 		<ul id="phonelist" class="propertylist">
 			<li class="template hidden" data-element="TEL">
 			<input type="checkbox" class="contacts_property tip" name="parameters[TYPE][]" value="PREF" title="<?php echo $l->t('Preferred'); ?>" />
-			<input type="text" required="required" class="nonempty contacts_property" name="value" value="" placeholder="<?php echo $l->t('Enter phone number'); ?>" />
+			<input type="text" required="required" class="nonempty contacts_property" name="value" value=""
+					placeholder="<?php echo $l->t('Enter phone number'); ?>" />
 			<select multiple="multiple" name="parameters[TYPE][]">
 				<?php echo OCP\html_select_options($_['phone_types'], array()) ?>
 			</select>
@@ -79,6 +80,28 @@ $id = isset($_['id']) ? $_['id'] : '';
 		</ul>
 	</div> <!-- Phone numbers -->
 
+	<!-- IMPP -->
+	<div id="ims" class="hidden contactsection">
+		<ul id="imlist" class="propertylist">
+			<li class="template hidden" data-element="IMPP">
+			<div class="select_wrapper">
+			<select class="impp" name="parameters[X-SERVICE-TYPE]">
+				<?php echo OCP\html_select_options($_['im_protocols'], array()) ?>
+			</select>
+			</div>
+			<div class="select_wrapper">
+			<select class="types" name="parameters[TYPE][]">
+				<option></option>
+				<?php echo OCP\html_select_options($_['impp_types'], array()) ?>
+			</select>
+			</div>
+			<input type="checkbox" class="contacts_property impp tip" name="parameters[TYPE][]" value="PREF" title="<?php echo $l->t('Preferred'); ?>" />
+			<input type="text" required="required" class="nonempty contacts_property" name="value" value=""
+					placeholder="<?php echo $l->t('Instant Messenger'); ?>" />
+			<a role="button" class="action delete" title="<?php echo $l->t('Delete IM'); ?>"></a></li>
+		</ul>
+	</div> <!-- IMPP -->
+
 	<!-- Addresses -->
 	<div id="addresses" class="hidden contactsection">
 		<dl class="addresscard template hidden" data-element="ADR"><dt>
@@ -105,6 +128,7 @@ $id = isset($_['id']) ? $_['id'] : '';
 			<li><a role="menuitem" data-type="BDAY"><?php echo $l->t('Birthday'); ?></a></li>
 			<li><a role="menuitem" data-type="TEL"><?php echo $l->t('Phone'); ?></a></li>
 			<li><a role="menuitem" data-type="EMAIL"><?php echo $l->t('Email'); ?></a></li>
+			<li><a role="menuitem" data-type="IMPP"><?php echo $l->t('Instant Messaging'); ?></a></li>
 			<li><a role="menuitem" data-type="ADR"><?php echo $l->t('Address'); ?></a></li>
 			<li><a role="menuitem" data-type="NOTE"><?php echo $l->t('Note'); ?></a></li>
 			<li><a role="menuitem" data-type="URL"><?php echo $l->t('Web site'); ?></a></li>