1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
18: abstract class Whups_Driver
19: {
20: 21: 22:
23: protected $_params;
24:
25: 26: 27: 28: 29: 30: 31:
32: public function __construct(array $params)
33: {
34: $this->_params = $params;
35: }
36:
37: 38: 39: 40: 41: 42:
43: public function setAttributes(array $info, Whups_Ticket &$ticket)
44: {
45: $ticket_id = $ticket->getId();
46:
47: foreach ($info as $name => $value) {
48: if (substr($name, 0, 10) == 'attribute_' &&
49: $ticket->get($name) != $value) {
50: $attribute_id = (int)substr($name, 10);
51: $serialized = $this->_serializeAttribute($value);
52: $ticket->change($name, $value);
53: $this->_setAttributeValue(
54: $ticket_id,
55: $attribute_id,
56: $serialized);
57: $this->updateLog($ticket_id, $GLOBALS['registry']->getAuth(), array('attribute' => $attribute_id . ':' . $serialized));
58: }
59: }
60: }
61:
62: 63: 64: 65: 66: 67: 68:
69: protected function _serializeAttribute($value)
70: {
71: if (!is_string($value)) {
72: return Horde_Serialize::serialize($value, Horde_Serialize::JSON);
73: }
74: return $value;
75: }
76:
77: 78: 79: 80: 81: 82: 83:
84: public function getHistory($ticket_id, Horde_Form $form = null)
85: {
86: $rows = $this->_getHistory($ticket_id);
87: $attributes = $attributeDetails = array();
88: foreach ($rows as $row) {
89: if ($row['log_type'] == 'attribute' &&
90: strpos($row['log_value'], ':')) {
91: $attributes[(int)$row['log_value']] = $row['attribute_name'];
92: }
93: if ($row['log_type'] == 'type') {
94: $attributeDetails += $this->getAttributesForType($row['log_value']);
95: }
96: }
97:
98: $renderer = new Horde_Core_Ui_VarRenderer_Html();
99: $history = array();
100: foreach ($rows as $row) {
101: $label = null;
102: $human = $value = $row['log_value'];
103: $type = $row['log_type'];
104: $transaction = $row['transaction_id'];
105:
106: $history[$transaction]['timestamp'] = $row['timestamp'];
107: $history[$transaction]['user_id'] = $row['user_id'];
108: $history[$transaction]['ticket_id'] = $row['ticket_id'];
109:
110: switch ($type) {
111: case 'comment':
112: $history[$transaction]['comment'] = $row['comment_text'];
113: $history[$transaction]['changes'][] = array(
114: 'type' => 'comment',
115: 'value' => $row['log_value'],
116: 'comment' => $row['comment_text']);
117: continue 2;
118:
119: case 'queue':
120: $label = $row['queue_name'];
121: break;
122:
123: case 'version':
124: $label = $row['version_name'];
125: break;
126:
127: case 'type':
128: $label = $row['type_name'];
129: break;
130:
131: case 'state':
132: $label = $row['state_name'];
133: break;
134:
135: case 'priority':
136: $label = $row['priority_name'];
137: break;
138:
139: case 'attribute':
140: continue 2;
141:
142: case 'due':
143: $label = $row['log_value_num'];
144: break;
145:
146: default:
147: if (strpos($type, 'attribute_') === 0) {
148: try {
149: $value = Horde_Serialize::unserialize(
150: $value, Horde_Serialize::JSON);
151: } catch (Horde_Serialize_Exception $e) {
152: }
153: $attribute = substr($type, 10);
154: if (isset($attributes[$attribute])) {
155: $label = $attributes[$attribute];
156: if ($form) {
157: if (isset($form->attributes[$attribute])) {
158: 159:
160: $field = $form->attributes[$attribute];
161: } else {
162: 163:
164: $detail = $attributeDetails[$attribute];
165: $field = new Horde_Form_Variable(
166: $detail['human_name'],
167: $type,
168: $form->getType($detail['type'],
169: $detail['params']),
170: $detail['required'],
171: $detail['readonly'],
172: $detail['desc']);
173: }
174: $human = $renderer->render(
175: $form,
176: $field,
177: new Horde_Variables(array($type => $value)));
178: }
179: $type = 'attribute';
180: } else {
181: $label = sprintf(_("Attribute %d"), $attribute);
182: }
183: }
184: break;
185: }
186:
187: $history[$transaction]['changes'][] = array(
188: 'type' => $type,
189: 'value' => $value,
190: 'human' => $human,
191: 'label' => $label);
192: }
193:
194: return $history;
195: }
196:
197: 198:
199: public function getQueue($queueId)
200: {
201: return $GLOBALS['registry']->call('tickets/getQueueDetails',
202: array($queueId));
203: }
204:
205: 206:
207: public function getQueues()
208: {
209: return $GLOBALS['registry']->call('tickets/listQueues');
210: }
211:
212: 213:
214: public function getVersionInfo($queue)
215: {
216: return $GLOBALS['registry']->call('tickets/listVersions',
217: array($queue));
218: }
219:
220: 221: 222:
223: public function getVersions($queue, $all = false)
224: {
225: if (empty($queue)) {
226: return array();
227: }
228:
229: $versioninfo = $this->getVersionInfo($queue);
230: $versions = array();
231: $old_versions = array();
232: foreach ($versioninfo as $vinfo) {
233: $name = $vinfo['name'];
234: if (!empty($vinfo['description'])) {
235: $name .= ': ' . $vinfo['description'];
236: }
237: if ($all && !$vinfo['active']) {
238: $name .= ' ' . _("(inactive)");
239: }
240: if ($vinfo['active']) {
241: $versions[$vinfo['id']] = $name;
242: } else {
243: $old_versions[$vinfo['id']] = $name;
244: }
245: }
246:
247: if ($old_versions && !$all) {
248: $versions[key($old_versions)] = _("Older? Please update first!");
249: } else {
250: $versions += $old_versions;
251: }
252:
253: return $versions;
254: }
255:
256: 257:
258: public function getVersion($version)
259: {
260: return $GLOBALS['registry']->call('tickets/getVersionDetails',
261: array($version));
262: }
263:
264: 265:
266: public function getCategories()
267: {
268: return array('unconfirmed' => _("Unconfirmed"),
269: 'new' => _("New"),
270: 'assigned' => _("Assigned"),
271: 'resolved' => _("Resolved"));
272: }
273:
274: 275: 276: 277: 278: 279: 280:
281: public function getAttributesForType($type = null)
282: {
283: $attributes = $this->_getAttributesForType($type);
284: foreach ($attributes as $id => $attribute) {
285: $attributes[$id] = array(
286: 'human_name' => $attribute['attribute_name'],
287: 'type' => $attribute['attribute_type'],
288: 'required' => $attribute['attribute_required'],
289: 'readonly' => false,
290: 'desc' => $attribute['attribute_description'],
291: 'params' => $attribute['attribute_params']);
292: }
293: return $attributes;
294: }
295:
296: 297: 298: 299: 300: 301: 302: 303: 304: 305:
306: public function getAllTicketAttributesWithNames($ticket_id)
307: {
308: $ta = $this->_getAllTicketAttributesWithNames($ticket_id);
309:
310: $attributes = array();
311: foreach ($ta as $id => $attribute) {
312: try {
313: $value = Horde_Serialize::unserialize(
314: $attribute['attribute_value'],
315: Horde_Serialize::JSON);
316: } catch (Horde_Serialize_Exception $e) {
317: $value = $attribute['attribute_value'];
318: }
319: $attributes[$attribute['attribute_id']] = array(
320: 'id' => $attribute['attribute_id'],
321: 'human_name' => $attribute['attribute_name'],
322: 'type' => $attribute['attribute_type'],
323: 'required' => $attribute['attribute_required'],
324: 'readonly' => false,
325: 'desc' => $attribute['attribute_description'],
326: 'params' => $attribute['attribute_params'],
327: 'value' => $value);
328: }
329: return $attributes;
330: }
331:
332: 333: 334: 335: 336: 337: 338: 339:
340: public function deleteQueue($queueId)
341: {
342: $perms = $GLOBALS['injector']->getInstance('Horde_Perms');
343: try {
344: $perm = $perms->getPermission("whups:queues:$queueId");
345: return $perms->removePermission($perm, true);
346: } catch (Horde_Perms_Exception $e) {}
347:
348: return true;
349: }
350:
351: 352: 353: 354: 355: 356: 357: 358:
359: public function deleteReply($reply)
360: {
361: $perms = $GLOBALS['injector']->getInstance('Horde_Perms');
362: try {
363: $perm = $perms->getPermission("whups:replies:$reply");
364: return $perms->removePermission($perm, true);
365: } catch (Horde_Perms_Exception $e) {}
366:
367: return true;
368: }
369:
370: 371:
372: public function filterTicketsByState($tickets, $state_category = array())
373: {
374: 375:
376: $tickets_filtered = array();
377: foreach ($tickets as $ticket) {
378: foreach ($state_category as $state) {
379: if ($ticket['state_category'] == $state) {
380: $tickets_filtered[] = $ticket;
381: }
382: }
383: }
384:
385: return $tickets_filtered;
386: }
387:
388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410:
411: public function mail(array $opts)
412: {
413: global $conf, $registry, $prefs;
414:
415: $opts = array_merge(array('ticket' => false, 'new' => false), $opts);
416:
417:
418: $mail = new Horde_Mime_Mail(array(
419: 'X-Whups-Generated' => 1,
420: 'User-Agent' => 'Whups ' . $registry->getVersion(),
421: 'Precedence' => 'bulk',
422: 'Auto-Submitted' => $opts['ticket'] ? 'auto-replied' : 'auto-generated'));
423:
424: $mail_always = null;
425: if ($opts['ticket'] && !empty($conf['mail']['always_copy'])) {
426: $mail_always = $conf['mail']['always_copy'];
427: if (strpos($mail_always, '<@>') !== false) {
428: try {
429: $mail_always = str_replace('<@>', $opts['ticket']->get('queue_name'), $mail_always);
430: } catch (Whups_Exception $e) {
431: $mail_always = null;
432: }
433: }
434: if ($mail_always && !isset($opts['recipients'][$mail_always])) {
435: $opts['recipients'][$mail_always] = 'always';
436: }
437: }
438:
439: if ($opts['ticket'] &&
440: ($queue = $this->getQueue($opts['ticket']->get('queue'))) &&
441: !empty($queue['email'])) {
442: $mail->addHeader('From', $queue['email']);
443: } elseif (!empty($conf['mail']['from_addr'])) {
444: $mail->addHeader('From', $conf['mail']['from_addr']);
445: } else {
446: $mail->addHeader('From', Whups::formatUser($opts['from']));
447: }
448: if (!empty($conf['mail']['return_path'])) {
449: $mail->addHeader('Return-Path', $conf['mail']['return_path']);
450: }
451:
452: if ($opts['ticket']) {
453: $opts['subject'] = '[' . $registry->get('name') . ' #'
454: . $opts['ticket']->getId() . '] ' . $opts['subject'];
455: }
456: $mail->addHeader('Subject', $opts['subject']);
457:
458:
459: if ($opts['ticket']) {
460: $comments = $this->getHistory($opts['ticket']->getId());
461: if ($conf['mail']['commenthistory'] == 'new' && count($comments)) {
462: $comments = array_pop($comments);
463: $comments = array($comments);
464: } elseif ($conf['mail']['commenthistory'] != 'chronological') {
465: $comments = array_reverse($comments);
466: }
467: } else {
468: $comments = array();
469: }
470:
471:
472: $seen_email_addresses = array();
473:
474:
475: if ($opts['ticket']) {
476: $vfs = $GLOBALS['injector']
477: ->getInstance('Horde_Core_Factory_Vfs')
478: ->create();
479: try {
480: $attachments = Whups::getAttachments($opts['ticket']->getId());
481: } catch (Whups_Exception $e) {
482: $attachments = array();
483: Horde::logMessage($e);
484: }
485: }
486:
487: foreach ($opts['recipients'] as $user => $role) {
488: if ($user == $opts['from'] &&
489: $user == $GLOBALS['registry']->getAuth() &&
490: $prefs->getValue('email_others_only')) {
491: continue;
492: }
493:
494: 495:
496: $to = $full_name = '';
497: if (!empty($mail_always) && $user == $mail_always) {
498: $details = null;
499: $mycomments = Whups::permissionsFilter(
500: $comments, 'comment', Horde_Perms::READ, '');
501: $to = $mail_always;
502: } else {
503: $details = Whups::getUserAttributes($user);
504: if (!empty($details['email'])) {
505: $to = Whups::formatUser($details);
506: $mycomments = Whups::permissionsFilter(
507: $comments, 'comment', Horde_Perms::READ, $details['user']);
508: }
509: $full_name = $details['name'];
510: }
511:
512: 513:
514: if (!$to) {
515: continue;
516: }
517:
518: if ($opts['ticket']) {
519:
520: $attachmentAdded = false;
521: if (empty($GLOBALS['conf']['mail']['link_attach'])) {
522: 523:
524: $mail->clearParts();
525: foreach ($mycomments as $comment) {
526: foreach ($comment['changes'] as $change) {
527: if ($change['type'] == 'attachment') {
528: foreach ($attachments as $attachment) {
529: if ($attachment['name'] == $change['value']) {
530: if (!isset($attachment['part'])) {
531: $attachment['part'] = new Horde_Mime_Part();
532: $attachment['part']->setType(Horde_Mime_Magic::filenameToMime($change['value'], false));
533: $attachment['part']->setDisposition('attachment');
534: $attachment['part']->setContents($vfs->read(Whups::VFS_ATTACH_PATH . '/' . $opts['ticket']->getId(), $change['value']));
535: $attachment['part']->setName($change['value']);
536: }
537: $mail->addMimePart($attachment['part']);
538: $attachmentAdded = true;
539: break;
540: }
541: }
542: }
543: }
544: }
545: }
546:
547: $formattedComment = $this->formatComments($mycomments, $opts['ticket']->getId());
548:
549: if (isset($details['type']) && $details['type'] == 'user') {
550: $user_prefs = $GLOBALS['injector']
551: ->getInstance('Horde_Core_Factory_Prefs')
552: ->create('whups', array('user' => $details['user']));
553: if (!$attachmentAdded &&
554: empty($formattedComment) &&
555: $user_prefs->getValue('email_comments_only')) {
556: continue;
557: }
558: }
559:
560: $opts['view']->comment = $formattedComment;
561: }
562:
563: try {
564: $addr_arr = Horde_Mime_Address::parseAddressList($to);
565: if (isset($addr_arr[0])) {
566: $bare_address = strtolower($addr_arr[0]['mailbox'] . '@' . $addr_arr[0]['host']);
567: if (!empty($seen_email_addresses[$bare_address])) {
568: continue;
569: }
570: $seen_email_addresses[$bare_address] = true;
571:
572: if (empty($full_name) && isset($addr_arr[0]['personal'])) {
573: $full_name = $addr_arr[0]['personal'];
574: }
575: }
576: } catch (Horde_Mime_Exception $e) {}
577:
578:
579: if (empty($full_name)) {
580: $full_name = $to;
581: }
582:
583: $opts['view']->full_name = $full_name;
584: $opts['view']->role = $role;
585: $mail->setBody($opts['view']->render($opts['template']));
586:
587: $mail->addHeader('Message-ID', Horde_Mime::generateMessageId());
588: if ($opts['ticket']) {
589: $message_id = '<whups-' . $opts['ticket']->getId() . '-'
590: . md5($user) . '@' . $conf['server']['name'] . '>';
591: if ($opts['new']) {
592: $mail->addHeader('Message-ID', $message_id);
593: } else {
594: $mail->addHeader('In-Reply-To', $message_id);
595: $mail->addHeader('References', $message_id);
596: }
597: }
598:
599: $mail->clearRecipients();
600: $mail->addHeader('To', $to);
601:
602: try {
603: $mail->send($GLOBALS['injector']->getInstance('Horde_Mail'), true);
604: $entry = sprintf('%s Message sent to %s from "%s"',
605: $_SERVER['REMOTE_ADDR'], $to,
606: $GLOBALS['registry']->getAuth());
607: Horde::logMessage($entry, 'INFO');
608: } catch (Horde_Mime_Exception $e) {
609: Horde::logMessage($e, 'ERR');
610: }
611: }
612: }
613:
614: 615: 616: 617: 618: 619: 620: 621:
622: public function ($comments, $ticket)
623: {
624: $text = '';
625: foreach ($comments as $comment) {
626: if (!empty($comment['comment_text'])) {
627: $text .= "\n"
628: . sprintf(_("%s (%s) wrote:"),
629: Whups::formatUser($comment['user_id']),
630: strftime('%Y-%m-%d %H:%M', $comment['timestamp']))
631: . "\n\n" . $comment['comment_text'] . "\n\n\n";
632: }
633:
634:
635: if (empty($GLOBALS['conf']['mail']['link_attach'])) {
636: continue;
637: }
638: foreach ($comment['changes'] as $change) {
639: if ($change['type'] != 'attachment') {
640: continue;
641: }
642: $url_params = array('actionID' => 'download_file',
643: 'file' => $change['value'],
644: 'ticket' => $ticket);
645: $text .= "\n"
646: . sprintf(_("%s (%s) uploaded: %s"),
647: Whups::formatUser($comment['user_id']),
648: strftime('%Y-%m-%d %H:%M', $comment['timestamp']),
649: $change['value'])
650: . "\n\n"
651: . Horde::url(Horde::downloadUrl($change['value'], $url_params), true)
652: . "\n\n\n";
653: }
654: }
655:
656: return $text;
657: }
658:
659: }
660: