1<?php 2/** 3 * Horde_ActiveSync_Request_ResolveRecipients:: 4 * 5 * @license http://www.horde.org/licenses/gpl GPLv2 6 * 7 * @copyright 2012-2020 Horde LLC (http://www.horde.org) 8 * @author Michael J Rubinsky <mrubinsk@horde.org> 9 * @package ActiveSync 10 */ 11/** 12 * ActiveSync Handler for resolving recipients. 13 * 14 * @license http://www.horde.org/licenses/gpl GPLv2 15 * 16 * @copyright 2012-2020 Horde LLC (http://www.horde.org) 17 * @author Michael J Rubinsky <mrubinsk@horde.org> 18 * @package ActiveSync 19 * @internal 20 */ 21class Horde_ActiveSync_Request_ResolveRecipients extends Horde_ActiveSync_Request_Base 22{ 23 const TAG_RESOLVERECIPIENTS = 'ResolveRecipients:ResolveRecipients'; 24 const TAG_RESPONSE = 'ResolveRecipients:Response'; 25 const TAG_STATUS = 'ResolveRecipients:Status'; 26 const TAG_TYPE = 'ResolveRecipients:Type'; 27 const TAG_RECIPIENT = 'ResolveRecipients:Recipient'; 28 const TAG_DISPLAYNAME = 'ResolveRecipients:DisplayName'; 29 const TAG_EMAILADDRESS = 'ResolveRecipients:EmailAddress'; 30 const TAG_CERTIFICATES = 'ResolveRecipients:Certificates'; 31 const TAG_CERTIFICATE = 'ResolveRecipients:Certificate'; 32 const TAG_MINICERTIFICATE = 'ResolveRecipients:MiniCertificate'; 33 const TAG_OPTIONS = 'ResolveRecipients:Options'; 34 const TAG_TO = 'ResolveRecipients:To'; 35 const TAG_CERTIFICATERETRIEVAL = 'ResolveRecipients:CertificateRetrieval'; 36 const TAG_RECIPIENTCOUNT = 'ResolveRecipients:RecipientCount'; 37 const TAG_MAXCERTIFICATES = 'ResolveRecipients:MaxCertificates'; 38 const TAG_MAXAMBIGUOUSRECIPIENTS = 'ResolveRecipients:MaxAmbiguousRecipients'; 39 const TAG_CERTIFICATECOUNT = 'ResolveRecipients:CertificateCount'; 40 const TAG_MAXSIZE = 'ResolveRecipients:MaxSize'; 41 const TAG_DATA = 'ResolveRecipients:Data'; 42 const TAG_PICTURE = 'ResolveRecipients:Picture'; 43 const TAG_MAXPICTURES = 'ResolveRecipients:MaxPictures'; 44 45 // 14 46 const TAG_AVAILABILITY = 'ResolveRecipients:Availability'; 47 const TAG_STARTTIME = 'ResolveRecipients:StartTime'; 48 const TAG_ENDTIME = 'ResolveRecipients:EndTime'; 49 const TAG_MERGEDFREEBUSY = 'ResolveRecipients:MergedFreeBusy'; 50 51 /* Certificate Retrieval */ 52 const CERT_RETRIEVAL_NONE = 1; 53 const CERT_RETRIEVAL_FULL = 2; 54 const CERT_RETRIEVAL_MINI = 3; 55 56 /* Global Status */ 57 const STATUS_SUCCESS = 1; 58 const STATUS_PROTERR = 5; 59 const STATUS_SERVERERR = 6; 60 61 /* Response Status */ 62 const STATUS_RESPONSE_SUCCESS = 1; 63 const STATUS_RESPONSE_AMBSUGG = 2; 64 const STATUS_RESPONSE_NONE = 4; 65 66 /* Certificate Status */ 67 const STATUS_CERT_SUCCESS = 1; 68 const STATUS_CERT_NOCERT = 7; 69 const STATUS_LIMIT = 8; 70 71 /* Availability Status */ 72 const STATUS_AVAIL_SUCCESS = 1; 73 const STATUS_AVAIL_MAXRECIPIENTS = 160; 74 const STATUS_AVAIL_MAXLIST = 161; 75 const STATUS_AVAIL_TEMPFAILURE = 162; 76 const STATUS_AVAIL_NOTFOUND = 163; 77 78 /** 79 * Handle the request 80 * 81 * @return boolean 82 * @throws Horde_ActiveSync_Exception 83 */ 84 protected function _handle() 85 { 86 $this->_logger->meta('Handling RESOLVERECIPIENTS command.'); 87 if (!$this->_decoder->getElementStartTag(self::TAG_RESOLVERECIPIENTS)) { 88 return false; 89 } 90 $status = self::STATUS_SUCCESS; 91 92 while ($status == self::STATUS_SUCCESS && 93 ($field = ($this->_decoder->getElementStartTag(self::TAG_TO) ? self::TAG_TO : 94 ($this->_decoder->getElementStartTag(self::TAG_OPTIONS) ? self::TAG_OPTIONS : 95 -1))) != -1) { 96 97 if ($field == self::TAG_OPTIONS) { 98 while ($status == self::STATUS_SUCCESS && 99 ($option = ($this->_decoder->getElementStartTag(self::TAG_CERTIFICATERETRIEVAL) ? self::TAG_CERTIFICATERETRIEVAL : 100 ($this->_decoder->getElementStartTag(self::TAG_MAXCERTIFICATES) ? self::TAG_MAXCERTIFICATES : 101 ($this->_decoder->getElementStartTag(self::TAG_MAXAMBIGUOUSRECIPIENTS) ? self::TAG_MAXAMBIGUOUSRECIPIENTS : 102 ($this->_decoder->getElementStartTag(self::TAG_AVAILABILITY) ? self::TAG_AVAILABILITY : 103 ($this->_decoder->getElementStartTag(self::TAG_PICTURE) ? self::TAG_PICTURE : 104 -1)))))) != -1) { 105 106 if ($option == self::TAG_AVAILABILITY) { 107 $options[self::TAG_AVAILABILITY] = true; 108 while ($status == self::STATUS_SUCCESS && 109 ($tag = ($this->_decoder->getElementStartTag(self::TAG_STARTTIME) ? self::TAG_STARTTIME : 110 ($this->_decoder->getElementStartTag(self::TAG_ENDTIME) ? self::TAG_ENDTIME : 111 -1))) != -1) { 112 $options[$tag] = $this->_decoder->getElementContent(); 113 if (!$this->_decoder->getElementEndTag()) { 114 $status = self::STATUS_PROTERR; 115 } 116 } 117 } elseif ($option == self::TAG_PICTURE) { 118 $options[self::TAG_PICTURE] = true; 119 while ($status == self::STATUS_SUCCESS && 120 ($tag = ($this->_decoder->getElementStartTag(self::TAG_MAXSIZE) ? self::TAG_MAXSIZE : 121 ($this->_decoder->getElementStartTag(self::TAG_MAXPICTURES) ? self::TAG_MAXPICTURES : 122 -1 ))) != -1) { 123 124 if ($tag == self::TAG_MAXSIZE) { 125 $options[self::TAG_MAXSIZE] = $this->_decoder->getElementContent(); 126 if (!$this->_decoder->getElementEndTag()) { 127 $status = self::STATUS_PROTERR; 128 } 129 } 130 if ($tag == self::TAG_MAXPICTURES) { 131 $options[self::TAG_MAXPICTURES] = $this->_decoder->getElementContent(); 132 if (!$this->_decoder->getElementEndTag()) { 133 $status = self::STATUS_PROTERR; 134 } 135 } 136 } 137 } else { 138 $options[$option] = $this->_decoder->getElementContent(); 139 } 140 141 if (!$this->_decoder->getElementEndTag()) { 142 $status = self::STATUS_PROTERR; 143 } 144 } 145 if (!$this->_decoder->getElementEndTag()) { 146 $status = self::STATUS_PROTERR; 147 } 148 } elseif ($field == self::TAG_TO) { 149 $content = $this->_decoder->getElementContent(); 150 $to[] = $content; 151 if (!$this->_decoder->getElementEndTag()) { 152 $status = self::STATUS_PROTERR; 153 } 154 } 155 } 156 157 // Verify max isn't attempted. 158 if (isset($options[self::TAG_AVAILABILITY]) && count($to) > 100) { 159 // Specs say to send this, but it's defined as a child of the 160 // self::TAG_AVAILABILITY response. If we have too many recipients, 161 // we don't check the availability?? Not sure what to do with this. 162 // For now, treat it as a protocol error. 163 //$avail_status = self::STATUS_AVAIL_MAXRECIPIENTS; 164 $status = self::STATUS_PROTERR; 165 } 166 167 $results = array(); 168 if ($status == self::STATUS_SUCCESS) { 169 foreach ($to as $item) { 170 $driver_opts = array( 171 'maxcerts' => !empty($options[self::TAG_MAXCERTIFICATES]) ? $options[self::TAG_MAXCERTIFICATES] : false, 172 'maxambiguous' => !empty($options[self::TAG_MAXAMBIGUOUSRECIPIENTS]) ? $options[self::TAG_MAXAMBIGUOUSRECIPIENTS] : false, 173 'starttime' => !empty($options[self::TAG_STARTTIME]) ? new Horde_Date($options[self::TAG_STARTTIME], 'utc') : false, 174 'endtime' => !empty($options[self::TAG_ENDTIME]) ? new Horde_Date($options[self::TAG_ENDTIME], 'utc') : false, 175 'pictures' => !empty($options[self::TAG_PICTURE]), 176 'maxsize' => !empty($options[self::TAG_MAXSIZE]) ? $options[self::TAG_MAXSIZE] : false, 177 'maxpictures' => !empty($options[self::TAG_MAXPICTURES]) ? $options[self::TAG_MAXPICTURES] : false, 178 ); 179 $results[$item] = $this->_driver->resolveRecipient( 180 isset($options[self::TAG_CERTIFICATERETRIEVAL]) ? 'certificate' : 'availability', 181 $item, 182 $driver_opts 183 ); 184 } 185 } 186 187 $this->_encoder->startWBXML(); 188 $this->_encoder->startTag(self::TAG_RESOLVERECIPIENTS); 189 190 $this->_encoder->startTag(self::TAG_STATUS); 191 $this->_encoder->content($status); 192 $this->_encoder->endTag(); 193 194 foreach ($to as $item) { 195 $this->_encoder->startTag(self::TAG_RESPONSE); 196 197 $this->_encoder->startTag(self::TAG_TO); 198 $this->_encoder->content($item); 199 $this->_encoder->endTag(); 200 201 $this->_encoder->startTag(self::TAG_STATUS); 202 if (empty($results[$item])) { 203 $responseStatus = self::STATUS_RESPONSE_NONE; 204 } elseif (count($results[$item]) > 1) { 205 $responseStatus = self::STATUS_RESPONSE_AMBSUGG; 206 } else { 207 $responseStatus = self::STATUS_RESPONSE_SUCCESS; 208 } 209 $this->_encoder->content($responseStatus); 210 $this->_encoder->endTag(); 211 212 $this->_encoder->startTag(self::TAG_RECIPIENTCOUNT); 213 $this->_encoder->content(count($results[$item])); 214 $this->_encoder->endTag(); 215 216 foreach ($results[$item] as $value) { 217 $this->_encoder->startTag(self::TAG_RECIPIENT); 218 219 $this->_encoder->startTag(self::TAG_TYPE); 220 $this->_encoder->content($value['type']); 221 $this->_encoder->endTag(); 222 223 $this->_encoder->startTag(self::TAG_DISPLAYNAME); 224 $this->_encoder->content($value['displayname']); 225 $this->_encoder->endTag(); 226 227 $this->_encoder->startTag(self::TAG_EMAILADDRESS); 228 $this->_encoder->content($value['emailaddress']); 229 $this->_encoder->endTag(); 230 231 if (isset($options[self::TAG_CERTIFICATERETRIEVAL]) && 232 $options[self::TAG_CERTIFICATERETRIEVAL] > 1) { 233 234 $this->_encoder->startTag(self::TAG_CERTIFICATES); 235 236 $this->_encoder->startTag(self::TAG_STATUS); 237 if (count($value['entries']) == 0) { 238 $certStatus = self::STATUS_CERT_NOCERT; 239 } else { 240 $certStatus = self::STATUS_CERT_SUCCESS; 241 } 242 $this->_encoder->content($certStatus); 243 $this->_encoder->endTag(); 244 245 $this->_encoder->startTag(self::TAG_CERTIFICATECOUNT); 246 $this->_encoder->content(count($value['entries'])); 247 $this->_encoder->endTag(); 248 249 switch ($options[self::TAG_CERTIFICATERETRIEVAL]) { 250 case self::CERT_RETRIEVAL_FULL: 251 foreach($value['entries'] as $cert) { 252 $this->_encoder->startTag(self::TAG_CERTIFICATE); 253 $this->_encoder->content($cert); 254 $this->_encoder->endTag(); 255 } 256 break; 257 case self::CERT_RETRIEVAL_MINI: 258 foreach($value['entries'] as $cert) { 259 $this->_encoder->startTag(self::TAG_MINICERTIFICATE); 260 $this->_encoder->content($cert); 261 $this->_encoder->endTag(); 262 } 263 } 264 $this->_encoder->endTag(); 265 } 266 267 if (isset($options[self::TAG_AVAILABILITY])) { 268 $this->_encoder->startTag(self::TAG_AVAILABILITY); 269 270 $this->_encoder->startTag(self::TAG_STATUS); 271 $this->_encoder->content(empty($value['availability']) ? self::STATUS_AVAIL_NOTFOUND : self::STATUS_AVAIL_SUCCESS); 272 $this->_encoder->endTag(); 273 274 if (!empty($value['availability'])) { 275 $this->_encoder->startTag(self::TAG_MERGEDFREEBUSY); 276 $this->_encoder->content($value['availability']); 277 $this->_encoder->endTag(); 278 } 279 $this->_encoder->endTag(); 280 } 281 282 if ($this->_device->version >= Horde_ActiveSync::VERSION_FOURTEENONE && 283 isset($options[self::TAG_PICTURE]) && 284 !empty($value['picture'])) { 285 286 $this->_encoder->startTag(self::TAG_PICTURE); 287 $value['picture']->encodeStream($this->_encoder); 288 $this->_encoder->endTag(); 289 } 290 291 $this->_encoder->endTag(); // end self::TAG_RECIPIENT 292 } 293 $this->_encoder->endTag(); // end self::TAG_RESPONSE 294 } 295 $this->_encoder->endTag(); // end self::TAG_RESOLVERECIPIENTS 296 297 return true; 298 } 299 300} 301