2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
39 * vCard implementation
44 protected $properties = array();
46 protected $name = 'no_name';
48 public function clear()
50 $this->properties = array();
53 function loadContact($contactid, $module='Contacts') {
54 global $app_list_strings;
56 require_once($GLOBALS['beanFiles'][$GLOBALS['beanList'][$module]]);
57 $contact = new $GLOBALS['beanList'][$module]();
58 $contact->retrieve($contactid);
59 // cn: bug 8504 - CF/LB break Outlook's vCard import
60 $bad = array("\n", "\r");
61 $good = array("=0A", "=0D");
63 if(strpos($contact->primary_address_street, "\n") || strpos($contact->primary_address_street, "\r")) {
64 $contact->primary_address_street = str_replace($bad, $good, $contact->primary_address_street);
65 $encoding = 'QUOTED-PRINTABLE';
68 $this->setName(from_html($contact->first_name), from_html($contact->last_name), $app_list_strings['salutation_dom'][from_html($contact->salutation)]);
69 if ( isset($contact->birthdate) )
70 $this->setBirthDate(from_html($contact->birthdate));
71 $this->setPhoneNumber(from_html($contact->phone_fax), 'FAX');
72 $this->setPhoneNumber(from_html($contact->phone_home), 'HOME');
73 $this->setPhoneNumber(from_html($contact->phone_mobile), 'CELL');
74 $this->setPhoneNumber(from_html($contact->phone_work), 'WORK');
75 $this->setEmail(from_html($contact->email1));
76 $this->setAddress(from_html($contact->primary_address_street), from_html($contact->primary_address_city), from_html($contact->primary_address_state), from_html($contact->primary_address_postalcode), from_html($contact->primary_address_country), 'WORK', $encoding);
77 if ( isset($contact->account_name) )
78 $this->setORG(from_html($contact->account_name), from_html($contact->department));
80 $this->setORG('', from_html($contact->department));
81 $this->setTitle($contact->title);
84 function setTitle($title){
85 $this->setProperty("TITLE",$title );
87 function setORG($org, $dep){
88 $this->setProperty("ORG","$org;$dep" );
90 function setAddress($address, $city, $state,$postal, $country, $type, $encoding=''){
91 if(!empty($encoding)) {
92 $encoding = ";ENCODING={$encoding}";
94 $this->setProperty("ADR;$type$encoding",";;$address;$city;$state;$postal;$country" );
97 function setName($first_name, $last_name, $prefix){
98 $this->name = strtr($first_name.'_'.$last_name, ' ' , '_');
99 $this->setProperty('N',$last_name.';'.$first_name.';;'.$prefix );
100 $this->setProperty('FN',"$prefix $first_name $last_name");
103 function setEmail($address){
104 $this->setProperty('EMAIL;INTERNET', $address);
107 function setPhoneNumber( $number, $type)
110 $this->setProperty("TEL;$type", $number);
113 $this->setProperty("TEL;WORK;$type", $number);
116 function setBirthDate($date){
117 $this->setProperty('BDAY',$date);
119 function getProperty($name){
120 if(isset($this->properties[$name]))
121 return $this->properties[$name];
125 function setProperty($name, $value){
126 $this->properties[$name] = $value;
131 $temp = "BEGIN:VCARD\n";
132 foreach($this->properties as $key=>$value){
134 $temp .= $key. ';CHARSET='.strtolower($locale->getExportCharset()).':'.$value."\n";
136 $temp .= $key. ':'.$value."\n";
139 $temp.= "END:VCARD\n";
145 function saveVCard(){
147 $content = $this->toString();
148 if ( !defined('SUGAR_PHPUNIT_RUNNER') ) {
149 header("Content-Disposition: attachment; filename={$this->name}.vcf");
150 header("Content-Type: text/x-vcard; charset=".$locale->getExportCharset());
151 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT" );
152 header("Last-Modified: " . TimeDate::httpTime() );
153 header("Cache-Control: max-age=0");
154 header("Pragma: public");
155 //bug45856 IIS Doesn't like this to be set and it causes the vCard to not get saved
156 if (preg_match('/iis/i', $_SERVER['SERVER_SOFTWARE']) === 0) {
157 header("Content-Length: ".strlen($content));
161 print $locale->translateCharset($content, 'UTF-8', $locale->getExportCharset());
164 function importVCard($filename, $module='Contacts'){
165 global $current_user;
166 $lines = file($filename);
168 $contact = loadBean($module);
170 $contact->title = 'imported';
171 $contact->assigned_user_id = $current_user->id;
175 for($index = 0; $index < sizeof($lines); $index++){
176 $line = $lines[$index];
178 // check the encoding and change it if needed
179 $locale = new Localization();
180 $encoding = $locale->detectCharset($line);
181 if ( $encoding != $GLOBALS['sugar_config']['default_charset'] ) {
182 $line = $locale->translateCharset($line,$encoding);
187 if(substr_count(strtoupper($line), 'END:VCARD')){
188 if(!isset($contact->last_name)){
189 $contact->last_name = $fullname;
193 $keyvalue = explode(':',$line);
194 if(sizeof($keyvalue)==2){
195 $value = $keyvalue[1];
196 for($newindex= $index + 1; $newindex < sizeof($lines), substr_count($lines[$newindex], ':') == 0; $newindex++){
197 $value .= $lines[$newindex];
200 $values = explode(';',$value );
201 $key = strtoupper($keyvalue[0]);
202 $key = strtr($key, '=', '');
203 $key = strtr($key, ',',';');
204 $keys = explode(';' ,$key);
206 if($keys[0] == 'TEL'){
207 if(substr_count($key, 'WORK') > 0){
208 if(substr_count($key, 'FAX') > 0){
209 if(!isset($contact->phone_fax)){
210 $contact->phone_fax = $value;
213 if(!isset($contact->phone_work)){
214 $contact->phone_work = $value;
218 if(substr_count($key, 'HOME') > 0){
219 if(substr_count($key, 'FAX') > 0){
220 if(!isset($contact->phone_fax)){
221 $contact->phone_fax = $value;
224 if(!isset($contact->phone_home)){
225 $contact->phone_home = $value;
229 if(substr_count($key, 'CELL') > 0){
230 if(!isset($contact->phone_mobile)){
231 $contact->phone_mobile = $value;
235 if(substr_count($key, 'FAX') > 0){
236 if(!isset($contact->phone_fax)){
237 $contact->phone_fax = $value;
244 if(sizeof($values) > 0)
245 $contact->last_name = $values[0];
246 if(sizeof($values) > 1)
247 $contact->first_name = $values[1];
248 if(sizeof($values) > 2)
249 $contact->salutation = $values[2];
254 if($keys[0] == 'FN'){
261 if($keys[0] == 'ADR'){
262 if(substr_count($key, 'WORK') > 0 && (substr_count($key, 'POSTAL') > 0|| substr_count($key, 'PARCEL') == 0)){
264 if(!isset($contact->primary_address_street) && sizeof($values) > 2){
265 $textBreaks = array("\n", "\r");
266 $vcardBreaks = array("=0A", "=0D");
267 $contact->primary_address_street = str_replace($vcardBreaks, $textBreaks, $values[2]);
269 if(!isset($contact->primary_address_city) && sizeof($values) > 3){
270 $contact->primary_address_city = $values[3];
272 if(!isset($contact->primary_address_state) && sizeof($values) > 4){
273 $contact->primary_address_state = $values[4];
275 if(!isset($contact->primary_address_postalcode) && sizeof($values) > 5){
276 $contact->primary_address_postalcode = $values[5];
278 if(!isset($contact->primary_address_country) && sizeof($values) > 6){
279 $contact->primary_address_country = $values[6];
284 if($keys[0] == 'TITLE'){
285 $contact->title = $value;
288 if($keys[0] == 'EMAIL'){
289 $field = 'email' . $email_suffix;
290 if(!isset($contact->$field)) {
291 $contact->$field = $value;
294 if($email_suffix == 1) {
295 $_REQUEST['email1'] = $value;
301 if($keys[0] == 'ORG'){
302 $GLOBALS['log']->debug('I found a company name');
304 $GLOBALS['log']->debug('I found a company name (fer real)');
305 if ( is_a($contact,"Contact") || is_a($contact,"Lead") ) {
306 $GLOBALS['log']->debug('And Im dealing with a person!');
307 $accountBean = loadBean('Accounts');
308 // It's a contact, we better try and match up an account
309 $full_company_name = trim($values[0]);
310 // Do we have a full company name match?
311 $result = $accountBean->retrieve_by_string_fields(array('name' => $full_company_name, 'deleted' => 0));
312 if ( ! isset($result->id) ) {
313 // Try to trim the full company name down, see if we get some other matches
314 $vCardTrimStrings = array('/ltd\.*/i'=>'',
320 // Allow users to override the trimming strings
321 if ( file_exists('custom/include/vCardTrimStrings.php') ) {
322 require_once('custom/include/vCardTrimStrings.php');
324 $short_company_name = trim(preg_replace(array_keys($vCardTrimStrings),$vCardTrimStrings,$full_company_name)," ,.");
326 $GLOBALS['log']->debug('Trying an extended search for: '.$short_company_name);
327 $result = $accountBean->retrieve_by_string_fields(array('name' => $short_company_name, 'deleted' => 0));
330 if ( is_a($contact,"Lead") || ! isset($result->id) ) {
331 // We could not find a parent account, or this is a lead so only copy the name, no linking
332 $GLOBALS['log']->debug("Did not find a matching company ($full_company_name)");
333 $contact->account_id = '';
334 $contact->account_name = $full_company_name;
336 $GLOBALS['log']->debug("Found a matching company: ".$result->name);
337 $contact->account_id = $result->id;
338 $contact->account_name = $result->name;
340 $contact->department = $values[1];
342 $contact->department = $value;
353 //FOUND THE BEGINING OF THE VCARD
354 if(!$start && substr_count(strtoupper($line), 'BEGIN:VCARD')){
360 if ( is_a($contact, "Contact") && empty($contact->account_id) && !empty($contact->account_name) ) {
361 $GLOBALS['log']->debug("Look ma! I'm creating a new account: ".$contact->account_name);
362 // We need to create a new account
363 $accountBean = loadBean('Accounts');
364 // Populate the newly created account with all of the contact information
365 foreach ( $contact->field_defs as $field_name => $field_def ) {
366 if ( !empty($contact->$field_name) ) {
367 $accountBean->$field_name = $contact->$field_name;
370 $accountBean->name = $contact->account_name;
371 $accountBean->save();
372 $contact->account_id = $accountBean->id;
375 $contactId = $contact->save();