Overview

Request 2897 (accepted)

Check in 3.5.11


roundcubemail-plugins-kolab.spec Changed
x
 
1
@@ -41,7 +41,7 @@
2
 %global dash_rel_suffix %{?rc_rel_suffix:-%{rc_rel_suffix}}
3
 
4
 Name:           roundcubemail-plugins-kolab
5
-Version:        3.5.10
6
+Version:        3.5.11
7
 
8
 Release:        1%{?dot_rel_suffix}%{?dist}
9
 
10
debian.changelog Changed
11
 
1
@@ -1,3 +1,9 @@
2
+roundcubemail-plugins-kolab (1:3.5.11-0~kolab1) unstable; urgency=low
3
+
4
+  * Release version 3.5.11
5
+
6
+ -- Jeroen van Meeuwen <vanmeeuwen@apheleia-it.ch>  Fri, 14 Jan 2022 11:11:11 +0200
7
+
8
 roundcubemail-plugins-kolab (1:3.5.10-0~kolab1) unstable; urgency=low
9
 
10
   * Release version 3.5.10
11
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/calendar/calendar.php -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/calendar/calendar.php Changed
208
 
1
@@ -1239,23 +1239,31 @@
2
                 $noreply = intval($noreply) || $status == 'needs-action' || $itip_sending === 0;
3
                 $reload  = $event['calendar'] != $ev['calendar'] || !empty($event['recurrence']) ? 2 : 1;
4
                 $emails  = $this->get_user_emails();
5
+                $ownedResourceEmails = $this->owned_resources_emails();
6
                 $organizer = null;
7
+                $resourceConfirmation = false;
8
 
9
                 foreach ($event['attendees'] as $i => $attendee) {
10
                     if ($attendee['role'] == 'ORGANIZER') {
11
                         $organizer = $attendee;
12
                     }
13
-                    else if (!empty($attendee['email']) && in_array(strtolower($attendee['email']), $emails)) {
14
+                    else if (!empty($attendee['email']) && in_array_nocase($attendee['email'], $emails)) {
15
                         $reply_sender = $attendee['email'];
16
                     }
17
+                    else if (!empty($attendee['cutype']) && $attendee['cutype'] == 'RESOURCE' && !empty($attendee['email']) && in_array_nocase($attendee['email'], $ownedResourceEmails)) {
18
+                        $resourceConfirmation = true;
19
+                        // Note on behalf of which resource this update is going to be sent out
20
+                        $event['_resource'] = $attendee['email'];
21
+                    }
22
                 }
23
 
24
                 if (!$noreply) {
25
                     $itip = $this->load_itip();
26
                     $itip->set_sender_email($reply_sender);
27
                     $event['thisandfuture'] = $event['_savemode'] == 'future';
28
+                    $bodytextprefix = $resourceConfirmation ? 'itipmailbodyresource' : 'itipmailbody';
29
 
30
-                    if ($organizer && $itip->send_itip_message($event, 'REPLY', $organizer, 'itipsubject' . $status, 'itipmailbody' . $status)) {
31
+                    if ($organizer && $itip->send_itip_message($event, 'REPLY', $organizer, 'itipsubject' . $status, $bodytextprefix . $status)) {
32
                         $mailto = !empty($organizer['name']) ? $organizer['name'] : $organizer['email'];
33
                         $msg    = $this->gettext(['name' => 'sentresponseto', 'vars' => ['mailto' => $mailto]]);
34
 
35
@@ -2006,10 +2014,12 @@
36
             }
37
 
38
             $identity['emails'][] = $this->rc->user->get_username();
39
+            $identity['ownedResources'] = $this->owned_resources_emails();
40
             $settings['identity'] = [
41
                 'name'   => $identity['name'],
42
                 'email'  => strtolower($identity['email']),
43
-                'emails' => ';' . strtolower(join(';', $identity['emails']))
44
+                'emails' => ';' . strtolower(join(';', $identity['emails'])),
45
+                'ownedResources' => ';' . strtolower(join(';', $identity['ownedResources']))
46
             ];
47
         }
48
 
49
@@ -2339,7 +2349,7 @@
50
         }
51
 
52
         $attachments = [];
53
-        $eventid     = 'cal-' . (!empty($event['id']) ? $event['id'] : 'new-event');
54
+        $eventid     = 'cal-' . (!empty($event['id']) ? $event['id'] : 'new');
55
 
56
         if (!empty($_SESSION[self::SESSION_KEY]) && $_SESSION[self::SESSION_KEY]['id'] == $eventid) {
57
             if (!empty($_SESSION[self::SESSION_KEY]['attachments'])) {
58
@@ -2868,6 +2878,21 @@
59
         exit;
60
     }
61
 
62
+    /**
63
+     * List email addressed of owned resources
64
+     */
65
+    private function owned_resources_emails()
66
+    {
67
+        $results = [];
68
+        if ($directory = $this->resources_directory()) {
69
+            foreach ($directory->load_resources($_SESSION['kolab_dn'], 5000, 'owner') as $rec) {
70
+                $results[] = $rec['email'];
71
+            }
72
+        }
73
+        return $results;
74
+    }
75
+
76
+
77
     /****  Event invitation plugin hooks ****/
78
 
79
     /**
80
@@ -3149,10 +3174,16 @@
81
      */
82
     private function mail_agenda_event_row($event, $class = '')
83
     {
84
-        $time = !empty($event['allday']) ? $this->gettext('all-day') :
85
-            $this->rc->format_date($event['start'], $this->rc->config->get('time_format'))
86
-            . ' - ' .
87
-            $this->rc->format_date($event['end'], $this->rc->config->get('time_format'));
88
+        if (!empty($event['allday'])) {
89
+            $time = $this->gettext('all-day');
90
+        }
91
+        else {
92
+            $start = is_object($event['start']) ? clone $event['start'] : $event['start'];
93
+            $end = is_object($event['end']) ? clone $event['end'] : $event['end'];
94
+
95
+            $time = $this->rc->format_date($start, $this->rc->config->get('time_format'))
96
+                . ' - ' . $this->rc->format_date($end, $this->rc->config->get('time_format'));
97
+        }
98
 
99
         return html::div(rtrim('event-row ' . ($class ?: $event['className'])),
100
             html::span('event-date', $time)
101
@@ -3217,7 +3248,7 @@
102
             // get prepared inline UI for this event object
103
             if ($ical_objects->method) {
104
                 $append   = '';
105
-                $date_str = $this->rc->format_date($event['start'], $this->rc->config->get('date_format'), empty($event['start']->_dateonly));
106
+                $date_str = $this->rc->format_date(clone $event['start'], $this->rc->config->get('date_format'), empty($event['start']->_dateonly));
107
                 $date     = new DateTime($event['start']->format('Y-m-d') . ' 12:00:00', new DateTimeZone('UTC'));
108
 
109
                 // prepare a small agenda preview to be filled with actual event data on async request
110
@@ -3406,39 +3437,38 @@
111
 
112
                     // only update attendee status
113
                     if ($event['_method'] == 'REPLY') {
114
-                        // try to identify the attendee using the email sender address
115
-                        $existing_attendee        = -1;
116
-                        $existing_attendee_emails = [];
117
-
118
-                        foreach ($existing['attendees'] as $i => $attendee) {
119
-                            $existing_attendee_emails[] = $attendee['email'];
120
-                            if ($this->itip->compare_email($attendee['email'], $event['_sender'], $event['_sender_utf'])) {
121
-                                $existing_attendee = $i;
122
-                            }
123
-                        }
124
+                        $existing_attendee_index  = -1;
125
 
126
                         $event_attendee   = null;
127
                         $update_attendees = [];
128
 
129
-                        foreach ($event['attendees'] as $attendee) {
130
-                            if ($this->itip->compare_email($attendee['email'], $event['_sender'], $event['_sender_utf'])) {
131
-                                $event_attendee       = $attendee;
132
-                                $update_attendees[]   = $attendee;
133
-                                $metadata['fallback'] = $attendee['status'];
134
-                                $metadata['attendee'] = $attendee['email'];
135
-                                $metadata['rsvp']     = !empty($attendee['rsvp']) || $attendee['role'] != 'NON-PARTICIPANT';
136
-
137
-                                if ($attendee['status'] != 'DELEGATED') {
138
-                                    break;
139
+                        if ($attendee = $this->itip->find_reply_attendee($event)) {
140
+                            $event_attendee       = $attendee;
141
+                            $update_attendees[]   = $attendee;
142
+                            $metadata['fallback'] = $attendee['status'];
143
+                            $metadata['attendee'] = $attendee['email'];
144
+                            $metadata['rsvp']     = !empty($attendee['rsvp']) || $attendee['role'] != 'NON-PARTICIPANT';
145
+
146
+                            $existing_attendee_emails = [];
147
+
148
+                            // Find the attendee to update
149
+                            foreach ($existing['attendees'] as $i => $existing_attendee) {
150
+                                $existing_attendee_emails[] = $existing_attendee['email'];
151
+                                if ($this->itip->compare_email($existing_attendee['email'], $attendee['email'])) {
152
+                                    $existing_attendee_index = $i;
153
                                 }
154
                             }
155
-                            // also copy delegate attendee
156
-                            else if (!empty($attendee['delegated-from'])
157
-                                && $this->itip->compare_email($attendee['delegated-from'], $event['_sender'], $event['_sender_utf'])
158
-                            ) {
159
-                                $update_attendees[] = $attendee;
160
-                                if (!in_array_nocase($attendee['email'], $existing_attendee_emails)) {
161
-                                    $existing['attendees'][] = $attendee;
162
+
163
+                            if ($attendee['status'] == 'DELEGATED') {
164
+                                //Also find and copy the delegatee
165
+                                $delegatee_email = $attendee['email'];
166
+                                $delegatees = array_filter($event['attendees'], function($attendee) use ($delegatee_email){ return $attendee['role'] != 'ORGANIZER' && $this->itip->compare_email($attendee['delegated-from'], $delegatee_email); });
167
+
168
+                                if ($delegatee = $this->itip->find_attendee_by_email($event['attendees'], 'delegated-from', $attendee['email'])) {
169
+                                    $update_attendees[] = $delegatee;
170
+                                    if (!in_array_nocase($delegatee['email'], $existing_attendee_emails)) {
171
+                                        $existing['attendees'][] = $delegated_attendee;
172
+                                    }
173
                                 }
174
                             }
175
                         }
176
@@ -3456,29 +3486,9 @@
177
                             }
178
                         }
179
 
180
-                        // Accept sender as a new participant (different email in From: and the iTip)
181
-                        // Use ATTENDEE entry from the iTip with replaced email address
182
-                        if (!$event_attendee) {
183
-                            // remove the organizer
184
-                            $itip_attendees = array_filter(
185
-                                $event['attendees'],
186
-                                function($item) { return $item['role'] != 'ORGANIZER'; }
187
-                            );
188
-
189
-                            // there must be only one attendee
190
-                            if (is_array($itip_attendees) && count($itip_attendees) == 1) {
191
-                                $event_attendee          = $itip_attendees[key($itip_attendees)];
192
-                                $event_attendee['email'] = $event['_sender'];
193
-                                $update_attendees[]      = $event_attendee;
194
-                                $metadata['fallback']    = $event_attendee['status'];
195
-                                $metadata['attendee']    = $event_attendee['email'];
196
-                                $metadata['rsvp']        = !empty($event_attendee['rsvp']) || $event_attendee['role'] != 'NON-PARTICIPANT';
197
-                            }
198
-                        }
199
-
200
                         // found matching attendee entry in both existing and new events
201
-                        if ($existing_attendee >= 0 && $event_attendee) {
202
-                            $existing['attendees'][$existing_attendee] = $event_attendee;
203
+                        if ($existing_attendee_index >= 0 && $event_attendee) {
204
+                            $existing['attendees'][$existing_attendee_index] = $event_attendee;
205
                             $success = $this->driver->update_attendees($existing, $update_attendees);
206
                         }
207
                         // update the entire attendees block
208
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/calendar/calendar_ui.js -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/calendar/calendar_ui.js Changed
44
 
1
@@ -399,7 +399,7 @@
2
         $('#event-alarm').show().find('.event-text').html(Q(event.alarms_text).replace(',', ',<br>'));
3
       if (calendar.name)
4
         $('#event-calendar').show().find('.event-text').html(Q(calendar.name)).addClass('cal-'+calendar.id);
5
-      if (event.categories)
6
+      if (event.categories && String(event.categories).length)
7
         $('#event-category').show().find('.event-text').text(event.categories).addClass('cat-'+String(event.categories).toLowerCase().replace(rcmail.identifier_expr, ''));
8
       if (event.free_busy)
9
         $('#event-free-busy').show().find('.event-text').text(rcmail.gettext(event.free_busy, 'calendar'));
10
@@ -460,7 +460,7 @@
11
         for (var j=0; j < num_attendees; j++) {
12
           data = event.attendees[j];
13
           if (data.email) {
14
-            if (data.role != 'ORGANIZER' && settings.identity.emails.indexOf(';'+data.email) >= 0) {
15
+            if (data.role != 'ORGANIZER' && is_this_me(data.email)) {
16
               mystatus = (data.status || 'UNKNOWN').toLowerCase();
17
               if (data.status == 'NEEDS-ACTION' || data.status == 'TENTATIVE' || data.rsvp)
18
                 rsvp = mystatus;
19
@@ -2380,6 +2380,14 @@
20
         add_attendee($.extend({ role:'REQ-PARTICIPANT', status:'NEEDS-ACTION', cutype:'RESOURCE' }, resource));
21
     }
22
 
23
+    var is_this_me = function(email)
24
+    {
25
+      if (settings.identity.emails.indexOf(';'+email) >= 0 || settings.identity.ownedResources.indexOf(';'+email) >= 0) {
26
+        return true;
27
+      }
28
+      return false;
29
+    };
30
+
31
     // when the user accepts or declines an event invitation
32
     var event_rsvp = function(response, delegate, replymode, event)
33
     {
34
@@ -2414,7 +2422,8 @@
35
         attendees = [];
36
         for (var data, i=0; i < me.selected_event.attendees.length; i++) {
37
           data = me.selected_event.attendees[i];
38
-          if (settings.identity.emails.indexOf(';'+String(data.email).toLowerCase()) >= 0) {
39
+          //FIXME this can only work if there is a single resource per invitation
40
+          if (is_this_me(String(data.email).toLowerCase())) {
41
             data.status = response.toUpperCase();
42
             data.rsvp = 0;  // unset RSVP flag
43
 
44
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/calendar/composer.json -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/calendar/composer.json Changed
10
 
1
@@ -4,7 +4,7 @@
2
     "description": "Calendar plugin",
3
     "homepage": "https://git.kolab.org/diffusion/RPK/",
4
     "license": "AGPLv3",
5
-    "version": "3.5.10",
6
+    "version": "3.5.11",
7
     "authors": [
8
         {
9
             "name": "Thomas Bruederli",
10
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/calendar/drivers/ldap/resources_driver_ldap.php -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/calendar/drivers/ldap/resources_driver_ldap.php Changed
27
 
1
@@ -41,12 +41,13 @@
2
     /**
3
      * Fetch resource objects to be displayed for booking
4
      *
5
-     * @param string $query Search query (optional)
6
-     * @param int    $num   Max size of the result
7
+     * @param string $query       Search query (optional)
8
+     * @param int    $num         Max size of the result
9
+     * @param string $searchField Field to search with query
10
      *
11
      * @return array List of resource records available for booking
12
      */
13
-    public function load_resources($query = null, $num = 5000)
14
+    public function load_resources($query = null, $num = 5000, $searchField = '*')
15
     {
16
         if (!($ldap = $this->connect())) {
17
             return [];
18
@@ -56,7 +57,7 @@
19
         $ldap->set_pagesize($num);
20
 
21
         if (isset($query)) {
22
-            $results = $ldap->search('*', $query, 0, true, true);
23
+            $results = $ldap->search($searchField, $query, 0, true, true);
24
         }
25
         else {
26
             $results = $ldap->list_records();
27
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/calendar/localization/en_US.inc -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/calendar/localization/en_US.inc Changed
12
 
1
@@ -207,6 +207,10 @@
2
 $labels['itipmailbodydelegated'] = "\$sender has delegated the participation in the following event:\n\n*\$title*\n\nWhen: \$date";
3
 $labels['itipmailbodydelegatedto'] = "\$sender has delegated the participation in the following event to you:\n\n*\$title*\n\nWhen: \$date";
4
 
5
+$labels['itipmailbodyresourceaccepted'] = "\$sender has accepted the following resource booking:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
6
+$labels['itipmailbodyresourcetentative'] = "\$sender has tentatively accepted the following resource booking:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
7
+$labels['itipmailbodyresourcedeclined'] = "\$sender has declined the the following resource booking:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees";
8
+
9
 $labels['itipdeclineevent'] = 'Do you want to decline your invitation to this event?';
10
 $labels['declinedeleteconfirm'] = 'Do you also want to delete this declined event from your calendar?';
11
 $labels['itipcomment'] = 'Invitation/notification comment';
12
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/kolab_2fa/composer.json -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/kolab_2fa/composer.json Changed
10
 
1
@@ -4,7 +4,7 @@
2
     "description": "Kolab 2-Factor Authentication",
3
     "homepage": "https://git.kolab.org/diffusion/RPK/",
4
     "license": "AGPLv3",
5
-    "version": "3.5.8",
6
+    "version": "3.5.11",
7
     "authors": [
8
         {
9
             "name": "Thomas Bruederli",
10
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/kolab_2fa/kolab2fa.js -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/kolab_2fa/kolab2fa.js Changed
31
 
1
@@ -128,11 +128,6 @@
2
      * Remove the given factor from the account
3
      */
4
     function remove_factor(id) {
5
-        if (rcmail.env.kolab_2fa_factors[id]) {
6
-            rcmail.env.kolab_2fa_factors[id].active = false;
7
-        }
8
-        render();
9
-
10
         var lock = rcmail.set_busy(true, 'saving');
11
         rcmail.http_post('plugin.kolab-2fa-save', { _method: id, _data: 'false' }, lock);
12
     }
13
@@ -184,7 +179,7 @@
14
     function require_high_security(func, exclude)
15
     {
16
         // request 2nd factor auth
17
-        if (!rcmail.env.session_secured || rcmail.env.session_secured < time() - 120) {
18
+        if (rcmail.env.session_secured !== true && rcmail.env.session_secured < time() - 180) {
19
             var method, name;
20
 
21
             // find an active factor
22
@@ -327,7 +322,7 @@
23
 
24
     // callback for save failure
25
     rcmail.addEventListener('plugin.reset_form', function(method) {
26
-        if (rcmail.env.kolab_2fa_factors[method]) {
27
+        if (method && rcmail.env.kolab_2fa_factors[method]) {
28
             rcmail.env.kolab_2fa_factors[method].active = false;
29
         }
30
 
31
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/kolab_2fa/kolab_2fa.php -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/kolab_2fa/kolab_2fa.php Changed
49
 
1
@@ -422,10 +422,7 @@
2
         $this->include_script('kolab2fa.js');
3
         $this->include_stylesheet($this->local_skin_path() . '/kolab2fa.css');
4
 
5
-        if ($this->check_secure_mode()) {
6
-            $this->api->output->set_env('session_secured', $_SESSION['kolab_2fa_secure_mode']);
7
-        }
8
-
9
+        $this->api->output->set_env('session_secured', $this->check_secure_mode());
10
         $this->api->output->add_label('save','cancel');
11
         $this->api->output->set_pagetitle($this->gettext('settingstitle'));
12
         $this->api->output->send('kolab_2fa.config');
13
@@ -671,7 +668,7 @@
14
         }
15
         else if ($errors) {
16
             $this->api->output->show_message($this->gettext('factorsaveerror'), 'error');
17
-            $this->api->output->command('plugin.reset_form', $method);
18
+            $this->api->output->command('plugin.reset_form', $data !== false ? $method : null);
19
         }
20
 
21
         $this->api->output->send();
22
@@ -779,12 +776,20 @@
23
     }
24
 
25
     /**
26
-     *
27
+     * Check whether the session is secured with 2FA (excluding the logon)
28
      */
29
     protected function check_secure_mode()
30
     {
31
-        $valid = ($_SESSION['kolab_2fa_secure_mode'] && $_SESSION['kolab_2fa_secure_mode'] > time() - 180);
32
-        return $valid;
33
-    }
34
+        // Allow admins that used kolab_auth's "login as" feature to act without
35
+        // being asked for the user's second factor
36
+        if (!empty($_SESSION['kolab_auth_admin']) && !empty($_SESSION['kolab_auth_password'])) {
37
+            return true;
38
+        }
39
 
40
-}
41
\ No newline at end of file
42
+        if ($_SESSION['kolab_2fa_secure_mode'] && $_SESSION['kolab_2fa_secure_mode'] > time() - 180) {
43
+            return $_SESSION['kolab_2fa_secure_mode'];
44
+        }
45
+
46
+        return false;
47
+    }
48
+}
49
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/kolab_delegation/composer.json -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/kolab_delegation/composer.json Changed
10
 
1
@@ -4,7 +4,7 @@
2
     "description": "Kolab delegation feature",
3
     "homepage": "https://git.kolab.org/diffusion/RPK/",
4
     "license": "AGPLv3",
5
-    "version": "3.5.6",
6
+    "version": "3.5.11",
7
     "authors": [
8
         {
9
             "name": "Aleksander Machniak",
10
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/kolab_delegation/kolab_delegation_engine.php -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/kolab_delegation/kolab_delegation_engine.php Changed
21
 
1
@@ -378,6 +378,8 @@
2
         // Definition of read and write ACL
3
         $right_types = $this->right_types();
4
 
5
+        $delegate_lc = strtolower($delegate);
6
+
7
         foreach ($folders as $folder) {
8
             // get only folders in personal namespace
9
             if ($storage->folder_namespace($folder) != 'personal') {
10
@@ -395,8 +397,8 @@
11
             // in edit mode, get folder ACL
12
             if ($delegate) {
13
                 // @TODO: cache ACL
14
-                $acl = $storage->get_acl($folder);
15
-                if ($acl = $acl[$delegate]) {
16
+                $imap_acl = $storage->get_acl($folder);
17
+                if (!empty($imap_acl) && (($acl = $imap_acl[$delegate]) || ($acl = $imap_acl[$delegate_lc]))) {
18
                     if ($this->acl_compare($acl, $right_types[self::ACL_WRITE])) {
19
                         $rights = self::ACL_WRITE;
20
                     }
21
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/libcalendaring/composer.json -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/libcalendaring/composer.json Changed
10
 
1
@@ -4,7 +4,7 @@
2
     "description": "Library providing common functions for calendaring plugins",
3
     "homepage": "https://git.kolab.org/diffusion/RPK/",
4
     "license": "AGPLv3",
5
-    "version": "3.5.10",
6
+    "version": "3.5.11",
7
     "authors": [
8
         {
9
             "name": "Thomas Bruederli",
10
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/libcalendaring/lib/libcalendaring_itip.php -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/libcalendaring/lib/libcalendaring_itip.php Changed
110
 
1
@@ -136,7 +136,7 @@
2
             'name' => $bodytext,
3
             'vars' => array(
4
                 'title'       => $event['title'],
5
-                'date'        => $this->lib->event_date_text($event, true) . $recurrence_info,
6
+                'date'        => $this->lib->event_date_text($event) . $recurrence_info,
7
                 'attendees'   => join(",\n ", $attendees_list),
8
                 'sender'      => $this->sender['name'],
9
                 'organizer'   => $this->sender['name'],
10
@@ -219,6 +219,11 @@
11
                 if ($attendee['role'] == 'ORGANIZER') {
12
                     $reply_attendees[] = $attendee;
13
                 }
14
+                // we accept on behalf of a resource
15
+                else if (strcasecmp($attendee['email'], $event['_resource']) == 0) {
16
+                    $replying_attendee = $attendee;
17
+                    $replying_attendee['sent-by'] = 'mailto:' . $from_utf;
18
+                }
19
                 else if (strcasecmp($attendee['email'], $from) == 0 || strcasecmp($attendee['email'], $from_utf) == 0) {
20
                     $replying_attendee = $attendee;
21
                     if ($attendee['status'] != 'DELEGATED') {
22
@@ -628,30 +633,13 @@
23
         if ($method == 'REPLY') {
24
             $title = $this->gettext('itipreply');
25
 
26
-            foreach ($event['attendees'] as $attendee) {
27
-                if (!empty($attendee['email']) && $attendee['role'] != 'ORGANIZER') {
28
-                    if (empty($event['_sender']) || self::compare_email($attendee['email'], $event['_sender'], $event['_sender_utf'])) {
29
-                        $metadata['attendee'] = $attendee['email'];
30
-                        $rsvp_status = strtoupper($attendee['status']);
31
-                        if ($attendee['delegated-to']) {
32
-                            $metadata['delegated-to'] = $attendee['delegated-to'];
33
-                        }
34
-                        break;
35
-                    }
36
-                }
37
-            }
38
-
39
-            // It may happen that sender's address is different in From: and the attached iTip
40
-            // In such case use the ATTENDEE entry with the address from From: header
41
-            if (empty($metadata['attendee']) && !empty($event['_sender'])) {
42
-                // remove the organizer
43
-                $itip_attendees = array_filter($event['attendees'], function($item) { return $item['role'] != 'ORGANIZER'; });
44
+            $attendee = self::find_reply_attendee($event);
45
 
46
-                // there must be only one attendee
47
-                if (is_array($itip_attendees) && count($itip_attendees) == 1) {
48
-                    $event_attendee       = $itip_attendees[key($itip_attendees)];
49
-                    $metadata['attendee'] = $event['_sender'];
50
-                    $rsvp_status          = strtoupper($event_attendee['status']);
51
+            if ($attendee) {
52
+                $metadata['attendee'] = $attendee['email'];
53
+                $rsvp_status = strtoupper($attendee['status']);
54
+                if ($attendee['delegated-to']) {
55
+                    $metadata['delegated-to'] = $attendee['delegated-to'];
56
                 }
57
             }
58
 
59
@@ -1008,4 +996,50 @@
60
 
61
         return $v1 || $v2;
62
     }
63
+
64
+    /**
65
+     * Find an attendee that is not the organizer and has an email matching $email_field
66
+     */
67
+    public function find_attendee_by_email($attendees, $email_field, $email, $email_utf = null) {
68
+        foreach ($attendees as $_attendee) {
69
+            if ($attendee['role'] == 'ORGANIZER') {
70
+                continue;
71
+            }
72
+            if (!empty($attendee[$email_field]) && self::compare_email($attendee[$email_field], $email, $email_utf)) {
73
+                return $attendee;
74
+            }
75
+        }
76
+        return null;
77
+    }
78
+
79
+    /**
80
+     * Find the replying attendee in a REPLY
81
+     */
82
+    public static function find_reply_attendee($event) {
83
+        // remove the organizer
84
+        $itip_attendees = array_filter($event['attendees'], function($item) { return $item['role'] != 'ORGANIZER' && !empty($item['email']); });
85
+        $attendee = null;
86
+
87
+        // According to rfc there should only be one attendee for a REPLY
88
+        if (count($itip_attendees) == 1) {
89
+            return array_pop($itip_attendees);
90
+        }
91
+
92
+        // If we don't have anything to match by, pick the first and hope for the best.
93
+        if (empty($event['_sender'])) {
94
+            return array_shift($itip_attendees);
95
+        }
96
+
97
+        // try to match by sent-by
98
+        if ($attendee = self::find_attendee_by_email($itip_attendees, 'sent-by', $event['_sender'], $event['_sender_utf'])) {
99
+            return $attendee;
100
+        }
101
+
102
+        // try to match by email
103
+        if ($attendee = self::find_attendee_by_email($itip_attendees, 'email', $event['_sender'], $event['_sender_utf'])) {
104
+            return $attendee;
105
+        }
106
+
107
+        return null;
108
+    }
109
 }
110
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/libcalendaring/libcalendaring.php -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/libcalendaring/libcalendaring.php Changed
90
 
1
@@ -288,19 +288,43 @@
2
     /**
3
      * Compose a date string for the given event
4
      */
5
-    public function event_date_text($event, $tzinfo = false)
6
+    public function event_date_text($event)
7
     {
8
         $fromto  = '--';
9
         $is_task = !empty($event['_type']) && $event['_type'] == 'task';
10
 
11
+        $this->date_format_defaults();
12
+
13
+        $date_format = self::to_php_date_format($this->rc->config->get('calendar_date_format', $this->defaults['calendar_date_format']));
14
+        $time_format = self::to_php_date_format($this->rc->config->get('calendar_time_format', $this->defaults['calendar_time_format']));
15
+
16
+        $getTimezone = function ($date) {
17
+            if ($newTz = $date->getTimezone()) {
18
+                return $newTz->getName();
19
+            }
20
+
21
+            return '';
22
+        };
23
+
24
+        $formatDate = function ($date, $format) use ($getTimezone) {
25
+            // This is a workaround for the rcmail::format_date() which does not play nice with timezone
26
+            $tz = $this->rc->config->get('timezone');
27
+            if ($dateTz = $getTimezone($date)) {
28
+                $this->rc->config->set('timezone', $dateTz);
29
+            }
30
+            $result = $this->rc->format_date($date, $format);
31
+            $this->rc->config->set('timezone', $tz);
32
+
33
+            return $result;
34
+        };
35
+
36
         // handle task objects
37
         if ($is_task && !empty($event['due']) && is_object($event['due'])) {
38
-            $date_format = !empty($event['due']->_dateonly) ? self::to_php_date_format($this->rc->config->get('calendar_date_format', $this->defaults['calendar_date_format'])) : null;
39
-            $fromto = $this->rc->format_date($event['due'], $date_format, false);
40
+            $fromto = $formatDate($event['due'], !empty($event['due']->_dateonly) ? $date_format : null);
41
 
42
             // add timezone information
43
-            if ($fromto && $tzinfo && ($tzname = $this->timezone->getName())) {
44
-                $fromto .= ' (' . strtr($tzname, '_', ' ') . ')';
45
+            if ($fromto && empty($event['due']->_dateonly) && ($tz = $getTimezone($event['due']))) {
46
+                $fromto .= ' (' . strtr($tz, '_', ' ') . ')';
47
             }
48
 
49
             return $fromto;
50
@@ -311,29 +335,24 @@
51
             return $fromto;
52
         }
53
 
54
-        $duration = $event['start']->diff($event['end'])->format('s');
55
-
56
-        $this->date_format_defaults();
57
-        $date_format = self::to_php_date_format($this->rc->config->get('calendar_date_format', $this->defaults['calendar_date_format']));
58
-        $time_format = self::to_php_date_format($this->rc->config->get('calendar_time_format', $this->defaults['calendar_time_format']));
59
-
60
         if ($event['allday']) {
61
-            $fromto = $this->rc->format_date($event['start'], $date_format, false);
62
-            if (($todate = $this->rc->format_date($event['end'], $date_format, false)) != $fromto)
63
+            $fromto = $formatDate($event['start'], $date_format);
64
+            if (($todate = $formatDate($event['end'], $date_format)) != $fromto) {
65
                 $fromto .= ' - ' . $todate;
66
+            }
67
         }
68
-        else if ($duration < 86400 && $event['start']->format('d') == $event['end']->format('d')) {
69
-            $fromto = $this->rc->format_date($event['start'], $date_format) . ' ' . $this->rc->format_date($event['start'], $time_format) .
70
-                ' - ' . $this->rc->format_date($event['end'], $time_format);
71
+        else if ($event['start']->format('Ymd') === $event['end']->format('Ymd')) {
72
+            $fromto = $formatDate($event['start'], $date_format) . ' ' . $formatDate($event['start'], $time_format) .
73
+                ' - ' . $formatDate($event['end'], $time_format);
74
         }
75
         else {
76
-            $fromto = $this->rc->format_date($event['start'], $date_format) . ' ' . $this->rc->format_date($event['start'], $time_format) .
77
-                ' - ' . $this->rc->format_date($event['end'], $date_format) . ' ' . $this->rc->format_date($event['end'], $time_format);
78
+            $fromto = $formatDate($event['start'], $date_format) . ' ' . $formatDate($event['start'], $time_format) .
79
+                ' - ' . $formatDate($event['end'], $date_format) . ' ' . $formatDate($event['end'], $time_format);
80
         }
81
 
82
         // add timezone information
83
-        if ($tzinfo && ($tzname = $this->timezone->getName())) {
84
-            $fromto .= ' (' . strtr($tzname, '_', ' ') . ')';
85
+        if ($fromto && empty($event['allday']) && ($tz = $getTimezone($event['start']))) {
86
+            $fromto .= ' (' . strtr($tz, '_', ' ') . ')';
87
         }
88
 
89
         return $fromto;
90
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/libkolab/composer.json -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/libkolab/composer.json Changed
10
 
1
@@ -4,7 +4,7 @@
2
     "description": "Plugin to setup a basic environment for the interaction with a Kolab server.",
3
     "homepage": "https://git.kolab.org/diffusion/RPK/",
4
     "license": "AGPLv3",
5
-    "version": "3.5.10",
6
+    "version": "3.5.11",
7
     "authors": [
8
         {
9
             "name": "Thomas Bruederli",
10
roundcubemail-plugins-kolab-3.5.10.tar.gz/plugins/libkolab/lib/kolab_attachments_handler.php -> roundcubemail-plugins-kolab-3.5.11.tar.gz/plugins/libkolab/lib/kolab_attachments_handler.php Changed
12
 
1
@@ -114,8 +114,9 @@
2
             $this->rc->upload_progress();
3
         }
4
 
5
-        $recid    = $id_prefix . rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
6
+        $id       = rcube_utils::get_input_value('_id', rcube_utils::INPUT_GPC);
7
         $uploadid = rcube_utils::get_input_value('_uploadid', rcube_utils::INPUT_GPC);
8
+        $recid    = $id_prefix . ($id ?: 'new');
9
 
10
         if (empty($_SESSION[$session_key]) || $_SESSION[$session_key]['id'] != $recid) {
11
             $_SESSION[$session_key] = array();
12
roundcubemail-plugins-kolab.dsc Changed
17
 
1
@@ -2,7 +2,7 @@
2
 Source: roundcubemail-plugins-kolab
3
 Binary: roundcubemail-plugins-kolab
4
 Architecture: all
5
-Version: 1:3.5.10-0~kolab1
6
+Version: 1:3.5.11-0~kolab1
7
 Maintainer: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com>
8
 Uploaders: Jeroen van Meeuwen <vanmeeuwen@kolabsys.com>
9
 Standards-Version: 3.9.3
10
@@ -37,5 +37,5 @@
11
  roundcubemail-plugin-tinymce-config deb web extra
12
  roundcubemail-plugin-wap-client deb web extra
13
 Files:
14
- 00000000000000000000000000000000 0 roundcubemail-plugins-kolab-3.5.10.tar.gz
15
+ 00000000000000000000000000000000 0 roundcubemail-plugins-kolab-3.5.11.tar.gz
16
  00000000000000000000000000000000 0 debian.tar.gz
17
Refresh
Refresh
Request History
Jeroen van Meeuwen's avatar

vanmeeuwen created request about 3 years ago

Check in 3.5.11


Jeroen van Meeuwen's avatar

vanmeeuwen accepted review about 3 years ago

Accept


Jeroen van Meeuwen's avatar

vanmeeuwen accepted review about 3 years ago

Accept


Jeroen van Meeuwen's avatar

vanmeeuwen approved review about 3 years ago

Accept


Jeroen van Meeuwen's avatar

vanmeeuwen accepted request about 3 years ago

Accept