diff --git a/apps/contacts/appinfo/app.php b/apps/contacts/appinfo/app.php new file mode 100644 index 0000000000..f38a45f279 --- /dev/null +++ b/apps/contacts/appinfo/app.php @@ -0,0 +1,18 @@ + 10, + 'id' => 'contacts', + 'name' => 'Contacts' )); + +OC_App::addNavigationEntry( array( + 'id' => 'contacts_index', + 'order' => 10, + 'href' => OC_Helper::linkTo( 'contacts', 'index.php' ), + 'icon' => OC_Helper::imagePath( 'contacts', 'icon.png' ), + 'name' => 'Addressbook' )); + +?> diff --git a/apps/contacts/appinfo/info.xml b/apps/contacts/appinfo/info.xml new file mode 100644 index 0000000000..93463b9cf0 --- /dev/null +++ b/apps/contacts/appinfo/info.xml @@ -0,0 +1,9 @@ + + + contacts + Contacts + 0.1 + AGPL + Jakob Sack + 2 + diff --git a/apps/contacts/carddav.php b/apps/contacts/carddav.php new file mode 100644 index 0000000000..ae2c5b9736 --- /dev/null +++ b/apps/contacts/carddav.php @@ -0,0 +1,28 @@ +setBaseUri($WEBROOT.'/apps/contacts/carddav.php'); +// Add plugins +$server->addPlugin(new Sabre_DAV_Auth_Plugin($authBackend,'ownCloud')); +$server->addPlugin(new Sabre_CardDAV_Plugin()); +$server->addPlugin(new Sabre_DAVACL_Plugin()); + +// And off we go! +$server->exec(); diff --git a/apps/contacts/css/styles.css b/apps/contacts/css/styles.css new file mode 100644 index 0000000000..8d1c8b69c3 --- /dev/null +++ b/apps/contacts/css/styles.css @@ -0,0 +1 @@ + diff --git a/apps/contacts/details.php b/apps/contacts/details.php new file mode 100644 index 0000000000..7ab1b64de2 --- /dev/null +++ b/apps/contacts/details.php @@ -0,0 +1,57 @@ +. + * + */ + +// Init owncloud +require_once('../../lib/base.php'); + +$id = $_GET['id']; + +$l10n = new OC_L10N('contacts'); + +// Check if we are a user +if( !OC_User::isLoggedIn()){ + echo $l10n->t('You need to log in!'); + exit(); +} + + +$card = OC_Contacts_Addressbook::findCard( $id ); +if( $card === false ){ + echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('Can not find Contact!')))); + exit(); +} + +$addressbook = OC_Contacts_Addressbook::findAddressbook( $card['addressbookid'] ); +if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){ + echo json_encode( array( 'status' => 'error', 'data' => array( 'message' => $l10n->t('This is not your contact!')))); + exit(); +} + +$vcard = Sabre_VObject_Reader::read($card['carddata']); +$details = OC_Contacts_Addressbook::structureContact($vcard); + +$tmpl = new OC_Template('contacts','_details'); +$tmpl->assign('details',$details); +$tmpl->assign('id',$id); +$page = $tmpl->fetchPage(); + +echo json_encode( array( 'status' => 'success', 'data' => array( 'page' => $page ))); diff --git a/apps/contacts/img/icon.png b/apps/contacts/img/icon.png new file mode 100644 index 0000000000..ea2ed9e333 Binary files /dev/null and b/apps/contacts/img/icon.png differ diff --git a/apps/contacts/index.php b/apps/contacts/index.php new file mode 100644 index 0000000000..2d5bcefd87 --- /dev/null +++ b/apps/contacts/index.php @@ -0,0 +1,68 @@ +. + * + */ + +function contactsort($a,$b){ + return strcmp($a['name'],$b['name']); +} + +// Init owncloud +require_once('../../lib/base.php'); + +// Check if we are a user +if( !OC_User::isLoggedIn()){ + header( 'Location: '.OC_Helper::linkTo( '', 'index.php' )); + exit(); +} + +// Load the files we need +OC_App::setActiveNavigationEntry( 'contacts_index' ); + +// Load a specific user? +$id = isset( $_GET['id'] ) ? $_GET['id'] : null; + +// Addressbooks to load +$openaddressbooks = explode(';',OC_Preferences::getValue(OC_User::getUser(),'contacts','openaddressbooks',null)); + +$contacts = array(); +foreach( $openaddressbooks as $addressbook ){ + $addressbookcontacts = OC_Contacts_Addressbook::allCards($addressbook); + foreach( $addressbookcontacts as $contact ){ + $contacts[] = array( 'name' => $contact['fullname'], 'id' => $contact['id'] ); + } +} + + +usort($contacts,'contactsort'); +$details = array(); + +if( !is_null($id) || count($contacts)){ + $contact = OC_Contacts_Addressbook::findCard(is_null($id)?$contacts[0]['id']:$id); + $vcard = Sabre_VObject_Reader::read($contact['carddata']); + $details = OC_Contacts_Addressbook::structureContact($vcard); +} + +// Process the template +$tmpl = new OC_Template( 'contacts', 'index', 'user' ); +$tmpl->assign('contacts', $contacts); +$tmpl->assign('details', $details ); +$tmpl->assign('id',$id); +$tmpl->printPage(); diff --git a/apps/contacts/js/interface.js b/apps/contacts/js/interface.js new file mode 100644 index 0000000000..045562b496 --- /dev/null +++ b/apps/contacts/js/interface.js @@ -0,0 +1,14 @@ +$(document).ready(function(){ + $('.contacts_contacts').find('li').live('click',function(){ + var id = $(this).attr('x-id'); + $.getJSON('details.php',{'id':id},function(jsondata){ + if(jsondata.status == 'success'){ + $('.contacts_details').html(jsondata.data.page); + } + else{ + alert(jsondata.data.message); + } + }); + return false; + }); +}); diff --git a/apps/contacts/lib/addressbook.php b/apps/contacts/lib/addressbook.php new file mode 100644 index 0000000000..c0f26c7df5 --- /dev/null +++ b/apps/contacts/lib/addressbook.php @@ -0,0 +1,287 @@ +. + * + */ +/* + * + * The following SQL statement is just a help for developers and will not be + * executed! + * + * CREATE TABLE contacts_addressbooks ( + * id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + * userid VARCHAR(255) NOT NULL, + * displayname VARCHAR(255), + * uri VARCHAR(100), + * description TEXT, + * ctag INT(11) UNSIGNED NOT NULL DEFAULT '1' + * ); + * + * CREATE TABLE contacts_cards ( + * id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + * addressbookid INT(11) UNSIGNED NOT NULL, + * fullname VARCHAR(255), + * carddata TEXT, + * uri VARCHAR(100), + * lastmodified INT(11) UNSIGNED + * ); + */ + +/** + * This class manages our addressbooks. + */ +class OC_Contacts_Addressbook{ + public static function allAddressbooks($uid){ + $stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE userid = ?' ); + $result = $stmt->execute(array($uid)); + + $addressbooks = array(); + while( $row = $result->fetchRow()){ + $addressbooks[] = $row; + } + + return $addressbooks; + } + + public static function allAddressbooksWherePrincipalURIIs($principaluri){ + $uid = self::extractUserID($principaluri); + return self::allAddressbooks($uid); + } + + public static function findAddressbook($id){ + $stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_addressbooks WHERE id = ?' ); + $result = $stmt->execute(array($id)); + + return $result->fetchRow(); + } + + public static function addAddressbook($userid,$name,$description){ + $all = self::allAddressbooks($userid); + $uris = array(); + foreach($all as $i){ + $uris[] = $i['uri']; + } + + $uri = self::createURI('name', $uris ); + + $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_addressbooks (userid,displayname,uri,description,ctag) VALUES(?,?,?,?,?)' ); + $result = $stmt->execute(array($userid,$name,$uri,$description,1)); + + return OC_DB::insertid(); + } + + public static function addAddressbookFromDAVData($principaluri,$uri,$name,$description){ + $userid = self::extractUserID($principaluri); + + $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_addressbooks (userid,displayname,uri,description,ctag) VALUES(?,?,?,?,?)' ); + $result = $stmt->execute(array($userid,$name,$uri,$description,1)); + + return OC_DB::insertid(); + } + + public static function editAddressbook($id,$name,$description){ + // Need these ones for checking uri + $addressbook = self::find($id); + + if(is_null($name)){ + $name = $addressbook['name']; + } + if(is_null($description)){ + $description = $addressbook['description']; + } + + $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_addressbooks SET displayname=?,description=?, ctag=ctag+1 WHERE id=?' ); + $result = $stmt->execute(array($name,$description,$id)); + + return true; + } + + public static function touchAddressbook($id){ + $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_addressbooks SET ctag = ctag + 1 WHERE id = ?' ); + $stmt->execute(array($id)); + + return true; + } + + public static function deleteAddressbook($id){ + $stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_cards WHERE id = ?' ); + $stmt->execute(array($id)); + + $stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE addressbookid = ?' ); + $stmt->execute(array($id)); + + return true; + } + + public static function allCards($id){ + $stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE addressbookid = ?' ); + $result = $stmt->execute(array($id)); + + $addressbooks = array(); + while( $row = $result->fetchRow()){ + $addressbooks[] = $row; + } + + return $addressbooks; + } + + public static function findCard($id){ + $stmt = OC_DB::prepare( 'SELECT * FROM *PREFIX*contacts_cards WHERE id = ?' ); + $result = $stmt->execute(array($id)); + + return $result->fetchRow(); + } + + 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)); + + return $result->fetchRow(); + } + + 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'; + } + } + $uri = self::createUID().'.vcf'; + + $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' ); + $result = $stmt->execute(array($id,$fn,$data,$uri,time())); + + self::touch($id); + + return OC_DB::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; + } + } + + $stmt = OC_DB::prepare( 'INSERT INTO *PREFIX*contacts_cards (addressbookid,fullname,carddata,uri,lastmodified) VALUES(?,?,?,?,?)' ); + $result = $stmt->execute(array($id,$fn,$data,$uri,time())); + + self::touch($id); + + return OC_DB::insertid; + } + + public static function editCard($id, $data){ + $oldcard = self::findCard($id,$aid,$uri); + $fn = null; + $card = Sabre_VObject_Reader::read($data); + foreach($card->children as $property){ + if($property->name == 'FN'){ + $fn = $property->value; + } + } + + $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' ); + $result = $stmt->execute(array($fn,$data,time(),$id)); + + self::touch($oldcard['addressbookid']); + + return true; + } + + 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; + } + } + + $stmt = OC_DB::prepare( 'UPDATE *PREFIX*contacts_cards SET fullname = ?,carddata = ?, lastmodified = ? WHERE id = ?' ); + $result = $stmt->execute(array($fn,$data,time(),$oldcard['id'])); + + self::touch($oldcard['addressbookid']); + + return true; + } + + public static function deleteCard($id){ + $stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE id = ?' ); + $stmt->execute(array($id)); + + return true; + } + + public static function deleteCardFromDAVData($aid,$uri){ + $stmt = OC_DB::prepare( 'DELETE FROM *PREFIX*contacts_addressbooks WHERE addressbookid = ? AND uri=?' ); + $stmt->execute(array($aid,$uri)); + + return true; + } + + public static function createURI($name,$existing){ + $name = strtolower($name); + $newname = $name; + $i = 1; + while(in_array($newname,$existing)){ + $newname = $name.$i; + $i = $i + 1; + } + return $newname; + } + + public static function createUID(){ + return substr(md5(rand().time()),0,10); + } + + public static function extractUserID($principaluri){ + list($prefix,$userid) = Sabre_DAV_URLUtil::splitPath($principaluri); + return $userid; + } + + public static function structureContact($object){ + $details = array(); + foreach($object->children as $property){ + $temp = array( + 'name' => $property->name, + 'value' => ($property->name == 'PHOTO' || $property->name == 'LOGO' ? null : $property->value ), + 'parameters' => array()); + foreach($property->parameters as $parameter){ + $temp['parameters'][] = array( 'name' => $parameter->name, 'value' => $parameter->value); + } + if(array_key_exists($property->name,$details)){ + $details[$property->name][] = $temp; + } + else{ + $details[$property->name] = array($temp); + } + } + return $details; + } +} diff --git a/apps/contacts/lib/connector_sabre.php b/apps/contacts/lib/connector_sabre.php new file mode 100644 index 0000000000..98e2598b3a --- /dev/null +++ b/apps/contacts/lib/connector_sabre.php @@ -0,0 +1,186 @@ + $i['id'], + 'uri' => $i['uri'], + 'principaluri' => 'principals/'.$i['userid'], + '{DAV:}displayname' => $i['displayname'], + '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' => $i['description'], + '{http://calendarserver.org/ns/}getctag' => $i['ctag'], + ); + } + + return $addressbooks; + } + + + /** + * Updates an addressbook's properties + * + * See Sabre_DAV_IProperties for a description of the mutations array, as + * well as the return value. + * + * @param mixed $addressbookid + * @param array $mutations + * @see Sabre_DAV_IProperties::updateProperties + * @return bool|array + */ + public function updateAddressBook($addressbookid, array $mutations) { + $name = null; + $description = null; + + foreach($mutations as $property=>$newvalue) { + switch($property) { + case '{DAV:}displayname' : + $name = $newvalue; + break; + case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' : + $description = $newvalue; + break; + default : + // If any unsupported values were being updated, we must + // let the entire request fail. + return false; + } + } + + OC_Contacts_Addressbook::editAddressbook($addressbookid,$name,$description); + + return true; + + } + + /** + * Creates a new address book + * + * @param string $principaluri + * @param string $url Just the 'basename' of the url. + * @param array $properties + * @return void + */ + public function createAddressBook($principaluri, $url, array $properties) { + + $displayname = null; + $description = null; + + foreach($properties as $property=>$newvalue) { + + switch($property) { + case '{DAV:}displayname' : + $displayname = $newvalue; + break; + case '{' . Sabre_CardDAV_Plugin::NS_CARDDAV . '}addressbook-description' : + $description = $newvalue; + break; + default : + throw new Sabre_DAV_Exception_BadRequest('Unknown property: ' . $property); + } + + } + + OC_Contacts_Addressbook::addAddressbookFromDAVData($principaluri,$url,$name,$description); + } + + /** + * Deletes an entire addressbook and all its contents + * + * @param int $addressbookid + * @return void + */ + public function deleteAddressBook($addressbookid) { + OC_Contacts_Addressbook::deleteAddressbook($addressbookid); + } + + /** + * Returns all cards for a specific addressbook id. + * + * @param mixed $addressbookid + * @return array + */ + public function getCards($addressbookid) { + $data = OC_Contacts_Addressbook::allCards($addressbookid); + $cards = array(); + foreach($data as $i){ + $cards[] = array( + 'id' => $i['id'], + 'carddata' => $i['carddata'], + 'uri' => $i['uri'], + 'lastmodified' => $i['lastmodified'] ); + } + + return $cards; + } + + /** + * Returns a specfic card + * + * @param mixed $addressbookid + * @param string $carduri + * @return array + */ + public function getCard($addressbookid, $carduri) { + return OC_Contacts_Addressbook::findCardWhereDAVDataIs($addressbookid,$carduri); + + } + + /** + * Creates a new card + * + * @param mixed $addressbookid + * @param string $carduri + * @param string $carddata + * @return bool + */ + public function createCard($addressbookid, $carduri, $carddata) { + OC_Contacts_Addressbook::addCardFromDAVData($addressbookid, $carduri, $carddata); + return true; + } + + /** + * Updates a card + * + * @param mixed $addressbookid + * @param string $carduri + * @param string $carddata + * @return bool + */ + public function updateCard($addressbookid, $carduri, $carddata) { + return OC_Contacts_Addressbook::editCardFromDAVData($addressbookid, $carduri, $carddata); + } + + /** + * Deletes a card + * + * @param mixed $addressbookid + * @param string $carduri + * @return bool + */ + public function deleteCard($addressbookid, $carduri) { + return OC_Contacts_Addressbook::deleteCardFromDAVData($addressbookid, $carduri); + } +} diff --git a/apps/contacts/photo.php b/apps/contacts/photo.php new file mode 100644 index 0000000000..62386421cd --- /dev/null +++ b/apps/contacts/photo.php @@ -0,0 +1,85 @@ +. + * + */ + +// Init owncloud +require_once('../../lib/base.php'); + +$id = $_GET['id']; + +$l10n = new OC_L10N('contacts'); + +// Check if we are a user +if( !OC_User::isLoggedIn()){ + echo $l10n->t('You need to log in!'); + exit(); +} + + +$card = OC_Contacts_Addressbook::findCard( $id ); +if( $card === false ){ + echo $l10n->t('Can not find Contact!'); + exit(); +} + +$addressbook = OC_Contacts_Addressbook::findAddressbook( $card['addressbookid'] ); +if( $addressbook === false || $addressbook['userid'] != OC_USER::getUser()){ + echo $l10n->t('This is not your contact!'); + exit(); +} + +$content = Sabre_VObject_Reader::read($card['carddata']); + +// Photo :-) +foreach($content->children as $child){ + if($child->name == 'PHOTO'){ + $mime = 'image/jpeg'; + foreach($child->parameters as $parameter){ + if( $parameter->name == 'TYPE' ){ + $mime = $parameter->value; + } + } + $photo = base64_decode($child->value); + header('Content-Type: '.$mime); + header('Content-Length: ' . strlen($photo)); + echo $photo; + exit(); + } +} +// Logo :-/ +foreach($content->children as $child){ + if($child->name == 'PHOTO'){ + $mime = 'image/jpeg'; + foreach($child->parameters as $parameter){ + if($parameter->name == 'TYPE'){ + $mime = $parameter->value; + } + } + $photo = base64_decode($child->value()); + header('Content-Type: '.$mime); + header('Content-Length: ' . strlen($photo)); + echo $photo; + exit(); + } +} + +// Not found :-( +echo $l10n->t('This card does not contain photo data!'); diff --git a/apps/contacts/templates/_contacts.php b/apps/contacts/templates/_contacts.php new file mode 100644 index 0000000000..bf633b79b0 --- /dev/null +++ b/apps/contacts/templates/_contacts.php @@ -0,0 +1,3 @@ + +
  • + diff --git a/apps/contacts/templates/_details.php b/apps/contacts/templates/_details.php new file mode 100644 index 0000000000..e27b17ef2e --- /dev/null +++ b/apps/contacts/templates/_details.php @@ -0,0 +1,4 @@ +Name + + + \ No newline at end of file diff --git a/apps/contacts/templates/index.php b/apps/contacts/templates/index.php new file mode 100644 index 0000000000..0cd214bfb1 --- /dev/null +++ b/apps/contacts/templates/index.php @@ -0,0 +1,13 @@ + + +
    + +
    +
    + inc("_details"); ?> +