Overview

Packages

  • awl
    • caldav-client-v2
    • RRule
  • davical
    • authentication
      • drivers
    • caldav
    • DAViCalSession
    • DAVTicket
    • external-bind
    • feed
    • HTTPAuthSession
    • iSchedule
    • iSchedule-POST
    • logging
    • metrics
    • Principal
    • propfind
    • PublicSession
    • Request
    • Resource
    • tzservice
  • None
  • PHP

Classes

  • CalDAVClient
  • CheckResult
  • setupFakeSession
  • VCard
  • VTimezone

Functions

  • access_ticket_browser
  • binding_row_editor
  • bindings_to_other_browser
  • bindings_to_us_browser
  • build_dependencies_table
  • build_privileges_html
  • build_site_statistics
  • BuildSqlFilter
  • calquery_apply_filter
  • cardquery_apply_filter
  • catch_setup_errors
  • check_awl_version
  • check_calendar
  • check_curl
  • check_database_connection
  • check_datetime
  • check_davical_version
  • check_gettext
  • check_iconv
  • check_ldap
  • check_magic_quotes_gpc
  • check_magic_quotes_runtime
  • check_pdo
  • check_pdo_pgsql
  • check_pgsql
  • check_real_php
  • check_schema_version
  • check_string
  • check_suhosin_server_strip
  • check_xml
  • collection_privilege_format_function
  • confirm_delete_bind_in
  • confirm_delete_binding
  • confirm_delete_collection
  • confirm_delete_principal
  • confirm_delete_ticket
  • do_error
  • edit_binding_row
  • edit_grant_row_collection
  • edit_grant_row_principal
  • edit_group_row
  • edit_ticket_row
  • errorResponse
  • expand_properties
  • fetch_external
  • get_address_properties
  • get_freebusy
  • get_href_containers
  • get_phpinfo
  • grant_row_editor
  • group_members_browser
  • group_memberships_browser
  • group_row_editor
  • handle_subaction
  • i18n
  • ischedule_get
  • log_setup_error
  • make_help_link
  • principal_collection_browser
  • principal_editor
  • principal_grants_browser
  • principal_privilege_format_function
  • send_page_header
  • SqlFilterCardDAV
  • SqlFilterFragment
  • ticket_row_editor
  • unicodeToUtf8
  • update_external
  • utf8ToUnicode
  • Overview
  • Package
  • Function
  • Tree
  • Deprecated
  • Todo
   1: <?php
   2: 
   3: param_to_global('id', 'int', 'old_id', 'principal_id' );
   4: 
   5: $privilege_names = array( 'read', 'write-properties', 'write-content', 'unlock', 'read-acl', 'read-current-user-privilege-set',
   6:                          'bind', 'unbind', 'write-acl', 'read-free-busy', 'schedule-deliver-invite', 'schedule-deliver-reply',
   7:                          'schedule-query-freebusy', 'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );
   8: $privilege_xlate = array(
   9:   'all' => translate('All privileges'),
  10:   'read' => translate('Read'),
  11:   'write-properties' => translate('Write Metadata'),
  12:   'write-content' => translate('Write Data'),
  13:   'unlock' => translate('Override a Lock'),
  14:   'read-acl' => translate('Read Access Controls'),
  15:   'read-current-user-privilege-set' => translate('Read Current User\'s Access'),
  16:   'bind' => translate('Create Events/Collections'),
  17:   'unbind' => translate('Delete Events/Collections'),
  18:   'write-acl' => translate('Write Access Controls'),
  19:   'read-free-busy' => translate('Read Free/Busy Information'),
  20:   'schedule-deliver-invite' => translate('Scheduling: Deliver an Invitation'),
  21:   'schedule-deliver-reply' => translate('Scheduling: Deliver a Reply'),
  22:   'schedule-query-freebusy' => translate('Scheduling: Query free/busy'),
  23:   'schedule-send-invite' => translate('Scheduling: Send an Invitation'),
  24:   'schedule-send-reply' => translate('Scheduling: Send a Reply'),
  25:   'schedule-send-freebusy' => translate('Scheduling: Send free/busy'),
  26:   'write' => translate('Write'),
  27:   'schedule-deliver' => translate('Scheduling: Delivery'),
  28:   'schedule-send' => translate('Scheduling: Sending')
  29: );
  30: 
  31: $can_write_principal = ($session->AllowedTo('Admin') || ($session->principal_id == $id));
  32: if ( !$can_write_principal && $id > 0 ) {
  33:   $target_principal = new Principal('principal_id', $id);
  34:   $can_write_principal = $session->HavePrivilegeTo('DAV::write', $target_principal->dav_name());
  35: }
  36: 
  37: 
  38: $delete_collection_confirmation_required = null;
  39: $delete_principal_confirmation_required = null;
  40: $delete_ticket_confirmation_required = null;
  41: $delete_bind_in_confirmation_required = null;
  42: $delete_binding_confirmation_required = null;
  43: 
  44: function handle_subaction( $subaction ) {
  45:   global $session, $c, $id, $editor;
  46:   global $delete_collection_confirmation_required;
  47:   global $delete_principal_confirmation_required;
  48:   global $delete_ticket_confirmation_required;
  49:   global $delete_bind_in_confirmation_required;
  50:   global $delete_binding_confirmation_required;
  51:   global $can_write_principal;
  52: 
  53:   dbg_error_log('admin-principal-edit',':handle_action: Action %s', $subaction );
  54: 
  55:   switch( $subaction ) {
  56:     case 'delete_collection':
  57:       dbg_error_log('admin-principal-edit',':handle_action: Deleting collection %s for principal %d', $_GET['dav_name'], $id );
  58:       if ($can_write_principal) {
  59:         if ( $session->CheckConfirmationHash('GET', 'confirm') ) {
  60:           dbg_error_log('admin-principal-edit',':handle_action: Allowed to delete collection %s for principal %d', $_GET['dav_name'], $id );
  61:           $qry = new AwlQuery('DELETE FROM collection WHERE dav_name=?;', $_GET['dav_name'] );
  62:           if ( $qry->Exec() ) {
  63:             $c->messages[] = i18n('Collection deleted.');
  64:             return true;
  65:           }
  66:           else {
  67:             $c->messages[] = i18n('There was an error writing to the database.');
  68:             return false;
  69:           }
  70:         }
  71:         else {
  72:           $c->messages[] = i18n('Please confirm deletion of collection - see below');
  73:           $delete_collection_confirmation_required = $session->BuildConfirmationHash('GET', 'confirm');
  74:           return false;
  75:         }
  76:       }
  77:       else {
  78:         $c->messages[] = i18n('You are not allowed to delete collections for this principal.');
  79:       }
  80:       break;
  81: 
  82:     case 'delete_principal':
  83:       dbg_error_log('admin-principal-edit',':handle_action: Deleting principal %d', $id );
  84:       if ( $session->AllowedTo('Admin') ) {
  85:         if ( isset($id) && $id > 1 && $session->CheckConfirmationHash('GET', 'confirm') ) {
  86:           dbg_error_log('admin-principal-edit',':handle_action: Allowed to delete principal %d -%s', $id );
  87:           $qry = new AwlQuery('DELETE FROM dav_principal WHERE principal_id=?', $id );
  88:           if ( $qry->Exec() ) {
  89:             $c->messages[] = i18n('Principal deleted.');
  90:             return true;
  91:           }
  92:           else {
  93:             $c->messages[] = i18n('There was an error writing to the database.');
  94:             return false;
  95:           }
  96:         }
  97:         else {
  98:           $c->messages[] = i18n('Please confirm deletion of the principal');
  99:           $delete_principal_confirmation_required = $session->BuildConfirmationHash('GET', 'confirm');
 100:           return false;
 101:         }
 102:       }
 103:       else {
 104:         $c->messages[] = i18n('You are not allowed to delete principals.');
 105:       }
 106:       break;
 107: 
 108:     case 'delete_ticket':
 109:       dbg_error_log('admin-principal-edit',':handle_action: Deleting ticket "%s" for principal %d', $_GET['ticket_id'], $id );
 110:       if ($can_write_principal) {
 111:         if ( $session->CheckConfirmationHash('GET', 'confirm') ) {
 112:           dbg_error_log('admin-principal-edit',':handle_action: Allowed to delete ticket "%s" for principal %d', $_GET['ticket_id'], $id );
 113:           $qry = new AwlQuery('DELETE FROM access_ticket WHERE ticket_id=?;', $_GET['ticket_id'] );
 114:           if ( $qry->Exec() ) {
 115:             $c->messages[] = i18n('Access ticket deleted.');
 116:             return true;
 117:           }
 118:           else {
 119:             $c->messages[] = i18n('There was an error writing to the database.');
 120:             return false;
 121:           }
 122:         }
 123:         else {
 124:           $c->messages[] = i18n('Please confirm deletion of access ticket - see below');
 125:           $delete_ticket_confirmation_required = $session->BuildConfirmationHash('GET', 'confirm');
 126:           return false;
 127:         }
 128:       }
 129:       else {
 130:         $c->messages[] = i18n('You are not allowed to delete tickets for this principal.');
 131:       }
 132:       break;
 133: 
 134:     case 'delete_bind_in':
 135:     case 'delete_binding':
 136:       dbg_error_log('admin-principal-edit',':handle_action: Deleting binding "%s" for principal %d', $_GET['bind_id'], $id );
 137:       if ($can_write_principal) {
 138:         if ( $session->CheckConfirmationHash('GET', 'confirm') ) {
 139:           dbg_error_log('admin-principal-edit',':handle_action: Allowed to delete binding "%s" for principal %d', $_GET['bind_id'], $id );
 140:           $qry = new AwlQuery('DELETE FROM dav_binding WHERE bind_id=?;', $_GET['bind_id'] );
 141:           if ( $qry->Exec() ) {
 142:             $c->messages[] = i18n('Binding deleted.');
 143:             return true;
 144:           }
 145:           else {
 146:             $c->messages[] = i18n('There was an error writing to the database.');
 147:             return false;
 148:           }
 149:         }
 150:         else {
 151:           $c->messages[] = i18n('Please confirm deletion of binding - see below');
 152:           if ( $subaction == 'delete_bind_in' ) {
 153:             $delete_bind_in_confirmation_required = $session->BuildConfirmationHash('GET', 'confirm');
 154:           }
 155:           else {
 156:             $delete_binding_confirmation_required = $session->BuildConfirmationHash('GET', 'confirm');
 157:           }
 158:           return false;
 159:         }
 160:       }
 161:       else {
 162:         $c->messages[] = i18n('You are not allowed to delete bindings for this principal.');
 163:       }
 164:       break;
 165: 
 166:       default:
 167:       return false;
 168:   }
 169:   return false;
 170: }
 171: 
 172: function principal_editor() {
 173:   global $c, $id, $can_write_principal, $session;
 174:   $editor = new Editor(translate('Principal'), 'dav_principal');
 175: 
 176:   $editor->SetLookup( 'date_format_type', "SELECT 'E', 'European' UNION SELECT 'U', 'US Format' UNION SELECT 'I', 'ISO Format'" );
 177:   $editor->SetLookup( 'type_id', 'SELECT principal_type_id, principal_type_desc FROM principal_type ORDER BY principal_type_id' );
 178:   $editor->SetLookup( 'locale', 'SELECT \'\', \''.translate("*** Default Locale ***").'\' UNION SELECT locale, locale_name_locale FROM supported_locales ORDER BY 1 ASC' );
 179:   $editor->AddAttribute( 'locale', 'title', translate("The preferred language for this person.") );
 180:   $editor->AddAttribute( 'fullname', 'title', translate("The full name for this person, group or other type of principal.") );
 181:   $editor->AddAttribute( 'email', 'title', translate("The email address identifies principals when processing invitations and freebusy lookups. It should be set to a unique value.") );
 182:   $editor->SetWhere( 'principal_id='.$id );
 183: 
 184:   $editor->AddField('is_admin', 'EXISTS( SELECT 1 FROM role_member WHERE role_no = 1 AND role_member.user_no = dav_principal.user_no )' );
 185:   $editor->AddAttribute('is_admin', 'title', translate('An "Administrator" user has full rights to the whole DAViCal System'));
 186: 
 187:   $post_values = false;
 188: 
 189:   if ( isset($_POST['xxxxusername']) ) {
 190:     $_POST['xxxxusername'] = trim(str_replace('/', '', $_POST['xxxxusername']));
 191:     if ( $_POST['xxxxusername'] == '' ) {
 192:       $c->messages[] = i18n("The username must not be blank, and may not contain a slash");
 193:       $can_write_principal = false;
 194:     }
 195:   };
 196:   if ( isset($_POST['fullname']) && trim($_POST['fullname']) == '' ) {
 197:     $c->messages[] = i18n("The full name must not be blank.");
 198:     $can_write_principal = false;
 199:   };
 200:   if ( isset($_POST['email']) && trim($_POST['email']) == '' ) {
 201:     $c->messages[] = i18n("The email address really should not be blank.");
 202:   }
 203: 
 204:   $pwstars = '@@@@@@@@@@';
 205:   if ( $can_write_principal && $editor->IsSubmit() ) {
 206:     $editor->WhereNewRecord( "principal_id=(SELECT CURRVAL('dav_id_seq'))" );
 207:     if ( ! $session->AllowedTo('Admin') ) {
 208:       unset($_POST['admin_role']);
 209:       unset($_POST['user_active']);
 210:     }
 211:     unset($_POST['password']);
 212:     if ( $_POST['newpass1'] != '' && $_POST['newpass1'] != $pwstars ) {
 213:       if ( $_POST['newpass1'] == $_POST['newpass2'] ) {
 214:         $_POST['password'] = $_POST['newpass1'];
 215:       }
 216:       else {
 217:         $c->messages[] = "Password not updated. The supplied passwords do not match.";
 218:       }
 219:     }
 220:     if ( isset($_POST['fullname']) && !isset($_POST['displayname']) ) {
 221:       $_POST['displayname'] = $_POST['fullname'];
 222:     }
 223:     if ( isset($_POST['locale']) ) {
 224:       awl_set_locale($_POST['locale']); // activate immediately
 225:     }
 226:     if ( isset($_POST['default_privileges']) ) {
 227:       $privilege_bitpos = array_flip($privilege_names);
 228:       $priv_names = array_keys($_POST['default_privileges']);
 229:       $privs = privilege_to_bits($priv_names);
 230:       $_POST['default_privileges'] = sprintf('%024s',decbin($privs));
 231:       $editor->Assign('default_privileges', $privs_dec);
 232:     }
 233:     if ( $editor->IsCreate() ) {
 234:       $c->messages[] = i18n("Creating new Principal record.");
 235:     }
 236:     else {
 237:       $c->messages[] = i18n("Updating Principal record.");
 238:     }
 239:     $editor->Write();
 240:     if ( $_POST['type_id'] != 3 && $editor->IsCreate() ) {
 241:       /** We only add the default calendar if it isn't a group, and this is a create action */
 242:       require_once('auth-functions.php');
 243:       CreateHomeCollections($editor->Value('username'), $c->default_timezone);
 244:       CreateDefaultRelationships($editor->Value('username'));
 245:     }
 246:     if ( $session->AllowedTo('Admin') ) {
 247:       if ( $_POST['is_admin'] == 'on' ) {
 248:         $sql = 'INSERT INTO role_member (role_no, user_no) SELECT 1, dav_principal.user_no FROM dav_principal WHERE user_no = :user_no AND NOT EXISTS(SELECT 1 FROM role_member rm WHERE rm.role_no = 1 AND rm.user_no = dav_principal.user_no )';
 249:         $editor->Assign('is_admin', 't');
 250:       }
 251:       else {
 252:         $sql = 'DELETE FROM role_member WHERE role_no = 1 AND user_no = :user_no';
 253:         $editor->Assign('is_admin', 'f');
 254:       }
 255:       $params[':user_no'] = $editor->Value('user_no');
 256:       $qry = new AwlQuery( $sql, $params );
 257:       $qry->Exec('admin-principal-edit');
 258:     }
 259:   }
 260:   else if ( isset($id) && $id > 0 ) {
 261:     $editor->GetRecord();
 262:     if ( $editor->IsSubmit() ) {
 263:       $c->messages[] = i18n('You do not have permission to modify this record.');
 264:     }
 265:   }
 266:   if ( $editor->Available() ) {
 267:     $c->page_title = $editor->Title(translate('Principal').': '.$editor->Value('fullname'));
 268:   }
 269:   else {
 270:     $c->page_title = $editor->Title(translate('Create New Principal'));
 271:     $privs = decbin(privilege_to_bits($c->default_privileges));
 272:     $editor->Assign('default_privileges', $privs);
 273:     $editor->Assign('user_active', 't');
 274:     foreach( $c->template_usr AS $k => $v ) {
 275:       $editor->Assign($k, $v);
 276:     }
 277:   }
 278:   if ( $post_values ) {
 279:     $editor->PostToValues();
 280:     if ( isset($_POST['default_privileges']) ) {
 281:       $privilege_bitpos = array_flip($privilege_names);
 282:       $priv_names = array_keys($_POST['default_privileges']);
 283:       $privs = privilege_to_bits($priv_names);
 284:       $_POST['default_privileges'] = sprintf('%024s',decbin($privs));
 285:       $editor->Assign('default_privileges', $_POST['default_privileges']);
 286:     }
 287:   }
 288: 
 289: 
 290:   $prompt_principal_id = translate('Principal ID');
 291:   $value_id = ( $editor->Available() ? '##principal_id.hidden####principal_id.value##' : translate('New Principal'));
 292:   $prompt_username = translate('Username');
 293:   $prompt_password_1 = translate('Change Password');
 294:   $prompt_password_2 = translate('Confirm Password');
 295:   $prompt_fullname = translate('Fullname');
 296:   $prompt_displayname = translate('Display Name');
 297:   $prompt_email = translate('Email Address');
 298:   $prompt_date_format = translate('Date Format Style');
 299:   $prompt_admin = translate('Administrator');
 300:   $prompt_active = translate('Active');
 301:   $prompt_locale = translate('Locale');
 302:   $prompt_type = translate('Principal Type');
 303:   $prompt_privileges = translate('Privileges granted to All Users');
 304: 
 305:   if ($can_write_principal) {
 306:     $privs_html = build_privileges_html( $editor, 'default_privileges');
 307:     $submit_row = '<tr> <th class="right"></th>                   <td class="left" colspan="2">##submit##</td> </tr>';
 308:   } else {
 309:     $privs_html = principal_privilege_format_function( $editor->Value('default_privileges') );
 310:     $submit_row = '';
 311:   }
 312: 
 313:   $admin_row_entry = '';
 314:   $delete_principal_button = '';
 315:   if ( $session->AllowedTo('Admin') ) {
 316:     $admin_row_entry = ' <tr> <th class="right">'.$prompt_admin.':</th><td class="left">##is_admin.checkbox##</td> </tr>';
 317:     $admin_row_entry .= ' <tr> <th class="right">'.$prompt_active.':</th><td class="left">##user_active.checkbox##</td> </tr>';
 318:     if ( isset($id) )
 319:       $delete_principal_button = '<a href="'.$c->base_url . '/admin.php?action=edit&t=principal&subaction=delete_principal&id='.$id.'" class="submit">' . translate("Delete Principal") . '</a>';
 320:   }
 321: 
 322:   $email_unique = '';
 323:   $qry = new AwlQuery('SELECT user_no FROM usr WHERE lower(usr.email) = lower(:email)',
 324:                         array( ':email' => $editor->Value('email') ));
 325:   $qry->Exec('principal-edit', __LINE__, __FILE__);
 326:   if ($qry->rows() > 1 ) {
 327:       $email_unique = ' <b style="color:red;">' . translate('Attention: email address not unique, scheduling may not work!') . '</b>';
 328:   }
 329: 
 330:   $id = $editor->Value('principal_id');
 331:   $template = <<<EOTEMPLATE
 332: ##form##
 333: <script language="javascript">
 334: function toggle_privileges() {
 335:   var argv = toggle_privileges.arguments;
 336:   var argc = argv.length;
 337: 
 338:   if ( argc < 2 ) {
 339:     return;
 340:   }
 341:   var match_me = argv[0];
 342: 
 343:   var set_to = -1;
 344:   if ( argv[1] == 'all' ) {
 345:     var form = document.getElementById(argv[2]);
 346:     var fieldcount = form.elements.length;
 347:     var matching = '/^' + match_me + '/';
 348:     for (var i = 0; i < fieldcount; i++) {
 349:       var fieldname = form.elements[i].name;
 350:       if ( fieldname.match( match_me ) ) {
 351:         if ( set_to == -1 ) {
 352:           set_to = ( form.elements[i].checked ? 0 : 1 );
 353:         }
 354:         form.elements[i].checked = set_to;
 355:       }
 356:     }
 357:   }
 358:   else {
 359:     for (var i = 1; i < argc; i++) {
 360:       var f = document.getElementById( match_me + '_' + argv[i]);
 361:       if ( set_to == -1 ) {
 362:         set_to = ( f.checked ? 0 : 1 );
 363:       }
 364:       f.checked = set_to;
 365:     }
 366:   }
 367: }
 368: </script>
 369: <style>
 370: th.right, label.privilege {
 371:   white-space:nowrap;
 372: }
 373: label.privilege {
 374:   margin:0.2em 1em 0.2em 0.1em;
 375:   padding:0 0.2em;
 376:   line-height:1.6em;
 377:   font-size:87%;
 378: }
 379: </style>
 380: <table>
 381:  <tr> <th class="right">$prompt_principal_id:</th><td class="left">
 382:   <table width="100%" class="form_inner"><tr>
 383:    <td>$value_id</td>
 384:    <td align="right">$delete_principal_button</td>
 385:   </tr></table>
 386:  </td></tr>
 387:  <tr> <th class="right">$prompt_username:</th>    <td class="left">##xxxxusername.input.50##</td> </tr>
 388:  <tr> <th class="right">$prompt_password_1:</th>  <td class="left">##newpass1.password.$pwstars##</td> </tr>
 389:  <tr> <th class="right">$prompt_password_2:</th>  <td class="left">##newpass2.password.$pwstars##</td> </tr>
 390:  <tr> <th class="right">$prompt_fullname:</th>    <td class="left">##fullname.input.50##</td> </tr>
 391:  <tr> <th class="right">$prompt_email:</th>       <td class="left">##email.input.50##$email_unique</td> </tr>
 392:  <tr> <th class="right">$prompt_locale:</th>      <td class="left">##locale.select##</td> </tr>
 393:  <tr> <th class="right">$prompt_date_format:</th> <td class="left">##date_format_type.select##</td> </tr>
 394:  <tr> <th class="right">$prompt_type:</th>        <td class="left">##type_id.select##</td> </tr>
 395:  $admin_row_entry
 396:  <tr> <th class="right" style="white-space:normal;">$prompt_privileges:</th><td class="left">$privs_html</td> </tr>
 397:  $submit_row
 398: </table>
 399: </form>
 400: EOTEMPLATE;
 401: 
 402:   $editor->SetTemplate( $template );
 403:   return $editor;
 404: }
 405: 
 406: 
 407: function build_privileges_html( $ed, $fname ) {
 408:   global $privilege_xlate, $privilege_names;
 409: 
 410:   $btn_all = htmlspecialchars(translate('All'));             $btn_all_title = htmlspecialchars(translate('Toggle all privileges'));
 411:   $btn_rw  = htmlspecialchars(translate('Read/Write'));      $btn_rw_title = htmlspecialchars(translate('Set read+write privileges'));
 412:   $btn_read = htmlspecialchars(translate('Read'));           $btn_read_title = htmlspecialchars(translate('Set read privileges'));
 413:   $btn_fb = htmlspecialchars(translate('Free/Busy'));        $btn_fb_title = htmlspecialchars(translate('Set free/busy privileges'));
 414:   $btn_sd = htmlspecialchars(translate('Schedule Deliver')); $btn_sd_title = htmlspecialchars(translate('Privileges to allow delivery of scheduling messages'));
 415:   $btn_ss = htmlspecialchars(translate('Schedule Send'));    $btn_ss_title = htmlspecialchars(translate('Privileges to delegate scheduling decisions'));
 416: 
 417:   $privs_dec = bindec($ed->Value($fname));
 418:   $privileges_set = sprintf('<div id="privileges"><input type="hidden" name="%s[fake_privilege_for_input]" value="0">%s', $fname, "\n");
 419:   for( $i=0; $i < count($privilege_names); $i++ ) {
 420:     $privilege_set = ( (1 << $i) & $privs_dec ? ' CHECKED' : '');
 421:     $privileges_set .= sprintf( '  <label class="privilege"><input name="%s[%s]" id="%s_%s" type="checkbox"%s>%s</label>'."\n",
 422:                   $fname, $privilege_names[$i], $fname, $privilege_names[$i], $privilege_set,
 423:                   $privilege_xlate[$privilege_names[$i]]);
 424:   }
 425:   $privileges_set .= '</div>'."\n";
 426: 
 427:   $form_id = $ed->Id();
 428:   $html = <<<EOTEMPLATE
 429: <input type="button" value="$btn_all" class="submit" title="$btn_all_title"
 430:  onclick="toggle_privileges('$fname', 'all', 'form_$form_id');">
 431: <input type="button" value="$btn_rw" class="submit" title="$btn_rw_title"
 432:  onclick="toggle_privileges('$fname', 'read', 'write-properties', 'write-content', 'bind', 'unbind', 'read-free-busy', 'read-current-user-privilege-set', 'schedule-deliver-invite', 'schedule-deliver-reply', 'schedule-query-freebusy', 'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );">
 433: <input type="button" value="$btn_read" class="submit" title="$btn_read_title"
 434:  onclick="toggle_privileges('$fname', 'read', 'read-free-busy', 'schedule-query-freebusy', 'read-current-user-privilege-set' );">
 435: <input type="button" value="$btn_fb" class="submit" title="$btn_fb_title"
 436:  onclick="toggle_privileges('$fname', 'read-free-busy', 'schedule-query-freebusy' );">
 437: <input type="button" value="$btn_sd" class="submit" title="$btn_sd_title"
 438:  onclick="toggle_privileges('$fname', 'schedule-deliver-invite', 'schedule-deliver-reply', 'schedule-query-freebusy' );">
 439: <input type="button" value="$btn_ss" class="submit" title="$btn_ss_title"
 440:  onclick="toggle_privileges('$fname', 'schedule-send-invite', 'schedule-send-reply', 'schedule-send-freebusy' );">
 441: <br>$privileges_set
 442: EOTEMPLATE;
 443: 
 444:   return $html;
 445: }
 446: 
 447: 
 448: /**
 449: * principal_privilege_format_function is for formatting the binary privileges from the
 450: * database, including localising them.  This is a hook function for a browser
 451: * column object, so it takes three parameters:
 452: * @param mixed $value The value of the column.
 453: * @param BrowserColumn $column The BrowserColumn object we are hooked into.
 454: * @param dbrow $row The row object we read from the database.
 455: * @return string The formatted privileges.
 456: */
 457: function principal_privilege_format_function( $value, $column, $row ) {
 458:   global $privilege_xlate;
 459: 
 460:   $privs = bits_to_privilege($value,'*');
 461:   $formatted = '';
 462:   foreach( $privs AS $k => $v ) {
 463:     $formatted .= ($formatted == '' ? '' : ', ');
 464:     $v = preg_replace( '{^.*:}', '', $v );
 465:     $formatted .= (isset($privilege_xlate[$v]) ? $privilege_xlate[$v] : $v );
 466:   }
 467:   return $formatted;
 468: }
 469: 
 470: 
 471: function confirm_delete_principal($confirmation_hash, $displayname ) {
 472:   $html = '<p class="error">';
 473:   $html .= sprintf('<b>%s</b> \'%s\' <a class="error" href="%s&%s">%s</a> %s',
 474:        translate('Deleting Principal:'), $displayname, $_SERVER['REQUEST_URI'],
 475:         $confirmation_hash, translate('Confirm Deletion of the Principal'),
 476:         translate('All of the principal\'s calendars and events will be unrecoverably deleted.') );
 477:   $html .= "</p>\n";
 478:   return $html;
 479: }
 480: 
 481: 
 482: 
 483: function group_memberships_browser() {
 484:   global $c, $id, $editor;
 485:   $browser = new Browser(translate('Group Memberships'));
 486: 
 487:   $browser->AddColumn( 'group_id', translate('ID'), 'right', '##principal_link##' );
 488:   $rowurl = $c->base_url . '/admin.php?action=edit&t=principal&id=';
 489:   $browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || principal_id || '\">' || principal_id || '</a>'" );
 490:   $browser->AddColumn( 'displayname', translate('Display Name') );
 491:   $browser->AddColumn( 'member_of', translate('Is Member of'), '', '', 'is_member_of_list(principal_id)' );
 492:   $browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
 493: 
 494:   $browser->SetOrdering( 'displayname', 'A' );
 495: 
 496:   $browser->SetJoins( "group_member LEFT JOIN dav_principal ON (group_id = principal_id) " );
 497:   $browser->SetWhere( 'user_active AND member_id = '.$id );
 498: 
 499:   if ( $c->enable_row_linking ) {
 500:     $browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
 501:   }
 502:   else {
 503:     $browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
 504:   }
 505:   $browser->DoQuery();
 506:   return $browser;
 507: }
 508: 
 509: 
 510: function group_row_editor() {
 511:   global $c, $id, $editor, $can_write_principal;
 512:   $grouprow = new Editor("Group Members", "group_member");
 513:   $sql = 'SELECT principal_id, coalesce(displayname,fullname,username) FROM dav_principal ';
 514:   $sql .= 'WHERE principal_id NOT IN (SELECT member_id FROM group_member WHERE group_id = '.$id.') ';
 515:   $sql .= 'AND principal_id != '.$id;
 516:   $sql .= 'ORDER BY 2';
 517:   $grouprow->SetLookup( 'member_id', $sql);
 518:   $grouprow->SetSubmitName( 'savegrouprow' );
 519: 
 520:   if ( $can_write_principal ) {
 521:     if ( $grouprow->IsSubmit() ) {
 522:       if ( $grouprow->IsUpdate() )
 523:         $c->messages[] = translate('Updating Member of this Group Principal');
 524:       else
 525:         $c->messages[] = translate('Adding new member to this Group Principal');
 526: 
 527:       $_POST['group_id'] = $id;
 528:       $member_id = intval($_POST['member_id']);
 529:       $grouprow->SetWhere( 'group_id='.$id.' AND member_id='.$member_id);
 530:       $grouprow->Write( );
 531:       unset($_GET['member_id']);
 532:     }
 533:     elseif ( isset($_GET['delete_member']) ) {
 534:       $qry = new AwlQuery('DELETE FROM group_member WHERE group_id=:group_id AND member_id = :member_id',
 535:                             array( ':group_id' => $id, ':member_id' => intval($_GET['delete_member']) ));
 536:       $qry->Exec('principal-edit');
 537:       $c->messages[] = translate('Member deleted from this Group Principal');
 538:     }
 539:   }
 540:   return $grouprow;
 541: }
 542: 
 543: 
 544: function edit_group_row( $row_data ) {
 545:   global $id, $grouprow;
 546: 
 547:   $form_url = preg_replace( '#&(edit|delete)_group=\d+#', '', $_SERVER['REQUEST_URI'] );
 548: 
 549:   $template = <<<EOTEMPLATE
 550: <form method="POST" enctype="multipart/form-data" id="add_group" action="$form_url">
 551:   <td class="left"><input type="hidden" name="id" value="$id"></td>
 552:   <td class="left" colspan="3">##member_id.select## &nbsp; ##Add.submit##</td>
 553:   <td class="center"></td>
 554: </form>
 555: 
 556: EOTEMPLATE;
 557: 
 558:   $grouprow->SetTemplate( $template );
 559:   $grouprow->Title("");
 560:   if ( $row_data->group_id > -1 ) $grouprow->SetRecord( $row_data );
 561: 
 562:   return $grouprow->Render();
 563: }
 564: 
 565: function group_members_browser() {
 566:   global $c, $id, $editor, $can_write_principal;
 567:   $browser = new Browser(translate('Group Members'));
 568: 
 569:   $browser->AddColumn( 'group_id', translate('ID'), 'right', '##principal_link##' );
 570:   $rowurl = $c->base_url . '/admin.php?action=edit&t=principal&id=';
 571:   $browser->AddHidden( 'principal_id' );
 572:   $browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || principal_id || '\">' || principal_id || '</a>'" );
 573:   $browser->AddColumn( 'displayname', translate('Display Name') );
 574:   $browser->AddColumn( 'member_of', translate('Is Member of'), '', '', 'is_member_of_list(principal_id)' );
 575:   $browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
 576: 
 577:   if ( $can_write_principal ) {
 578:     $del_link  = '<a href="'.$c->base_url.'/admin.php?action=edit&t=principal&id='.$id.'&delete_member=##principal_id##" class="submit" title="">'.translate('Remove').'</a>';
 579:     $browser->AddColumn( 'action', translate('Action'), 'center', '', "'$edit_link&nbsp;$del_link'" );
 580:   }
 581: 
 582:   $browser->SetOrdering( 'displayname', 'A' );
 583: 
 584:   $browser->SetJoins( "group_member LEFT JOIN dav_principal ON (member_id = principal_id) " );
 585:   $browser->SetWhere( 'user_active AND group_id = '.$id );
 586: 
 587:   if ( $c->enable_row_linking ) {
 588:     $browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
 589:   }
 590:   else {
 591:     $browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
 592:   }
 593:   $browser->DoQuery();
 594: 
 595:   if ( $can_write_principal ) {
 596:     $browser->ExtraRowFormat( '<tr class="r%d">', '</tr>', '#even' );
 597:     $extra_row = array( 'group_id' => -1 );
 598:     $browser->MatchedRow('group_id', -1, 'edit_group_row');
 599:     $extra_row = (object) $extra_row;
 600:     $browser->AddRow($extra_row);
 601:   }
 602:   return $browser;
 603: }
 604: 
 605: 
 606: function grant_row_editor() {
 607:   global $c, $id, $editor, $can_write_principal, $privilege_names;
 608: 
 609:   $grantrow = new Editor("Grants", "grants");
 610:   $grantrow->SetSubmitName( 'savegrantrow' );
 611:   $edit_grant_clause = '';
 612:   if ( isset($_GET['edit_grant']) ) {
 613:     $edit_grant_clause = ' AND to_principal != '.intval($_GET['edit_grant']);
 614:   }
 615:   $grantrow->SetLookup( 'to_principal', 'SELECT principal_id, displayname FROM dav_principal WHERE user_active AND principal_id NOT IN (SELECT to_principal FROM grants WHERE by_principal = '.$id.$edit_grant_clause.') ORDER BY fullname' );
 616:   if ( $can_write_principal ) {
 617:     if ( $grantrow->IsSubmit() ) {
 618:       if ( $grantrow->IsUpdate() )
 619:         $c->messages[] = translate('Updating grants by this Principal');
 620:       else
 621:         $c->messages[] = translate('Granting new privileges from this Principal');
 622:       $_POST['by_principal'] = $id;
 623:       $to_principal = intval($_POST['to_principal']);
 624:       $orig_to_id =  intval($_POST['orig_to_id']);
 625:       $grantrow->SetWhere( 'by_principal='.$id.' AND to_principal='.$orig_to_id);
 626:       if ( isset($_POST['grant_privileges']) ) {
 627:         $privilege_bitpos = array_flip($privilege_names);
 628:         $priv_names = array_keys($_POST['grant_privileges']);
 629:         $privs_dec = privilege_to_bits($priv_names);
 630:         $_POST['privileges'] = sprintf('%024s',decbin($privs_dec));
 631:         $grantrow->Assign('privileges', $privs_dec);
 632:       }
 633:       $grantrow->Write( );
 634:       unset($_GET['to_principal']);
 635:     }
 636:     elseif ( isset($_GET['delete_grant']) ) {
 637:       $qry = new AwlQuery("DELETE FROM grants WHERE by_principal=:grantor_id AND to_principal = :to_principal",
 638:                             array( ':grantor_id' => $id, ':to_principal' => intval($_GET['delete_grant']) ));
 639:       $qry->Exec('principal-edit');
 640:       $c->messages[] = translate('Deleted a grant from this Principal');
 641:     }
 642:   }
 643:   return $grantrow;
 644: }
 645: 
 646: 
 647: function edit_grant_row_principal( $row_data ) {
 648:   global $id, $grantrow;
 649: 
 650:   $orig_to_id = intval($row_data->to_principal);
 651:   if ( $orig_to_id > -1 ) {
 652:     $grantrow->SetRecord( $row_data );
 653:   }
 654:   else {
 655:     $grantrow->Initialise( $row_data );
 656:   }
 657: 
 658:   $privs_html = build_privileges_html( $grantrow, 'grant_privileges' );
 659: 
 660:   $form_id = $grantrow->Id();
 661:   $form_url = preg_replace( '#&(edit|delete)_grant=\d+#', '', $_SERVER['REQUEST_URI'] );
 662: 
 663:   $template = <<<EOTEMPLATE
 664: <form method="POST" enctype="multipart/form-data" id="form_$form_id" action="$form_url">
 665:   <td class="left" colspan="2"><input type="hidden" name="id" value="$id"><input type="hidden" name="orig_to_id" value="$orig_to_id">##to_principal.select##</td>
 666:   <td class="left" colspan="2">$privs_html</td>
 667:   <td class="center">##submit##</td>
 668: </form>
 669: 
 670: EOTEMPLATE;
 671: 
 672:   $grantrow->SetTemplate( $template );
 673:   $grantrow->Title("");
 674: 
 675:   return $grantrow->Render();
 676: }
 677: 
 678: 
 679: function principal_grants_browser() {
 680:   global $c, $id, $editor, $can_write_principal;
 681:     $browser = new Browser(translate('Principal Grants'));
 682: 
 683:   $browser->AddColumn( 'to_principal', translate('To ID'), 'right', '##principal_link##' );
 684:   $rowurl = $c->base_url . '/admin.php?action=edit&t=principal&id=';
 685:   $browser->AddHidden( 'principal_link', "'<a href=\"$rowurl' || to_principal || '\">' || to_principal || '</a>'" );
 686:   $browser->AddHidden( 'grant_privileges', 'privileges' );
 687:   $browser->AddColumn( 'displayname', translate('Display Name') );
 688:   $browser->AddColumn( 'privs', translate('Privileges'), '', '', 'privileges', '', '', 'principal_privilege_format_function' );
 689:   $browser->AddColumn( 'members', translate('Has Members'), '', '', 'has_members_list(principal_id)' );
 690: 
 691:   if ( $can_write_principal ) {
 692:     $del_link  = '<a href="'.$c->base_url.'/admin.php?action=edit&t=principal&id='.$id.'&delete_grant=##to_principal##" class="submit" title="">'.translate('Revoke').'</a>';
 693:     $edit_link  = '<a href="'.$c->base_url.'/admin.php?action=edit&t=principal&id='.$id.'&edit_grant=##to_principal##" class="submit" title="">'.translate('Edit').'</a>';
 694:     $browser->AddColumn( 'action', translate('Action'), 'center', '', "'$edit_link&nbsp;$del_link'" );
 695:   }
 696: 
 697:   $browser->SetOrdering( 'displayname', 'A' );
 698: 
 699:   $browser->SetJoins( "grants LEFT JOIN dav_principal ON (to_principal = principal_id) " );
 700:   $browser->SetWhere( 'by_principal = '.$id );
 701: 
 702:   if ( $c->enable_row_linking ) {
 703:     $browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit principal details').'" class="r%d">', '</tr>', '#even' );
 704:   }
 705:   else {
 706:     $browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
 707:   }
 708:   $browser->DoQuery();
 709: 
 710: 
 711:   if ( $can_write_principal ) {
 712:     if ( isset($_GET['edit_grant']) ) {
 713:       $browser->MatchedRow('to_principal', $_GET['edit_grant'], 'edit_grant_row_principal');
 714:     }
 715:     else if ( isset($id ) ) {
 716:       $browser->ExtraRowFormat( '<tr class="r%d">', '</tr>', '#even' );
 717:       $extra_row = array( 'to_principal' => -1 );
 718:       $browser->MatchedRow('to_principal', -1, 'edit_grant_row_principal');
 719:       $extra_row = (object) $extra_row;
 720:       $browser->AddRow($extra_row);
 721:     }
 722:   }
 723:   return $browser;
 724: }
 725: 
 726: 
 727: function ticket_row_editor() {
 728:   global $c, $id, $editor, $can_write_principal, $privilege_names;
 729: 
 730:   $ticketrow = new Editor("Tickets", "access_ticket");
 731:   $ticketrow->SetSubmitName( 'ticketrow' );
 732:   if ( $can_write_principal && $ticketrow->IsSubmit() ) {
 733: 
 734:     $username = $editor->Value('username');
 735:     $ugly_path = $_POST['target'];
 736:     if ( $ugly_path == '/'.$username || $ugly_path == '/'.$username.'/' ) {
 737:       $target_collection = $id;
 738:     }
 739:     else {
 740:       $username_len = strlen($username) + 2;
 741:       $sql = "SELECT collection_id FROM collection WHERE dav_name = :exact_name";
 742:       $sql .= " AND substring(dav_name FROM 1 FOR $username_len) = '/$username/'";
 743:       $params = array( ':exact_name' => $ugly_path );
 744:       if ( !preg_match( '#/$#', $ugly_path ) ) {
 745:         $sql .= " OR dav_name = :truncated_name OR dav_name = :trailing_slash_name";
 746:         $params[':truncated_name'] = preg_replace( '#[^/]*$#', '', $ugly_path);
 747:         $params[':trailing_slash_name'] = $ugly_path."/";
 748:       }
 749:       $sql .= " ORDER BY LENGTH(dav_name) DESC LIMIT 1";
 750:       $qry = new AwlQuery( $sql, $params );
 751:       if ( $qry->Exec() && $qry->rows() > 0 ) {
 752:         $row = $qry->Fetch();
 753:         $target_collection = $row->collection_id;
 754:       }
 755:       else {
 756:         $c->messages[] = translate('Can only add tickets for existing collection paths which you own');
 757:         return $ticketrow;
 758:       }
 759:     }
 760: 
 761:     $_POST['dav_owner_id'] = $id;
 762:     $_POST['target_collection_id'] = $target_collection;
 763:     $ticket_id = check_by_regex($_POST['ticket_id'], '/[A-Za-z0-9]+/');
 764:     $ticketrow->SetWhere( 'dav_owner_id='.$id.' AND ticket_id='.AwlQuery::quote($ticket_id));
 765:     if ( isset($_POST['ticket_privileges']) ) {
 766:       $privilege_bitpos = array_flip($privilege_names);
 767:       $priv_names = array_keys($_POST['ticket_privileges']);
 768:       $privs_dec = privilege_to_bits($priv_names);
 769:       $_POST['privileges'] = sprintf('%024s',decbin($privs_dec));
 770:       $ticketrow->Assign('privileges', $privs_dec);
 771:     }
 772:     $c->messages[] = translate('Creating new ticket granting privileges to this Principal');
 773:     $ticketrow->Write( );
 774:   }
 775:   return $ticketrow;
 776: }
 777: 
 778: 
 779: function edit_ticket_row( $row_data ) {
 780:   global $id, $ticketrow;
 781: 
 782:   if ( isset($row_data->ticket_id) ) {
 783:     $ticketrow->Initialise( $row_data );
 784:   }
 785: 
 786:   $privs_html = build_privileges_html( $ticketrow, 'ticket_privileges' );
 787: 
 788:   $form_id = $ticketrow->Id();
 789:   $ticket_id = $row_data->ticket_id;
 790:   $form_url = preg_replace( '#&(edit|delete)_[a-z]+=\d+#', '', $_SERVER['REQUEST_URI'] );
 791: 
 792:   $template = <<<EOTEMPLATE
 793: <form method="POST" enctype="multipart/form-data" id="form_$form_id" action="$form_url">
 794:   <td class="left">$ticket_id<input type="hidden" name="id" value="$id"><input type="hidden" name="ticket_id" value="$ticket_id"></td>
 795:   <td class="left"><input type="text" name="target" value="$row_data->target"></td>
 796:   <td class="left"><input type="text" name="expires" value="$row_data->expires" size="10"></td>
 797:   <td class="left">$privs_html</td>
 798:   <td class="center">##submit##</td>
 799: </form>
 800: 
 801: EOTEMPLATE;
 802: 
 803:   $ticketrow->SetTemplate( $template );
 804:   $ticketrow->Title("");
 805: 
 806:   return $ticketrow->Render();
 807: }
 808: 
 809: 
 810: function access_ticket_browser() {
 811:   global $c, $id, $editor, $can_write_principal;
 812: 
 813:   $browser = new Browser(translate('Access Tickets'));
 814: 
 815:   if ( $can_write_principal ) {
 816:     $browser->AddColumn( 'ticket_id', translate('Ticket ID'), '', '' );
 817:   }
 818:   $browser->AddColumn( 'target', translate('Target'), '', '<td style="white-space:nowrap;">%s</td>', "COALESCE(d.dav_name,c.dav_name)" );
 819:   $browser->AddColumn( 'expires', translate('Expires'), '', '', 'TO_CHAR(expires,\'YYYY-MM-DD HH:MI:SS\')');
 820:   $browser->AddColumn( 'privs', translate('Privileges'), '', '', 'privileges', '', '', 'principal_privilege_format_function' );
 821:   if ($can_write_principal) {
 822:     $delurl = $c->base_url . '/admin.php?action=edit&t=principal&id='.$id.'&ticket_id=##URL:ticket_id##&subaction=delete_ticket';
 823:     $browser->AddColumn( 'delete', translate('Action'), 'center', '', "'<a class=\"submit\" href=\"$delurl\">".translate('Delete')."</a>'" );
 824:   }
 825: 
 826:   $browser->SetOrdering( 'target', 'A' );
 827: 
 828:   $browser->SetJoins( 'access_ticket t LEFT JOIN collection c ON (target_collection_id=collection_id) LEFT JOIN caldav_data d ON (target_resource_id=dav_id)' );
 829:   $browser->SetWhere( 'dav_owner_id = '.intval($editor->Value('principal_id')) );
 830: 
 831:   $browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
 832: 
 833:   $browser->DoQuery();
 834: 
 835:   if ( $can_write_principal ) {
 836:     $ticket_id = substr( str_replace('/', '', str_replace('+', '',base64_encode(sha1(date('r') .rand(0,2100000000) . microtime(true),true)))), 7, 8);
 837:     $extra_row = array( 'ticket_id' => $ticket_id,
 838:                         'expires' => date( 'Y-m-d', time() + (86400 * 31) ),
 839:                         'target' => '/'.$editor->Value('username').'/'.$c->home_calendar_name.'/'
 840:                       );
 841:     $browser->MatchedRow('ticket_id', $ticket_id, 'edit_ticket_row');
 842:     $browser->AddRow($extra_row);
 843:   }
 844:   return $browser;
 845: }
 846: 
 847: 
 848: function confirm_delete_ticket($confirmation_hash) {
 849:   $html = '<table><tr><td class="error">';
 850:   $html .= sprintf('<b>%s</b> "%s" <a class="error" href="%s&%s">%s</a> %s',
 851:               translate('Deleting Ticket:'), $_GET['ticket_id'], $_SERVER['REQUEST_URI'],
 852:               $confirmation_hash,
 853:               translate('Confirm Deletion of the Ticket'),
 854:               translate('The access ticket will be deleted.') );
 855:   $html .= "</td></tr></table>\n";
 856:   return $html;
 857: }
 858: 
 859: 
 860: function principal_collection_browser() {
 861:   global $c, $page_elements, $id, $editor, $can_write_principal;
 862: 
 863:   $browser = new Browser(translate('Principal Collections'));
 864: 
 865:   $browser->AddColumn( 'collection_id', translate('ID'), 'right', '##collection_link##' );
 866:   $rowurl = $c->base_url . '/admin.php?action=edit&t=collection&id=';
 867:   $browser->AddHidden( 'collection_link', "'<a href=\"$rowurl' || collection_id || '\">' || collection_id || '</a>'" );
 868:   $browser->AddColumn( 'dav_name', translate('Path') );
 869:   $browser->AddColumn( 'dav_displayname', translate('Display Name') );
 870:   $browser->AddColumn( 'publicly_readable', translate('Public'), 'centre', '', 'CASE WHEN publicly_readable THEN \''.translate('Yes').'\' ELSE \''.translate('No').'\' END' );
 871:   $browser->AddColumn( 'privs', translate('Privileges'), '', '',
 872:           "COALESCE( privileges_list(default_privileges), '[".translate('from principal')."]')" );
 873:   if ($can_write_principal) {
 874:     $delurl = $c->base_url . '/admin.php?action=edit&t=principal&id='.$id.'&dav_name=##URL:dav_name##&subaction=delete_collection';
 875:     $browser->AddColumn( 'delete', translate('Action'), 'center', '', "'<a class=\"submit\" href=\"$delurl\" title=\"\">".translate('Delete')."</a>'" );
 876:   }
 877: 
 878:   $browser->SetOrdering( 'dav_name', 'A' );
 879: 
 880:   $browser->SetJoins( "collection " );
 881:   $browser->SetWhere( 'user_no = '.intval($editor->Value('user_no')) );
 882: 
 883:   if ($can_write_principal) {
 884:     $browser->ExtraRowFormat( '<tr class="r%d">', '</tr>', '#even' );
 885:     $browser->AddRow( array( 'dav_name' => '<a href="'.$rowurl.'&user_no='.intval($editor->Value('user_no')).'" class="submit">'.translate('Create Collection').'</a>' ));
 886:   }
 887: 
 888:   if ( $c->enable_row_linking ) {
 889:     $browser->RowFormat( '<tr onMouseover="LinkHref(this,1);" title="'.translate('Click to edit collection details').'" class="r%d">', '</tr>', '#even' );
 890:   }
 891:   else {
 892:     $browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
 893:   }
 894:   $browser->DoQuery();
 895:   return $browser;
 896: }
 897: 
 898: function confirm_delete_collection($confirmation_hash) {
 899:   $html = '<table><tr><td class="error">';
 900:   $html .= sprintf('<b>%s</b> "%s" <a class="error" href="%s&%s">%s</a> %s',
 901:               translate('Deleting Collection:'), $_GET['dav_name'], $_SERVER['REQUEST_URI'],
 902:               $confirmation_hash,
 903:               translate('Confirm Deletion of the Collection'),
 904:               translate('All collection data will be unrecoverably deleted.') );
 905:   $html .= "</td></tr></table>\n";
 906:   return $html;
 907: }
 908: 
 909: 
 910: function binding_row_editor() {
 911:   global $c, $id, $editor, $can_write_principal;
 912: 
 913:   $bindingrow = new Editor("Bindings", "dav_binding");
 914:   $bindingrow->SetSubmitName( 'bindingrow' );
 915:   if ( $can_write_principal && $bindingrow->IsSubmit() ) {
 916:     if ( substr($_POST['dav_name'], -1) != '/' ) {
 917:       $_POST['dav_name'] .= '/';
 918:     }
 919: 
 920:     $dav_name = $_POST['dav_name'];
 921:     $parent = '/'.$editor->Value('username').'/';
 922:     if ( strpos($dav_name, $parent) !== 0 ) {
 923:       $c->messages[] = translate("Can only bind collections into the current principal's namespace");
 924:       return $bindingrow;
 925:     }
 926:     if ( substr_count($dav_name, '/') != 3 || substr_count($dav_name, '\\') > 0 ) {
 927:       $c->messages[] = translate("Bound As is invalid");
 928:       return $bindingrow;
 929:     }
 930:     $qry = new AwlQuery('SELECT dav_name FROM collection where dav_name = :dav_name UNION SELECT dav_name FROM dav_binding WHERE dav_name = :dav_name', array( ':dav_name' => $dav_name) );
 931:     if ( $qry->Exec('dav_name') && $qry->rows() > 0 ) {
 932:       $c->messages[] = translate('A resource already exists at the destination.');
 933:       return $bindingrow;
 934:     }
 935: 
 936:     if ( empty($_POST['access_ticket_id']) )
 937:       $_POST['access_ticket_id'] = null;
 938:     $_POST['dav_owner_id'] = $id;
 939:     $_POST['parent_container'] = $parent;
 940: 
 941:     //  external binds shouldn't ever point back to ourselves but they should be a valid http[s] url
 942:     $href = $_POST['source'];
 943:     if ( preg_match ( '{^(?:https?://|file:///)([^/]+)(:[0-9]\+)?/.+$}', $href, $matches )
 944:         && strcasecmp( $matches[0], 'localhost' ) !== 0 && strcasecmp( $matches[0], '127.0.0.1' ) !== 0
 945:         && strcasecmp( $matches[0], $_SERVER['SERVER_NAME'] ) !== 0 && strcasecmp( $matches[0], $_SERVER['SERVER_ADDR'] ) !== 0
 946:     ) {
 947:       $path = '/.external/' . md5($href);
 948:       $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = :dav_name ', array( ':dav_name' => $path ));
 949:       if ( $qry->rows() == 1 && ($row = $qry->Fetch()) ) {
 950:         $dav_id = $row->collection_id;
 951:       }
 952:       else {
 953:         $qry->QDo( 'INSERT INTO collection ( user_no, parent_container, dav_name, dav_etag, dav_displayname,
 954:                                               is_calendar, is_addressbook, resourcetypes, created )
 955:                                 VALUES( :user_no, :parent_container, :dav_name, :dav_etag, :dav_displayname,
 956:                                         :is_calendar, :is_addressbook, :resourcetypes, current_timestamp )',
 957:             array(
 958:               ':user_no'          => $editor->Value('user_no'),
 959:               ':parent_container' => '/.external/',
 960:               ':dav_name'         => $path,
 961:               ':dav_etag'         => md5( $editor->Value('user_no') . $path ),
 962:               ':dav_displayname'  => $_POST['dav_displayname'],
 963:               ':is_calendar'      => 't',
 964:               ':is_addressbook'   => 'f',
 965:               ':resourcetypes'    => '<DAV::collection/><urn:ietf:params:xml:ns:caldav:calendar/>'
 966:             )
 967:         );
 968: 
 969:         $qry->QDo('SELECT collection_id FROM collection WHERE dav_name = :dav_name ', array( ':dav_name' => $path ));
 970:         if ( $qry->rows() != 1 || !($row = $qry->Fetch()) ) {
 971:           $c->messages[] = translate('Database Error');
 972:           return $bindingrow;
 973:         }
 974:         $dav_id = $row->collection_id;
 975:       }
 976: 
 977:       $_POST['bound_source_id'] = $dav_id;
 978:       $_POST['external_url'] = $href;
 979:       $_POST['external_type'] = 'calendar';
 980:     }
 981:     else {
 982:       // internal bind
 983:       require_once('DAVResource.php');
 984:       $source = new DAVResource( $href );
 985:       if ( !$source->Exists() || $source->IsPrincipal() || !$source->IsCollection() || $source->dav_name() == '/' ) {
 986:         $c->messages[] = translate('The BIND Request MUST identify an existing resource.');
 987:         return $bindingrow;
 988:       }
 989:       if ( $source->IsBinding() )
 990:         $source = new DAVResource( $source->bound_from() );
 991:       $_POST['bound_source_id'] = $source->collection_id();
 992:     }
 993: 
 994:     $c->messages[] = 'Creating new binding for this principal';
 995:     $bindingrow->SetWhere( "dav_name = '$dav_name'" );
 996:     $bindingrow->Write();
 997:   }
 998:   return $bindingrow;
 999: }
1000: 
1001: 
1002: function edit_binding_row( $row_data ) {
1003:   global $id, $bindingrow;
1004: 
1005:   if ( isset($row_data->dav_name) ) {
1006:     $bindingrow->Initialise( $row_data );
1007:   }
1008: 
1009:   $form_id = $bindingrow->Id();
1010:   $form_url = preg_replace( '#&(edit|delete)_[a-z]+=\d+#', '', $_SERVER['REQUEST_URI'] );
1011:   $source_title = translate('Path to collection you wish to bind, like /user1/calendar/ or https://cal.example.com/user2/cal/');
1012:   $access_title = translate('optional');
1013: 
1014:   $template = <<<EOTEMPLATE
1015: <form method="POST" enctype="multipart/form-data" id="form_$form_id" action="$form_url">
1016:   <td class="left">&nbsp;<input type="hidden" name="id" value="$id"></td>
1017:   <td class="left"><input type="text" name="dav_name" value="$row_data->dav_name" size="25"></td>
1018:   <td class="left"><input type="text" name="dav_displayname" size="20"></td>
1019:   <td class="left"><input type="text" name="source" size="40" title="$source_title"></td>
1020:   <td class="left"><input type="text" name="access_ticket_id" size="10" title="$access_title"></td>
1021:   <td class="left">&nbsp;</td>
1022:   <td class="center">##submit##</td>
1023: </form>
1024: EOTEMPLATE;
1025: 
1026:   $bindingrow->SetTemplate( $template );
1027:   $bindingrow->Title("");
1028: 
1029:   return $bindingrow->Render();
1030: }
1031: 
1032: 
1033: function bindings_to_other_browser() {
1034:   global $c, $editor, $can_write_principal;
1035:   $browser = new Browser(translate('Bindings to other collections'));
1036:   $browser->AddColumn( 'bind_id', translate('ID'), '', '' );
1037:   $browser->AddHidden( 'b.dav_owner_id' );
1038:   $browser->AddHidden( 'p.principal_id' );
1039:   $browser->AddColumn( 'bound_as', translate('Bound As'), '', '<td style="white-space:nowrap;">%s</td>', 'b.dav_name' );
1040:   $browser->AddColumn( 'dav_displayname', translate('Display Name'), '', '', 'b.dav_displayname' );
1041:   $browser->AddColumn( 'dav_name', translate('To Collection'), '', '<td style="white-space:nowrap;">%s</td>', 'c.dav_name' );
1042:   $browser->AddColumn( 'access_ticket_id', translate('Ticket ID'), '', '' );
1043:   $browser->AddColumn( 'privs', translate('Privileges'), '', '', "privileges_list(privileges)" );
1044:   if ($can_write_principal) {
1045:     $delurl = $c->base_url . sprintf('/admin.php?action=edit&t=principal&id=%s&bind_id=##bind_id##&subaction=delete_bind_in', $editor->Value('principal_id'));
1046:     $browser->AddColumn( 'delete', translate('Action'), 'center', '', "'<a class=\"submit\" href=\"$delurl\">".translate('Delete')."</a>'" );
1047:   }
1048: 
1049:   $browser->SetOrdering( 'bound_as', 'A' );
1050: 
1051:   $browser->SetJoins( 'dav_binding b LEFT JOIN collection c ON (bound_source_id=collection_id) LEFT JOIN access_ticket t ON (ticket_id=access_ticket_id) LEFT JOIN principal p USING(user_no)' );
1052:   $browser->SetWhere( 'b.dav_name ~ '.sprintf("'^/%s/'", $editor->Value('username')) );
1053: 
1054:   $browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
1055: 
1056:   $browser->DoQuery();
1057: 
1058:   if ( $can_write_principal ) {
1059:     $extra_row = (object) array( 'bind_id' => -1,
1060:                                  'dav_name' => '/'.$editor->Value('username').'/boundcalendar/'
1061:                                );
1062:     $browser->MatchedRow('bind_id', -1, 'edit_binding_row');
1063:     $browser->AddRow($extra_row);
1064:   }
1065:   return $browser;
1066: }
1067: 
1068: function confirm_delete_bind_in($confirmation_hash) {
1069:   $html = '<table><tr><td class="error">';
1070:   $html .= sprintf('<b>%s</b> "%s" <a class="error" href="%s&%s">%s</a> %s',
1071:               translate('Deleting Binding:'), $_GET['bind_id'], $_SERVER['REQUEST_URI'],
1072:               $confirmation_hash,
1073:               translate('Confirm Deletion of the Binding'),
1074:               translate('The binding will be deleted.') );
1075:   $html .= "</td></tr></table>\n";
1076:   return $html;
1077: }
1078: 
1079: 
1080: function bindings_to_us_browser() {
1081:   global $c, $editor, $session;
1082:   $browser = new Browser(translate('Bindings to this Principal\'s Collections'));
1083:   $browser->AddColumn( 'bind_id', translate('ID'), '', '' );
1084:   $browser->AddHidden( 'b.dav_owner_id' );
1085:   $browser->AddHidden( 'p.principal_id' );
1086:   $browser->AddColumn( 'dav_name', translate('Collection'), '', '<td style="white-space:nowrap;">%s</td>', 'c.dav_name' );
1087:   $browser->AddColumn( 'bound_as', translate('Bound As'), '', '<td style="white-space:nowrap;">%s</td>', 'b.dav_name' );
1088:   $browser->AddColumn( 'access_ticket_id', translate('Ticket ID'), '', '' );
1089:   $browser->AddColumn( 'privs', translate('Privileges'), '', '', "privileges_list(privileges)" );
1090:   if ( $session->AllowedTo('Admin') ) {
1091:     $delurl = $c->base_url . '/admin.php?action=edit&t=principal&id=##principal_id##&bind_id=##bind_id##&subaction=delete_binding';
1092:     $browser->AddColumn( 'delete', translate('Action'), 'center', '', "'<a class=\"submit\" href=\"$delurl\">".translate('Delete')."</a>'" );
1093:   }
1094: 
1095:   $browser->SetOrdering( 'dav_name', 'A' );
1096: 
1097:   $browser->SetJoins( 'dav_binding b LEFT JOIN collection c ON (bound_source_id=collection_id) LEFT JOIN access_ticket t ON (ticket_id=access_ticket_id) LEFT JOIN principal p USING(user_no)' );
1098:   $browser->SetWhere( 'p.principal_id = '.intval($editor->Value('principal_id')) );
1099: 
1100:   $browser->RowFormat( '<tr class="r%d">', '</tr>', '#even' );
1101: 
1102:   $browser->DoQuery();
1103:   return $browser;
1104: }
1105: 
1106: function confirm_delete_binding( $confirmation_hash ) {
1107:   $html = '<table><tr><td class="error">';
1108:   $html .= sprintf('<b>%s</b> "%s" <a class="error" href="%s&%s">%s</a> %s',
1109:               translate('Deleting Binding:'), $_GET['bind_id'], $_SERVER['REQUEST_URI'],
1110:               $confirmation_hash,
1111:               translate('Confirm Deletion of the Binding'),
1112:               translate('The binding will be deleted.') );
1113:   $html .= "</td></tr></table>\n";
1114:   return $html;
1115: }
1116: 
1117: 
1118: if ( isset($_GET['subaction']) ) {
1119:   if ( handle_subaction($_GET['subaction']) && 'delete_principal' == $_GET['subaction'] ) {
1120:     return true;
1121:   }
1122: }
1123: 
1124: $editor = principal_editor();
1125: $page_elements[] = $editor;
1126: 
1127: if ( isset($id) && $id > 0 ) {
1128:   $c->stylesheets[] = 'css/browse.css';
1129:   $c->scripts[] = 'js/browse.js';
1130: 
1131:   if ( isset($delete_principal_confirmation_required) )
1132:     $page_elements[] = confirm_delete_principal($delete_principal_confirmation_required, $editor->Value('displayname'));
1133: 
1134: 
1135:   $page_elements[] = group_memberships_browser();
1136:   if ( $editor->Value('type_id') == 3 ) {
1137:     $grouprow = group_row_editor();
1138:     $page_elements[] = group_members_browser();
1139:   }
1140:   $grantrow = grant_row_editor();
1141:   $page_elements[] = principal_grants_browser();
1142:   if ( isset($delete_grant_confirmation_required) ) $page_elements[] = confirm_delete_grant($delete_grant_confirmation_required);
1143: 
1144:   $ticketrow = ticket_row_editor();
1145:   $page_elements[] = access_ticket_browser();
1146:   if ( isset($delete_ticket_confirmation_required) ) $page_elements[] = confirm_delete_ticket($delete_ticket_confirmation_required);
1147: 
1148:   $page_elements[] = principal_collection_browser();
1149:   if ( isset($delete_collection_confirmation_required) ) $page_elements[] = confirm_delete_collection($delete_collection_confirmation_required);
1150: 
1151:   $bindingrow = binding_row_editor();
1152:   $page_elements[] = bindings_to_other_browser();
1153:   if ( isset($delete_bind_in_confirmation_required) ) $page_elements[] = confirm_delete_bind_in($delete_bind_in_confirmation_required);
1154: 
1155:   $page_elements[] = bindings_to_us_browser();
1156:   if ( isset($delete_binding_confirmation_required) ) $page_elements[] = confirm_delete_binding($delete_binding_confirmation_required);
1157: }
1158: 
DAViCal API documentation generated by ApiGen 2.8.0