From 5fed5bab4a45038f0b1b250170782d3e95b37abd Mon Sep 17 00:00:00 2001
From: Jakob Sack <mail@jakobsack.de>
Date: Thu, 8 Sep 2011 23:36:47 +0200
Subject: [PATCH] Improving contacts

---
 apps/contacts/ajax/addproperty.php            |   6 +
 apps/contacts/ajax/deleteproperty.php         |   6 +
 apps/contacts/ajax/getdetails.php             |   6 +
 apps/contacts/ajax/setproperty.php            |   6 +
 apps/contacts/ajax/showsetproperty.php        |   6 +
 apps/contacts/index.php                       |   3 +
 apps/contacts/js/interface.js                 |  18 +-
 apps/contacts/l10n/.gitkeep                   |   0
 apps/contacts/lib/addressbook.php             | 218 ++++++++++++++++--
 apps/contacts/templates/index.php             |   9 +-
 apps/contacts/templates/part.addcardform.php  |   4 +-
 apps/contacts/templates/part.details.php      |   8 +-
 .../templates/part.setpropertyform.php        |  16 +-
 13 files changed, 263 insertions(+), 43 deletions(-)
 create mode 100644 apps/contacts/l10n/.gitkeep

diff --git a/apps/contacts/ajax/addproperty.php b/apps/contacts/ajax/addproperty.php
index d92566d6a1..68075efc6a 100644
--- a/apps/contacts/ajax/addproperty.php
+++ b/apps/contacts/ajax/addproperty.php
@@ -44,6 +44,12 @@ if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
 	exit();
 }
 
+// Check if the card is valid
+if( !OC_Contacts_Addressbook::isValidVObject($card['carddata'])){
+	echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('Unable to parse vCard!'))));
+	exit();
+}
+
 $vcard = Sabre_VObject_Reader::read($card['carddata']);
 
 $name = $_POST['name'];
diff --git a/apps/contacts/ajax/deleteproperty.php b/apps/contacts/ajax/deleteproperty.php
index d141cc00b8..f73758a367 100644
--- a/apps/contacts/ajax/deleteproperty.php
+++ b/apps/contacts/ajax/deleteproperty.php
@@ -48,6 +48,12 @@ if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
 	exit();
 }
 
+// Check if the card is valid
+if( !OC_Contacts_Addressbook::isValidVObject($card['carddata'])){
+	echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('Unable to parse vCard!'))));
+	exit();
+}
+
 $vcard = Sabre_VObject_Reader::read($card['carddata']);
 $line = null;
 for($i=0;$i<count($vcard->children);$i++){
diff --git a/apps/contacts/ajax/getdetails.php b/apps/contacts/ajax/getdetails.php
index 4ee3625afc..ddd29be95c 100644
--- a/apps/contacts/ajax/getdetails.php
+++ b/apps/contacts/ajax/getdetails.php
@@ -46,6 +46,12 @@ if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
 	exit();
 }
 
+// Check if the card is valid
+if( !OC_Contacts_Addressbook::isValidVObject($card['carddata'])){
+	echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('Unable to parse vCard!'))));
+	exit();
+}
+
 $vcard = Sabre_VObject_Reader::read($card['carddata']);
 $details = OC_Contacts_Addressbook::structureContact($vcard);
 $tmpl = new OC_Template('contacts','part.details');
diff --git a/apps/contacts/ajax/setproperty.php b/apps/contacts/ajax/setproperty.php
index 08d8892254..f3b8e0c56b 100644
--- a/apps/contacts/ajax/setproperty.php
+++ b/apps/contacts/ajax/setproperty.php
@@ -45,6 +45,12 @@ if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
 	exit();
 }
 
+// Check if the card is valid
+if( !OC_Contacts_Addressbook::isValidVObject($card['carddata'])){
+	echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('Unable to parse vCard!'))));
+	exit();
+}
+
 $vcard = Sabre_VObject_Reader::read($card['carddata']);
 $line = null;
 for($i=0;$i<count($vcard->children);$i++){
diff --git a/apps/contacts/ajax/showsetproperty.php b/apps/contacts/ajax/showsetproperty.php
index a00043384f..adae17553c 100644
--- a/apps/contacts/ajax/showsetproperty.php
+++ b/apps/contacts/ajax/showsetproperty.php
@@ -45,6 +45,12 @@ if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){
 	exit();
 }
 
+// Check if the card is valid
+if( !OC_Contacts_Addressbook::isValidVObject($card['carddata'])){
+	echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('Unable to parse vCard!'))));
+	exit();
+}
+
 $vcard = Sabre_VObject_Reader::read($card['carddata']);
 $line = null;
 for($i=0;$i<count($vcard->children);$i++){
diff --git a/apps/contacts/index.php b/apps/contacts/index.php
index 0d4ff83ef8..a8926cd96f 100644
--- a/apps/contacts/index.php
+++ b/apps/contacts/index.php
@@ -60,6 +60,9 @@ $contacts = array();
 foreach( $openaddressbooks as $addressbook ){
 	$addressbookcontacts = OC_Contacts_Addressbook::allCards($addressbook);
 	foreach( $addressbookcontacts as $contact ){
+		if(is_null($contact['fullname'])){
+			continue;
+		}
 		$contacts[] = array( 'name' => $contact['fullname'], 'id' => $contact['id'] );
 	}
 }
diff --git a/apps/contacts/js/interface.js b/apps/contacts/js/interface.js
index b8a66d51aa..66ee677219 100644
--- a/apps/contacts/js/interface.js
+++ b/apps/contacts/js/interface.js
@@ -1,15 +1,25 @@
 $(document).ready(function(){
-	/* $('.contacts_addressbooksexpander').click(function(){
-		$('.contacts_addressbooksdetails').toggle();
-		return false;
-	});*/
+	/*-------------------------------------------------------------------------
+	 * Actions for startup
+	 *-----------------------------------------------------------------------*/
+	if( $('#leftcontent li').length > 0 ){
+		$('#leftcontent li').first().addClass('active');
+	}
 
+	/*-------------------------------------------------------------------------
+	 * Event handlers
+	 *-----------------------------------------------------------------------*/
 	$('#leftcontent li').live('click',function(){
 		var id = $(this).data('id');
+		var oldid = $('#rightcontent').data('id');
+		if(oldid != 0){
+			$('#leftcontent li[data-id="'+oldid+'"]').removeClass('active');
+		}
 		$.getJSON('ajax/getdetails.php',{'id':id},function(jsondata){
 			if(jsondata.status == 'success'){
 				$('#rightcontent').data('id',jsondata.data.id);
 				$('#rightcontent').html(jsondata.data.page);
+				$('#leftcontent li[data-id="'+jsondata.data.id+'"]').addClass('active');
 			}
 			else{
 				alert(jsondata.data.message);
diff --git a/apps/contacts/l10n/.gitkeep b/apps/contacts/l10n/.gitkeep
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/apps/contacts/lib/addressbook.php b/apps/contacts/lib/addressbook.php
index 9a5dea6f45..89894d33b5 100644
--- a/apps/contacts/lib/addressbook.php
+++ b/apps/contacts/lib/addressbook.php
@@ -47,6 +47,11 @@
  * This class manages our addressbooks.
  */
 class OC_Contacts_Addressbook{
+	/**
+	 * @brief Returns the list of addressbooks for a specific user.
+	 * @param string $uid
+	 * @return array
+	 */
 	public static function allAddressbooks($uid){
 		$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE userid = ?' );
 		$result = $stmt->execute(array($uid));
@@ -59,11 +64,21 @@ class OC_Contacts_Addressbook{
 		return $addressbooks;
 	}
 	
+	/**
+	 * @brief Returns the list of addressbooks for a principal (DAV term of user)
+	 * @param string $principaluri
+	 * @return array
+	 */
 	public static function allAddressbooksWherePrincipalURIIs($principaluri){
 		$uid = self::extractUserID($principaluri);
 		return self::allAddressbooks($uid);
 	}
 
+	/**
+	 * @brief Gets the data of one address book
+	 * @param integer $id
+	 * @return associative array
+	 */
 	public static function findAddressbook($id){
 		$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE id = ?' );
 		$result = $stmt->execute(array($id));
@@ -71,6 +86,13 @@ class OC_Contacts_Addressbook{
 		return $result->fetchRow();
 	}
 
+	/**
+	 * @brief Creates a new address book
+	 * @param string $userid
+	 * @param string $name
+	 * @param string $description
+	 * @return insertid
+	 */
 	public static function addAddressbook($userid,$name,$description){
 		$all = self::allAddressbooks($userid);
 		$uris = array();
@@ -86,6 +108,14 @@ class OC_Contacts_Addressbook{
 		return OC_DB::insertid();
 	}
 
+	/**
+	 * @brief Creates a new address book from the data sabredav provides
+	 * @param string $principaluri
+	 * @param string $uri
+	 * @param string $name
+	 * @param string $description
+	 * @return insertid
+	 */
 	public static function addAddressbookFromDAVData($principaluri,$uri,$name,$description){
 		$userid = self::extractUserID($principaluri);
 		
@@ -95,6 +125,13 @@ class OC_Contacts_Addressbook{
 		return OC_DB::insertid();
 	}
 
+	/**
+	 * @brief Edits an addressbook
+	 * @param integer $id
+	 * @param string $name
+	 * @param string $description
+	 * @return boolean
+	 */
 	public static function editAddressbook($id,$name,$description){
 		// Need these ones for checking uri
 		$addressbook = self::find($id);
@@ -112,6 +149,11 @@ class OC_Contacts_Addressbook{
 		return true;
 	}
 
+	/**
+	 * @brief Updates ctag for addressbook
+	 * @param integer $id
+	 * @return boolean
+	 */
 	public static function touchAddressbook($id){
 		$stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_addressbooks SET ctag = ctag + 1 WHERE id = ?' );
 		$stmt->execute(array($id));
@@ -119,6 +161,11 @@ class OC_Contacts_Addressbook{
 		return true;
 	}
 
+	/**
+	 * @brief removes an address book
+	 * @param integer $id
+	 * @return boolean
+	 */
 	public static function deleteAddressbook($id){
 		$stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE id = ?' );
 		$stmt->execute(array($id));
@@ -129,6 +176,14 @@ class OC_Contacts_Addressbook{
 		return true;
 	}
 
+	/**
+	 * @brief Returns all cards of an address book
+	 * @param integer $id
+	 * @return array
+	 *
+	 * The cards are associative arrays. You'll find the original vCard in
+	 * ['carddata']
+	 */
 	public static function allCards($id){
 		$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid = ?' );
 		$result = $stmt->execute(array($id));
@@ -141,6 +196,11 @@ class OC_Contacts_Addressbook{
 		return $addressbooks;
 	}
 	
+	/**
+	 * @brief Returns a card
+	 * @param integer $id
+	 * @return associative array
+	 */
 	public static function findCard($id){
 		$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE id = ?' );
 		$result = $stmt->execute(array($id));
@@ -148,6 +208,12 @@ class OC_Contacts_Addressbook{
 		return $result->fetchRow();
 	}
 
+	/**
+	 * @brief finds a card by its DAV Data
+	 * @param integer $aid Addressbook id
+	 * @param string $uri the uri ('filename')
+	 * @return associative array
+	 */
 	public static function findCardWhereDAVDataIs($aid,$uri){
 		$stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid = ? AND uri = ?' );
 		$result = $stmt->execute(array($aid,$uri));
@@ -155,23 +221,36 @@ class OC_Contacts_Addressbook{
 		return $result->fetchRow();
 	}
 
+	/**
+	 * @brief Adds a card
+	 * @param integer $id Addressbook id
+	 * @param string $data  vCard file
+	 * @return insertid
+	 */
 	public static function addCard($id,$data){
 		$fn = null;
 		$uri = null;
-		$card = Sabre_VObject_Reader::read($data);
-		foreach($card->children as $property){
-			if($property->name == 'FN'){
-				$fn = $property->value;
-			}
-			elseif(is_null($uri) && $property->name == 'UID' ){
-				$uri = $property->value.'.vcf';
+		if(self::isValidVObject($data)){
+			$card = Sabre_VObject_Reader::read($data);
+			foreach($card->children as $property){
+				if($property->name == 'FN'){
+					$fn = $property->value;
+				}
+				elseif(is_null($uri) && $property->name == 'UID' ){
+					$uri = $property->value.'.vcf';
+				}
 			}
+			if(is_null($uri)){
+				$uid = self::createUID();
+				$uri = $uid.'.vcf';
+				$card->add(new Sabre_VObject_Property('UID',$uid));
+				$data = $card->serialize();
+			};
 		}
-		if(is_null($uri)){
+		else{
+			// that's hard. Creating a UID and not saving it
 			$uid = self::createUID();
 			$uri = $uid.'.vcf';
-			$card->add(new Sabre_VObject_Property('UID',$uid));
-			$data = $card->serialize();
 		};
 
 		$stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' );
@@ -182,12 +261,21 @@ class OC_Contacts_Addressbook{
 		return OC_DB::insertid();
 	}
 
+	/**
+	 * @brief Adds a card with the data provided by sabredav
+	 * @param integer $id Addressbook id
+	 * @param string $uri   the uri the card will have
+	 * @param string $data  vCard file
+	 * @return insertid
+	 */
 	public static function addCardFromDAVData($id,$uri,$data){
 		$fn = null;
-		$card = Sabre_VObject_Reader::read($data);
-		foreach($card->children as $property){
-			if($property->name == 'FN'){
-				$fn = $property->value;
+		if(self::isValidVObject($data)){
+			$card = Sabre_VObject_Reader::read($data);
+			foreach($card->children as $property){
+				if($property->name == 'FN'){
+					$fn = $property->value;
+				}
 			}
 		}
 
@@ -199,13 +287,21 @@ class OC_Contacts_Addressbook{
 		return OC_DB::insertid();
 	}
 
+	/**
+	 * @brief edits a card
+	 * @param integer $id id of card
+	 * @param string $data  vCard file
+	 * @return boolean
+	 */
 	public static function editCard($id, $data){
 		$oldcard = self::findCard($id);
 		$fn = null;
-		$card = Sabre_VObject_Reader::read($data);
-		foreach($card->children as $property){
-			if($property->name == 'FN'){
-				$fn = $property->value;
+		if(self::isValidVObject($data)){
+			$card = Sabre_VObject_Reader::read($data);
+			foreach($card->children as $property){
+				if($property->name == 'FN'){
+					$fn = $property->value;
+				}
 			}
 		}
 
@@ -217,14 +313,23 @@ class OC_Contacts_Addressbook{
 		return true;
 	}
 
+	/**
+	 * @brief edits a card with the data provided by sabredav
+	 * @param integer $id Addressbook id
+	 * @param string $uri   the uri of the card
+	 * @param string $data  vCard file
+	 * @return boolean
+	 */
 	public static function editCardFromDAVData($aid,$uri,$data){
 		$oldcard = self::findCardWhereDAVDataIs($aid,$uri);
 
 		$fn = null;
-		$card = Sabre_VObject_Reader::read($data);
-		foreach($card->children as $property){
-			if($property->name == 'FN'){
-				$fn = $property->value;
+		if(self::isValidVObject($data)){
+			$card = Sabre_VObject_Reader::read($data);
+			foreach($card->children as $property){
+				if($property->name == 'FN'){
+					$fn = $property->value;
+				}
 			}
 		}
 
@@ -236,6 +341,11 @@ class OC_Contacts_Addressbook{
 		return true;
 	}
 	
+	/**
+	 * @brief deletes a card
+	 * @param integer $id id of card
+	 * @return boolean
+	 */
 	public static function deleteCard($id){
 		$stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_cards WHERE id = ?' );
 		$stmt->execute(array($id));
@@ -243,6 +353,12 @@ class OC_Contacts_Addressbook{
 		return true;
 	}
 
+	/**
+	 * @brief deletes a card with the data provided by sabredav
+	 * @param integer $id Addressbook id
+	 * @param string $uri the uri of the card
+	 * @return boolean
+	 */
 	public static function deleteCardFromDAVData($aid,$uri){
 		$stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_cards WHERE addressbookid = ? AND uri=?' );
 		$stmt->execute(array($aid,$uri));
@@ -250,6 +366,12 @@ class OC_Contacts_Addressbook{
 		return true;
 	}
 	
+	/**
+	 * @brief Creates a URI for Addressbook
+	 * @param string $name name of the addressbook
+	 * @param array  $existing the uri of the card
+	 * @return boolean
+	 */
 	public static function createURI($name,$existing){
 		$name = strtolower($name);
 		$newname = $name;
@@ -261,15 +383,28 @@ class OC_Contacts_Addressbook{
 		return $newname;
 	}
 
+	/**
+	 * @brief Creates a UID
+	 * @return string
+	 */
 	public static function createUID(){
 		return substr(md5(rand().time()),0,10);
 	}
 	
+	/**
+	 * @brief gets the userid from a principal path
+	 * @return string
+	 */
 	public static function extractUserID($principaluri){
 		list($prefix,$userid) = Sabre_DAV_URLUtil::splitPath($principaluri);
 		return $userid;
 	}
 
+	/**
+	 * @brief Escapes semicolons
+	 * @param string $value
+	 * @return string
+	 */
 	public static function escapeSemicolons($value){
 		foreach($value as &$i ){
 			$i = implode("\\\\;", explode(';', $i));
@@ -277,6 +412,11 @@ class OC_Contacts_Addressbook{
 		return implode(';',$value);
 	}
 
+	/**
+	 * @brief Creates an array out of a multivalue property
+	 * @param string $value
+	 * @return array
+	 */
 	public static function unescapeSemicolons($value){
 		$array = explode(';',$value);
 		for($i=0;$i<count($array);$i++){
@@ -294,6 +434,13 @@ class OC_Contacts_Addressbook{
 		return $array;
 	}
 
+	/**
+	 * @brief Data structure of vCard
+	 * @param object $property
+	 * @return associative array
+	 *
+	 * look at code ...
+	 */
 	public static function structureContact($object){
 		$details = array();
 		foreach($object->children as $property){
@@ -308,6 +455,17 @@ class OC_Contacts_Addressbook{
 		return $details;
 	}
 	
+	/**
+	 * @brief Data structure of properties
+	 * @param object $property
+	 * @return associative array
+	 *
+	 * returns an associative array with 
+	 * ['name'] name of property
+	 * ['value'] htmlspecialchars escaped value of property
+	 * ['parameters'] associative array name=>value
+	 * ['checksum'] checksum of whole property
+	 */
 	public static function structureProperty($property){
 		$value = $property->value;
 		$value = htmlspecialchars($value);
@@ -329,4 +487,20 @@ class OC_Contacts_Addressbook{
 		}
 		return $temp;
 	}
+
+	/**
+	 * @brief Checks if SabreDAV can parse the file
+	 * @param string vCard
+	 * @return boolean
+	 *
+	 * The code is largely copypasted from Sabre_VObject_Reader
+	 */
+	public static function isValidVObject($data){
+		try {
+			Sabre_VObject_Reader::read($data);
+			return true;
+		} catch (Exception $e) {
+			return false;
+		}
+	}
 }
diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php
index 46e85a09d1..6d67584b29 100644
--- a/apps/contacts/templates/index.php
+++ b/apps/contacts/templates/index.php
@@ -3,15 +3,16 @@ OC_Util::addScript('contacts','interface');
 OC_Util::addStyle('contacts','styles');
 ?>
 
+<div id="controls">
+	<form>
+		<input type="button" id="contacts_newcontact" value="<?php echo $l->t('Add Contact'); ?>">
+	</form>
+</div>
 <div id="leftcontent" class="leftcontent">
 	<ul>
 		<?php echo $this->inc("part.contacts"); ?>
 	</ul>
-	<a id="contacts_newcontact"><?php echo $l->t('Add Contact'); ?></a>
 </div>
 <div id="rightcontent" class="rightcontent" data-id="<?php echo $_['id']; ?>">
 	<?php echo $this->inc("part.details"); ?>
 </div>
-<?php if(count($_['addressbooks']) == 1 ): ?>
-	<?php echo $l->t('The path to this addressbook is %s', array(((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST'].OC::$WEBROOT.'/apps/contacts/carddav.php/addressbooks/'.OC_User::getUser().'/'.$_['addressbooks'][0]['uri'])); ?>
-<?php endif; ?>
diff --git a/apps/contacts/templates/part.addcardform.php b/apps/contacts/templates/part.addcardform.php
index 94a59fe097..e87c64507d 100644
--- a/apps/contacts/templates/part.addcardform.php
+++ b/apps/contacts/templates/part.addcardform.php
@@ -2,12 +2,14 @@
 	<?php if(count($_['addressbooks'])==1): ?>
 		<input type="hidden" name="id" value="<?php echo $_['addressbooks'][0]['id']; ?>">
 	<?php else: ?>
+		<label for="id"><?php echo $l->t('Group'); ?></label>
 		<select name="id" size="1">
 			<?php foreach($_['addressbooks'] as $addressbook): ?>
 				<option value="<?php echo $addressbook['id']; ?>"><?php echo $addressbook['displayname']; ?></option>
 			<?php endforeach; ?>
 		</select>
 	<?php endif; ?>
+	<label for="fn"><?php echo $l->t('Name'); ?></label>
 	<input type="text" name="fn" value=""><br>
-	<input type="submit">
+	<input type="submit" name="submit" value="<?php echo $l->t('Create Contact'); ?>">
 </form>
diff --git a/apps/contacts/templates/part.details.php b/apps/contacts/templates/part.details.php
index 81b32f2ff5..c6bedcdd91 100644
--- a/apps/contacts/templates/part.details.php
+++ b/apps/contacts/templates/part.details.php
@@ -29,7 +29,7 @@
 	</table>
 <?php endif; ?>
 
-<div id="contacts_cardoptions">
-	<a id="contacts_deletecard"><img class="svg action" alt="<?php echo $l->t('Delete');?>" src="<?php echo image_path('', 'actions/delete.svg'); ?>" /></a>
-	<a id="contacts_addproperty"><img class="svg action" alt="<?php echo $l->t('Download');?>" src="<?php echo image_path('', 'actions/download.svg'); ?>" /></a>
-</div>
+<form>
+	<input type="button" id="contacts_deletecard" value="<?php echo $l->t('Delete');?>">
+	<input type="button" id="contacts_addproperty" value="<?php echo $l->t('Add Property');?>">
+</form>
diff --git a/apps/contacts/templates/part.setpropertyform.php b/apps/contacts/templates/part.setpropertyform.php
index d8127bb08b..52483ebf4b 100644
--- a/apps/contacts/templates/part.setpropertyform.php
+++ b/apps/contacts/templates/part.setpropertyform.php
@@ -2,17 +2,17 @@
 	<input type="hidden" name="checksum" value="<?php echo $_['property']['checksum']; ?>">
 	<input type="hidden" name="id" value="<?php echo $_['id']; ?>">
 	<?php if($_['property']['name']=='ADR'): ?>
-		<?php echo $l->t('PO Box'); ?> <input type="text" name="value[0]" value="<?php echo $_['property']['value'][0]; ?>">
-		<?php echo $l->t('Extended Address'); ?> <input type="text" name="value[1]" value="<?php echo $_['property']['value'][1]; ?>">
-		<?php echo $l->t('Street Name'); ?> <input type="text" name="value[2]" value="<?php echo $_['property']['value'][2]; ?>">
-		<?php echo $l->t('City'); ?> <input type="text" name="value[3]" value="<?php echo $_['property']['value'][3]; ?>">
-		<?php echo $l->t('Region'); ?> <input type="text" name="value[4]" value="<?php echo $_['property']['value'][4]; ?>">
-		<?php echo $l->t('Postal Code'); ?> <input type="text" name="value[5]" value="<?php echo $_['property']['value'][5]; ?>">
-		<?php echo $l->t('Country'); ?> <input type="text" name="value[6]" value="<?php echo $_['property']['value'][6]; ?>">
+		<label><?php echo $l->t('PO Box'); ?></label> <input type="text" name="value[0]" value="<?php echo $_['property']['value'][0]; ?>"><br>
+		<label><?php echo $l->t('Extended Address'); ?></label> <input type="text" name="value[1]" value="<?php echo $_['property']['value'][1]; ?>"><br>
+		<label><?php echo $l->t('Street Name'); ?></label> <input type="text" name="value[2]" value="<?php echo $_['property']['value'][2]; ?>"><br>
+		<label><?php echo $l->t('City'); ?></label> <input type="text" name="value[3]" value="<?php echo $_['property']['value'][3]; ?>"><br>
+		<label><?php echo $l->t('Region'); ?></label> <input type="text" name="value[4]" value="<?php echo $_['property']['value'][4]; ?>"><br>
+		<label><?php echo $l->t('Postal Code'); ?></label> <input type="text" name="value[5]" value="<?php echo $_['property']['value'][5]; ?>"><br>
+		<label><?php echo $l->t('Country'); ?></label> <input type="text" name="value[6]" value="<?php echo $_['property']['value'][6]; ?>"><br>
 	<?php elseif($_['property']['name']=='TEL'): ?>
 		<input type="text" name="value" value="<?php echo $_['property']['value']; ?>">
 	<?php else: ?>
 		<input type="text" name="value" value="<?php echo $_['property']['value']; ?>">
 	<?php endif; ?>
-	<input type="submit">
+	<input type="submit" value="<?php echo $l->t('Edit'); ?>">
 </form>
-- 
GitLab