= Resources =

In imip-agent, resources are a special kind of user that act upon requests
to schedule events and that perform such scheduling autonomously, meaning
that no human intervention is necessary when such resources receive messages
containing invitations.

By default, the [[../AgentPrograms|agent program]] responsible for resources
merely attempts to fit a received event into the resource's schedule. However,
in some organisations and environments, it is likely to be the case that other
policies are needed to ensure that a resource is not misused, overused or made
unnecessarily unavailable.

The [[../Preferences|preferences]] provide a way of controlling the behaviour
of resources, just as with any other kind of user, but certain preferences
are central to the configuration of resources.

<<TableOfContents(2,4)>>

== Scheduling Functions ==

The [[../Preferences#scheduling_function|scheduling_function]] setting
indicates the behaviour of a resource when a valid request to schedule an
event has been received. By default, a value equivalent to the following is
employed:

{{{{#!table
'''Scheduling Functions''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
schedule_in_freebusy
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan];

  subgraph {
    rank=same;
    schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold];
    freebusy [label="Free/busy",shape=folder];
  }

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  mail -> schedule_in_freebusy -> schedule -> accept;
  schedule_in_freebusy -> decline [style=dashed];
  freebusy -> schedule_in_freebusy;
}
}}}

}}}}

As described above, this merely attempts to schedule an event in the free
periods of the resource's schedule. However, no attempt is made to reject the
booking of the resource according to the identity of the organiser.

=== Identity Controls ===

Although identity controls may be implemented in the e-mail system,
effectively preventing the messages from addresses other than those within
an organisation (for example) from being delivered to the resource, it is
possible to use scheduling functions to implement such controls instead.

==== Same Domain Membership ====

For instance, the following combines the default free/busy check with a
test that the organiser belongs to the same Internet mail domain (by using
the organiser's address):

{{{{#!table
'''Scheduling Functions''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
schedule_in_freebusy
same_domain_only
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan];

  subgraph {
    rank=same;
    schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold];
    freebusy [label="Free/busy",shape=folder];
  }

  same_domain_only [label="Organiser has resource domain?",shape=ellipse,style=filled,fillcolor=gold];

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  mail -> schedule_in_freebusy -> same_domain_only -> schedule -> accept;
  schedule_in_freebusy -> decline [style=dashed];
  same_domain_only -> decline [style=dashed];
  freebusy -> schedule_in_freebusy;
}
}}}

}}}}

Note that if the first function is omitted, no check against the resource's
schedule will occur, so it is necessary to mention any such function in the
list.

==== Access Control Lists ====

A simple domain-related test may not be sufficient to control access to a
resource. Thus, another function is provided to exercise a finer degree of
control over event participants. For example:

{{{{#!table
'''Scheduling Functions and Data''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
schedule_in_freebusy
access_control_list
}}}

Access control list:

{{{
accept
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan];

  subgraph {
    rank=same;
    schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold];
    freebusy [label="Free/busy",shape=folder];
  }

  subgraph {
    rank=same;
    access_control_list [label="Access control list permits booking?",shape=ellipse,style=filled,fillcolor=gold];
    acl [label="acl setting",shape=folder];
  }

  accept_default [label="Accept invitation by default",shape=ellipse,style=filled,fillcolor=darkorange];
  end_acl [label="end",shape=ellipse,style=filled,fillcolor=darkorange];

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  mail -> schedule_in_freebusy -> access_control_list -> accept_default -> end_acl -> schedule -> accept;
  end_acl -> decline [style=dashed];
  schedule_in_freebusy -> decline [style=dashed];
  freebusy -> schedule_in_freebusy;
  acl -> access_control_list;
}
}}}

}}}}

To accompany the scheduling functions, the [[../Preferences#acl|acl]] setting
in the resource's preferences must be set, or if a separate file is more
appropriate, its full path may be given as an argument to `access_control_list`:

{{{
schedule_in_freebusy
access_control_list /etc/imip-agent/resources.acl
}}}

Within the file provided by the setting or separate file, a list of rules
must describe the handling procedure for an event. For example, the following
was given in the above example:

{{{
accept
}}}

This will merely accept all invitations, anyway. However, it may be
appropriate to prevent certain users from using resources. For example:

{{{{#!table
'''Scheduling Functions and Data''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
schedule_in_freebusy
access_control_list
}}}

Access control list:

{{{
accept
decline attendee simon.skunk@example.com
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan];

  subgraph {
    rank=same;
    schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold];
    freebusy [label="Free/busy",shape=folder];
  }

  subgraph {
    rank=same;
    access_control_list [label="Access control list permits booking?",shape=ellipse,style=filled,fillcolor=gold];
    acl [label="acl setting",shape=folder];
  }

  accept_default [label="Accept invitation by default",shape=ellipse,style=filled,fillcolor=darkorange];
  decline_attendee [label="Is attendee simon.skunk@example.com?",shape=ellipse,style=filled,fillcolor=darkorange];
  end_acl [label="end",shape=ellipse,style=filled,fillcolor=darkorange];

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  mail -> schedule_in_freebusy -> access_control_list -> accept_default -> decline_attendee -> end_acl -> schedule -> accept;
  end_acl -> decline [style=dashed];
  schedule_in_freebusy -> decline [style=dashed];
  freebusy -> schedule_in_freebusy;
  acl -> access_control_list;
}
}}}

}}}}

This example indicates that by default, invitations will be accepted, but if
one of the attendees of an event is `simon.skunk@example.com`, the invitation
will be declined. However, it may be the case that this rule should be
overridden under certain circumstances. For example:

{{{{#!table
'''Scheduling Functions and Data''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
schedule_in_freebusy
access_control_list
}}}

Access control list:

{{{
accept
decline attendee simon.skunk@example.com
accept organiser paul.boddie@example.com
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  mail [label="Incoming mail",shape=folder,style=filled,fillcolor=cyan];

  subgraph {
    rank=same;
    schedule_in_freebusy [label="Can schedule in free/busy?",shape=ellipse,style=filled,fillcolor=gold];
    freebusy [label="Free/busy",shape=folder];
  }

  subgraph {
    rank=same;
    access_control_list [label="Access control list permits booking?",shape=ellipse,style=filled,fillcolor=gold];
    acl [label="acl setting",shape=folder];
  }

  accept_default [label="Accept invitation by default",shape=ellipse,style=filled,fillcolor=darkorange];
  decline_attendee [label="Is attendee simon.skunk@example.com?",shape=ellipse,style=filled,fillcolor=darkorange];
  accept_organiser [label="Is organiser paul.boddie@example.com?",shape=ellipse,style=filled,fillcolor=darkorange];
  end_acl [label="end",shape=ellipse,style=filled,fillcolor=darkorange];

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  mail -> schedule_in_freebusy -> access_control_list -> accept_default -> decline_attendee -> accept_organiser -> end_acl -> schedule -> accept;
  end_acl -> decline [style=dashed];
  schedule_in_freebusy -> decline [style=dashed];
  freebusy -> schedule_in_freebusy;
  acl -> access_control_list;
}
}}}

}}}}

Here, the stated organiser may still arrange a booking of the resource where
the previously-mentioned attendee is involved.

=== Quota Controls ===

In contrast to each user's stored information which consolidates information
related to that user's own schedule, the quota system consolidates information
related to the schedules of one or more resources, thus enabling observations
to be made about their collective usage.

First, consider a resource such as a car where an organiser of an event may be
booking the car for travel purposes. A quota prevents the organiser from
booking the resource too much and denying other users access to it.

Now consider a number of separate car resources. An organiser might attempt to
get around any individual resource quota by booking a number of different cars.
By grouping the resources together, the organiser will exhaust a quota set on
the group of resources as reservations are made for the different members of
the group.

==== Initialising Quotas ====

Within the journal storage area (described in the
[[../FilesystemUsage|filesystem guide]] and [[../DatabaseStore|database guide]]),
a quota group directory must be initialised with a `limits` file indicating
the amount of time that can be occupied by the cumulative total of all events
scheduled by an individual user or a group of which they are a member. For
example:

{{{
mailto:vincent.vole@example.com PT10H
}}}

This indicates that the given user may only reserve 10 hours of events or less.
Attempts to schedule more time will be declined.

To impose a general quota, the special `*` identity can be used:

{{{
* PT10H
}}}

When a user identity is not listed and no general quota is defined, that
particular user will be unable to reserve the resource unless defined as a
member of a group listed in the `limits` file, as described below.

{{{{#!wiki tip
In a deployment using the [[../FileStore|file store]], files as described
above and below hold mappings and definitions in the given format. In a
deployment using the [[../DatabaseStore|database store]], database tables
hold such mappings with each column dedicated to a particular kind of
information.

The examples here can be transcribed by just taking each
element and putting it in the appropriate column within a table, making
sure to set the `quota` column to indicate which quota is involved. For
example, to set the above limits in PostgreSQL, the following operations
may be used:

{{{
insert into quota_limits (quota, user_group, quota_limit) values (
  'mailto:resource-car-cadillac@example.com',
  'mailto:vincent.vole@example.com',
  'PT10H');
insert into quota_limits (quota, user_group, quota_limit) values (
  'mailto:resource-car-cadillac@example.com',
  '*',
  'PT10H');
}}}

Here, the `quota` column is set to `mailto:resource-car-cadillac@example.com`.
In a file-based journal, the equivalent `limits` file would be placed within a
quota directory having the name `mailto:resource-car-cadillac@example.com`.
}}}}

==== Sharing Quotas Across Users ====

When the use of resources is to be shared between users in such a way that
groups of users will be sharing a single quota, the `groups` file in the
quota directory must be defined, mapping each user identity to the group to
which they will belong. For example:

{{{
mailto:vincent.vole@example.com developers
mailto:harvey.horse@example.com developers
mailto:paul.boddie@example.com developers
mailto:simon.skunk@example.com testers
}}}

The group identity can then be employed in the `limits` file:

{{{
developers PT10H
testers PT20H
}}}

Limits apply to individuals, then to groups, then the general quota applies.
Thus, when a group is not listed, the general quota applies; without a general
quota (and without matching individually), a group member will be unable to
reserve the resource.

==== Individual Resource Quotas ====

The trivial case of applying quotas is to give a resource its own quota. This
is achieved by not specifying any arguments to the `check_quota` scheduling
function or to the `add_to_quota` and `remove_from_quota` functions.

{{{{#!table
'''Scheduling Functions''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
check_quota
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  subgraph {
    rank=same;
    mail [label="Incoming mail\nfrom vincent.vole@example.com",shape=folder,style=filled,fillcolor=cyan];
    cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan];
  }

  subgraph {
    rank=same;
    check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold];
    quota [label="Quota for resource",shape=folder];
    quota_for_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; 
  }

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange];
  remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange];

  mail -> check_quota -> schedule -> accept;
  check_quota -> decline [style=dashed];
  schedule -> add_to_quota -> quota;
  quota -> quota_for_vole -> check_quota;

  cancel -> remove_from_quota -> quota;
}
}}}

}}}}

==== Common Resource Quotas ====

By indicating an argument to the different functions, a common quota can be
employed. In the following example, both resources would employ the given
function invocations to pool their knowledge about their schedules.

{{{{#!table
'''Scheduling Functions''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
check_quota cars
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  subgraph {
    rank=same;
    mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan];
    mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan];
    cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan];
  }

  subgraph {
    rank=same;
    check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold];
    quota_cars [label="Quota for cars",shape=folder];
    quota_cars_vole [label="...applying to\nvincent.vole@example.com",shape=folder];
  }

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange];
  remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange];

  mail_cadillac -> check_quota;
  mail_pontiac -> check_quota -> schedule -> accept;
  check_quota -> decline [style=dashed];
  schedule -> add_to_quota -> quota_cars;
  quota_cars -> quota_cars_vole -> check_quota;

  cancel -> remove_from_quota -> quota_cars;
}
}}}

}}}}

==== Collective Scheduling ====

Consider two separate resources: both may be reserved at the same time by the
same organiser; neither resource would normally decline the reservation on the
basis of schedule availability, should the period concerned be free. However,
it may be undesirable for one organiser to occupy both resources at the same
time.

Consequently, a mechanism is required to pool the resource schedules in such a
way that any reservation performed for one resource at a given point in time
prohibits another reservation performed for a related resource at the same
point in time by the same user.

The free/busy records held for a given quota group permit such collective
scheduling decisions and are employed as follows:

{{{{#!table
'''Scheduling Functions''' || '''Decision Process'''
==
<style="vertical-align: top;">

{{{
schedule_within_quota cars
}}}

||

{{{#!graphviz
//format=svg
//transform=notugly
digraph scheduling_decisions {
  node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"];
  edge [tooltip="Scheduling decisions"];

  subgraph {
    rank=same;
    mail_cadillac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-cadillac@example.com",shape=folder,style=filled,fillcolor=cyan];
    mail_pontiac [label="Incoming mail\nfrom vincent.vole@example.com\nto resource-car-pontiac@example.com",shape=folder,style=filled,fillcolor=cyan];
    cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan];
  }

  subgraph {
    rank=same;
    schedule_across_quota [label="Can be scheduled within the quota?",shape=ellipse,style=filled,fillcolor=gold];
    quota_cars [label="Quota for cars",shape=folder];
    freebusy_cars_vole [label="...recording schedule for\nvincent.vole@example.com",shape=folder];
  }

  schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold];

  subgraph {
    rank=same;
    accept [label="Accept",shape=folder,style=filled,fillcolor=cyan];
    decline [label="Decline",shape=folder,style=filled,fillcolor=cyan];
  }

  add_to_quota_freebusy [label="Add to quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange];
  remove_from_quota_freebusy [label="Remove from quota free/busy",shape=ellipse,style=filled,fillcolor=darkorange];

  mail_cadillac -> schedule_across_quota;
  mail_pontiac -> schedule_across_quota -> schedule -> accept;
  schedule_across_quota -> decline [style=dashed];
  schedule -> add_to_quota_freebusy -> quota_cars -> freebusy_cars_vole;
  freebusy_cars_vole -> schedule_across_quota;

  cancel -> remove_from_quota_freebusy -> freebusy_cars_vole;
}
}}}

}}}}
