[Rt-commit] rt branch, 4.0-trunk, updated. rt-4.0.0rc6-70-g01b8939

Alex Vandiver alexmv at bestpractical.com
Thu Mar 3 05:32:58 EST 2011


The branch, 4.0-trunk has been updated
       via  01b89391ecb9ae2c65ffca99cfa25f9299ca59fc (commit)
       via  316384de89bbd7aace14580c42162b8462ff35c7 (commit)
       via  ae8e19a2f39c820f76442df6e3185c52124ccdee (commit)
       via  d880947fe6689c39b0712e3688b3213134029a66 (commit)
       via  498644e2e05fa70c1efdca4ff92d193ecc968bc4 (commit)
       via  cdafa34ddf702836964fc9bb577f20237f33108e (commit)
       via  fbefa7c59043154642fc1a81c01e7199f0b47bb8 (commit)
       via  8bb388497b7101c3f1708b718b28f0fcb4be59ee (commit)
       via  5baa7a23f87d20e5100c820c8ddbe43c3e0401bd (commit)
       via  4d88f274ce83315c463d9b3e1c5b2b45cc5a935f (commit)
       via  d519cfe134243b01bf38b828c48eb0d8cbc79c8c (commit)
       via  28720cfa508b3949d9cd7642febbd39554d9aa11 (commit)
       via  ffbfd6791bc53527603186424877a64175d52757 (commit)
       via  5a62cc5ae9b6d43322b65fdbdad3f34c882b3e15 (commit)
       via  6a57e9d6ce74e1d9ae991ca4399b2c73a6845d8b (commit)
       via  d7c0b8ff4ac83584d89c5ad54b11eccac379f1ea (commit)
       via  8bd0b01e913c6607110380fa5fac5d1eb9a33c74 (commit)
       via  57f2f3520e159d11a08cd875d83bb808daa1b307 (commit)
       via  f36d8f5b9fb5db6e5ff25d4bb848ab9fe3b36b73 (commit)
       via  ed213e899d28e48287073d9b7569764c0db5024d (commit)
       via  53498597e3f1c56dff2728a757df5c158a071439 (commit)
       via  028accbf5c9bae8f29566a05e539db8964d7c0e6 (commit)
       via  71257f360205cb25af4908d2abaa86d554e453df (commit)
       via  fc8e58f3fb4c67f8ddc02c165a310abc53defa0e (commit)
       via  3729163a2f38b6a62eda6a306477453c6e02f47b (commit)
       via  60b11288015f6ecd4b5c7769fad004b6d14994f6 (commit)
       via  7d013df119368b237b04471171f7c6f261cc61b8 (commit)
       via  517661c52769bfb5c2795af872bbed04d75a8a87 (commit)
       via  b6726198fd58b8fded2095487634faf6f63e6a2e (commit)
       via  82f35ca45b3586f840fda1f9e5b5f810e089f4ad (commit)
       via  186f258732149e9c6132491a750f4cbc8b96402f (commit)
       via  0f30911b2485398ab579dabac0d75e4ac01c1e0e (commit)
       via  89409590b6e9ba0efb4d353af9fabdc36f45f62c (commit)
       via  c29cd8bdb0e0b0390b3784a6e0c0621cb86183cf (commit)
       via  3384147ca2c58833db4d7c6b2c1f2a226329d842 (commit)
       via  ca5d8258ae2dd9ddc274af4b966c5c0650020dd5 (commit)
       via  25e298a83136ab488e3f88d31fdff16e3b833cfa (commit)
       via  201632a8977c019f7d5425784d3fcd7d7149854e (commit)
       via  0a39766a21dfc299fbdf1319724a500d67a7ccf3 (commit)
       via  df0937185d2de222403c2a41077ef7aaf2332993 (commit)
       via  e6520d2da78614cb8079a370cdac87f66d57c5bb (commit)
       via  2318579ccc3bcbe7b0a318688aa98a705a26604c (commit)
       via  377c5b140dacb746deea2f933e28f65281601f7b (commit)
       via  692e7c103a52db9f47fab5e7f81abb20504b2e88 (commit)
       via  c3f38ccce846717fac335dd30de525809b380a87 (commit)
       via  b9dda9ccf7f9d645d1bc43a0ff5cf9566060f43a (commit)
       via  08058010f2f2ab16b73e7e5b59b2f47c744c7ce2 (commit)
       via  e01f7de9875f3c96f3fe304d897826b4ab7935d4 (commit)
       via  390a444165c03cbfb7974fcbb8315b3654ca9029 (commit)
       via  404c473d367ebb6219cd4cc2da914b8c42d01a2f (commit)
       via  2ba267bd4f9dbca142e5fd4f20eb4e0a706ed3f9 (commit)
       via  a620b8bb60eee12c0fe6c988417b7090eaabfbd8 (commit)
       via  63abc24227975ec7f31ff103355bb874d7e805b0 (commit)
       via  b4073b3172b0a3165ef5ca07f6aa0a2918a2edfd (commit)
       via  2dfb3db7675d774721d73ff04f9a131f3af043ac (commit)
       via  9f9e70a2d3a75d4cb58faa66f6991a76a641f3e7 (commit)
       via  6e223eaa3fe997597c6ff5ade920c8c15abb2a46 (commit)
       via  071d5d94c0ad476551c7704709ad4a6a03bb8e0f (commit)
       via  1d061b476ace6b86bd19fc764dba046e6b8385f6 (commit)
       via  5d0d9ceababa754bd3a2278efa35b71568a41938 (commit)
       via  eed01cfa281e4f1afc413949ec74da916cf7b7e6 (commit)
       via  0e9297df62ac13927ff0f6ed5f61e8c61ccadfe2 (commit)
       via  bef216fc7dad54487d43d83954c8a30cd6fb126a (commit)
       via  d158630a2e048ee053a2a25f1fd6515562174c55 (commit)
       via  4069372f8de3563e0a11bd47be722678bd1c01cf (commit)
       via  ceea9409679cdf5ca4f85213183a92ec95a9e69c (commit)
       via  bb0d89da2cd689fcbb760ee4dac270e2683fb1f5 (commit)
       via  9c0e75c6ef281098c1708222796ba0e46d31b977 (commit)
       via  b09d48a1d32f69f1fe57c70fc961ec6e4917d863 (commit)
       via  00ed25ea22e3add1ebb29c81c09c6dbf502a1d58 (commit)
       via  f7a66ac50f47b8ac19100e27ecf62aa9943a915b (commit)
       via  e0819e6bc7ad78f388303c4c62951f46882c5289 (commit)
       via  e2343efbc61ae269331a3c52951bd21c6ae0c560 (commit)
       via  f108641c17d2aa887842aecd42e23a65f19534fb (commit)
       via  f2332fafe055be11c7f07a58b60607a6a9e85435 (commit)
       via  5d5c2218b8ce4d6053009113fa29fe3af60f1475 (commit)
       via  30a71f4dc7b0784e8a1ace43d2f28f0e2056c0a1 (commit)
       via  bbe970f1ef6299eadc5827c182f83aa744809ec9 (commit)
       via  33739de717f4bfd11d0e2067d7f75c6641d95498 (commit)
       via  f1c7518b33af21d49220ba042e4a7a171dacdd01 (commit)
       via  f6f4a9e7b5a411b78f22f92a2a836e0a3d2e6083 (commit)
       via  e69d1ae186e209ba67f770be0aef9025638433be (commit)
       via  3415cf7d7d4c81786fcd89d27418250fa799e609 (commit)
       via  b89a604cd36c34995eb8bde1db587bdc86fb1642 (commit)
       via  7e1535c3b8cd0ddf2419a38275d4e47337bb38e6 (commit)
      from  0ee6ad45c8fc42217d30b515e87bab8c56842416 (commit)

Summary of changes:
 Makefile.in                                        |    4 +-
 README                                             |    4 +-
 bin/rt-crontool.in                                 |    4 +-
 bin/rt-mailgate.in                                 |    6 +-
 bin/rt.in                                          |    4 +-
 devel/license_tag                                  |    5 +-
 docs/web_deployment.pod                            |   69 +++-----------------
 etc/RT_Config.pm.in                                |    2 +-
 etc/upgrade/3.8-branded-queues-extension.in        |   30 ++++----
 etc/upgrade/3.8-ical-extension.in                  |   30 ++++----
 etc/upgrade/3.8.2/content                          |    6 +-
 etc/upgrade/generate-rtaddressregexp.in            |   30 ++++----
 etc/upgrade/shrink_cgm_table.pl                    |   48 +++++++++++++-
 etc/upgrade/shrink_transactions_table.pl           |   48 +++++++++++++-
 etc/upgrade/split-out-cf-categories.in             |   30 ++++----
 etc/upgrade/upgrade-articles.in                    |    2 +-
 etc/upgrade/upgrade-mysql-schema.pl                |   48 +++++++++++++-
 etc/upgrade/vulnerable-passwords.in                |   48 +++++++++++++-
 lib/RT.pm                                          |    9 ++-
 lib/RT/ACE.pm                                      |   52 +++++++--------
 lib/RT/ACL.pm                                      |    4 +-
 lib/RT/Action.pm                                   |    4 +-
 lib/RT/Action/AutoOpen.pm                          |    4 +-
 lib/RT/Action/Autoreply.pm                         |    4 +-
 lib/RT/Action/CreateTickets.pm                     |    4 +-
 lib/RT/Action/EscalatePriority.pm                  |    4 +-
 lib/RT/Action/ExtractSubjectTag.pm                 |    4 +-
 lib/RT/Action/LinearEscalate.pm                    |    4 +-
 lib/RT/Action/Notify.pm                            |    4 +-
 lib/RT/Action/NotifyAsComment.pm                   |    4 +-
 lib/RT/Action/NotifyGroup.pm                       |    4 +-
 lib/RT/Action/NotifyGroupAsComment.pm              |    4 +-
 lib/RT/Action/RecordComment.pm                     |    4 +-
 lib/RT/Action/RecordCorrespondence.pm              |    4 +-
 lib/RT/Action/ResolveMembers.pm                    |    4 +-
 lib/RT/Action/SendEmail.pm                         |    4 +-
 lib/RT/Action/SetPriority.pm                       |    4 +-
 lib/RT/Action/SetStatus.pm                         |    4 +-
 lib/RT/Action/UserDefined.pm                       |    4 +-
 lib/RT/Approval.pm                                 |    4 +-
 lib/RT/Approval/Rule.pm                            |    4 +-
 lib/RT/Approval/Rule/Created.pm                    |    4 +-
 lib/RT/Approval/Rule/NewPending.pm                 |    4 +-
 lib/RT/Approval/Rule/Passed.pm                     |    4 +-
 lib/RT/Approval/Rule/Rejected.pm                   |    4 +-
 lib/RT/Article.pm                                  |    4 +-
 lib/RT/Articles.pm                                 |    5 +-
 lib/RT/Attachment.pm                               |    4 +-
 lib/RT/Attachments.pm                              |    4 +-
 lib/RT/Attribute.pm                                |    4 +-
 lib/RT/Attributes.pm                               |    4 +-
 lib/RT/Base.pm                                     |    4 +-
 lib/RT/CachedGroupMember.pm                        |    4 +-
 lib/RT/CachedGroupMembers.pm                       |    4 +-
 lib/RT/Class.pm                                    |    5 +-
 lib/RT/Classes.pm                                  |    5 +-
 lib/RT/Condition.pm                                |    4 +-
 lib/RT/Condition/AnyTransaction.pm                 |    4 +-
 lib/RT/Condition/BeforeDue.pm                      |    4 +-
 lib/RT/Condition/CloseTicket.pm                    |    4 +-
 lib/RT/Condition/Overdue.pm                        |    4 +-
 lib/RT/Condition/OwnerChange.pm                    |    4 +-
 lib/RT/Condition/PriorityChange.pm                 |    4 +-
 lib/RT/Condition/PriorityExceeds.pm                |    4 +-
 lib/RT/Condition/QueueChange.pm                    |    4 +-
 lib/RT/Condition/ReopenTicket.pm                   |    4 +-
 lib/RT/Condition/StatusChange.pm                   |    4 +-
 lib/RT/Condition/UserDefined.pm                    |    4 +-
 lib/RT/Config.pm                                   |   11 ++--
 lib/RT/Crypt/GnuPG.pm                              |    4 +-
 lib/RT/CurrentUser.pm                              |    4 +-
 lib/RT/CustomField.pm                              |    4 +-
 lib/RT/CustomFieldValue.pm                         |    5 +-
 lib/RT/CustomFieldValues.pm                        |    4 +-
 lib/RT/CustomFieldValues/External.pm               |    4 +-
 lib/RT/CustomFieldValues/Groups.pm                 |    4 +-
 lib/RT/CustomFields.pm                             |    4 +-
 lib/RT/Dashboard.pm                                |    4 +-
 lib/RT/Dashboard/Mailer.pm                         |    5 +-
 lib/RT/Dashboards.pm                               |    4 +-
 lib/RT/Date.pm                                     |    4 +-
 lib/RT/EmailParser.pm                              |    4 +-
 lib/RT/Generated.pm.in                             |   48 ++++++++++++++
 lib/RT/Graph/Tickets.pm                            |    4 +-
 lib/RT/Group.pm                                    |   48 +++++++++++++-
 lib/RT/GroupMember.pm                              |   48 +++++++++++++-
 lib/RT/GroupMembers.pm                             |    4 +-
 lib/RT/Groups.pm                                   |    4 +-
 lib/RT/Handle.pm                                   |    4 +-
 lib/RT/I18N.pm                                     |    8 +-
 lib/RT/I18N/cs.pm                                  |    4 +-
 lib/RT/I18N/i_default.pm                           |    4 +-
 lib/RT/I18N/ru.pm                                  |    4 +-
 lib/RT/Installer.pm                                |    4 +-
 lib/RT/Interface/CLI.pm                            |   12 ++--
 lib/RT/Interface/Email.pm                          |    7 +-
 lib/RT/Interface/Email/Auth/GnuPG.pm               |    4 +-
 lib/RT/Interface/Email/Auth/MailFrom.pm            |    4 +-
 lib/RT/Interface/REST.pm                           |    4 +-
 lib/RT/Interface/Web.pm                            |    4 +-
 lib/RT/Interface/Web/Handler.pm                    |    4 +-
 lib/RT/Interface/Web/Menu.pm                       |    4 +-
 lib/RT/Interface/Web/QueryBuilder.pm               |    4 +-
 lib/RT/Interface/Web/QueryBuilder/Tree.pm          |    4 +-
 lib/RT/Interface/Web/Request.pm                    |    4 +-
 lib/RT/Interface/Web/Session.pm                    |    4 +-
 lib/RT/Lifecycle.pm                                |    4 +-
 lib/RT/Link.pm                                     |    4 +-
 lib/RT/Links.pm                                    |   15 +----
 lib/RT/ObjectClass.pm                              |    4 +-
 lib/RT/ObjectClasses.pm                            |    4 +-
 lib/RT/ObjectCustomField.pm                        |    4 +-
 lib/RT/ObjectCustomFieldValue.pm                   |    4 +-
 lib/RT/ObjectCustomFieldValues.pm                  |    4 +-
 lib/RT/ObjectCustomFields.pm                       |    4 +-
 lib/RT/ObjectTopic.pm                              |    5 +-
 lib/RT/ObjectTopics.pm                             |    4 +-
 lib/RT/Plugin.pm                                   |    5 +-
 lib/RT/Principal.pm                                |    4 +-
 lib/RT/Principals.pm                               |    4 +-
 lib/RT/Queue.pm                                    |    4 +-
 lib/RT/Queues.pm                                   |    4 +-
 lib/RT/Record.pm                                   |    6 +-
 lib/RT/Reminders.pm                                |    4 +-
 lib/RT/Report/Tickets.pm                           |    4 +-
 lib/RT/Report/Tickets/Entry.pm                     |    4 +-
 lib/RT/Rule.pm                                     |    4 +-
 lib/RT/Ruleset.pm                                  |    4 +-
 lib/RT/SQL.pm                                      |    4 +-
 lib/RT/SavedSearch.pm                              |    4 +-
 lib/RT/SavedSearches.pm                            |    4 +-
 lib/RT/Scrip.pm                                    |    4 +-
 lib/RT/ScripAction.pm                              |    4 +-
 lib/RT/ScripActions.pm                             |    4 +-
 lib/RT/ScripCondition.pm                           |    4 +-
 lib/RT/ScripConditions.pm                          |    4 +-
 lib/RT/Scrips.pm                                   |    4 +-
 lib/RT/Search.pm                                   |    4 +-
 lib/RT/Search/ActiveTicketsInQueue.pm              |    4 +-
 lib/RT/Search/FromSQL.pm                           |    4 +-
 lib/RT/Search/Googleish.pm                         |    4 +-
 lib/RT/SearchBuilder.pm                            |    4 +-
 lib/RT/SharedSetting.pm                            |    4 +-
 lib/RT/SharedSettings.pm                           |    4 +-
 lib/RT/Shredder.pm                                 |    9 ++-
 lib/RT/Shredder/ACE.pm                             |    4 +-
 lib/RT/Shredder/Attachment.pm                      |    4 +-
 lib/RT/Shredder/CachedGroupMember.pm               |    4 +-
 lib/RT/Shredder/Constants.pm                       |    4 +-
 lib/RT/Shredder/CustomField.pm                     |    4 +-
 lib/RT/Shredder/CustomFieldValue.pm                |    4 +-
 lib/RT/Shredder/Dependencies.pm                    |    4 +-
 lib/RT/Shredder/Dependency.pm                      |    4 +-
 lib/RT/Shredder/Exceptions.pm                      |    4 +-
 lib/RT/Shredder/Group.pm                           |    4 +-
 lib/RT/Shredder/GroupMember.pm                     |    4 +-
 lib/RT/Shredder/Link.pm                            |    4 +-
 lib/RT/Shredder/ObjectCustomFieldValue.pm          |    4 +-
 lib/RT/Shredder/POD.pm                             |    4 +-
 lib/RT/Shredder/Plugin.pm                          |    6 +-
 lib/RT/Shredder/Plugin/Attachments.pm              |    4 +-
 lib/RT/Shredder/Plugin/Base.pm                     |    4 +-
 lib/RT/Shredder/Plugin/Base/Dump.pm                |    4 +-
 lib/RT/Shredder/Plugin/Base/Search.pm              |    7 +-
 lib/RT/Shredder/Plugin/Objects.pm                  |    4 +-
 lib/RT/Shredder/Plugin/SQLDump.pm                  |    4 +-
 lib/RT/Shredder/Plugin/Summary.pm                  |    4 +-
 lib/RT/Shredder/Plugin/Tickets.pm                  |    4 +-
 lib/RT/Shredder/Plugin/Users.pm                    |    4 +-
 lib/RT/Shredder/Principal.pm                       |    4 +-
 lib/RT/Shredder/Queue.pm                           |    4 +-
 lib/RT/Shredder/Record.pm                          |    4 +-
 lib/RT/Shredder/Scrip.pm                           |    4 +-
 lib/RT/Shredder/ScripAction.pm                     |    4 +-
 lib/RT/Shredder/ScripCondition.pm                  |    4 +-
 lib/RT/Shredder/Template.pm                        |    4 +-
 lib/RT/Shredder/Ticket.pm                          |    4 +-
 lib/RT/Shredder/Transaction.pm                     |    4 +-
 lib/RT/Shredder/User.pm                            |    4 +-
 lib/RT/Squish.pm                                   |    4 +-
 lib/RT/Squish/CSS.pm                               |    4 +-
 lib/RT/Squish/JS.pm                                |    4 +-
 lib/RT/System.pm                                   |    4 +-
 lib/RT/Template.pm                                 |    4 +-
 lib/RT/Templates.pm                                |    4 +-
 lib/RT/Test.pm                                     |   13 +++-
 lib/RT/Test/Apache.pm                              |   48 ++++++++++++++
 lib/RT/Test/Email.pm                               |    4 +-
 lib/RT/Test/GnuPG.pm                               |   48 ++++++++++++++
 lib/RT/Test/Web.pm                                 |    4 +-
 lib/RT/Ticket.pm                                   |   10 ++--
 lib/RT/Tickets.pm                                  |    4 +-
 lib/RT/Tickets_SQL.pm                              |    4 +-
 lib/RT/Topic.pm                                    |    4 +-
 lib/RT/Topics.pm                                   |    5 +-
 lib/RT/Transaction.pm                              |    4 +-
 lib/RT/Transactions.pm                             |    4 +-
 lib/RT/URI.pm                                      |    4 +-
 lib/RT/URI/a.pm                                    |    5 +-
 lib/RT/URI/base.pm                                 |    4 +-
 lib/RT/URI/fsck_com_article.pm                     |    5 +-
 lib/RT/URI/fsck_com_rt.pm                          |    4 +-
 lib/RT/URI/t.pm                                    |    4 +-
 lib/RT/User.pm                                     |    6 +-
 lib/RT/Users.pm                                    |    4 +-
 lib/RT/Util.pm                                     |    4 +-
 sbin/rt-attributes-viewer.in                       |    4 +-
 sbin/rt-clean-sessions.in                          |    4 +-
 sbin/rt-dump-metadata.in                           |    4 +-
 sbin/rt-email-dashboards.in                        |    4 +-
 sbin/rt-email-digest.in                            |    4 +-
 sbin/rt-email-group-admin.in                       |    4 +-
 sbin/rt-fulltext-indexer.in                        |   30 ++++----
 sbin/rt-message-catalog                            |    4 +-
 sbin/rt-server.in                                  |    6 +-
 sbin/rt-session-viewer.in                          |   30 ++++----
 sbin/rt-setup-database.in                          |    4 +-
 sbin/rt-setup-fulltext-index.in                    |    4 +-
 sbin/rt-shredder.in                                |    4 +-
 sbin/rt-test-dependencies.in                       |    6 +-
 sbin/rt-validator.in                               |    7 +-
 .../html/Admin/Articles/Classes/CustomFields.html  |    7 +-
 share/html/Admin/Articles/Classes/GroupRights.html |    7 +-
 share/html/Admin/Articles/Classes/Modify.html      |    7 +-
 share/html/Admin/Articles/Classes/Objects.html     |    4 +-
 share/html/Admin/Articles/Classes/Topics.html      |    7 +-
 share/html/Admin/Articles/Classes/UserRights.html  |    7 +-
 share/html/Admin/Articles/Classes/index.html       |    7 +-
 share/html/Admin/Articles/Elements/Topics          |    7 +-
 share/html/Admin/Articles/index.html               |    7 +-
 share/html/Admin/CustomFields/GroupRights.html     |    4 +-
 share/html/Admin/CustomFields/Modify.html          |    4 +-
 share/html/Admin/CustomFields/Objects.html         |    4 +-
 share/html/Admin/CustomFields/UserRights.html      |    4 +-
 share/html/Admin/CustomFields/index.html           |    4 +-
 share/html/Admin/Elements/AddCustomFieldValue      |    4 +-
 share/html/Admin/Elements/ConfigureMyRT            |    4 +-
 share/html/Admin/Elements/CreateUserCalled         |    4 +-
 share/html/Admin/Elements/EditCustomField          |    4 +-
 share/html/Admin/Elements/EditCustomFieldValues    |    4 +-
 .../Admin/Elements/EditCustomFieldValuesSource     |    4 +-
 share/html/Admin/Elements/EditCustomFields         |    4 +-
 share/html/Admin/Elements/EditQueueWatcherGroup    |    4 +-
 share/html/Admin/Elements/EditQueueWatchers        |    4 +-
 share/html/Admin/Elements/EditRights               |    4 +-
 share/html/Admin/Elements/EditRightsCategoryTabs   |   47 +++++++++++++
 share/html/Admin/Elements/EditScrip                |    4 +-
 share/html/Admin/Elements/EditScrips               |    4 +-
 share/html/Admin/Elements/EditTemplates            |    4 +-
 share/html/Admin/Elements/EditUserComments         |    4 +-
 share/html/Admin/Elements/Header                   |    4 +-
 share/html/Admin/Elements/ListGlobalCustomFields   |    4 +-
 share/html/Admin/Elements/ListGlobalScrips         |    4 +-
 share/html/Admin/Elements/ModifyTemplate           |    4 +-
 share/html/Admin/Elements/PickCustomFields         |    4 +-
 share/html/Admin/Elements/PickObjects              |    4 +-
 share/html/Admin/Elements/Portal                   |   47 +++++++++++++
 share/html/Admin/Elements/QueueRightsForUser       |    4 +-
 share/html/Admin/Elements/SelectCustomField        |    4 +-
 .../Admin/Elements/SelectCustomFieldLookupType     |    4 +-
 .../Admin/Elements/SelectCustomFieldRenderType     |    4 +-
 share/html/Admin/Elements/SelectCustomFieldType    |    4 +-
 share/html/Admin/Elements/SelectGroups             |    4 +-
 share/html/Admin/Elements/SelectModifyGroup        |    4 +-
 share/html/Admin/Elements/SelectModifyQueue        |    4 +-
 share/html/Admin/Elements/SelectModifyUser         |    4 +-
 share/html/Admin/Elements/SelectNewGroupMembers    |    4 +-
 share/html/Admin/Elements/SelectRights             |   30 ++++----
 share/html/Admin/Elements/SelectScrip              |    4 +-
 share/html/Admin/Elements/SelectScripAction        |    4 +-
 share/html/Admin/Elements/SelectScripCondition     |    4 +-
 share/html/Admin/Elements/SelectSingleOrMultiple   |    4 +-
 share/html/Admin/Elements/SelectStage              |    4 +-
 share/html/Admin/Elements/SelectTemplate           |    4 +-
 share/html/Admin/Elements/SelectUsers              |    4 +-
 share/html/Admin/Elements/ShowKeyInfo              |    4 +-
 .../Admin/Global/CustomFields/Class-Article.html   |    7 +-
 share/html/Admin/Global/CustomFields/Groups.html   |    4 +-
 .../Admin/Global/CustomFields/Queue-Tickets.html   |    4 +-
 .../Global/CustomFields/Queue-Transactions.html    |    4 +-
 share/html/Admin/Global/CustomFields/Queues.html   |    4 +-
 share/html/Admin/Global/CustomFields/Users.html    |    4 +-
 share/html/Admin/Global/CustomFields/index.html    |    4 +-
 share/html/Admin/Global/GroupRights.html           |    4 +-
 share/html/Admin/Global/MyRT.html                  |    4 +-
 share/html/Admin/Global/Scrip.html                 |    4 +-
 share/html/Admin/Global/Scrips.html                |    4 +-
 share/html/Admin/Global/Template.html              |    4 +-
 share/html/Admin/Global/Templates.html             |    4 +-
 share/html/Admin/Global/Theme.html                 |    4 +-
 share/html/Admin/Global/Topics.html                |    7 +-
 share/html/Admin/Global/UserRights.html            |    4 +-
 share/html/Admin/Global/index.html                 |    4 +-
 share/html/Admin/Groups/GroupRights.html           |    4 +-
 share/html/Admin/Groups/History.html               |    4 +-
 share/html/Admin/Groups/Members.html               |    4 +-
 share/html/Admin/Groups/Modify.html                |    4 +-
 share/html/Admin/Groups/UserRights.html            |    4 +-
 share/html/Admin/Groups/index.html                 |    4 +-
 share/html/Admin/Queues/CustomField.html           |    4 +-
 share/html/Admin/Queues/CustomFields.html          |    4 +-
 share/html/Admin/Queues/GroupRights.html           |    4 +-
 share/html/Admin/Queues/History.html               |    4 +-
 share/html/Admin/Queues/Modify.html                |    4 +-
 share/html/Admin/Queues/People.html                |    4 +-
 share/html/Admin/Queues/Scrip.html                 |    4 +-
 share/html/Admin/Queues/Scrips.html                |    4 +-
 share/html/Admin/Queues/Template.html              |    4 +-
 share/html/Admin/Queues/Templates.html             |    4 +-
 share/html/Admin/Queues/UserRights.html            |    4 +-
 share/html/Admin/Queues/index.html                 |    4 +-
 share/html/Admin/Tools/Configuration.html          |    4 +-
 share/html/Admin/Tools/Queries.html                |    4 +-
 share/html/Admin/Tools/Shredder/Dumps/dhandler     |    4 +-
 .../Admin/Tools/Shredder/Elements/DumpFileLink     |    4 +-
 .../Admin/Tools/Shredder/Elements/Error/NoRights   |    4 +-
 .../Admin/Tools/Shredder/Elements/Error/NoStorage  |    4 +-
 .../Tools/Shredder/Elements/Object/RT--Attachment  |    4 +-
 .../Tools/Shredder/Elements/Object/RT--Ticket      |    4 +-
 .../Admin/Tools/Shredder/Elements/Object/RT--User  |    4 +-
 .../Admin/Tools/Shredder/Elements/ObjectCheckBox   |    4 +-
 .../Admin/Tools/Shredder/Elements/PluginArguments  |    4 +-
 .../html/Admin/Tools/Shredder/Elements/PluginHelp  |    4 +-
 .../Admin/Tools/Shredder/Elements/SelectObjects    |    4 +-
 .../Admin/Tools/Shredder/Elements/SelectPlugin     |    4 +-
 share/html/Admin/Tools/Shredder/autohandler        |    4 +-
 share/html/Admin/Tools/Shredder/index.html         |    4 +-
 share/html/Admin/Tools/index.html                  |    4 +-
 share/html/Admin/Users/CustomFields.html           |    4 +-
 share/html/Admin/Users/GnuPG.html                  |    4 +-
 share/html/Admin/Users/History.html                |    4 +-
 share/html/Admin/Users/Memberships.html            |    4 +-
 share/html/Admin/Users/Modify.html                 |    4 +-
 share/html/Admin/Users/MyRT.html                   |    4 +-
 share/html/Admin/Users/index.html                  |    4 +-
 share/html/Admin/autohandler                       |    4 +-
 share/html/Admin/index.html                        |    4 +-
 share/html/Approvals/Display.html                  |    4 +-
 share/html/Approvals/Elements/Approve              |    4 +-
 share/html/Approvals/Elements/PendingMyApproval    |    4 +-
 share/html/Approvals/Elements/ShowDependency       |    4 +-
 share/html/Approvals/autohandler                   |    4 +-
 share/html/Approvals/index.html                    |    4 +-
 share/html/Articles/Article/Delete.html            |    7 +-
 share/html/Articles/Article/Display.html           |    7 +-
 share/html/Articles/Article/Edit.html              |    7 +-
 share/html/Articles/Article/Elements/EditBasics    |    7 +-
 .../Articles/Article/Elements/EditCustomFields     |    7 +-
 share/html/Articles/Article/Elements/EditLinks     |    7 +-
 share/html/Articles/Article/Elements/EditTopics    |    7 +-
 .../Article/Elements/LinkEntryInstructions         |    7 +-
 share/html/Articles/Article/Elements/Preformatted  |    7 +-
 .../Articles/Article/Elements/SearchByCustomField  |    7 +-
 .../Articles/Article/Elements/SelectSavedSearches  |    7 +-
 .../Articles/Article/Elements/SelectSearchPrivacy  |    7 +-
 share/html/Articles/Article/Elements/ShowHistory   |    7 +-
 share/html/Articles/Article/Elements/ShowLinks     |    7 +-
 .../Articles/Article/Elements/ShowSavedSearches    |    7 +-
 .../Articles/Article/Elements/ShowSearchCriteria   |    7 +-
 share/html/Articles/Article/Elements/ShowTopics    |    7 +-
 share/html/Articles/Article/ExtractFromTicket.html |    7 +-
 share/html/Articles/Article/ExtractIntoClass.html  |    7 +-
 share/html/Articles/Article/ExtractIntoTopic.html  |    7 +-
 share/html/Articles/Article/History.html           |    7 +-
 share/html/Articles/Article/PreCreate.html         |    7 +-
 share/html/Articles/Article/Search.html            |    7 +-
 share/html/Articles/Elements/BeforeMessageBox      |    7 +-
 share/html/Articles/Elements/CheckSkipCreate       |    7 +-
 share/html/Articles/Elements/CreateArticle         |    7 +-
 share/html/Articles/Elements/GotoArticle           |    7 +-
 share/html/Articles/Elements/Header                |    7 +-
 share/html/Articles/Elements/IncludeArticle        |    7 +-
 share/html/Articles/Elements/NewestArticles        |    7 +-
 share/html/Articles/Elements/QuickSearch           |    7 +-
 share/html/Articles/Elements/SelectClass           |    7 +-
 share/html/Articles/Elements/ShowTopic             |    7 +-
 share/html/Articles/Elements/UpdatedArticles       |    7 +-
 share/html/Articles/Topics.html                    |    7 +-
 share/html/Articles/index.html                     |    7 +-
 share/html/Dashboards/Elements/DashboardsForObject |    4 +-
 share/html/Dashboards/Elements/Deleted             |    4 +-
 share/html/Dashboards/Elements/HiddenSearches      |    4 +-
 share/html/Dashboards/Elements/ListOfDashboards    |    4 +-
 share/html/Dashboards/Elements/SelectPrivacy       |    4 +-
 share/html/Dashboards/Elements/ShowDashboards      |    4 +-
 .../html/Dashboards/Elements/ShowPortlet/component |    4 +-
 .../html/Dashboards/Elements/ShowPortlet/dashboard |    4 +-
 share/html/Dashboards/Elements/ShowPortlet/search  |    4 +-
 share/html/Dashboards/Modify.html                  |    4 +-
 share/html/Dashboards/Queries.html                 |    4 +-
 share/html/Dashboards/Render.html                  |    4 +-
 share/html/Dashboards/Subscription.html            |    4 +-
 share/html/Dashboards/dhandler                     |    4 +-
 share/html/Dashboards/index.html                   |    4 +-
 share/html/Download/CustomFieldValue/dhandler      |    4 +-
 share/html/Elements/BevelBoxRaisedEnd              |    4 +-
 share/html/Elements/BevelBoxRaisedStart            |    4 +-
 share/html/Elements/Callback                       |    4 +-
 share/html/Elements/Checkbox                       |    4 +-
 share/html/Elements/CollectionAsTable/Header       |    4 +-
 share/html/Elements/CollectionAsTable/ParseFormat  |    4 +-
 share/html/Elements/CollectionAsTable/Row          |    4 +-
 share/html/Elements/CollectionList                 |    4 +-
 share/html/Elements/CollectionListPaging           |    4 +-
 share/html/Elements/ColumnMap                      |    4 +-
 share/html/Elements/CreateTicket                   |    4 +-
 share/html/Elements/Dashboards                     |    4 +-
 share/html/Elements/EditCustomField                |    4 +-
 share/html/Elements/EditCustomFieldAutocomplete    |    4 +-
 share/html/Elements/EditCustomFieldBinary          |    4 +-
 share/html/Elements/EditCustomFieldCombobox        |    4 +-
 share/html/Elements/EditCustomFieldDate            |    4 +-
 share/html/Elements/EditCustomFieldDateTime        |    4 +-
 share/html/Elements/EditCustomFieldFreeform        |    4 +-
 share/html/Elements/EditCustomFieldIPAddress       |   30 ++++----
 share/html/Elements/EditCustomFieldIPAddressRange  |   30 ++++----
 share/html/Elements/EditCustomFieldImage           |    4 +-
 share/html/Elements/EditCustomFieldSelect          |    4 +-
 share/html/Elements/EditCustomFieldText            |    4 +-
 share/html/Elements/EditCustomFieldWikitext        |    4 +-
 share/html/Elements/EditLinks                      |    4 +-
 share/html/Elements/EditPassword                   |    4 +-
 share/html/Elements/EditTimeValue                  |    4 +-
 share/html/Elements/EmailInput                     |    4 +-
 share/html/Elements/Error                          |    4 +-
 share/html/Elements/Footer                         |    4 +-
 share/html/Elements/GnuPG/KeyIssues                |    4 +-
 share/html/Elements/GnuPG/SelectKeyForEncryption   |    4 +-
 share/html/Elements/GnuPG/SelectKeyForSigning      |    4 +-
 share/html/Elements/GnuPG/SignEncryptWidget        |    4 +-
 share/html/Elements/GotoTicket                     |    4 +-
 share/html/Elements/Header                         |    4 +-
 share/html/Elements/HeaderJavascript               |    4 +-
 share/html/Elements/ListActions                    |    4 +-
 share/html/Elements/ListMenu                       |    4 +-
 share/html/Elements/Login                          |    4 +-
 share/html/Elements/Logo                           |    4 +-
 share/html/Elements/MakeClicky                     |    4 +-
 share/html/Elements/Menu                           |    4 +-
 share/html/Elements/MessageBox                     |    4 +-
 share/html/Elements/MyAdminQueues                  |    4 +-
 share/html/Elements/MyRT                           |    4 +-
 share/html/Elements/MyReminders                    |    4 +-
 share/html/Elements/MyRequests                     |    4 +-
 share/html/Elements/MySupportQueues                |    4 +-
 share/html/Elements/MyTickets                      |    4 +-
 share/html/Elements/PageLayout                     |    4 +-
 share/html/Elements/PersonalQuickbar               |    4 +-
 share/html/Elements/QueriesAsComment               |   47 +++++++++++++
 share/html/Elements/QueryString                    |    4 +-
 share/html/Elements/QueueSummaryByLifecycle        |    4 +-
 share/html/Elements/QueueSummaryByStatus           |    4 +-
 share/html/Elements/QuickCreate                    |    4 +-
 share/html/Elements/Quicksearch                    |    4 +-
 share/html/Elements/RT__Article/ColumnMap          |   30 ++++----
 share/html/Elements/RT__Class/ColumnMap            |    7 +-
 share/html/Elements/RT__CustomField/ColumnMap      |    4 +-
 share/html/Elements/RT__Dashboard/ColumnMap        |    4 +-
 share/html/Elements/RT__Group/ColumnMap            |    4 +-
 share/html/Elements/RT__Queue/ColumnMap            |    4 +-
 share/html/Elements/RT__SavedSearch/ColumnMap      |    4 +-
 share/html/Elements/RT__Scrip/ColumnMap            |    4 +-
 share/html/Elements/RT__Template/ColumnMap         |    4 +-
 share/html/Elements/RT__Ticket/ColumnMap           |    4 +-
 share/html/Elements/RT__User/ColumnMap             |    4 +-
 share/html/Elements/Refresh                        |    4 +-
 share/html/Elements/RefreshHomepage                |    4 +-
 share/html/Elements/SavedSearches                  |    4 +-
 share/html/Elements/ScrubHTML                      |    4 +-
 share/html/Elements/Section                        |    4 +-
 share/html/Elements/SelectAttachmentField          |    4 +-
 share/html/Elements/SelectBoolean                  |    4 +-
 share/html/Elements/SelectCustomFieldOperator      |    4 +-
 share/html/Elements/SelectCustomFieldValue         |    4 +-
 share/html/Elements/SelectDate                     |    4 +-
 share/html/Elements/SelectDateRelation             |    4 +-
 share/html/Elements/SelectDateType                 |    4 +-
 share/html/Elements/SelectEqualityOperator         |    4 +-
 share/html/Elements/SelectGroups                   |    4 +-
 share/html/Elements/SelectIPRelation               |    4 +-
 share/html/Elements/SelectLang                     |    4 +-
 share/html/Elements/SelectLinkType                 |    4 +-
 share/html/Elements/SelectMatch                    |    4 +-
 share/html/Elements/SelectNewTicketQueue           |    4 +-
 share/html/Elements/SelectOwner                    |    4 +-
 share/html/Elements/SelectOwnerAutocomplete        |    4 +-
 share/html/Elements/SelectOwnerDropdown            |    4 +-
 share/html/Elements/SelectPriority                 |    4 +-
 share/html/Elements/SelectQueue                    |    4 +-
 share/html/Elements/SelectResultsPerPage           |    4 +-
 share/html/Elements/SelectSortOrder                |    4 +-
 share/html/Elements/SelectStatus                   |    4 +-
 share/html/Elements/SelectTicketSortBy             |    4 +-
 share/html/Elements/SelectTicketTypes              |    4 +-
 share/html/Elements/SelectTimeUnits                |    4 +-
 share/html/Elements/SelectTimezone                 |    4 +-
 share/html/Elements/SelectUsers                    |    4 +-
 share/html/Elements/SelectWatcherType              |    4 +-
 share/html/Elements/SetupSessionCookie             |    4 +-
 share/html/Elements/ShowCustomFieldBinary          |    4 +-
 share/html/Elements/ShowCustomFieldDate            |    4 +-
 share/html/Elements/ShowCustomFieldDateTime        |    4 +-
 share/html/Elements/ShowCustomFieldImage           |    4 +-
 share/html/Elements/ShowCustomFieldText            |    4 +-
 share/html/Elements/ShowCustomFieldWikitext        |    4 +-
 share/html/Elements/ShowCustomFields               |    4 +-
 share/html/Elements/ShowLink                       |    4 +-
 share/html/Elements/ShowLinks                      |    4 +-
 share/html/Elements/ShowMemberships                |    4 +-
 share/html/Elements/ShowRelationLabel              |    4 +-
 share/html/Elements/ShowReminders                  |    8 +-
 share/html/Elements/ShowSearch                     |    4 +-
 share/html/Elements/ShowUser                       |    4 +-
 share/html/Elements/ShowUserConcise                |    4 +-
 share/html/Elements/ShowUserEmailFrequency         |    4 +-
 share/html/Elements/ShowUserVerbose                |    4 +-
 share/html/Elements/SimpleSearch                   |    4 +-
 share/html/Elements/Submit                         |    4 +-
 share/html/Elements/Tabs                           |   12 ++--
 share/html/Elements/TicketList                     |    4 +-
 share/html/Elements/TitleBox                       |    4 +-
 share/html/Elements/TitleBoxEnd                    |    4 +-
 share/html/Elements/TitleBoxStart                  |    4 +-
 share/html/Elements/ValidateCustomFields           |    4 +-
 share/html/Elements/WidgetBar                      |    4 +-
 share/html/Helpers/Autocomplete/CustomFieldValues  |    4 +-
 share/html/Helpers/Autocomplete/Groups             |    4 +-
 share/html/Helpers/Autocomplete/Owners             |    4 +-
 share/html/Helpers/Autocomplete/Users              |    4 +-
 share/html/Helpers/TicketHistory                   |    4 +-
 share/html/Helpers/Toggle/ShowRequestor            |    4 +-
 share/html/Helpers/Toggle/TicketBookmark           |    4 +-
 share/html/Install/Basics.html                     |    4 +-
 share/html/Install/DatabaseDetails.html            |    4 +-
 share/html/Install/DatabaseType.html               |    4 +-
 share/html/Install/Elements/Errors                 |    4 +-
 share/html/Install/Elements/Wrapper                |    4 +-
 share/html/Install/Finish.html                     |    4 +-
 share/html/Install/Global.html                     |    4 +-
 share/html/Install/Initialize.html                 |    4 +-
 share/html/Install/Sendmail.html                   |    4 +-
 share/html/Install/autohandler                     |    4 +-
 share/html/Install/index.html                      |    4 +-
 share/html/NoAuth/Helpers/CustomLogo               |    4 +-
 share/html/NoAuth/Login.html                       |   30 ++++----
 share/html/NoAuth/Logout.html                      |    4 +-
 share/html/NoAuth/Reminder.html                    |    4 +-
 share/html/NoAuth/RichText/dhandler                |    4 +-
 share/html/NoAuth/css/aileron/InHeader             |    4 +-
 share/html/NoAuth/css/aileron/base.css             |    4 +-
 share/html/NoAuth/css/aileron/boxes.css            |    4 +-
 share/html/NoAuth/css/aileron/forms.css            |   47 +++++++++++++
 share/html/NoAuth/css/aileron/layout.css           |    4 +-
 share/html/NoAuth/css/aileron/login.css            |   47 +++++++++++++
 share/html/NoAuth/css/aileron/main.css             |    4 +-
 share/html/NoAuth/css/aileron/misc.css             |    5 +-
 share/html/NoAuth/css/aileron/msie-pie.css         |   48 +++++++++++++-
 share/html/NoAuth/css/aileron/msie.css             |    5 +-
 share/html/NoAuth/css/aileron/msie6.css            |    5 +-
 share/html/NoAuth/css/aileron/nav.css              |    4 +-
 share/html/NoAuth/css/aileron/ticket-lists.css     |    4 +-
 share/html/NoAuth/css/aileron/ticket-search.css    |    4 +-
 share/html/NoAuth/css/aileron/ticket.css           |    4 +-
 share/html/NoAuth/css/autohandler                  |    4 +-
 share/html/NoAuth/css/ballard/InHeader             |    4 +-
 share/html/NoAuth/css/ballard/base.css             |    4 +-
 share/html/NoAuth/css/ballard/boxes.css            |    4 +-
 share/html/NoAuth/css/ballard/layout.css           |    4 +-
 share/html/NoAuth/css/ballard/main.css             |    4 +-
 share/html/NoAuth/css/ballard/misc.css             |    5 +-
 share/html/NoAuth/css/ballard/msie.css             |    4 +-
 share/html/NoAuth/css/ballard/msie6.css            |    4 +-
 share/html/NoAuth/css/ballard/nav.css              |    5 +-
 share/html/NoAuth/css/ballard/ticket-lists.css     |    4 +-
 share/html/NoAuth/css/ballard/ticket-search.css    |    4 +-
 share/html/NoAuth/css/ballard/ticket.css           |    4 +-
 share/html/NoAuth/css/base/admin.css               |    4 +-
 share/html/NoAuth/css/base/articles.css            |   47 +++++++++++++
 share/html/NoAuth/css/base/collection.css          |    4 +-
 share/html/NoAuth/css/base/farbtastic.css          |    4 +-
 share/html/NoAuth/css/base/forms.css               |    4 +-
 share/html/NoAuth/css/base/history-folding.css     |   47 +++++++++++++
 share/html/NoAuth/css/base/jquery-ui.css           |    4 +-
 share/html/NoAuth/css/base/login.css               |    4 +-
 share/html/NoAuth/css/base/main.css                |    4 +-
 share/html/NoAuth/css/base/misc.css                |    4 +-
 share/html/NoAuth/css/base/nav.css                 |   47 +++++++++++++
 share/html/NoAuth/css/base/portlets.css            |    4 +-
 share/html/NoAuth/css/base/rights-editor.css       |    4 +-
 share/html/NoAuth/css/base/tablesorter.css         |   13 ++++
 share/html/NoAuth/css/base/theme-editor.css        |    4 +-
 share/html/NoAuth/css/base/ticket-form.css         |    4 +-
 share/html/NoAuth/css/base/ticket.css              |    4 +-
 share/html/NoAuth/css/base/tools.css               |    4 +-
 share/html/NoAuth/css/base/ui.timepickr.custom.css |   47 +++++++++++++
 share/html/NoAuth/css/dhandler                     |    4 +-
 share/html/NoAuth/css/print.css                    |    4 +-
 share/html/NoAuth/css/web2/InHeader                |    5 +-
 share/html/NoAuth/css/web2/base.css                |    4 +-
 share/html/NoAuth/css/web2/boxes.css               |    4 +-
 share/html/NoAuth/css/web2/layout.css              |    4 +-
 share/html/NoAuth/css/web2/main.css                |    4 +-
 share/html/NoAuth/css/web2/misc.css                |    5 +-
 share/html/NoAuth/css/web2/msie-pie.css            |   47 +++++++++++++
 share/html/NoAuth/css/web2/msie.css                |    4 +-
 share/html/NoAuth/css/web2/msie6.css               |    4 +-
 share/html/NoAuth/css/web2/nav.css                 |    5 +-
 share/html/NoAuth/css/web2/ticket-lists.css        |    4 +-
 share/html/NoAuth/css/web2/ticket-search.css       |    4 +-
 share/html/NoAuth/css/web2/ticket.css              |    4 +-
 share/html/NoAuth/iCal/dhandler                    |    4 +-
 share/html/NoAuth/js/autohandler                   |    4 +-
 share/html/NoAuth/js/cascaded.js                   |    4 +-
 share/html/NoAuth/js/combobox.js                   |    4 +-
 share/html/NoAuth/js/dhandler                      |    4 +-
 share/html/NoAuth/js/farbtastic.js                 |    4 +-
 share/html/NoAuth/js/history-folding.js            |   47 +++++++++++++
 share/html/NoAuth/js/jquery-ui-patch-datepicker.js |   47 +++++++++++++
 share/html/NoAuth/js/jquery.tablesorter.min.js     |   14 ++++-
 share/html/NoAuth/js/jquery_noconflict.js          |    4 +-
 share/html/NoAuth/js/late.js                       |   47 +++++++++++++
 share/html/NoAuth/js/titlebox-state.js             |    4 +-
 share/html/NoAuth/js/userautocomplete.js           |    4 +-
 share/html/NoAuth/js/util.js                       |    4 +-
 share/html/NoAuth/rss/dhandler                     |    4 +-
 share/html/Prefs/MyRT.html                         |    4 +-
 share/html/Prefs/Other.html                        |    4 +-
 share/html/Prefs/Quicksearch.html                  |    4 +-
 share/html/Prefs/Search.html                       |    4 +-
 share/html/Prefs/SearchOptions.html                |    4 +-
 share/html/REST/1.0/Forms/attachment/default       |    4 +-
 share/html/REST/1.0/Forms/group/customfields       |    4 +-
 share/html/REST/1.0/Forms/group/default            |    4 +-
 share/html/REST/1.0/Forms/group/ns                 |    4 +-
 share/html/REST/1.0/Forms/queue/customfields       |    4 +-
 share/html/REST/1.0/Forms/queue/default            |    4 +-
 share/html/REST/1.0/Forms/queue/ns                 |    4 +-
 share/html/REST/1.0/Forms/queue/ticketcustomfields |    4 +-
 share/html/REST/1.0/Forms/ticket/attachments       |    4 +-
 share/html/REST/1.0/Forms/ticket/comment           |    4 +-
 share/html/REST/1.0/Forms/ticket/default           |    4 +-
 share/html/REST/1.0/Forms/ticket/history           |    4 +-
 share/html/REST/1.0/Forms/ticket/links             |    4 +-
 share/html/REST/1.0/Forms/ticket/merge             |    4 +-
 share/html/REST/1.0/Forms/ticket/take              |    4 +-
 share/html/REST/1.0/Forms/transaction/default      |    4 +-
 share/html/REST/1.0/Forms/user/default             |    4 +-
 share/html/REST/1.0/Forms/user/ns                  |    4 +-
 share/html/REST/1.0/NoAuth/mail-gateway            |    4 +-
 share/html/REST/1.0/autohandler                    |    4 +-
 share/html/REST/1.0/dhandler                       |    4 +-
 share/html/REST/1.0/logout                         |    4 +-
 share/html/REST/1.0/search/dhandler                |    4 +-
 share/html/REST/1.0/search/ticket                  |    4 +-
 share/html/REST/1.0/ticket/comment                 |    4 +-
 share/html/REST/1.0/ticket/link                    |    4 +-
 share/html/REST/1.0/ticket/merge                   |    4 +-
 share/html/Search/Article.html                     |   31 ++++-----
 share/html/Search/Build.html                       |    4 +-
 share/html/Search/Bulk.html                        |    4 +-
 share/html/Search/Chart                            |    4 +-
 share/html/Search/Chart.html                       |    4 +-
 share/html/Search/Edit.html                        |    4 +-
 share/html/Search/Elements/Article                 |    4 +-
 share/html/Search/Elements/BuildFormatString       |    4 +-
 share/html/Search/Elements/Chart                   |    4 +-
 share/html/Search/Elements/ConditionRow            |    4 +-
 share/html/Search/Elements/DisplayOptions          |    4 +-
 share/html/Search/Elements/EditFormat              |    4 +-
 share/html/Search/Elements/EditQuery               |    4 +-
 share/html/Search/Elements/EditSearches            |    4 +-
 share/html/Search/Elements/EditSort                |   47 +++++++++++++
 share/html/Search/Elements/Graph                   |    4 +-
 share/html/Search/Elements/NewListActions          |    4 +-
 share/html/Search/Elements/PickBasics              |    4 +-
 share/html/Search/Elements/PickCFs                 |    4 +-
 share/html/Search/Elements/PickCriteria            |    4 +-
 share/html/Search/Elements/ResultsRSSView          |    4 +-
 share/html/Search/Elements/SearchPrivacy           |    4 +-
 share/html/Search/Elements/SearchesForObject       |    4 +-
 share/html/Search/Elements/SelectAndOr             |    4 +-
 share/html/Search/Elements/SelectChartType         |    4 +-
 share/html/Search/Elements/SelectGroup             |    4 +-
 share/html/Search/Elements/SelectGroupBy           |    4 +-
 share/html/Search/Elements/SelectLinks             |    4 +-
 share/html/Search/Elements/SelectPersonType        |    4 +-
 share/html/Search/Elements/SelectSearchObject      |    4 +-
 .../html/Search/Elements/SelectSearchesForObjects  |    4 +-
 share/html/Search/Graph.html                       |    4 +-
 share/html/Search/Results.html                     |    4 +-
 share/html/Search/Results.rdf                      |    4 +-
 share/html/Search/Results.tsv                      |    4 +-
 share/html/Search/Simple.html                      |    4 +-
 share/html/SelfService/Article/Display.html        |    7 +-
 share/html/SelfService/Article/Search.html         |    7 +-
 share/html/SelfService/Article/autohandler         |    7 +-
 share/html/SelfService/Attachment/dhandler         |    4 +-
 share/html/SelfService/Closed.html                 |    4 +-
 share/html/SelfService/Create.html                 |    4 +-
 share/html/SelfService/CreateTicketInQueue.html    |    4 +-
 share/html/SelfService/Display.html                |    4 +-
 share/html/SelfService/Elements/GotoTicket         |    4 +-
 share/html/SelfService/Elements/Header             |    4 +-
 share/html/SelfService/Elements/MyRequests         |    4 +-
 share/html/SelfService/Elements/SearchArticle      |    7 +-
 share/html/SelfService/Error.html                  |    4 +-
 share/html/SelfService/Prefs.html                  |    4 +-
 share/html/SelfService/Update.html                 |    4 +-
 share/html/SelfService/index.html                  |    4 +-
 share/html/Ticket/Attachment/WithHeaders/dhandler  |    4 +-
 share/html/Ticket/Attachment/dhandler              |    4 +-
 share/html/Ticket/Create.html                      |    4 +-
 share/html/Ticket/Display.html                     |    4 +-
 share/html/Ticket/Elements/AddAttachments          |    4 +-
 share/html/Ticket/Elements/AddWatchers             |    4 +-
 share/html/Ticket/Elements/Bookmark                |    4 +-
 share/html/Ticket/Elements/BulkLinks               |    4 +-
 share/html/Ticket/Elements/ClickToShowHistory      |    4 +-
 share/html/Ticket/Elements/EditBasics              |    4 +-
 share/html/Ticket/Elements/EditCustomFields        |    4 +-
 share/html/Ticket/Elements/EditDates               |    4 +-
 share/html/Ticket/Elements/EditPeople              |    4 +-
 .../Ticket/Elements/EditTransactionCustomFields    |    4 +-
 share/html/Ticket/Elements/EditWatchers            |    4 +-
 share/html/Ticket/Elements/FindAttachments         |    4 +-
 share/html/Ticket/Elements/FindTransactions        |   47 +++++++++++++
 share/html/Ticket/Elements/FoldStanzaJS            |   47 +++++++++++++
 share/html/Ticket/Elements/LoadTextAttachments     |    4 +-
 share/html/Ticket/Elements/PreviewScrips           |    4 +-
 share/html/Ticket/Elements/Reminders               |    4 +-
 share/html/Ticket/Elements/ShowAttachments         |    4 +-
 share/html/Ticket/Elements/ShowBasics              |    4 +-
 share/html/Ticket/Elements/ShowCustomFields        |    4 +-
 share/html/Ticket/Elements/ShowDates               |    4 +-
 share/html/Ticket/Elements/ShowDependencies        |    4 +-
 share/html/Ticket/Elements/ShowGnuPGStatus         |    4 +-
 share/html/Ticket/Elements/ShowGroupMembers        |    4 +-
 share/html/Ticket/Elements/ShowHistory             |    4 +-
 share/html/Ticket/Elements/ShowMembers             |    4 +-
 share/html/Ticket/Elements/ShowMessageHeaders      |    4 +-
 share/html/Ticket/Elements/ShowMessageStanza       |    4 +-
 share/html/Ticket/Elements/ShowParents             |    4 +-
 share/html/Ticket/Elements/ShowPeople              |    4 +-
 share/html/Ticket/Elements/ShowPriority            |    4 +-
 share/html/Ticket/Elements/ShowQueue               |    4 +-
 share/html/Ticket/Elements/ShowRequestor           |    4 +-
 share/html/Ticket/Elements/ShowRequestorExtraInfo  |    4 +-
 share/html/Ticket/Elements/ShowRequestorTickets    |    4 +-
 .../Ticket/Elements/ShowRequestorTicketsActive     |    4 +-
 share/html/Ticket/Elements/ShowRequestorTicketsAll |    4 +-
 .../Ticket/Elements/ShowRequestorTicketsInactive   |    4 +-
 .../html/Ticket/Elements/ShowSimplifiedRecipients  |   47 +++++++++++++
 share/html/Ticket/Elements/ShowSummary             |    4 +-
 share/html/Ticket/Elements/ShowTime                |    4 +-
 share/html/Ticket/Elements/ShowTransaction         |    4 +-
 .../Ticket/Elements/ShowTransactionAttachments     |    4 +-
 share/html/Ticket/Elements/ShowUpdateStatus        |    4 +-
 share/html/Ticket/Elements/ShowUserEntry           |    4 +-
 share/html/Ticket/Elements/UpdateCc                |    4 +-
 share/html/Ticket/Forward.html                     |    4 +-
 share/html/Ticket/GnuPG.html                       |    4 +-
 .../Ticket/Graphs/Elements/EditGraphProperties     |    4 +-
 share/html/Ticket/Graphs/Elements/ShowGraph        |    4 +-
 share/html/Ticket/Graphs/Elements/ShowLegends      |    4 +-
 share/html/Ticket/Graphs/dhandler                  |    5 +-
 share/html/Ticket/Graphs/index.html                |    4 +-
 share/html/Ticket/History.html                     |    4 +-
 share/html/Ticket/Modify.html                      |    4 +-
 share/html/Ticket/ModifyAll.html                   |    4 +-
 share/html/Ticket/ModifyDates.html                 |    4 +-
 share/html/Ticket/ModifyLinks.html                 |    4 +-
 share/html/Ticket/ModifyPeople.html                |    4 +-
 share/html/Ticket/Reminders.html                   |    4 +-
 share/html/Ticket/ShowEmailRecord.html             |    4 +-
 share/html/Ticket/Update.html                      |    4 +-
 share/html/Tools/MyDay.html                        |    4 +-
 share/html/Tools/MyReminders.html                  |    8 +-
 share/html/Tools/Offline.html                      |    4 +-
 share/html/Tools/index.html                        |    4 +-
 share/html/User/Prefs.html                         |    4 +-
 share/html/Widgets/BulkEdit                        |    4 +-
 share/html/Widgets/BulkProcess                     |    4 +-
 share/html/Widgets/ComboBox                        |    4 +-
 share/html/Widgets/FinalizeWidgetArguments         |    4 +-
 share/html/Widgets/Form/Boolean                    |    4 +-
 share/html/Widgets/Form/Integer                    |    4 +-
 share/html/Widgets/Form/Select                     |    4 +-
 share/html/Widgets/Form/String                     |    4 +-
 share/html/Widgets/SavedSearch                     |    4 +-
 share/html/Widgets/SelectionBox                    |    4 +-
 share/html/Widgets/TitleBox                        |    4 +-
 share/html/Widgets/TitleBoxEnd                     |    4 +-
 share/html/Widgets/TitleBoxStart                   |    4 +-
 share/html/autohandler                             |    4 +-
 share/html/dhandler                                |    4 +-
 share/html/index.html                              |    4 +-
 share/html/l                                       |    4 +-
 share/html/m/_elements/full_site_link              |    4 +-
 share/html/m/_elements/header                      |    4 +-
 share/html/m/_elements/menu                        |    4 +-
 share/html/m/_elements/raw_style                   |    4 +-
 share/html/m/_elements/ticket_list                 |    4 +-
 share/html/m/_elements/ticket_menu                 |    4 +-
 share/html/m/_elements/wrapper                     |    4 +-
 share/html/m/dhandler                              |    4 +-
 share/html/m/index.html                            |    4 +-
 share/html/m/login                                 |    4 +-
 share/html/m/logout                                |    4 +-
 share/html/m/style.css                             |    4 +-
 share/html/m/ticket/create                         |    4 +-
 share/html/m/ticket/history                        |    4 +-
 share/html/m/ticket/modify                         |    4 +-
 share/html/m/ticket/reply                          |    4 +-
 share/html/m/ticket/select_create_queue            |    4 +-
 share/html/m/ticket/show                           |    4 +-
 share/html/m/tickets/requested                     |    4 +-
 share/html/m/tickets/search                        |    4 +-
 t/data/configs/apache2.2+mod_perl.conf.in          |    4 +-
 t/web/cf_datetime.t                                |    2 +-
 819 files changed, 3219 insertions(+), 1934 deletions(-)

- Log -----------------------------------------------------------------
commit 316384de89bbd7aace14580c42162b8462ff35c7
Merge: 0ee6ad4 5a62cc5
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Thu Mar 3 04:43:15 2011 -0500

    Merge branch '3.8-trunk' into 4.0-trunk

diff --cc bin/rt-mailgate.in
index 74d0a03,c1a57cb..9f43248
--- a/bin/rt-mailgate.in
+++ b/bin/rt-mailgate.in
@@@ -268,13 -186,13 +268,13 @@@ sub slurp_message 
          print STDERR "$0: Couldn't create temp file, using memory\n";
          print STDERR "error: $@\n" if $@;
  
-         my $message = \do { local ( @ARGV, $/ ); <> };
 -        my $message = \do { local (@ARGV, $/); <STDIN> };
++        my $message = \do { local ( @ARGV, $/ ); <STDIN> };
          unless ( $$message =~ /\S/ ) {
              print STDERR "$0: no message passed on STDIN\n";
 -            exit 0;
 +            $self->exit_with_success;
          }
 -        $$message = $opts{'headers'} . $$message if $opts{'headers'};
 -        return ( content => $message );
 +        $$message = $opts->{'headers'} . $$message if $opts->{'headers'};
 +        return ( { content => $message } );
      }
  
      binmode $fh;
diff --cc etc/upgrade/3.8.2/content
index b0dbb47,d8f54e9..0eef401
--- a/etc/upgrade/3.8.2/content
+++ b/etc/upgrade/3.8.2/content
@@@ -2,12 -2,12 +2,12 @@@
      sub {
          $RT::Logger->warning(
              "Going to add [OLD] prefix to all templates in approvals queue."
-             ." If you never used approvals then you can delete all these"
-             ." templates with [OLD] prefix. Leave the new ones there because"
-             ." maybe you will eventually want to use start using approvals."
+             ." If you have never used approvals, you can safely delete all the"
+             ." templates with the [OLD] prefix. Leave the new Approval templates because"
+             ." you may eventually want to start using approvals."
          );
  
 -        my $approvals_q = RT::Queue->new( $RT::SystemUser );
 +        my $approvals_q = RT::Queue->new( RT->SystemUser );
          $approvals_q->Load('___Approvals');
          unless ( $approvals_q->id ) {
              $RT::Logger->error("You have no approvals queue.");
diff --cc lib/RT.pm
index 865bc02,0000000..d93e5c7
mode 100644,000000..100644
--- a/lib/RT.pm
+++ b/lib/RT.pm
@@@ -1,791 -1,0 +1,794 @@@
 +# BEGIN BPS TAGGED BLOCK {{{
 +#
 +# COPYRIGHT:
 +#
 +# This software is Copyright (c) 1996-2010 Best Practical Solutions, LLC
 +#                                          <jesse at bestpractical.com>
 +#
 +# (Except where explicitly superseded by other copyright notices)
 +#
 +#
 +# LICENSE:
 +#
 +# This work is made available to you under the terms of Version 2 of
 +# the GNU General Public License. A copy of that license should have
 +# been provided with this software, but in any event can be snarfed
 +# from www.gnu.org.
 +#
 +# This work is distributed in the hope that it will be useful, but
 +# WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +# General Public License for more details.
 +#
 +# You should have received a copy of the GNU General Public License
 +# along with this program; if not, write to the Free Software
 +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 +# 02110-1301 or visit their web page on the internet at
 +# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
 +#
 +#
 +# CONTRIBUTION SUBMISSION POLICY:
 +#
 +# (The following paragraph is not intended to limit the rights granted
 +# to you to modify and distribute this software under the terms of
 +# the GNU General Public License and is only of importance to you if
 +# you choose to contribute your changes and enhancements to the
 +# community by submitting them to Best Practical Solutions, LLC.)
 +#
 +# By intentionally submitting any modifications, corrections or
 +# derivatives to this work, or any other work intended for use with
 +# Request Tracker, to Best Practical Solutions, LLC, you confirm that
 +# you are the copyright holder for those contributions and you grant
 +# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
 +# royalty-free, perpetual, license to use, copy, create derivative
 +# works based on those contributions, and sublicense and distribute
 +# those contributions and any derivatives thereof.
 +#
 +# END BPS TAGGED BLOCK }}}
 +
 +use strict;
 +use warnings;
 +
 +package RT;
 +
 +
 +use File::Spec ();
 +use Cwd ();
 +
 +use vars qw($Config $System $SystemUser $Nobody $Handle $Logger $_Privileged $_Unprivileged $_INSTALL_MODE);
 +
 +use vars qw($BasePath
 + $EtcPath
 + $BinPath
 + $SbinPath
 + $VarPath
 + $LexiconPath
 + $PluginPath
 + $LocalPath
 + $LocalEtcPath
 + $LocalLibPath
 + $LocalLexiconPath
 + $LocalPluginPath
 + $MasonComponentRoot
 + $MasonLocalComponentRoot
 + $MasonDataDir
 + $MasonSessionDir);
 +
 +
 +RT->LoadGeneratedData();
 +
 +=head1 NAME
 +
 +RT - Request Tracker
 +
 +=head1 SYNOPSIS
 +
 +A fully featured request tracker package
 +
 +=head1 DESCRIPTION
 +
 +=head2 INITIALIZATION
 +
 +=head2 LoadConfig
 +
 +Load RT's config file.  First, the site configuration file
 +(F<RT_SiteConfig.pm>) is loaded, in order to establish overall site
 +settings like hostname and name of RT instance.  Then, the core
 +configuration file (F<RT_Config.pm>) is loaded to set fallback values
 +for all settings; it bases some values on settings from the site
 +configuration file.
 +
 +In order for the core configuration to not override the site's
 +settings, the function C<Set> is used; it only sets values if they
 +have not been set already.
 +
 +=cut
 +
 +sub LoadConfig {
 +    require RT::Config;
 +    $Config = RT::Config->new;
 +    $Config->LoadConfigs;
 +    require RT::I18N;
 +
 +    # RT::Essentials mistakenly recommends that WebPath be set to '/'.
 +    # If the user does that, do what they mean.
 +    $RT::WebPath = '' if ($RT::WebPath eq '/');
 +
 +    # fix relative LogDir and GnuPG homedir
 +    unless ( File::Spec->file_name_is_absolute( $Config->Get('LogDir') ) ) {
 +        $Config->Set( LogDir =>
 +              File::Spec->catfile( $BasePath, $Config->Get('LogDir') ) );
 +    }
 +
 +    my $gpgopts = $Config->Get('GnuPGOptions');
 +    unless ( File::Spec->file_name_is_absolute( $gpgopts->{homedir} ) ) {
 +        $gpgopts->{homedir} = File::Spec->catfile( $BasePath, $gpgopts->{homedir} );
 +    }
 +
 +    return $Config;
 +}
 +
 +=head2 Init
 +
 +L<Connect to the database /ConnectToDatabase>, L<initilizes system objects /InitSystemObjects>,
 +L<preloads classes /InitClasses> and L<set up logging /InitLogging>.
 +
 +=cut
 +
 +sub Init {
 +
 +    CheckPerlRequirements();
 +
 +    InitPluginPaths();
 +
 +    #Get a database connection
 +    ConnectToDatabase();
 +    InitSystemObjects();
 +    InitClasses();
 +    InitLogging();
 +    InitPlugins();
 +    RT::I18N->Init;
 +    RT->Config->PostLoadCheck;
 +
 +}
 +
 +=head2 ConnectToDatabase
 +
 +Get a database connection. See also </Handle>.
 +
 +=cut
 +
 +sub ConnectToDatabase {
 +    require RT::Handle;
 +    $Handle = RT::Handle->new unless $Handle;
 +    $Handle->Connect;
 +    return $Handle;
 +}
 +
 +=head2 InitLogging
 +
 +Create the Logger object and set up signal handlers.
 +
 +=cut
 +
 +sub InitLogging {
 +
 +    # We have to set the record separator ($, man perlvar)
 +    # or Log::Dispatch starts getting
 +    # really pissy, as some other module we use unsets it.
 +    $, = '';
 +    use Log::Dispatch 1.6;
 +
 +    my %level_to_num = (
 +        map( { $_ => } 0..7 ),
 +        debug     => 0,
 +        info      => 1,
 +        notice    => 2,
 +        warning   => 3,
 +        error     => 4, 'err' => 4,
 +        critical  => 5, crit  => 5,
 +        alert     => 6,
 +        emergency => 7, emerg => 7,
 +    );
 +
 +    unless ( $RT::Logger ) {
 +
 +        $RT::Logger = Log::Dispatch->new;
 +
 +        my $stack_from_level;
 +        if ( $stack_from_level = RT->Config->Get('LogStackTraces') ) {
 +            # if option has old style '\d'(true) value
 +            $stack_from_level = 0 if $stack_from_level =~ /^\d+$/;
 +            $stack_from_level = $level_to_num{ $stack_from_level } || 0;
 +        } else {
 +            $stack_from_level = 99; # don't log
 +        }
 +
 +        my $simple_cb = sub {
 +            # if this code throw any warning we can get segfault
 +            no warnings;
 +            my %p = @_;
 +
 +            # skip Log::* stack frames
 +            my $frame = 0;
 +            $frame++ while caller($frame) && caller($frame) =~ /^Log::/;
 +            my ($package, $filename, $line) = caller($frame);
 +
 +            $p{'message'} =~ s/(?:\r*\n)+$//;
 +            return "[". gmtime(time) ."] [". $p{'level'} ."]: "
 +                . $p{'message'} ." ($filename:$line)\n";
 +        };
 +
 +        my $syslog_cb = sub {
 +            # if this code throw any warning we can get segfault
 +            no warnings;
 +            my %p = @_;
 +
 +            my $frame = 0; # stack frame index
 +            # skip Log::* stack frames
 +            $frame++ while caller($frame) && caller($frame) =~ /^Log::/;
 +            my ($package, $filename, $line) = caller($frame);
 +
 +            # syswrite() cannot take utf8; turn it off here.
 +            Encode::_utf8_off($p{message});
 +
 +            $p{message} =~ s/(?:\r*\n)+$//;
 +            if ($p{level} eq 'debug') {
 +                return "$p{message}\n";
 +            } else {
 +                return "$p{message} ($filename:$line)\n";
 +            }
 +        };
 +
 +        my $stack_cb = sub {
 +            no warnings;
 +            my %p = @_;
 +            return $p{'message'} unless $level_to_num{ $p{'level'} } >= $stack_from_level;
 +
 +            require Devel::StackTrace;
 +            my $trace = Devel::StackTrace->new( ignore_class => [ 'Log::Dispatch', 'Log::Dispatch::Base' ] );
 +            return $p{'message'} . $trace->as_string;
 +
 +            # skip calling of the Log::* subroutins
 +            my $frame = 0;
 +            $frame++ while caller($frame) && caller($frame) =~ /^Log::/;
 +            $frame++ while caller($frame) && (caller($frame))[3] =~ /^Log::/;
 +
 +            $p{'message'} .= "\nStack trace:\n";
 +            while( my ($package, $filename, $line, $sub) = caller($frame++) ) {
 +                $p{'message'} .= "\t$sub(...) called at $filename:$line\n";
 +            }
 +            return $p{'message'};
 +        };
 +
 +        if ( $Config->Get('LogToFile') ) {
 +            my ($filename, $logdir) = (
 +                $Config->Get('LogToFileNamed') || 'rt.log',
 +                $Config->Get('LogDir') || File::Spec->catdir( $VarPath, 'log' ),
 +            );
 +            if ( $filename =~ m![/\\]! ) { # looks like an absolute path.
 +                ($logdir) = $filename =~ m{^(.*[/\\])};
 +            }
 +            else {
 +                $filename = File::Spec->catfile( $logdir, $filename );
 +            }
 +
 +            unless ( -d $logdir && ( ( -f $filename && -w $filename ) || -w $logdir ) ) {
 +                # localizing here would be hard when we don't have a current user yet
 +                die "Log file '$filename' couldn't be written or created.\n RT can't run.";
 +            }
 +
 +            require Log::Dispatch::File;
 +            $RT::Logger->add( Log::Dispatch::File->new
 +                           ( name=>'file',
 +                             min_level=> $Config->Get('LogToFile'),
 +                             filename=> $filename,
 +                             mode=>'append',
 +                             callbacks => [ $simple_cb, $stack_cb ],
 +                           ));
 +        }
 +        if ( $Config->Get('LogToScreen') ) {
 +            require Log::Dispatch::Screen;
 +            $RT::Logger->add( Log::Dispatch::Screen->new
 +                         ( name => 'screen',
 +                           min_level => $Config->Get('LogToScreen'),
 +                           callbacks => [ $simple_cb, $stack_cb ],
 +                           stderr => 1,
 +                         ));
 +        }
 +        if ( $Config->Get('LogToSyslog') ) {
 +            require Log::Dispatch::Syslog;
 +            $RT::Logger->add(Log::Dispatch::Syslog->new
 +                         ( name => 'syslog',
 +                           ident => 'RT',
 +                           min_level => $Config->Get('LogToSyslog'),
 +                           callbacks => [ $syslog_cb, $stack_cb ],
 +                           stderr => 1,
 +                           $Config->Get('LogToSyslogConf'),
 +                         ));
 +        }
 +    }
 +    InitSignalHandlers();
 +}
 +
 +sub InitSignalHandlers {
 +
 +# Signal handlers
 +## This is the default handling of warnings and die'ings in the code
 +## (including other used modules - maybe except for errors catched by
 +## Mason).  It will log all problems through the standard logging
 +## mechanism (see above).
 +
 +    $SIG{__WARN__} = sub {
 +        # The 'wide character' warnings has to be silenced for now, at least
 +        # until HTML::Mason offers a sane way to process both raw output and
 +        # unicode strings.
 +        # use 'goto &foo' syntax to hide ANON sub from stack
 +        if( index($_[0], 'Wide character in ') != 0 ) {
 +            unshift @_, $RT::Logger, qw(level warning message);
 +            goto &Log::Dispatch::log;
 +        }
 +    };
 +
 +#When we call die, trap it and log->crit with the value of the die.
 +
 +    $SIG{__DIE__}  = sub {
 +        # if we are not in eval and perl is not parsing code
 +        # then rollback transactions and log RT error
 +        unless ($^S || !defined $^S ) {
 +            $RT::Handle->Rollback(1) if $RT::Handle;
 +            $RT::Logger->crit("$_[0]") if $RT::Logger;
 +        }
 +        die $_[0];
 +    };
 +}
 +
 +
 +sub CheckPerlRequirements {
 +    if ($^V < 5.008003) {
 +        die sprintf "RT requires Perl v5.8.3 or newer.  Your current Perl is v%vd\n", $^V;
 +    }
 +
 +    # use $error here so the following "die" can still affect the global $@
 +    my $error;
 +    {
 +        local $@;
 +        eval {
 +            my $x = '';
 +            my $y = \$x;
 +            require Scalar::Util;
 +            Scalar::Util::weaken($y);
 +        };
 +        $error = $@;
 +    }
 +
 +    if ($error) {
 +        die <<"EOF";
 +
 +RT requires the Scalar::Util module be built with support for  the 'weaken'
 +function.
 +
 +It is sometimes the case that operating system upgrades will replace
 +a working Scalar::Util with a non-working one. If your system was working
 +correctly up until now, this is likely the cause of the problem.
 +
 +Please reinstall Scalar::Util, being careful to let it build with your C
 +compiler. Usually this is as simple as running the following command as
 +root.
 +
 +    perl -MCPAN -e'install Scalar::Util'
 +
 +EOF
 +
 +    }
 +}
 +
 +=head2 InitClasses
 +
 +Load all modules that define base classes.
 +
 +=cut
 +
 +sub InitClasses {
 +    shift if @_%2; # so we can call it as a function or method
 +    my %args = (@_);
 +    require RT::Tickets;
 +    require RT::Transactions;
 +    require RT::Attachments;
 +    require RT::Users;
 +    require RT::Principals;
 +    require RT::CurrentUser;
 +    require RT::Templates;
 +    require RT::Queues;
 +    require RT::ScripActions;
 +    require RT::ScripConditions;
 +    require RT::Scrips;
 +    require RT::Groups;
 +    require RT::GroupMembers;
 +    require RT::CustomFields;
 +    require RT::CustomFieldValues;
 +    require RT::ObjectCustomFields;
 +    require RT::ObjectCustomFieldValues;
 +    require RT::Attributes;
 +    require RT::Dashboard;
 +    require RT::Approval;
 +    require RT::Lifecycle;
 +    require RT::Article;
 +    require RT::Articles;
 +    require RT::Class;
 +    require RT::Classes;
 +    require RT::ObjectClass;
 +    require RT::ObjectClasses;
 +    require RT::ObjectTopic;
 +    require RT::ObjectTopics;
 +    require RT::Topic;
 +    require RT::Topics;
 +
 +    # on a cold server (just after restart) people could have an object
 +    # in the session, as we deserialize it so we never call constructor
 +    # of the class, so the list of accessible fields is empty and we die
 +    # with "Method xxx is not implemented in RT::SomeClass"
 +    $_->_BuildTableAttributes foreach qw(
 +        RT::Ticket
 +        RT::Transaction
 +        RT::Attachment
 +        RT::User
 +        RT::Principal
 +        RT::Template
 +        RT::Queue
 +        RT::ScripAction
 +        RT::ScripCondition
 +        RT::Scrip
 +        RT::Group
 +        RT::GroupMember
 +        RT::CustomField
 +        RT::CustomFieldValue
 +        RT::ObjectCustomField
 +        RT::ObjectCustomFieldValue
 +        RT::Attribute
 +    );
 +
 +    if ( $args{'Heavy'} ) {
 +        # load scrips' modules
 +        my $scrips = RT::Scrips->new(RT->SystemUser);
 +        $scrips->Limit( FIELD => 'Stage', OPERATOR => '!=', VALUE => 'Disabled' );
 +        while ( my $scrip = $scrips->Next ) {
-             $scrip->LoadModules;
++            local $@;
++            eval { $scrip->LoadModules } or
++                $RT::Logger->error("Invalid Scrip ".$scrip->Id.".  Unable to load the Action or Condition.  ".
++                                   "You should delete or repair this Scrip in the admin UI.\n$@\n");
 +        }
 +
 +	foreach my $class ( grep $_, RT->Config->Get('CustomFieldValuesSources') ) {
 +            local $@;
 +            eval "require $class; 1" or $RT::Logger->error(
 +                "Class '$class' is listed in CustomFieldValuesSources option"
 +                ." in the config, but we failed to load it:\n$@\n"
 +            );
 +        }
 +
 +    }
 +}
 +
 +=head2 InitSystemObjects
 +
 +Initializes system objects: C<$RT::System>, C<RT->SystemUser>
 +and C<RT->Nobody>.
 +
 +=cut
 +
 +sub InitSystemObjects {
 +
 +    #RT's system user is a genuine database user. its id lives here
 +    require RT::CurrentUser;
 +    $SystemUser = RT::CurrentUser->new;
 +    $SystemUser->LoadByName('RT_System');
 +
 +    #RT's "nobody user" is a genuine database user. its ID lives here.
 +    $Nobody = RT::CurrentUser->new;
 +    $Nobody->LoadByName('Nobody');
 +
 +    require RT::System;
 +    $System = RT::System->new( $SystemUser );
 +}
 +
 +=head1 CLASS METHODS
 +
 +=head2 Config
 +
 +Returns the current L<config object RT::Config>, but note that
 +you must L<load config /LoadConfig> first otherwise this method
 +returns undef.
 +
 +Method can be called as class method.
 +
 +=cut
 +
 +sub Config { return $Config || shift->LoadConfig(); }
 +
 +=head2 DatabaseHandle
 +
 +Returns the current L<database handle object RT::Handle>.
 +
 +See also L</ConnectToDatabase>.
 +
 +=cut
 +
 +sub DatabaseHandle { return $Handle }
 +
 +=head2 Logger
 +
 +Returns the logger. See also L</InitLogging>.
 +
 +=cut
 +
 +sub Logger { return $Logger }
 +
 +=head2 System
 +
 +Returns the current L<system object RT::System>. See also
 +L</InitSystemObjects>.
 +
 +=cut
 +
 +sub System { return $System }
 +
 +=head2 SystemUser
 +
 +Returns the system user's object, it's object of
 +L<RT::CurrentUser> class that represents the system. See also
 +L</InitSystemObjects>.
 +
 +=cut
 +
 +sub SystemUser { return $SystemUser }
 +
 +=head2 Nobody
 +
 +Returns object of Nobody. It's object of L<RT::CurrentUser> class
 +that represents a user who can own ticket and nothing else. See
 +also L</InitSystemObjects>.
 +
 +=cut
 +
 +sub Nobody { return $Nobody }
 +
 +sub PrivilegedUsers {
 +    if (!$_Privileged) {
 +    $_Privileged = RT::Group->new(RT->SystemUser);
 +    $_Privileged->LoadSystemInternalGroup('Privileged');
 +    }
 +    return $_Privileged;
 +}
 +
 +sub UnprivilegedUsers {
 +    if (!$_Unprivileged) {
 +    $_Unprivileged = RT::Group->new(RT->SystemUser);
 +    $_Unprivileged->LoadSystemInternalGroup('Unprivileged');
 +    }
 +    return $_Unprivileged;
 +}
 +
 +
 +=head2 Plugins
 +
 +Returns a listref of all Plugins currently configured for this RT instance.
 +You can define plugins by adding them to the @Plugins list in your RT_SiteConfig
 +
 +=cut
 +
 +our @PLUGINS = ();
 +sub Plugins {
 +    my $self = shift;
 +    unless (@PLUGINS) {
 +        $self->InitPluginPaths;
 +        @PLUGINS = $self->InitPlugins;
 +    }
 +    return \@PLUGINS;
 +}
 +
 +=head2 PluginDirs
 +
 +Takes optional subdir (e.g. po, lib, etc.) and return plugins' dirs that exist.
 +
 +This code chacke plugins names or anything else and required when main config
 +is loaded to load plugins' configs.
 +
 +=cut
 +
 +sub PluginDirs {
 +    my $self = shift;
 +    my $subdir = shift;
 +
 +    require RT::Plugin;
 +
 +    my @res;
 +    foreach my $plugin (grep $_, RT->Config->Get('Plugins')) {
 +        my $path = RT::Plugin->new( name => $plugin )->Path( $subdir );
 +        next unless -d $path;
 +        push @res, $path;
 +    }
 +    return @res;
 +}
 +
 +=head2 InitPluginPaths
 +
 +Push plugins' lib paths into @INC right after F<local/lib>.
 +In case F<local/lib> isn't in @INC, append them to @INC
 +
 +=cut
 +
 +sub InitPluginPaths {
 +    my $self = shift || __PACKAGE__;
 +
 +    my @lib_dirs = $self->PluginDirs('lib');
 +
 +    my @tmp_inc;
 +    my $added;
 +    for (@INC) {
 +        if ( Cwd::realpath($_) eq $RT::LocalLibPath) {
 +            push @tmp_inc, $_, @lib_dirs;
 +            $added = 1;
 +        } else {
 +            push @tmp_inc, $_;
 +        }
 +    }
 +
 +    # append @lib_dirs in case $RT::LocalLibPath isn't in @INC
 +    push @tmp_inc, @lib_dirs unless $added;
 +
 +    my %seen;
 +    @INC = grep !$seen{$_}++, @tmp_inc;
 +}
 +
 +=head2 InitPlugins
 +
 +Initialze all Plugins found in the RT configuration file, setting up their lib and HTML::Mason component roots.
 +
 +=cut
 +
 +sub InitPlugins {
 +    my $self    = shift;
 +    my @plugins;
 +    require RT::Plugin;
 +    foreach my $plugin (grep $_, RT->Config->Get('Plugins')) {
 +        $plugin->require;
 +        die $UNIVERSAL::require::ERROR if ($UNIVERSAL::require::ERROR);
 +        push @plugins, RT::Plugin->new(name =>$plugin);
 +    }
 +    return @plugins;
 +}
 +
 +
 +sub InstallMode {
 +    my $self = shift;
 +    if (@_) {
 +         $_INSTALL_MODE = shift;
 +         if($_INSTALL_MODE) {
 +             require RT::CurrentUser;
 +            $SystemUser = RT::CurrentUser->new();
 +         }
 +    }
 +    return $_INSTALL_MODE;
 +}
 +
 +sub LoadGeneratedData {
 +    my $class = shift;
 +    my $pm_path = ( File::Spec->splitpath( $INC{'RT.pm'} ) )[1];
 +
 +    require "$pm_path/RT/Generated.pm" || die "Couldn't load RT::Generated: $@";
 +    $class->CanonicalizeGeneratedPaths();
 +}
 +
 +sub CanonicalizeGeneratedPaths {
 +    my $class = shift;
 +    unless ( File::Spec->file_name_is_absolute($EtcPath) ) {
 +
 +   # if BasePath exists and is absolute, we won't infer it from $INC{'RT.pm'}.
 +   # otherwise RT.pm will make the source dir(where we configure RT) be the
 +   # BasePath instead of the one specified by --prefix
 +        unless ( -d $BasePath
 +                 && File::Spec->file_name_is_absolute($BasePath) )
 +        {
 +            my $pm_path = ( File::Spec->splitpath( $INC{'RT.pm'} ) )[1];
 +
 +     # need rel2abs here is to make sure path is absolute, since $INC{'RT.pm'}
 +     # is not always absolute
 +            $BasePath = File::Spec->rel2abs(
 +                          File::Spec->catdir( $pm_path, File::Spec->updir ) );
 +        }
 +
 +        $BasePath = Cwd::realpath($BasePath);
 +
 +        for my $path (
 +                    qw/EtcPath BinPath SbinPath VarPath LocalPath LocalEtcPath
 +                    LocalLibPath LexiconPath LocalLexiconPath PluginPath
 +                    LocalPluginPath MasonComponentRoot MasonLocalComponentRoot
 +                    MasonDataDir MasonSessionDir/
 +                     )
 +        {
 +            no strict 'refs';
 +
 +            # just change relative ones
 +            $$path = File::Spec->catfile( $BasePath, $$path )
 +                unless File::Spec->file_name_is_absolute($$path);
 +        }
 +    }
 +
 +}
 +
 +=head2 AddJavaScript
 +
 +helper method to add js files to C<JSFiles> config.
 +to add extra css files, you can add the following line
 +in the plugin's main file:
 +
 +    RT->AddJavaScript( 'foo.js', 'bar.js' ); 
 +
 +=cut
 +
 +sub AddJavaScript {
 +    my $self = shift;
 +
 +    my @old = RT->Config->Get('JSFiles');
 +    RT->Config->Set( 'JSFiles', @old, @_ );
 +    return RT->Config->Get('JSFiles');
 +}
 +
 +=head2 AddStyleSheets
 +
 +helper method to add css files to C<CSSFiles> config
 +
 +to add extra css files, you can add the following line
 +in the plugin's main file:
 +
 +    RT->AddStyleSheets( 'foo.css', 'bar.css' ); 
 +
 +=cut
 +
 +sub AddStyleSheets {
 +    my $self = shift;
 +    my @old = RT->Config->Get('CSSFiles');
 +    RT->Config->Set( 'CSSFiles', @old, @_ );
 +    return RT->Config->Get('CSSFiles');
 +}
 +
 +=head2 JavaScript
 +
 +helper method of RT->Config->Get('JSFiles')
 +
 +=cut
 +
 +sub JavaScript {
 +    return RT->Config->Get('JSFiles');
 +}
 +
 +=head2 StyleSheets
 +
 +helper method of RT->Config->Get('CSSFiles')
 +
 +=cut
 +
 +sub StyleSheets {
 +    return RT->Config->Get('CSSFiles');
 +}
 +
 +=head1 BUGS
 +
 +Please report them to rt-bugs at bestpractical.com, if you know what's
 +broken and have at least some idea of what needs to be fixed.
 +
 +If you're not sure what's going on, report them rt-devel at lists.bestpractical.com.
 +
 +=head1 SEE ALSO
 +
 +L<RT::StyleGuide>
 +L<DBIx::SearchBuilder>
 +
 +
 +=cut
 +
 +require RT::Base;
 +RT::Base->_ImportOverlays();
 +
 +1;
diff --cc lib/RT/ACE.pm
index 4c7a22c,8c2551c..0515eeb
mode 100644,100755..100644
--- a/lib/RT/ACE.pm
+++ b/lib/RT/ACE.pm
@@@ -207,379 -101,26 +207,379 @@@ PARAMS is a parameter hash with the fol
  
  sub Create {
      my $self = shift;
 -    my %args = ( 
 -                PrincipalType => '',
 -                PrincipalId => '0',
 -                RightName => '',
 -                ObjectType => '',
 -                ObjectId => '0',
 -                DelegatedBy => '0',
 -                DelegatedFrom => '0',
 -
 -		  @_);
 -    $self->SUPER::Create(
 -                         PrincipalType => $args{'PrincipalType'},
 -                         PrincipalId => $args{'PrincipalId'},
 -                         RightName => $args{'RightName'},
 -                         ObjectType => $args{'ObjectType'},
 -                         ObjectId => $args{'ObjectId'},
 -                         DelegatedBy => $args{'DelegatedBy'},
 -                         DelegatedFrom => $args{'DelegatedFrom'},
 -);
 +    my %args = (
 +        PrincipalId   => undef,
 +        PrincipalType => undef,
 +        RightName     => undef,
 +        Object        => undef,
 +        @_
 +    );
 +
 +    unless ( $args{'RightName'} ) {
 +        return ( 0, $self->loc('No right specified') );
 +    }
 +
 +    #if we haven't specified any sort of right, we're talking about a global right
 +    if (!defined $args{'Object'} && !defined $args{'ObjectId'} && !defined $args{'ObjectType'}) {
 +        $args{'Object'} = $RT::System;
 +    }
 +    ($args{'Object'}, $args{'ObjectType'}, $args{'ObjectId'}) = $self->_ParseObjectArg( %args );
 +    unless( $args{'Object'} ) {
 +	return ( 0, $self->loc("System error. Right not granted.") );
 +    }
 +
 +    # Validate the principal
 +    my $princ_obj;
 +    ( $princ_obj, $args{'PrincipalType'} ) =
 +      $self->_CanonicalizePrincipal( $args{'PrincipalId'},
 +                                     $args{'PrincipalType'} );
 +
 +    unless ( $princ_obj->id ) {
 +        return ( 0,
 +                 $self->loc( 'Principal [_1] not found.', $args{'PrincipalId'} )
 +        );
 +    }
 +
 +    # }}}
 +
 +    # Check the ACL
 +
 +    if (ref( $args{'Object'}) eq 'RT::Group' ) {
 +        unless ( $self->CurrentUser->HasRight( Object => $args{'Object'},
 +                                                  Right => 'AdminGroup' )
 +          ) {
 +            return ( 0, $self->loc('Permission Denied') );
 +        }
 +    }
 +
 +    else {
 +        unless ( $self->CurrentUser->HasRight( Object => $args{'Object'}, Right => 'ModifyACL' )) {
 +            return ( 0, $self->loc('Permission Denied') );
 +        }
 +    }
 +    # }}}
 +
 +    # Canonicalize and check the right name
 +    my $canonic_name = $self->CanonicalizeRightName( $args{'RightName'} );
 +    unless ( $canonic_name ) {
 +        return ( 0, $self->loc("Invalid right. Couldn't canonicalize right '[_1]'", $args{'RightName'}) );
 +    }
 +    $args{'RightName'} = $canonic_name;
 +
 +    #check if it's a valid RightName
 +    if ( $args{'Object'}->can('AvailableRights') ) {
 +        my $available = $args{'Object'}->AvailableRights;
 +        unless ( grep $_ eq $args{'RightName'}, map $self->CanonicalizeRightName( $_ ), keys %$available ) {
 +            $RT::Logger->warning(
 +                "Couldn't validate right name '$args{'RightName'}'"
 +                ." for object of ". ref( $args{'Object'} ) ." class"
 +            );
 +            return ( 0, $self->loc('Invalid right') );
 +        }
 +    }
 +    # }}}
 +
 +    # Make sure the right doesn't already exist.
 +    $self->LoadByCols( PrincipalId   => $princ_obj->id,
 +                       PrincipalType => $args{'PrincipalType'},
 +                       RightName     => $args{'RightName'},
 +                       ObjectType    => $args{'ObjectType'},
 +                       ObjectId      => $args{'ObjectId'},
 +                   );
 +    if ( $self->Id ) {
 +        return ( 0, $self->loc('That principal already has that right') );
 +    }
 +
 +    my $id = $self->SUPER::Create( PrincipalId   => $princ_obj->id,
 +                                   PrincipalType => $args{'PrincipalType'},
 +                                   RightName     => $args{'RightName'},
 +                                   ObjectType    => ref( $args{'Object'} ),
 +                                   ObjectId      => $args{'Object'}->id,
 +                               );
 +
 +    #Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
 +    RT::Principal->InvalidateACLCache();
 +
 +    if ( $id ) {
 +        return ( $id, $self->loc('Right Granted') );
 +    }
 +    else {
 +        return ( 0, $self->loc('System error. Right not granted.') );
 +    }
 +}
 +
 +
 +
 +=head2 Delete { InsideTransaction => undef}
 +
 +Delete this object. This method should ONLY ever be called from RT::User or RT::Group (or from itself)
 +If this is being called from within a transaction, specify a true value for the parameter InsideTransaction.
 +Really, DBIx::SearchBuilder should use and/or fake subtransactions
 +
 +This routine will also recurse and delete any delegations of this right
 +
 +=cut
 +
 +sub Delete {
 +    my $self = shift;
 +
 +    unless ( $self->Id ) {
 +        return ( 0, $self->loc('Right not loaded.') );
 +    }
 +
 +    # A user can delete an ACE if the current user has the right to modify it and it's not a delegated ACE
 +    # or if it's a delegated ACE and it was delegated by the current user
 +    unless ($self->CurrentUser->HasRight(Right => 'ModifyACL', Object => $self->Object)) {
 +        return ( 0, $self->loc('Permission Denied') );
 +    }
 +    $self->_Delete(@_);
 +}
 +
 +# Helper for Delete with no ACL check
 +sub _Delete {
 +    my $self = shift;
 +    my %args = ( InsideTransaction => undef,
 +                 @_ );
 +
 +    my $InsideTransaction = $args{'InsideTransaction'};
 +
 +    $RT::Handle->BeginTransaction() unless $InsideTransaction;
 +
 +    my ( $val, $msg ) = $self->SUPER::Delete(@_);
 +
 +    if ($val) {
 +	#Clear the key cache. TODO someday we may want to just clear a little bit of the keycache space. 
 +	# TODO what about the groups key cache?
 +	RT::Principal->InvalidateACLCache();
 +        $RT::Handle->Commit() unless $InsideTransaction;
 +        return ( $val, $self->loc('Right revoked') );
 +    }
 +
 +    $RT::Handle->Rollback() unless $InsideTransaction;
 +    return ( 0, $self->loc('Right could not be revoked') );
 +}
 +
 +
 +
 +=head2 _BootstrapCreate
 +
 +Grant a right with no error checking and no ACL. this is _only_ for 
 +installation. If you use this routine without the author's explicit 
 +written approval, he will hunt you down and make you spend eternity
 +translating mozilla's code into FORTRAN or intercal.
 +
 +If you think you need this routine, you've mistaken. 
 +
 +=cut
 +
 +sub _BootstrapCreate {
 +    my $self = shift;
 +    my %args = (@_);
 +
 +    # When bootstrapping, make sure we get the _right_ users
 +    if ( $args{'UserId'} ) {
 +        my $user = RT::User->new( $self->CurrentUser );
 +        $user->Load( $args{'UserId'} );
 +        delete $args{'UserId'};
 +        $args{'PrincipalId'}   = $user->PrincipalId;
 +        $args{'PrincipalType'} = 'User';
 +    }
 +
 +    my $id = $self->SUPER::Create(%args);
 +
 +    if ( $id > 0 ) {
 +        return ($id);
 +    }
 +    else {
 +        $RT::Logger->err('System error. right not granted.');
 +        return (undef);
 +    }
 +
 +}
 +
 +
 +
 +sub RightName {
 +    my $self = shift;
 +    my $val = $self->_Value('RightName');
 +    return $val unless $val;
 +
 +    my $available = $self->Object->AvailableRights;
 +    foreach my $right ( keys %$available ) {
 +        return $right if $val eq $self->CanonicalizeRightName($right);
 +    }
 +
 +    $RT::Logger->error("Invalid right. Couldn't canonicalize right '$val'");
 +    return $val;
 +}
 +
 +=head2 CanonicalizeRightName <RIGHT>
 +
 +Takes a queue or system right name in any case and returns it in
 +the correct case. If it's not found, will return undef.
 +
 +=cut
 +
 +sub CanonicalizeRightName {
 +    my $self  = shift;
 +    return $LOWERCASERIGHTNAMES{ lc shift };
 +}
 +
 +
 +
 +
 +=head2 Object
 +
 +If the object this ACE applies to is a queue, returns the queue object. 
 +If the object this ACE applies to is a group, returns the group object. 
 +If it's the system object, returns undef. 
 +
 +If the user has no rights, returns undef.
 +
 +=cut
 +
 +
 +
 +
 +sub Object {
 +    my $self = shift;
 +
 +    my $appliesto_obj;
 +
 +    if ($self->__Value('ObjectType') && $OBJECT_TYPES{$self->__Value('ObjectType')} ) {
 +        $appliesto_obj =  $self->__Value('ObjectType')->new($self->CurrentUser);
 +        unless (ref( $appliesto_obj) eq $self->__Value('ObjectType')) {
 +            return undef;
 +        }
 +        $appliesto_obj->Load( $self->__Value('ObjectId') );
 +        return ($appliesto_obj);
 +     }
 +    else {
 +        $RT::Logger->warning( "$self -> Object called for an object "
 +                              . "of an unknown type:"
 +                              . $self->__Value('ObjectType') );
 +        return (undef);
 +    }
 +}
 +
 +
 +
 +=head2 PrincipalObj
 +
 +Returns the RT::Principal object for this ACE. 
 +
 +=cut
 +
 +sub PrincipalObj {
 +    my $self = shift;
 +
 +    my $princ_obj = RT::Principal->new( $self->CurrentUser );
 +    $princ_obj->Load( $self->__Value('PrincipalId') );
 +
 +    unless ( $princ_obj->Id ) {
 +        $RT::Logger->err(
 +                   "ACE " . $self->Id . " couldn't load its principal object" );
 +    }
 +    return ($princ_obj);
 +
 +}
 +
  
 +
 +
 +sub _Set {
 +    my $self = shift;
 +    return ( 0, $self->loc("ACEs can only be created and deleted.") );
 +}
 +
 +
 +
 +sub _Value {
 +    my $self = shift;
 +
 +    if ( $self->PrincipalObj->IsGroup
 +            && $self->PrincipalObj->Object->HasMemberRecursively(
 +                                                $self->CurrentUser->PrincipalObj
 +            )
 +      ) {
 +        return ( $self->__Value(@_) );
 +    }
 +    elsif ( $self->CurrentUser->HasRight(Right => 'ShowACL', Object => $self->Object) ) {
 +        return ( $self->__Value(@_) );
 +    }
 +    else {
 +        return undef;
 +    }
 +}
 +
 +
 +
 +
 +
 +=head2 _CanonicalizePrincipal (PrincipalId, PrincipalType)
 +
 +Takes a principal id and a principal type.
 +
 +If the principal is a user, resolves it to the proper acl equivalence group.
 +Returns a tuple of  (RT::Principal, PrincipalType)  for the principal we really want to work with
 +
 +=cut
 +
 +sub _CanonicalizePrincipal {
 +    my $self       = shift;
 +    my $princ_id   = shift;
 +    my $princ_type = shift || '';
 +
 +    my $princ_obj = RT::Principal->new(RT->SystemUser);
 +    $princ_obj->Load($princ_id);
 +
 +    unless ( $princ_obj->Id ) {
 +        use Carp;
 +        $RT::Logger->crit(Carp::longmess);
 +        $RT::Logger->crit("Can't load a principal for id $princ_id");
 +        return ( $princ_obj, undef );
 +    }
 +
 +    # Rights never get granted to users. they get granted to their 
 +    # ACL equivalence groups
 +    if ( $princ_type eq 'User' ) {
 +        my $equiv_group = RT::Group->new( $self->CurrentUser );
 +        $equiv_group->LoadACLEquivalenceGroup($princ_obj);
 +        unless ( $equiv_group->Id ) {
 +            $RT::Logger->crit( "No ACL equiv group for princ " . $princ_obj->id );
 +            return ( RT::Principal->new(RT->SystemUser), undef );
 +        }
 +        $princ_obj  = $equiv_group->PrincipalObj();
 +        $princ_type = 'Group';
 +
 +    }
 +    return ( $princ_obj, $princ_type );
 +}
 +
 +sub _ParseObjectArg {
 +    my $self = shift;
 +    my %args = ( Object    => undef,
 +                 ObjectId    => undef,
 +                 ObjectType    => undef,
 +                 @_ );
 +
 +    if( $args{'Object'} && ($args{'ObjectId'} || $args{'ObjectType'}) ) {
 +	$RT::Logger->crit( "Method called with an ObjectType or an ObjectId and Object args" );
 +	return ();
-     } elsif( $args{'Object'} && !UNIVERSAL::can($args{'Object'},'id') ) {
++    } elsif( $args{'Object'} && ref($args{'Object'}) &&  !$args{'Object'}->can('id') ) {
 +	$RT::Logger->crit( "Method called called Object that has no id method" );
 +	return ();
 +    } elsif( $args{'Object'} ) {
 +	my $obj = $args{'Object'};
 +	return ($obj, ref $obj, $obj->id);
 +    } elsif ( $args{'ObjectType'} ) {
 +	my $obj =  $args{'ObjectType'}->new( $self->CurrentUser );
 +	$obj->Load( $args{'ObjectId'} );
 +	return ($obj, ref $obj, $obj->id);
 +    } else {
 +	$RT::Logger->crit( "Method called with wrong args" );
 +	return ();
 +    }
  }
  
  
diff --cc lib/RT/Interface/CLI.pm
index 1b044da,343edbf..643b205
mode 100644,100755..100644
--- a/lib/RT/Interface/CLI.pm
+++ b/lib/RT/Interface/CLI.pm
@@@ -195,9 -200,9 +195,9 @@@ sub GetMessageContent 
      
      #Load the sourcefile, if it's been handed to us
      if ($source) {
 -    open( SOURCE, '<', $source ) or die $!;
 +	open( SOURCE, '<', $source ) or die $!;
- 	@lines = (<SOURCE>);
- 	close (SOURCE);
+ 	@lines = (<SOURCE>) or die $!;
+ 	close (SOURCE) or die $!;
      }
      elsif ($args{'Content'}) {
  	@lines = split('\n',$args{'Content'});
diff --cc lib/RT/Interface/Email.pm
index d07f9ad,9e535f6..021c62d
mode 100644,100755..100644
--- a/lib/RT/Interface/Email.pm
+++ b/lib/RT/Interface/Email.pm
diff --cc lib/RT/Links.pm
index db23d98,bd0b297..3138315
mode 100644,100755..100644
--- a/lib/RT/Links.pm
+++ b/lib/RT/Links.pm
@@@ -60,61 -68,24 +60,50 @@@
  
  =head1 METHODS
  
 +
 +
  =cut
  
 +
  package RT::Links;
  
 -use RT::SearchBuilder;
 +use strict;
 +use warnings;
 +
 +
  use RT::Link;
  
 -use vars qw( @ISA );
 - at ISA= qw(RT::SearchBuilder);
 +use base 'RT::SearchBuilder';
  
 +sub Table { 'Links'}
  
 -sub _Init {
 -    my $self = shift;
 -    $self->{'table'} = 'Links';
 -    $self->{'primary_key'} = 'id';
  
 +use RT::URI;
  
 -    return ( $self->SUPER::_Init(@_) );
 +sub Limit  {
 +    my $self = shift;
 +    my %args = ( ENTRYAGGREGATOR => 'AND',
 +		 OPERATOR => '=',
 +		 @_);
-     
-     #if someone's trying to search for tickets, try to resolve the uris for searching.
-     
-     if (  ( $args{'OPERATOR'} eq '=') and
- 	      ( ( $args{'FIELD'}  eq 'Base') or ($args{'FIELD'} eq 'Target') )
-        ) {
- 	  my $dummy = RT::URI->new($self->CurrentUser);
- 	   $dummy->FromURI($args{'VALUE'});
- 	   # $uri = $dummy->URI;
-     }
- 
 +
 +    # If we're limiting by target, order by base
 +    # (Order by the thing that's changing)
 +
 +    if ( ($args{'FIELD'} eq 'Target') or 
 +	 ($args{'FIELD'} eq 'LocalTarget') ) {
 +	$self->OrderBy (ALIAS => 'main',
 +			FIELD => 'Base',
 +			ORDER => 'ASC');
 +    }
 +    elsif ( ($args{'FIELD'} eq 'Base') or 
 +	    ($args{'FIELD'} eq 'LocalBase') ) {
 +	$self->OrderBy (ALIAS => 'main',
 +			FIELD => 'Target',
 +			ORDER => 'ASC');
 +    }
 +    
 +
 +    $self->SUPER::Limit(%args);
  }
  
  
diff --cc lib/RT/Record.pm
index 26a8f2f,804adb8..8b987cc
mode 100644,100755..100644
--- a/lib/RT/Record.pm
+++ b/lib/RT/Record.pm
@@@ -722,8 -723,7 +722,8 @@@ Takes a potentially large attachment. R
  sub _EncodeLOB {
          my $self = shift;
          my $Body = shift;
-         my $MIMEType = shift;
+         my $MIMEType = shift || '';
 +        my $Filename = shift;
  
          my $ContentEncoding = 'none';
  
diff --cc lib/RT/User.pm
index 40855bd,af36c85..8a8e312
mode 100644,100755..100644
--- a/lib/RT/User.pm
+++ b/lib/RT/User.pm
@@@ -60,1525 -68,23 +60,1525 @@@
  
  =cut
  
 +
  package RT::User;
 -use RT::Record; 
  
 +use strict;
 +use warnings;
 +
 +
 +use base 'RT::Record';
 +
 +sub Table {'Users'}
 +
 +
 +
 +
 +
 +
 +use Digest::SHA;
 +use Digest::MD5;
 +use RT::Principals;
 +use RT::ACE;
 +use RT::Interface::Email;
 +use Encode;
 +use Text::Password::Pronounceable;
 +
 +sub _OverlayAccessible {
 +    {
 +
 +        Name                    => { public => 1,  admin => 1 },
 +          Password              => { read   => 0 },
 +          EmailAddress          => { public => 1 },
 +          Organization          => { public => 1,  admin => 1 },
 +          RealName              => { public => 1 },
 +          NickName              => { public => 1 },
 +          Lang                  => { public => 1 },
 +          EmailEncoding         => { public => 1 },
 +          WebEncoding           => { public => 1 },
 +          ExternalContactInfoId => { public => 1,  admin => 1 },
 +          ContactInfoSystem     => { public => 1,  admin => 1 },
 +          ExternalAuthId        => { public => 1,  admin => 1 },
 +          AuthSystem            => { public => 1,  admin => 1 },
 +          Gecos                 => { public => 1,  admin => 1 },
 +          PGPKey                => { public => 1,  admin => 1 },
 +
 +    }
 +}
 +
 +
 +
 +=head2 Create { PARAMHASH }
 +
 +
 +
 +=cut
 +
 +
 +sub Create {
 +    my $self = shift;
 +    my %args = (
 +        Privileged => 0,
 +        Disabled => 0,
 +        EmailAddress => '',
 +        _RecordTransaction => 1,
 +        @_    # get the real argumentlist
 +    );
 +
 +    # remove the value so it does not cripple SUPER::Create
 +    my $record_transaction = delete $args{'_RecordTransaction'};
 +
 +    #Check the ACL
 +    unless ( $self->CurrentUser->HasRight(Right => 'AdminUsers', Object => $RT::System) ) {
 +        return ( 0, $self->loc('Permission Denied') );
 +    }
 +
 +
 +    unless ($self->CanonicalizeUserInfo(\%args)) {
 +        return ( 0, $self->loc("Could not set user info") );
 +    }
 +
 +    $args{'EmailAddress'} = $self->CanonicalizeEmailAddress($args{'EmailAddress'});
 +
 +    # if the user doesn't have a name defined, set it to the email address
 +    $args{'Name'} = $args{'EmailAddress'} unless ($args{'Name'});
 +
 +
 +
 +    my $privileged = delete $args{'Privileged'};
 +
 +
 +    if ($args{'CryptedPassword'} ) {
 +        $args{'Password'} = $args{'CryptedPassword'};
 +        delete $args{'CryptedPassword'};
 +    } elsif ( !$args{'Password'} ) {
 +        $args{'Password'} = '*NO-PASSWORD*';
 +    } else {
 +        my ($ok, $msg) = $self->ValidatePassword($args{'Password'});
 +        return ($ok, $msg) if !$ok;
 +
 +        $args{'Password'} = $self->_GeneratePassword($args{'Password'});
 +    }
 +
 +    #TODO Specify some sensible defaults.
 +
 +    unless ( $args{'Name'} ) {
 +        return ( 0, $self->loc("Must specify 'Name' attribute") );
 +    }
 +
 +    #SANITY CHECK THE NAME AND ABORT IF IT'S TAKEN
 +    if (RT->SystemUser) {   #This only works if RT::SystemUser has been defined
 +        my $TempUser = RT::User->new(RT->SystemUser);
 +        $TempUser->Load( $args{'Name'} );
 +        return ( 0, $self->loc('Name in use') ) if ( $TempUser->Id );
 +
 +        my ($val, $message) = $self->ValidateEmailAddress( $args{'EmailAddress'} );
 +        return (0, $message) unless ( $val );
 +    } else {
 +        $RT::Logger->warning( "$self couldn't check for pre-existing users");
 +    }
 +
 +
 +    $RT::Handle->BeginTransaction();
 +    # Groups deal with principal ids, rather than user ids.
 +    # When creating this user, set up a principal Id for it.
 +    my $principal = RT::Principal->new($self->CurrentUser);
 +    my $principal_id = $principal->Create(PrincipalType => 'User',
 +                                Disabled => $args{'Disabled'},
 +                                ObjectId => '0');
 +    # If we couldn't create a principal Id, get the fuck out.
 +    unless ($principal_id) {
 +        $RT::Handle->Rollback();
 +        $RT::Logger->crit("Couldn't create a Principal on new user create.");
 +        $RT::Logger->crit("Strange things are afoot at the circle K");
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +    $principal->__Set(Field => 'ObjectId', Value => $principal_id);
 +    delete $args{'Disabled'};
 +
 +    $self->SUPER::Create(id => $principal_id , %args);
 +    my $id = $self->Id;
 +
 +    #If the create failed.
 +    unless ($id) {
 +        $RT::Handle->Rollback();
 +        $RT::Logger->error("Could not create a new user - " .join('-', %args));
 +
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +    my $aclstash = RT::Group->new($self->CurrentUser);
 +    my $stash_id = $aclstash->_CreateACLEquivalenceGroup($principal);
 +
 +    unless ($stash_id) {
 +        $RT::Handle->Rollback();
 +        $RT::Logger->crit("Couldn't stash the user in groupmembers");
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +
 +    my $everyone = RT::Group->new($self->CurrentUser);
 +    $everyone->LoadSystemInternalGroup('Everyone');
 +    unless ($everyone->id) {
 +        $RT::Logger->crit("Could not load Everyone group on user creation.");
 +        $RT::Handle->Rollback();
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +
 +    my ($everyone_id, $everyone_msg) = $everyone->_AddMember( InsideTransaction => 1, PrincipalId => $self->PrincipalId);
 +    unless ($everyone_id) {
 +        $RT::Logger->crit("Could not add user to Everyone group on user creation.");
 +        $RT::Logger->crit($everyone_msg);
 +        $RT::Handle->Rollback();
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +
 +    my $access_class = RT::Group->new($self->CurrentUser);
 +    if ($privileged)  {
 +        $access_class->LoadSystemInternalGroup('Privileged');
 +    } else {
 +        $access_class->LoadSystemInternalGroup('Unprivileged');
 +    }
 +
 +    unless ($access_class->id) {
 +        $RT::Logger->crit("Could not load Privileged or Unprivileged group on user creation");
 +        $RT::Handle->Rollback();
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +
 +    my ($ac_id, $ac_msg) = $access_class->_AddMember( InsideTransaction => 1, PrincipalId => $self->PrincipalId);
 +
 +    unless ($ac_id) {
 +        $RT::Logger->crit("Could not add user to Privileged or Unprivileged group on user creation. Aborted");
 +        $RT::Logger->crit($ac_msg);
 +        $RT::Handle->Rollback();
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +
 +    if ( $record_transaction ) {
 +        $self->_NewTransaction( Type => "Create" );
 +    }
 +
 +    $RT::Handle->Commit;
 +
 +    return ( $id, $self->loc('User created') );
 +}
 +
 +=head2 ValidatePassword STRING
 +
 +Returns either (0, "failure reason") or 1 depending on whether the given
 +password is valid.
 +
 +=cut
 +
 +sub ValidatePassword {
 +    my $self = shift;
 +    my $password = shift;
 +
 +    if ( length($password) < RT->Config->Get('MinimumPasswordLength') ) {
 +        return ( 0, $self->loc("Password needs to be at least [_1] characters long", RT->Config->Get('MinimumPasswordLength')) );
 +    }
 +
 +    return 1;
 +}
 +
 +=head2 SetPrivileged BOOL
 +
 +If passed a true value, makes this user a member of the "Privileged"  PseudoGroup.
 +Otherwise, makes this user a member of the "Unprivileged" pseudogroup.
 +
 +Returns a standard RT tuple of (val, msg);
 +
 +
 +=cut
 +
 +sub SetPrivileged {
 +    my $self = shift;
 +    my $val = shift;
 +
 +    #Check the ACL
 +    unless ( $self->CurrentUser->HasRight(Right => 'AdminUsers', Object => $RT::System) ) {
 +        return ( 0, $self->loc('Permission Denied') );
 +    }
 +
 +    $self->_SetPrivileged($val);
 +}
 +
 +sub _SetPrivileged {
 +    my $self = shift;
 +    my $val = shift;
 +    my $priv = RT::Group->new($self->CurrentUser);
 +    $priv->LoadSystemInternalGroup('Privileged');
 +    unless ($priv->Id) {
 +        $RT::Logger->crit("Could not find Privileged pseudogroup");
 +        return(0,$self->loc("Failed to find 'Privileged' users pseudogroup."));
 +    }
 +
 +    my $unpriv = RT::Group->new($self->CurrentUser);
 +    $unpriv->LoadSystemInternalGroup('Unprivileged');
 +    unless ($unpriv->Id) {
 +        $RT::Logger->crit("Could not find unprivileged pseudogroup");
 +        return(0,$self->loc("Failed to find 'Unprivileged' users pseudogroup"));
 +    }
 +
 +    my $principal = $self->PrincipalId;
 +    if ($val) {
 +        if ($priv->HasMember($principal)) {
 +            #$RT::Logger->debug("That user is already privileged");
 +            return (0,$self->loc("That user is already privileged"));
 +        }
 +        if ($unpriv->HasMember($principal)) {
 +            $unpriv->_DeleteMember($principal);
 +        } else {
 +        # if we had layered transactions, life would be good
 +        # sadly, we have to just go ahead, even if something
 +        # bogus happened
 +            $RT::Logger->crit("User ".$self->Id." is neither privileged nor ".
 +                "unprivileged. something is drastically wrong.");
 +        }
 +        my ($status, $msg) = $priv->_AddMember( InsideTransaction => 1, PrincipalId => $principal);
 +        if ($status) {
 +            return (1, $self->loc("That user is now privileged"));
 +        } else {
 +            return (0, $msg);
 +        }
 +    } else {
 +        if ($unpriv->HasMember($principal)) {
 +            #$RT::Logger->debug("That user is already unprivileged");
 +            return (0,$self->loc("That user is already unprivileged"));
 +        }
 +        if ($priv->HasMember($principal)) {
 +            $priv->_DeleteMember( $principal );
 +        } else {
 +        # if we had layered transactions, life would be good
 +        # sadly, we have to just go ahead, even if something
 +        # bogus happened
 +            $RT::Logger->crit("User ".$self->Id." is neither privileged nor ".
 +                "unprivileged. something is drastically wrong.");
 +        }
 +        my ($status, $msg) = $unpriv->_AddMember( InsideTransaction => 1, PrincipalId => $principal);
 +        if ($status) {
 +            return (1, $self->loc("That user is now unprivileged"));
 +        } else {
 +            return (0, $msg);
 +        }
 +    }
 +}
 +
 +=head2 Privileged
 +
 +Returns true if this user is privileged. Returns undef otherwise.
 +
 +=cut
 +
 +sub Privileged {
 +    my $self = shift;
 +    if ( RT->PrivilegedUsers->HasMember( $self->id ) ) {
 +        return(1);
 +    } else {
 +        return(undef);
 +    }
 +}
 +
 +#create a user without validating _any_ data.
 +
 +#To be used only on database init.
 +# We can't localize here because it's before we _have_ a loc framework
 +
 +sub _BootstrapCreate {
 +    my $self = shift;
 +    my %args = (@_);
 +
 +    $args{'Password'} = '*NO-PASSWORD*';
 +
 +
 +    $RT::Handle->BeginTransaction();
 +
 +    # Groups deal with principal ids, rather than user ids.
 +    # When creating this user, set up a principal Id for it.
 +    my $principal = RT::Principal->new($self->CurrentUser);
 +    my $principal_id = $principal->Create(PrincipalType => 'User', ObjectId => '0');
 +    $principal->__Set(Field => 'ObjectId', Value => $principal_id);
 +
 +    # If we couldn't create a principal Id, get the fuck out.
 +    unless ($principal_id) {
 +        $RT::Handle->Rollback();
 +        $RT::Logger->crit("Couldn't create a Principal on new user create. Strange things are afoot at the circle K");
 +        return ( 0, 'Could not create user' );
 +    }
 +    $self->SUPER::Create(id => $principal_id, %args);
 +    my $id = $self->Id;
 +    #If the create failed.
 +      unless ($id) {
 +      $RT::Handle->Rollback();
 +      return ( 0, 'Could not create user' ) ; #never loc this
 +    }
 +
 +    my $aclstash = RT::Group->new($self->CurrentUser);
 +    my $stash_id  = $aclstash->_CreateACLEquivalenceGroup($principal);
 +
 +    unless ($stash_id) {
 +        $RT::Handle->Rollback();
 +        $RT::Logger->crit("Couldn't stash the user in groupmembers");
 +        return ( 0, $self->loc('Could not create user') );
 +    }
 +
 +    $RT::Handle->Commit();
 +
 +    return ( $id, 'User created' );
 +}
 +
 +sub Delete {
 +    my $self = shift;
 +
 +    return ( 0, $self->loc('Deleting this object would violate referential integrity') );
 +
 +}
 +
 +=head2 Load
 +
 +Load a user object from the database. Takes a single argument.
 +If the argument is numerical, load by the column 'id'. If a user
 +object or its subclass passed then loads the same user by id.
 +Otherwise, load by the "Name" column which is the user's textual
 +username.
 +
 +=cut
 +
 +sub Load {
 +    my $self = shift;
 +    my $identifier = shift || return undef;
 +
 +    if ( $identifier !~ /\D/ ) {
 +        return $self->SUPER::LoadById( $identifier );
 +    } elsif ( UNIVERSAL::isa( $identifier, 'RT::User' ) ) {
 +        return $self->SUPER::LoadById( $identifier->Id );
 +    } else {
 +        return $self->LoadByCol( "Name", $identifier );
 +    }
 +}
 +
 +=head2 LoadByEmail
 +
 +Tries to load this user object from the database by the user's email address.
 +
 +=cut
 +
 +sub LoadByEmail {
 +    my $self    = shift;
 +    my $address = shift;
 +
 +    # Never load an empty address as an email address.
 +    unless ($address) {
 +        return (undef);
 +    }
 +
 +    $address = $self->CanonicalizeEmailAddress($address);
 +
 +    #$RT::Logger->debug("Trying to load an email address: $address");
 +    return $self->LoadByCol( "EmailAddress", $address );
 +}
 +
 +=head2 LoadOrCreateByEmail ADDRESS
 +
 +Attempts to find a user who has the provided email address. If that fails, creates an unprivileged user with
 +the provided email address and loads them. Address can be provided either as L<Email::Address> object
 +or string which is parsed using the module.
 +
 +Returns a tuple of the user's id and a status message.
 +0 will be returned in place of the user's id in case of failure.
 +
 +=cut
 +
 +sub LoadOrCreateByEmail {
 +    my $self = shift;
 +    my $email = shift;
 +
 +    my ($message, $name);
 +    if ( UNIVERSAL::isa( $email => 'Email::Address' ) ) {
 +        ($email, $name) = ($email->address, $email->phrase);
 +    } else {
 +        ($email, $name) = RT::Interface::Email::ParseAddressFromHeader( $email );
 +    }
 +
 +    $self->LoadByEmail( $email );
 +    $self->Load( $email ) unless $self->Id;
 +    $message = $self->loc('User loaded');
 +
 +    unless( $self->Id ) {
 +        my $val;
 +        ($val, $message) = $self->Create(
 +            Name         => $email,
 +            EmailAddress => $email,
 +            RealName     => $name,
 +            Privileged   => 0,
 +            Comments     => 'Autocreated when added as a watcher',
 +        );
 +        unless ( $val ) {
 +            # Deal with the race condition of two account creations at once
 +            $self->LoadByEmail( $email );
 +            unless ( $self->Id ) {
 +                sleep 5;
 +                $self->LoadByEmail( $email );
 +            }
 +            if ( $self->Id ) {
 +                $RT::Logger->error("Recovered from creation failure due to race condition");
 +                $message = $self->loc("User loaded");
 +            } else {
 +                $RT::Logger->crit("Failed to create user ". $email .": " .$message);
 +            }
 +        }
 +    }
 +    return (0, $message) unless $self->id;
 +    return ($self->Id, $message);
 +}
 +
 +=head2 ValidateEmailAddress ADDRESS
 +
 +Returns true if the email address entered is not in use by another user or is
 +undef or ''. Returns false if it's in use.
 +
 +=cut
 +
 +sub ValidateEmailAddress {
 +    my $self  = shift;
 +    my $Value = shift;
 +
 +    # if the email address is null, it's always valid
 +    return (1) if ( !$Value || $Value eq "" );
 +
 +    if ( RT->Config->Get('ValidateUserEmailAddresses') ) {
 +        # We only allow one valid email address
 +        my @addresses = Email::Address->parse($Value);
 +        return ( 0, $self->loc('Invalid syntax for email address') ) unless ( ( scalar (@addresses) == 1 ) && ( $addresses[0]->address ) );
 +    }
 +
 +
 +    my $TempUser = RT::User->new(RT->SystemUser);
 +    $TempUser->LoadByEmail($Value);
 +
 +    if ( $TempUser->id && ( !$self->id || $TempUser->id != $self->id ) )
 +    {    # if we found a user with that address
 +            # it's invalid to set this user's address to it
 +        return ( 0, $self->loc('Email address in use') );
 +    } else {    #it's a valid email address
 +        return (1);
 +    }
 +}
 +
 +=head2 SetEmailAddress
 +
 +Check to make sure someone else isn't using this email address already
 +so that a better email address can be returned
 +
 +=cut
 +
 +sub SetEmailAddress {
 +    my $self = shift;
 +    my $Value = shift;
 +
 +    my ($val, $message) = $self->ValidateEmailAddress( $Value );
 +    if ( $val ) {
 +        return $self->_Set( Field => 'EmailAddress', Value => $Value );
 +    } else {
 +        return ( 0, $message )
 +    }
 +
 +}
 +
 +=head2 EmailFrequency
 +
 +Takes optional Ticket argument in paramhash. Returns 'no email',
 +'squelched', 'daily', 'weekly' or empty string depending on
 +user preferences.
 +
 +=over 4
 +
 +=item 'no email' - user has no email, so can not recieve notifications.
 +
 +=item 'squelched' - returned only when Ticket argument is provided and
 +notifications to the user has been supressed for this ticket.
 +
 +=item 'daily' - retruned when user recieve daily messages digest instead
 +of immediate delivery.
 +
 +=item 'weekly' - previous, but weekly.
 +
 +=item empty string returned otherwise.
 +
 +=back
 +
 +=cut
 +
 +sub EmailFrequency {
 +    my $self = shift;
 +    my %args = (
 +        Ticket => undef,
 +        @_
 +    );
 +    return '' unless $self->id && $self->id != RT->Nobody->id
 +        && $self->id != RT->SystemUser->id;
 +    return 'no email address' unless my $email = $self->EmailAddress;
 +    return 'email disabled for ticket' if $args{'Ticket'} &&
 +        grep lc $email eq lc $_->Content, $args{'Ticket'}->SquelchMailTo;
 +    my $frequency = RT->Config->Get( 'EmailFrequency', $self ) || '';
 +    return 'daily' if $frequency =~ /daily/i;
 +    return 'weekly' if $frequency =~ /weekly/i;
 +    return '';
 +}
 +
 +=head2 CanonicalizeEmailAddress ADDRESS
 +
 +CanonicalizeEmailAddress converts email addresses into canonical form.
 +it takes one email address in and returns the proper canonical
 +form. You can dump whatever your proper local config is in here.  Note
 +that it may be called as a static method; in this case the first argument
 +is class name not an object.
 +
 +=cut
 +
 +sub CanonicalizeEmailAddress {
 +    my $self = shift;
 +    my $email = shift;
 +    # Example: the following rule would treat all email
 +    # coming from a subdomain as coming from second level domain
 +    # foo.com
 +    if ( my $match   = RT->Config->Get('CanonicalizeEmailAddressMatch') and
 +         my $replace = RT->Config->Get('CanonicalizeEmailAddressReplace') )
 +    {
 +        $email =~ s/$match/$replace/gi;
 +    }
 +    return ($email);
 +}
 +
 +=head2 CanonicalizeUserInfo HASH of ARGS
 +
 +CanonicalizeUserInfo can convert all User->Create options.
 +it takes a hashref of all the params sent to User->Create and
 +returns that same hash, by default nothing is done.
 +
 +This function is intended to allow users to have their info looked up via
 +an outside source and modified upon creation.
 +
 +=cut
 +
 +sub CanonicalizeUserInfo {
 +    my $self = shift;
 +    my $args = shift;
 +    my $success = 1;
 +
 +    return ($success);
 +}
 +
 +
 +=head2 Password and authentication related functions
 +
 +=head3 SetRandomPassword
 +
 +Takes no arguments. Returns a status code and a new password or an error message.
 +If the status is 1, the second value returned is the new password.
 +If the status is anything else, the new value returned is the error code.
 +
 +=cut
 +
 +sub SetRandomPassword {
 +    my $self = shift;
 +
 +    unless ( $self->CurrentUserCanModify('Password') ) {
 +        return ( 0, $self->loc("Permission Denied") );
 +    }
 +
 +
 +    my $min = ( RT->Config->Get('MinimumPasswordLength') > 6 ?  RT->Config->Get('MinimumPasswordLength') : 6);
 +    my $max = ( RT->Config->Get('MinimumPasswordLength') > 8 ?  RT->Config->Get('MinimumPasswordLength') : 8);
 +
 +    my $pass = $self->GenerateRandomPassword( $min, $max) ;
 +
 +    # If we have "notify user on
 +
 +    my ( $val, $msg ) = $self->SetPassword($pass);
 +
 +    #If we got an error return the error.
 +    return ( 0, $msg ) unless ($val);
 +
 +    #Otherwise, we changed the password, lets return it.
 +    return ( 1, $pass );
 +
 +}
 +
 +=head3 ResetPassword
 +
 +Returns status, [ERROR or new password].  Resets this user's password to
 +a randomly generated pronouncable password and emails them, using a
 +global template called "RT_PasswordChange", which can be overridden
 +with global templates "RT_PasswordChange_Privileged" or "RT_PasswordChange_NonPrivileged"
 +for privileged and Non-privileged users respectively.
 +
 +=cut
 +
 +sub ResetPassword {
 +    my $self = shift;
 +
 +    unless ( $self->CurrentUserCanModify('Password') ) {
 +        return ( 0, $self->loc("Permission Denied") );
 +    }
 +    my ( $status, $pass ) = $self->SetRandomPassword();
 +
 +    unless ($status) {
 +        return ( 0, "$pass" );
 +    }
 +
 +    my $ret = RT::Interface::Email::SendEmailUsingTemplate(
 +        To        => $self->EmailAddress,
 +        Template  => 'PasswordChange',
 +        Arguments => {
 +            NewPassword => $pass,
 +        },
 +    );
 +
 +    if ($ret) {
 +        return ( 1, $self->loc('New password notification sent') );
 +    } else {
 +        return ( 0, $self->loc('Notification could not be sent') );
 +    }
 +
 +}
 +
 +=head3 GenerateRandomPassword MIN_LEN and MAX_LEN
 +
 +Returns a random password between MIN_LEN and MAX_LEN characters long.
 +
 +=cut
 +
 +sub GenerateRandomPassword {
 +    my $self = shift;   # just to drop it
 +    return Text::Password::Pronounceable->generate(@_);
 +}
 +
 +sub SafeSetPassword {
 +    my $self = shift;
 +    my %args = (
 +        Current      => undef,
 +        New          => undef,
 +        Confirmation => undef,
 +        @_,
 +    );
 +    return (1) unless defined $args{'New'} && length $args{'New'};
 +
 +    my %cond = $self->CurrentUserRequireToSetPassword;
 +
 +    unless ( $cond{'CanSet'} ) {
 +        return (0, $self->loc('You can not set password.') .' '. $cond{'Reason'} );
 +    }
 +
 +    my $error = '';
 +    if ( $cond{'RequireCurrent'} && !$self->CurrentUser->IsPassword($args{'Current'}) ) {
 +        if ( defined $args{'Current'} && length $args{'Current'} ) {
 +            $error = $self->loc("Please enter your current password correctly.");
 +        } else {
 +            $error = $self->loc("Please enter your current password.");
 +        }
 +    } elsif ( $args{'New'} ne $args{'Confirmation'} ) {
 +        $error = $self->loc("Passwords do not match.");
 +    }
 +
 +    if ( $error ) {
 +        $error .= ' '. $self->loc('Password has not been set.');
 +        return (0, $error);
 +    }
 +
 +    return $self->SetPassword( $args{'New'} );
 +}
 +
 +=head3 SetPassword
 +
 +Takes a string. Checks the string's length and sets this user's password
 +to that string.
 +
 +=cut
 +
 +sub SetPassword {
 +    my $self     = shift;
 +    my $password = shift;
 +
 +    unless ( $self->CurrentUserCanModify('Password') ) {
 +        return ( 0, $self->loc('Password: Permission Denied') );
 +    }
 +
 +    if ( !$password ) {
 +        return ( 0, $self->loc("No password set") );
 +    } else {
 +        my ($val, $msg) = $self->ValidatePassword($password);
 +        return ($val, $msg) if !$val;
 +
 +        my $new = !$self->HasPassword;
 +        $password = $self->_GeneratePassword($password);
 +
 +        ( $val, $msg ) = $self->_Set(Field => 'Password', Value => $password);
 +        if ($val) {
 +            return ( 1, $self->loc("Password set") ) if $new;
 +            return ( 1, $self->loc("Password changed") );
 +        } else {
 +            return ( $val, $msg );
 +        }
 +    }
 +
 +}
 +
 +sub _GeneratePassword_sha512 {
 +    my $self = shift;
 +    my ($password, $salt) = @_;
 +
 +    # Generate a 16-character base64 salt
 +    unless ($salt) {
 +        $salt = "";
 +        $salt .= ("a".."z", "A".."Z","0".."9", "+", "/")[rand 64]
 +            for 1..16;
 +    }
 +
 +    my $sha = Digest::SHA->new(512);
 +    $sha->add($salt);
 +    $sha->add(encode_utf8($password));
 +    return join("!", "", "sha512", $salt, $sha->b64digest);
 +}
 +
 +=head3 _GeneratePassword PASSWORD [, SALT]
  
 -use vars qw( @ISA );
 - at ISA= qw( RT::Record );
 +Returns a string to store in the database.  This string takes the form:
  
 -sub _Init {
 -  my $self = shift; 
 +   !method!salt!hash
  
 -  $self->Table('Users');
 -  $self->SUPER::_Init(@_);
 +By default, the method is currently C<sha512>.
 +
 +=cut
 +
 +sub _GeneratePassword {
 +    my $self = shift;
 +    return $self->_GeneratePassword_sha512(@_);
 +}
 +
 +=head3 HasPassword
 +
 +Returns true if the user has a valid password, otherwise returns false.
 +
 +=cut
 +
 +sub HasPassword {
 +    my $self = shift;
 +    my $pwd = $self->__Value('Password');
 +    return undef if !defined $pwd
 +                    || $pwd eq ''
 +                    || $pwd eq '*NO-PASSWORD*';
 +    return 1;
 +}
 +
 +=head3 IsPassword
 +
 +Returns true if the passed in value is this user's password.
 +Returns undef otherwise.
 +
 +=cut
 +
 +sub IsPassword {
 +    my $self  = shift;
 +    my $value = shift;
 +
 +    #TODO there isn't any apparent way to legitimately ACL this
 +
 +    # RT does not allow null passwords
 +    if ( ( !defined($value) ) or ( $value eq '' ) ) {
 +        return (undef);
 +    }
 +
 +   if ( $self->PrincipalObj->Disabled ) {
 +        $RT::Logger->info(
 +            "Disabled user " . $self->Name . " tried to log in" );
 +        return (undef);
 +    }
 +
 +    unless ($self->HasPassword) {
 +        return(undef);
 +     }
 +
 +    my $stored = $self->__Value('Password');
 +    if ($stored =~ /^!/) {
 +        # If it's a new-style (>= RT 4.0) password, it starts with a '!'
 +        my (undef, $method, $salt, undef) = split /!/, $stored;
 +        if ($method eq "sha512") {
 +            return $self->_GeneratePassword_sha512($value, $salt) eq $stored;
 +        } else {
 +            $RT::Logger->warn("Unknown hash method $method");
 +            return 0;
 +        }
 +    } elsif (length $stored == 40) {
 +        # The truncated SHA256(salt,MD5(passwd)) form from 2010/12 is 40 characters long
 +        my $hash = MIME::Base64::decode_base64($stored);
 +        # Decoding yields 30 byes; first 4 are the salt, the rest are substr(SHA256,0,26)
 +        my $salt = substr($hash, 0, 4, "");
 +        return 0 unless substr(Digest::SHA::sha256($salt . Digest::MD5::md5($value)), 0, 26) eq $hash;
 +    } elsif (length $stored == 32) {
 +        # Hex nonsalted-md5
 +        return 0 unless Digest::MD5::md5_hex(encode_utf8($value)) eq $stored;
 +    } elsif (length $stored == 22) {
 +        # Base64 nonsalted-md5
 +        return 0 unless Digest::MD5::md5_base64(encode_utf8($value)) eq $stored;
 +    } elsif (length $stored == 13) {
 +        # crypt() output
 +        return 0 unless crypt(encode_utf8($value), $stored) eq $stored;
 +    } else {
 +        $RT::Logger->warn("Unknown password form");
 +        return 0;
 +    }
 +
 +    # We got here by validating successfully, but with a legacy
 +    # password form.  Update to the most recent form.
 +    my $obj = $self->isa("RT::CurrentUser") ? $self->UserObj : $self;
 +    $obj->_Set(Field => 'Password', Value =>  $self->_GeneratePassword($value) );
 +    return 1;
 +}
 +
 +sub CurrentUserRequireToSetPassword {
 +    my $self = shift;
 +
 +    my %res = (
 +        CanSet => 1,
 +        Reason => '',
 +        RequireCurrent => 1,
 +    );
 +
 +    if ( RT->Config->Get('WebExternalAuth')
 +        && !RT->Config->Get('WebFallbackToInternalAuth')
 +    ) {
 +        $res{'CanSet'} = 0;
 +        $res{'Reason'} = $self->loc("External authentication enabled.");
 +    } elsif ( !$self->CurrentUser->HasPassword ) {
 +        if ( $self->CurrentUser->id == ($self->id||0) ) {
 +            # don't require current password if user has no
 +            $res{'RequireCurrent'} = 0;
 +        } else {
 +            $res{'CanSet'} = 0;
 +            $res{'Reason'} = $self->loc("Your password is not set.");
 +        }
 +    }
 +
 +    return %res;
  }
  
 +=head3 AuthToken
  
 +Returns an authentication string associated with the user. This
 +string can be used to generate passwordless URLs to integrate
 +RT with services and programms like callendar managers, rss
 +readers and other.
 +
 +=cut
 +
 +sub AuthToken {
 +    my $self = shift;
 +    my $secret = $self->_Value( AuthToken => @_ );
 +    return $secret if $secret;
 +
 +    $secret = substr(Digest::MD5::md5_hex(time . {} . rand()),0,16);
 +
 +    my $tmp = RT::User->new( RT->SystemUser );
 +    $tmp->Load( $self->id );
 +    my ($status, $msg) = $tmp->SetAuthToken( $secret );
 +    unless ( $status ) {
 +        $RT::Logger->error( "Couldn't set auth token: $msg" );
 +        return undef;
 +    }
 +    return $secret;
 +}
 +
 +=head3 GenerateAuthToken
 +
 +Generate a random authentication string for the user.
 +
 +=cut
 +
 +sub GenerateAuthToken {
 +    my $self = shift;
 +    my $token = substr(Digest::MD5::md5_hex(time . {} . rand()),0,16);
 +    return $self->SetAuthToken( $token );
 +}
 +
 +=head3 GenerateAuthString
 +
 +Takes a string and returns back a hex hash string. Later you can use
 +this pair to make sure it's generated by this user using L</ValidateAuthString>
 +
 +=cut
 +
 +sub GenerateAuthString {
 +    my $self = shift;
 +    my $protect = shift;
 +
 +    my $str = $self->AuthToken . $protect;
 +    utf8::encode($str);
 +
 +    return substr(Digest::MD5::md5_hex($str),0,16);
 +}
 +
 +=head3 ValidateAuthString
 +
 +Takes auth string and protected string. Returns true is protected string
 +has been protected by user's L</AuthToken>. See also L</GenerateAuthString>.
 +
 +=cut
 +
 +sub ValidateAuthString {
 +    my $self = shift;
 +    my $auth_string = shift;
 +    my $protected = shift;
 +
 +    my $str = $self->AuthToken . $protected;
 +    utf8::encode( $str );
 +
 +    return $auth_string eq substr(Digest::MD5::md5_hex($str),0,16);
 +}
 +
 +=head2 SetDisabled
 +
 +Toggles the user's disabled flag.
 +If this flag is
 +set, all password checks for this user will fail. All ACL checks for this
 +user will fail. The user will appear in no user listings.
 +
 +=cut
 +
 +sub SetDisabled {
 +    my $self = shift;
 +    my $val = shift;
 +    unless ( $self->CurrentUser->HasRight(Right => 'AdminUsers', Object => $RT::System) ) {
 +        return (0, $self->loc('Permission Denied'));
 +    }
 +
 +    $RT::Handle->BeginTransaction();
 +    my $set_err = $self->PrincipalObj->SetDisabled($val);
 +    unless ($set_err) {
 +        $RT::Handle->Rollback();
 +        $RT::Logger->warning(sprintf("Couldn't %s user %s", ($val == 1) ? "disable" : "enable", $self->PrincipalObj->Id));
 +        return (undef);
 +    }
 +    $self->_NewTransaction( Type => ($val == 1) ? "Disabled" : "Enabled" );
 +
 +    $RT::Handle->Commit();
 +
 +    if ( $val == 1 ) {
 +        return (1, $self->loc("User disabled"));
 +    } else {
 +        return (1, $self->loc("User enabled"));
 +    }
 +
 +}
  
 +=head2 Disabled
 +
 +Returns true if user is disabled or false otherwise
 +
 +=cut
 +
 +sub Disabled {
 +    my $self = shift;
 +    return $self->PrincipalObj->Disabled(@_);
 +}
 +
 +=head2 PrincipalObj
 +
 +Returns the principal object for this user. returns an empty RT::Principal
 +if there's no principal object matching this user.
 +The response is cached. PrincipalObj should never ever change.
 +
 +=cut
 +
 +sub PrincipalObj {
 +    my $self = shift;
 +
 +    unless ( $self->id ) {
 +        $RT::Logger->error("Couldn't get principal for an empty user");
 +        return undef;
 +    }
 +
 +    if ( !$self->{_principal_obj} ) {
 +
 +        my $obj = RT::Principal->new( $self->CurrentUser );
 +        $obj->LoadById( $self->id );
 +        if (! $obj->id ) {
 +            $RT::Logger->crit( 'No principal for user #' . $self->id );
 +            return undef;
 +        } elsif ( $obj->PrincipalType ne 'User' ) {
 +            $RT::Logger->crit(   'User #' . $self->id . ' has principal of ' . $obj->PrincipalType . ' type' );
 +            return undef;
 +        }
 +        $self->{_principal_obj} = $obj;
 +    }
 +    return $self->{_principal_obj};
 +}
 +
 +
 +=head2 PrincipalId
 +
 +Returns this user's PrincipalId
 +
 +=cut
 +
 +sub PrincipalId {
 +    my $self = shift;
 +    return $self->Id;
 +}
 +
 +=head2 HasGroupRight
 +
 +Takes a paramhash which can contain
 +these items:
 +    GroupObj => RT::Group or Group => integer
 +    Right => 'Right'
 +
 +
 +Returns 1 if this user has the right specified in the paramhash for the Group
 +passed in.
 +
 +Returns undef if they don't.
 +
 +=cut
 +
 +sub HasGroupRight {
 +    my $self = shift;
 +    my %args = (
 +        GroupObj    => undef,
 +        Group       => undef,
 +        Right       => undef,
 +        @_
 +    );
 +
 +
 +    if ( defined $args{'Group'} ) {
 +        $args{'GroupObj'} = RT::Group->new( $self->CurrentUser );
 +        $args{'GroupObj'}->Load( $args{'Group'} );
 +    }
 +
 +    # Validate and load up the GroupId
 +    unless ( ( defined $args{'GroupObj'} ) and ( $args{'GroupObj'}->Id ) ) {
 +        return undef;
 +    }
 +
 +    # Figure out whether a user has the right we're asking about.
 +    my $retval = $self->HasRight(
 +        Object => $args{'GroupObj'},
 +        Right     => $args{'Right'},
 +    );
 +
 +    return ($retval);
 +}
 +
 +=head2 OwnGroups
 +
 +Returns a group collection object containing the groups of which this
 +user is a member.
 +
 +=cut
 +
 +sub OwnGroups {
 +    my $self = shift;
 +    my $groups = RT::Groups->new($self->CurrentUser);
 +    $groups->LimitToUserDefinedGroups;
 +    $groups->WithMember(
 +        PrincipalId => $self->Id,
 +        Recursively => 1
 +    );
 +    return $groups;
 +}
 +
 +=head2 HasRight
 +
 +Shim around PrincipalObj->HasRight. See L<RT::Principal>.
 +
 +=cut
 +
 +sub HasRight {
 +    my $self = shift;
 +    return $self->PrincipalObj->HasRight(@_);
 +}
 +
 +=head2 CurrentUserCanModify RIGHT
 +
 +If the user has rights for this object, either because
 +he has 'AdminUsers' or (if he's trying to edit himself and the right isn't an
 +admin right) 'ModifySelf', return 1. otherwise, return undef.
 +
 +=cut
 +
 +sub CurrentUserCanModify {
 +    my $self  = shift;
 +    my $field = shift;
 +
 +    if ( $self->CurrentUser->HasRight(Right => 'AdminUsers', Object => $RT::System) ) {
 +        return (1);
 +    }
 +
 +    #If the field is marked as an "administrators only" field,
 +    # don't let the user touch it.
 +    elsif ( $self->_Accessible( $field, 'admin' ) ) {
 +        return (undef);
 +    }
 +
 +    #If the current user is trying to modify themselves
 +    elsif ( ( $self->id == $self->CurrentUser->id )
 +        and ( $self->CurrentUser->HasRight(Right => 'ModifySelf', Object => $RT::System) ) )
 +    {
 +        return (1);
 +    }
 +
 +    #If we don't have a good reason to grant them rights to modify
 +    # by now, they lose
 +    else {
 +        return (undef);
 +    }
 +
 +}
  
 +=head2 CurrentUserHasRight
 +
 +Takes a single argument. returns 1 if $Self->CurrentUser
 +has the requested right. returns undef otherwise
 +
 +=cut
 +
 +sub CurrentUserHasRight {
 +    my $self  = shift;
 +    my $right = shift;
 +
 +    return ( $self->CurrentUser->HasRight(Right => $right, Object => $RT::System) );
 +}
 +
 +sub _PrefName {
 +    my $name = shift;
 +    if (ref $name) {
 +        $name = ref($name).'-'.$name->Id;
 +    }
 +
 +    return 'Pref-'.$name;
 +}
 +
 +=head2 Preferences NAME/OBJ DEFAULT
 +
 +Obtain user preferences associated with given object or name.
 +Returns DEFAULT if no preferences found.  If DEFAULT is a hashref,
 +override the entries with user preferences.
 +
 +=cut
 +
 +sub Preferences {
 +    my $self  = shift;
 +    my $name = _PrefName (shift);
 +    my $default = shift;
 +
 +    my $attr = RT::Attribute->new( $self->CurrentUser );
 +    $attr->LoadByNameAndObject( Object => $self, Name => $name );
 +
 +    my $content = $attr->Id ? $attr->Content : undef;
 +    unless ( ref $content eq 'HASH' ) {
 +        return defined $content ? $content : $default;
 +    }
 +
 +    if (ref $default eq 'HASH') {
 +        for (keys %$default) {
 +            exists $content->{$_} or $content->{$_} = $default->{$_};
 +        }
 +    } elsif (defined $default) {
 +        $RT::Logger->error("Preferences $name for user".$self->Id." is hash but default is not");
 +    }
 +    return $content;
 +}
 +
 +=head2 SetPreferences NAME/OBJ VALUE
 +
 +Set user preferences associated with given object or name.
 +
 +=cut
 +
 +sub SetPreferences {
 +    my $self = shift;
 +    my $name = _PrefName( shift );
 +    my $value = shift;
 +
 +    return (0, $self->loc("No permission to set preferences"))
 +        unless $self->CurrentUserCanModify('Preferences');
 +
 +    my $attr = RT::Attribute->new( $self->CurrentUser );
 +    $attr->LoadByNameAndObject( Object => $self, Name => $name );
 +    if ( $attr->Id ) {
 +        return $attr->SetContent( $value );
 +    } else {
 +        return $self->AddAttribute( Name => $name, Content => $value );
 +    }
 +}
 +
 +=head2 WatchedQueues ROLE_LIST
 +
 +Returns a RT::Queues object containing every queue watched by the user.
 +
 +Takes a list of roles which is some subset of ('Cc', 'AdminCc').  Defaults to:
 +
 +$user->WatchedQueues('Cc', 'AdminCc');
 +
 +=cut
 +
 +sub WatchedQueues {
 +
 +    my $self = shift;
 +    my @roles = @_ || ('Cc', 'AdminCc');
 +
 +    $RT::Logger->debug('WatcheQueues got user ' . $self->Name);
 +
 +    my $watched_queues = RT::Queues->new($self->CurrentUser);
 +
 +    my $group_alias = $watched_queues->Join(
 +                                             ALIAS1 => 'main',
 +                                             FIELD1 => 'id',
 +                                             TABLE2 => 'Groups',
 +                                             FIELD2 => 'Instance',
 +                                           );
 +
 +    $watched_queues->Limit(
 +                            ALIAS => $group_alias,
 +                            FIELD => 'Domain',
 +                            VALUE => 'RT::Queue-Role',
 +                            ENTRYAGGREGATOR => 'AND',
 +                          );
 +    if (grep { $_ eq 'Cc' } @roles) {
 +        $watched_queues->Limit(
 +                                SUBCLAUSE => 'LimitToWatchers',
 +                                ALIAS => $group_alias,
 +                                FIELD => 'Type',
 +                                VALUE => 'Cc',
 +                                ENTRYAGGREGATOR => 'OR',
 +                              );
 +    }
 +    if (grep { $_ eq 'AdminCc' } @roles) {
 +        $watched_queues->Limit(
 +                                SUBCLAUSE => 'LimitToWatchers',
 +                                ALIAS => $group_alias,
 +                                FIELD => 'Type',
 +                                VALUE => 'AdminCc',
 +                                ENTRYAGGREGATOR => 'OR',
 +                              );
 +    }
 +
 +    my $queues_alias = $watched_queues->Join(
 +                                              ALIAS1 => $group_alias,
 +                                              FIELD1 => 'id',
 +                                              TABLE2 => 'CachedGroupMembers',
 +                                              FIELD2 => 'GroupId',
 +                                            );
 +    $watched_queues->Limit(
 +                            ALIAS => $queues_alias,
 +                            FIELD => 'MemberId',
 +                            VALUE => $self->PrincipalId,
 +                          );
 +
 +    $RT::Logger->debug("WatchedQueues got " . $watched_queues->Count . " queues");
 +
 +    return $watched_queues;
 +
 +}
 +
 +sub _Set {
 +    my $self = shift;
 +
 +    my %args = (
 +        Field => undef,
 +        Value => undef,
 +    TransactionType   => 'Set',
 +    RecordTransaction => 1,
 +        @_
 +    );
 +
 +    # Nobody is allowed to futz with RT_System or Nobody
 +
 +    if ( ($self->Id == RT->SystemUser->Id )  ||
 +         ($self->Id == RT->Nobody->Id)) {
 +        return ( 0, $self->loc("Can not modify system users") );
 +    }
 +    unless ( $self->CurrentUserCanModify( $args{'Field'} ) ) {
 +        return ( 0, $self->loc("Permission Denied") );
 +    }
 +
 +    my $Old = $self->SUPER::_Value("$args{'Field'}");
 +
 +    my ($ret, $msg) = $self->SUPER::_Set( Field => $args{'Field'},
 +                      Value => $args{'Value'} );
 +
 +    #If we can't actually set the field to the value, don't record
 +    # a transaction. instead, get out of here.
 +    if ( $ret == 0 ) { return ( 0, $msg ); }
 +
 +    if ( $args{'RecordTransaction'} == 1 ) {
 +
 +        my ( $Trans, $Msg, $TransObj ) = $self->_NewTransaction(
 +                                               Type => $args{'TransactionType'},
 +                                               Field     => $args{'Field'},
 +                                               NewValue  => $args{'Value'},
 +                                               OldValue  => $Old,
 +                                               TimeTaken => $args{'TimeTaken'},
 +        );
 +        return ( $Trans, scalar $TransObj->BriefDescription );
 +    } else {
 +        return ( $ret, $msg );
 +    }
 +}
 +
 +=head2 _Value
 +
 +Takes the name of a table column.
 +Returns its value as a string, if the user passes an ACL check
 +
 +=cut
 +
 +sub _Value {
 +
 +    my $self  = shift;
 +    my $field = shift;
 +
 +    #if the field is public, return it.
 +    if ( $self->_Accessible( $field, 'public' ) ) {
 +        return ( $self->SUPER::_Value($field) );
 +
 +    }
 +
 +    #If the user wants to see their own values, let them
 +    # TODO figure ouyt a better way to deal with this
 +    elsif ( defined($self->Id) && $self->CurrentUser->Id == $self->Id ) {
 +        return ( $self->SUPER::_Value($field) );
 +    }
 +
 +    #If the user has the admin users right, return the field
 +    elsif ( $self->CurrentUser->HasRight(Right =>'AdminUsers', Object => $RT::System) ) {
 +        return ( $self->SUPER::_Value($field) );
 +    } else {
 +        return (undef);
 +    }
 +
 +}
 +
 +=head2 FriendlyName
 +
 +Return the friendly name
 +
 +=cut
 +
 +sub FriendlyName {
 +    my $self = shift;
 +    return $self->RealName if defined($self->RealName);
 +    return $self->Name if defined($self->Name);
 +    return "";
 +}
 +
 +=head2 PreferredKey
 +
 +Returns the preferred key of the user. If none is set, then this will query
 +GPG and set the preferred key to the maximally trusted key found (and then
 +return it). Returns C<undef> if no preferred key can be found.
 +
 +=cut
 +
 +sub PreferredKey
 +{
 +    my $self = shift;
 +    return undef unless RT->Config->Get('GnuPG')->{'Enable'};
 +
 +    if ( ($self->CurrentUser->Id != $self->Id )  &&
 +          !$self->CurrentUser->HasRight(Right =>'AdminUsers', Object => $RT::System) ) {
 +          return undef;
 +    }
 +
 +
 +
 +    my $prefkey = $self->FirstAttribute('PreferredKey');
 +    return $prefkey->Content if $prefkey;
 +
 +    # we don't have a preferred key for this user, so now we must query GPG
 +    require RT::Crypt::GnuPG;
 +    my %res = RT::Crypt::GnuPG::GetKeysForEncryption($self->EmailAddress);
 +    return undef unless defined $res{'info'};
 +    my @keys = @{ $res{'info'} };
 +    return undef if @keys == 0;
 +
 +    if (@keys == 1) {
 +        $prefkey = $keys[0]->{'Fingerprint'};
 +    } else {
 +        # prefer the maximally trusted key
 +        @keys = sort { $b->{'TrustLevel'} <=> $a->{'TrustLevel'} } @keys;
 +        $prefkey = $keys[0]->{'Fingerprint'};
 +    }
 +
 +    $self->SetAttribute(Name => 'PreferredKey', Content => $prefkey);
 +    return $prefkey;
 +}
 +
 +sub PrivateKey {
 +    my $self = shift;
 +
 +
 +    #If the user wants to see their own values, let them.
 +    #If the user is an admin, let them.
 +    #Otherwwise, don't let them.
 +    #
 +    if ( ($self->CurrentUser->Id != $self->Id )  &&
 +          !$self->CurrentUser->HasRight(Right =>'AdminUsers', Object => $RT::System) ) {
 +          return undef;
 +    }
 +
 +    my $key = $self->FirstAttribute('PrivateKey') or return undef;
 +    return $key->Content;
 +}
 +
 +sub SetPrivateKey {
 +    my $self = shift;
 +    my $key = shift;
 +
 +    unless ($self->CurrentUserCanModify('PrivateKey')) {
 +        return (0, $self->loc("Permission Denied"));
 +    }
 +
 +    unless ( $key ) {
 +        my ($status, $msg) = $self->DeleteAttribute('PrivateKey');
 +        unless ( $status ) {
 +            $RT::Logger->error( "Couldn't delete attribute: $msg" );
 +            return ($status, $self->loc("Couldn't unset private key"));
 +        }
 +        return ($status, $self->loc("Unset private key"));
 +    }
 +
 +    # check that it's really private key
 +    {
 +        my %tmp = RT::Crypt::GnuPG::GetKeysForSigning( $key );
 +        return (0, $self->loc("No such key or it's not suitable for signing"))
 +            if $tmp{'exit_code'} || !$tmp{'info'};
 +    }
 +
 +    my ($status, $msg) = $self->SetAttribute(
 +        Name => 'PrivateKey',
 +        Content => $key,
 +    );
 +    return ($status, $self->loc("Couldn't set private key"))
 +        unless $status;
-     return ($status, $self->loc("Unset private key"));
++    return ($status, $self->loc("Set private key"));
 +}
 +
 +sub BasicColumns {
 +    (
 +    [ Name => 'Username' ],
 +    [ EmailAddress => 'Email' ],
 +    [ RealName => 'Name' ],
 +    [ Organization => 'Organization' ],
 +    );
 +}
  
  =head2 Create PARAMHASH
  

commit 01b89391ecb9ae2c65ffca99cfa25f9299ca59fc
Merge: 316384d ae8e19a
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Thu Mar 3 04:49:19 2011 -0500

    Merge branch '4.0.0-releng' into 4.0-trunk


-----------------------------------------------------------------------


More information about the Rt-commit mailing list