activeldap3 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. data/.gitignore +6 -0
  2. data/CHANGES +691 -0
  3. data/COPYING +340 -0
  4. data/LICENSE +58 -0
  5. data/README +154 -0
  6. data/Rakefile +121 -0
  7. data/TODO +32 -0
  8. data/activeldap3.gemspec +18 -0
  9. data/benchmark/bench-al.rb +263 -0
  10. data/benchmark/config.yaml.sample +5 -0
  11. data/examples/al-admin/README +182 -0
  12. data/examples/al-admin/Rakefile +16 -0
  13. data/examples/al-admin/app/controllers/account_controller.rb +60 -0
  14. data/examples/al-admin/app/controllers/application_controller.rb +46 -0
  15. data/examples/al-admin/app/controllers/attributes_controller.rb +17 -0
  16. data/examples/al-admin/app/controllers/directory_controller.rb +49 -0
  17. data/examples/al-admin/app/controllers/object_classes_controller.rb +17 -0
  18. data/examples/al-admin/app/controllers/syntaxes_controller.rb +17 -0
  19. data/examples/al-admin/app/controllers/users_controller.rb +66 -0
  20. data/examples/al-admin/app/controllers/welcome_controller.rb +12 -0
  21. data/examples/al-admin/app/helpers/account_helper.rb +2 -0
  22. data/examples/al-admin/app/helpers/application_helper.rb +46 -0
  23. data/examples/al-admin/app/helpers/attributes_helper.rb +15 -0
  24. data/examples/al-admin/app/helpers/directory_helper.rb +7 -0
  25. data/examples/al-admin/app/helpers/object_classes_helper.rb +10 -0
  26. data/examples/al-admin/app/helpers/syntaxes_helper.rb +10 -0
  27. data/examples/al-admin/app/helpers/url_helper.rb +17 -0
  28. data/examples/al-admin/app/helpers/users_helper.rb +17 -0
  29. data/examples/al-admin/app/helpers/welcome_helper.rb +2 -0
  30. data/examples/al-admin/app/models/entry.rb +23 -0
  31. data/examples/al-admin/app/models/ldap_user.rb +58 -0
  32. data/examples/al-admin/app/models/user.rb +91 -0
  33. data/examples/al-admin/app/views/_entry/_attributes_information.html.erb +29 -0
  34. data/examples/al-admin/app/views/_entry/_entry.html.erb +15 -0
  35. data/examples/al-admin/app/views/_schema/_aliases.html.erb +7 -0
  36. data/examples/al-admin/app/views/_switcher/_after.html.erb +2 -0
  37. data/examples/al-admin/app/views/_switcher/_before.html.erb +5 -0
  38. data/examples/al-admin/app/views/account/login.html.erb +26 -0
  39. data/examples/al-admin/app/views/account/sign_up.html.erb +29 -0
  40. data/examples/al-admin/app/views/attributes/_attributes.html.erb +19 -0
  41. data/examples/al-admin/app/views/attributes/_detail.html.erb +29 -0
  42. data/examples/al-admin/app/views/attributes/index.html.erb +3 -0
  43. data/examples/al-admin/app/views/attributes/show.html.erb +31 -0
  44. data/examples/al-admin/app/views/directory/_tree.html.erb +10 -0
  45. data/examples/al-admin/app/views/directory/_tree_view_js.html.erb +25 -0
  46. data/examples/al-admin/app/views/directory/index.html.erb +13 -0
  47. data/examples/al-admin/app/views/directory/populate.html.erb +2 -0
  48. data/examples/al-admin/app/views/layouts/_footer.html.erb +11 -0
  49. data/examples/al-admin/app/views/layouts/_header_menu.html.erb +10 -0
  50. data/examples/al-admin/app/views/layouts/_main_menu.html.erb +18 -0
  51. data/examples/al-admin/app/views/layouts/application.html.erb +57 -0
  52. data/examples/al-admin/app/views/object_classes/_attributes.html.erb +28 -0
  53. data/examples/al-admin/app/views/object_classes/_object_classes.html.erb +19 -0
  54. data/examples/al-admin/app/views/object_classes/index.html.erb +3 -0
  55. data/examples/al-admin/app/views/object_classes/show.html.erb +39 -0
  56. data/examples/al-admin/app/views/syntaxes/_detail.html.erb +14 -0
  57. data/examples/al-admin/app/views/syntaxes/_syntaxes.html.erb +19 -0
  58. data/examples/al-admin/app/views/syntaxes/index.html.erb +3 -0
  59. data/examples/al-admin/app/views/syntaxes/show.html.erb +22 -0
  60. data/examples/al-admin/app/views/users/_attributes_update_form.html.erb +42 -0
  61. data/examples/al-admin/app/views/users/_form.html.erb +13 -0
  62. data/examples/al-admin/app/views/users/_object_classes_update_form.html.erb +46 -0
  63. data/examples/al-admin/app/views/users/_password_change_form.html.erb +20 -0
  64. data/examples/al-admin/app/views/users/edit.html.erb +15 -0
  65. data/examples/al-admin/app/views/users/index.html.erb +10 -0
  66. data/examples/al-admin/app/views/users/show.html.erb +11 -0
  67. data/examples/al-admin/app/views/welcome/index.html.erb +13 -0
  68. data/examples/al-admin/config.ru +7 -0
  69. data/examples/al-admin/config/boot.rb +110 -0
  70. data/examples/al-admin/config/database.yml.example +19 -0
  71. data/examples/al-admin/config/environment.rb +73 -0
  72. data/examples/al-admin/config/environments/development.rb +17 -0
  73. data/examples/al-admin/config/environments/production.rb +24 -0
  74. data/examples/al-admin/config/environments/test.rb +22 -0
  75. data/examples/al-admin/config/initializers/exception_notifier.rb +2 -0
  76. data/examples/al-admin/config/initializers/fast_gettext.rb +3 -0
  77. data/examples/al-admin/config/initializers/inflections.rb +10 -0
  78. data/examples/al-admin/config/initializers/mime_types.rb +5 -0
  79. data/examples/al-admin/config/initializers/session_store.rb +23 -0
  80. data/examples/al-admin/config/ldap.yml.example +21 -0
  81. data/examples/al-admin/config/routes.rb +58 -0
  82. data/examples/al-admin/db/migrate/001_create_users.rb +16 -0
  83. data/examples/al-admin/doc/README_FOR_APP +2 -0
  84. data/examples/al-admin/lib/authenticated_system.rb +124 -0
  85. data/examples/al-admin/lib/authenticated_test_helper.rb +113 -0
  86. data/examples/al-admin/lib/ldap_test_helper.rb +38 -0
  87. data/examples/al-admin/lib/tasks/testing.rake +10 -0
  88. data/examples/al-admin/po/en/al-admin.po +343 -0
  89. data/examples/al-admin/po/ja/al-admin.po +343 -0
  90. data/examples/al-admin/po/nl/al-admin.po +380 -0
  91. data/examples/al-admin/public/.htaccess +40 -0
  92. data/examples/al-admin/public/404.html +30 -0
  93. data/examples/al-admin/public/500.html +30 -0
  94. data/examples/al-admin/public/dispatch.cgi +10 -0
  95. data/examples/al-admin/public/dispatch.fcgi +24 -0
  96. data/examples/al-admin/public/dispatch.rb +10 -0
  97. data/examples/al-admin/public/favicon.ico +0 -0
  98. data/examples/al-admin/public/images/active-ldap.svg +6351 -0
  99. data/examples/al-admin/public/images/al-admin.png +0 -0
  100. data/examples/al-admin/public/images/al-admin.svg +6371 -0
  101. data/examples/al-admin/public/images/header-background.png +0 -0
  102. data/examples/al-admin/public/images/header-background.svg +99 -0
  103. data/examples/al-admin/public/images/rails.png +0 -0
  104. data/examples/al-admin/public/images/spinelz/accordion_tab_left_active.gif +0 -0
  105. data/examples/al-admin/public/images/spinelz/accordion_tab_left_inactive.gif +0 -0
  106. data/examples/al-admin/public/images/spinelz/accordion_tab_middle_active.gif +0 -0
  107. data/examples/al-admin/public/images/spinelz/accordion_tab_middle_inactive.gif +0 -0
  108. data/examples/al-admin/public/images/spinelz/accordion_tab_right_active.gif +0 -0
  109. data/examples/al-admin/public/images/spinelz/accordion_tab_right_inactive.gif +0 -0
  110. data/examples/al-admin/public/images/spinelz/balloon_back.gif +0 -0
  111. data/examples/al-admin/public/images/spinelz/balloon_bottom_left.gif +0 -0
  112. data/examples/al-admin/public/images/spinelz/balloon_bottom_middle.gif +0 -0
  113. data/examples/al-admin/public/images/spinelz/balloon_bottom_right.gif +0 -0
  114. data/examples/al-admin/public/images/spinelz/balloon_left_down_arrow.gif +0 -0
  115. data/examples/al-admin/public/images/spinelz/balloon_left_up_arrow.gif +0 -0
  116. data/examples/al-admin/public/images/spinelz/balloon_middle_left.gif +0 -0
  117. data/examples/al-admin/public/images/spinelz/balloon_middle_right.gif +0 -0
  118. data/examples/al-admin/public/images/spinelz/balloon_right_down_arrow.gif +0 -0
  119. data/examples/al-admin/public/images/spinelz/balloon_right_up_arrow.gif +0 -0
  120. data/examples/al-admin/public/images/spinelz/balloon_top_left.gif +0 -0
  121. data/examples/al-admin/public/images/spinelz/balloon_top_middle.gif +0 -0
  122. data/examples/al-admin/public/images/spinelz/balloon_top_right.gif +0 -0
  123. data/examples/al-admin/public/images/spinelz/barchart_h.gif +0 -0
  124. data/examples/al-admin/public/images/spinelz/barchart_v.gif +0 -0
  125. data/examples/al-admin/public/images/spinelz/button.gif +0 -0
  126. data/examples/al-admin/public/images/spinelz/calendar_default_handler.gif +0 -0
  127. data/examples/al-admin/public/images/spinelz/calendar_delete.gif +0 -0
  128. data/examples/al-admin/public/images/spinelz/calendar_next.gif +0 -0
  129. data/examples/al-admin/public/images/spinelz/calendar_next_second.gif +0 -0
  130. data/examples/al-admin/public/images/spinelz/calendar_pre.gif +0 -0
  131. data/examples/al-admin/public/images/spinelz/calendar_pre_second.gif +0 -0
  132. data/examples/al-admin/public/images/spinelz/calendar_private_icon.gif +0 -0
  133. data/examples/al-admin/public/images/spinelz/calendar_schedule.gif +0 -0
  134. data/examples/al-admin/public/images/spinelz/calender_back.gif +0 -0
  135. data/examples/al-admin/public/images/spinelz/calender_back_second.gif +0 -0
  136. data/examples/al-admin/public/images/spinelz/datepicker2_back.gif +0 -0
  137. data/examples/al-admin/public/images/spinelz/datepicker2_back_second.gif +0 -0
  138. data/examples/al-admin/public/images/spinelz/datepicker2_next.gif +0 -0
  139. data/examples/al-admin/public/images/spinelz/datepicker2_next_second.gif +0 -0
  140. data/examples/al-admin/public/images/spinelz/datepicker2_pre.gif +0 -0
  141. data/examples/al-admin/public/images/spinelz/datepicker2_pre_second.gif +0 -0
  142. data/examples/al-admin/public/images/spinelz/datepicker_back.gif +0 -0
  143. data/examples/al-admin/public/images/spinelz/datepicker_back_second.gif +0 -0
  144. data/examples/al-admin/public/images/spinelz/datepicker_next.gif +0 -0
  145. data/examples/al-admin/public/images/spinelz/datepicker_next_second.gif +0 -0
  146. data/examples/al-admin/public/images/spinelz/datepicker_pre.gif +0 -0
  147. data/examples/al-admin/public/images/spinelz/datepicker_pre_second.gif +0 -0
  148. data/examples/al-admin/public/images/spinelz/grid_down.gif +0 -0
  149. data/examples/al-admin/public/images/spinelz/grid_state.gif +0 -0
  150. data/examples/al-admin/public/images/spinelz/grid_up.gif +0 -0
  151. data/examples/al-admin/public/images/spinelz/icon_day.gif +0 -0
  152. data/examples/al-admin/public/images/spinelz/icon_month.gif +0 -0
  153. data/examples/al-admin/public/images/spinelz/icon_week.gif +0 -0
  154. data/examples/al-admin/public/images/spinelz/menubar_back.gif +0 -0
  155. data/examples/al-admin/public/images/spinelz/menubar_subcontents_back.gif +0 -0
  156. data/examples/al-admin/public/images/spinelz/navPanel_tab_left_active.gif +0 -0
  157. data/examples/al-admin/public/images/spinelz/navPanel_tab_left_inactive.gif +0 -0
  158. data/examples/al-admin/public/images/spinelz/navPanel_tab_middle_active.gif +0 -0
  159. data/examples/al-admin/public/images/spinelz/navPanel_tab_middle_inactive.gif +0 -0
  160. data/examples/al-admin/public/images/spinelz/navPanel_tab_right_active.gif +0 -0
  161. data/examples/al-admin/public/images/spinelz/navPanel_tab_right_inactive.gif +0 -0
  162. data/examples/al-admin/public/images/spinelz/select_date.gif +0 -0
  163. data/examples/al-admin/public/images/spinelz/selectabletable_selected.gif +0 -0
  164. data/examples/al-admin/public/images/spinelz/sideBarBox_about.gif +0 -0
  165. data/examples/al-admin/public/images/spinelz/sideBarBox_menu.gif +0 -0
  166. data/examples/al-admin/public/images/spinelz/sideBarBox_sample.gif +0 -0
  167. data/examples/al-admin/public/images/spinelz/sideBarBox_tabBottomActive.gif +0 -0
  168. data/examples/al-admin/public/images/spinelz/sideBarBox_tabBottomInactive.gif +0 -0
  169. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleActive.gif +0 -0
  170. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleActive2.gif +0 -0
  171. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleInactive.gif +0 -0
  172. data/examples/al-admin/public/images/spinelz/sideBarBox_tabMiddleInactive2.gif +0 -0
  173. data/examples/al-admin/public/images/spinelz/sideBarBox_tabTopActive.gif +0 -0
  174. data/examples/al-admin/public/images/spinelz/sideBarBox_tabTopInactive.gif +0 -0
  175. data/examples/al-admin/public/images/spinelz/sideBarBox_tabbar.gif +0 -0
  176. data/examples/al-admin/public/images/spinelz/sortableTable_down.gif +0 -0
  177. data/examples/al-admin/public/images/spinelz/sortableTable_normal.gif +0 -0
  178. data/examples/al-admin/public/images/spinelz/sortableTable_up.gif +0 -0
  179. data/examples/al-admin/public/images/spinelz/switcher_close.gif +0 -0
  180. data/examples/al-admin/public/images/spinelz/switcher_open.gif +0 -0
  181. data/examples/al-admin/public/images/spinelz/tabBox_close.gif +0 -0
  182. data/examples/al-admin/public/images/spinelz/tabBox_tabLeftActive.gif +0 -0
  183. data/examples/al-admin/public/images/spinelz/tabBox_tabLeftInactive.gif +0 -0
  184. data/examples/al-admin/public/images/spinelz/tabBox_tabMiddleActive.gif +0 -0
  185. data/examples/al-admin/public/images/spinelz/tabBox_tabMiddleInactive.gif +0 -0
  186. data/examples/al-admin/public/images/spinelz/tabBox_tabRightActive.gif +0 -0
  187. data/examples/al-admin/public/images/spinelz/tabBox_tabRightInactive.gif +0 -0
  188. data/examples/al-admin/public/images/spinelz/tab_bar.gif +0 -0
  189. data/examples/al-admin/public/images/spinelz/table_back.gif +0 -0
  190. data/examples/al-admin/public/images/spinelz/timepicker_clock.gif +0 -0
  191. data/examples/al-admin/public/images/spinelz/toolbar_close.gif +0 -0
  192. data/examples/al-admin/public/images/spinelz/toolbar_left.gif +0 -0
  193. data/examples/al-admin/public/images/spinelz/toolbar_max.gif +0 -0
  194. data/examples/al-admin/public/images/spinelz/toolbar_middle.gif +0 -0
  195. data/examples/al-admin/public/images/spinelz/toolbar_min.gif +0 -0
  196. data/examples/al-admin/public/images/spinelz/toolbar_next.gif +0 -0
  197. data/examples/al-admin/public/images/spinelz/toolbar_right.gif +0 -0
  198. data/examples/al-admin/public/images/spinelz/treeview_dir.gif +0 -0
  199. data/examples/al-admin/public/images/spinelz/treeview_file.gif +0 -0
  200. data/examples/al-admin/public/images/spinelz/treeview_group.gif +0 -0
  201. data/examples/al-admin/public/images/spinelz/treeview_group_special.gif +0 -0
  202. data/examples/al-admin/public/images/spinelz/treeview_state.gif +0 -0
  203. data/examples/al-admin/public/images/spinelz/treeview_user.gif +0 -0
  204. data/examples/al-admin/public/images/spinelz/window_bottom_left.gif +0 -0
  205. data/examples/al-admin/public/images/spinelz/window_bottom_middle.gif +0 -0
  206. data/examples/al-admin/public/images/spinelz/window_bottom_right.gif +0 -0
  207. data/examples/al-admin/public/images/spinelz/window_close.gif +0 -0
  208. data/examples/al-admin/public/images/spinelz/window_max.gif +0 -0
  209. data/examples/al-admin/public/images/spinelz/window_middle_left.gif +0 -0
  210. data/examples/al-admin/public/images/spinelz/window_middle_right.gif +0 -0
  211. data/examples/al-admin/public/images/spinelz/window_min.gif +0 -0
  212. data/examples/al-admin/public/images/spinelz/window_top_left.gif +0 -0
  213. data/examples/al-admin/public/images/spinelz/window_top_middle.gif +0 -0
  214. data/examples/al-admin/public/images/spinelz/window_top_right.gif +0 -0
  215. data/examples/al-admin/public/javascripts/application.js +2 -0
  216. data/examples/al-admin/public/javascripts/controls.js +963 -0
  217. data/examples/al-admin/public/javascripts/dragdrop.js +973 -0
  218. data/examples/al-admin/public/javascripts/effects.js +1128 -0
  219. data/examples/al-admin/public/javascripts/prototype.js +4320 -0
  220. data/examples/al-admin/public/javascripts/spinelz/accordion.js +185 -0
  221. data/examples/al-admin/public/javascripts/spinelz/ajaxHistory.js +157 -0
  222. data/examples/al-admin/public/javascripts/spinelz/balloon.js +287 -0
  223. data/examples/al-admin/public/javascripts/spinelz/barchart.js +524 -0
  224. data/examples/al-admin/public/javascripts/spinelz/calendar.js +3012 -0
  225. data/examples/al-admin/public/javascripts/spinelz/colorpicker.js +128 -0
  226. data/examples/al-admin/public/javascripts/spinelz/datepicker.js +438 -0
  227. data/examples/al-admin/public/javascripts/spinelz/grid.js +1391 -0
  228. data/examples/al-admin/public/javascripts/spinelz/grid_resizeEx.js +100 -0
  229. data/examples/al-admin/public/javascripts/spinelz/grid_sortabletableEx.js +129 -0
  230. data/examples/al-admin/public/javascripts/spinelz/inplaceEditorEx.js +148 -0
  231. data/examples/al-admin/public/javascripts/spinelz/menubar.js +232 -0
  232. data/examples/al-admin/public/javascripts/spinelz/navPanel.js +170 -0
  233. data/examples/al-admin/public/javascripts/spinelz/selectableTable.js +433 -0
  234. data/examples/al-admin/public/javascripts/spinelz/sideBarBox.js +282 -0
  235. data/examples/al-admin/public/javascripts/spinelz/sideBarBox_effects.js +83 -0
  236. data/examples/al-admin/public/javascripts/spinelz/sortableTable.js +270 -0
  237. data/examples/al-admin/public/javascripts/spinelz/switcher.js +78 -0
  238. data/examples/al-admin/public/javascripts/spinelz/tabBox.js +469 -0
  239. data/examples/al-admin/public/javascripts/spinelz/timepicker.js +384 -0
  240. data/examples/al-admin/public/javascripts/spinelz/toolbar.js +152 -0
  241. data/examples/al-admin/public/javascripts/spinelz/treeview.js +703 -0
  242. data/examples/al-admin/public/javascripts/spinelz/window.js +641 -0
  243. data/examples/al-admin/public/javascripts/spinelz/window_resizeEx.js +130 -0
  244. data/examples/al-admin/public/javascripts/spinelz_lib/builder.js +131 -0
  245. data/examples/al-admin/public/javascripts/spinelz_lib/controls.js +835 -0
  246. data/examples/al-admin/public/javascripts/spinelz_lib/dragdrop.js +944 -0
  247. data/examples/al-admin/public/javascripts/spinelz_lib/effects.js +1090 -0
  248. data/examples/al-admin/public/javascripts/spinelz_lib/json.js +139 -0
  249. data/examples/al-admin/public/javascripts/spinelz_lib/prototype.js +2515 -0
  250. data/examples/al-admin/public/javascripts/spinelz_lib/resize.js +215 -0
  251. data/examples/al-admin/public/javascripts/spinelz_lib/scriptaculous.js +51 -0
  252. data/examples/al-admin/public/javascripts/spinelz_lib/slider.js +278 -0
  253. data/examples/al-admin/public/javascripts/spinelz_lib/spinelz_util.js +1266 -0
  254. data/examples/al-admin/public/javascripts/spinelz_lib/unittest.js +564 -0
  255. data/examples/al-admin/public/robots.txt +1 -0
  256. data/examples/al-admin/public/stylesheets/account.css +41 -0
  257. data/examples/al-admin/public/stylesheets/attributes.css +1 -0
  258. data/examples/al-admin/public/stylesheets/base.css +104 -0
  259. data/examples/al-admin/public/stylesheets/detail.css +36 -0
  260. data/examples/al-admin/public/stylesheets/directory.css +22 -0
  261. data/examples/al-admin/public/stylesheets/object-classes.css +6 -0
  262. data/examples/al-admin/public/stylesheets/rails.css +35 -0
  263. data/examples/al-admin/public/stylesheets/spinelz/accordion.css +59 -0
  264. data/examples/al-admin/public/stylesheets/spinelz/balloon.css +151 -0
  265. data/examples/al-admin/public/stylesheets/spinelz/calendar.css +564 -0
  266. data/examples/al-admin/public/stylesheets/spinelz/datepicker.css +175 -0
  267. data/examples/al-admin/public/stylesheets/spinelz/grid.css +137 -0
  268. data/examples/al-admin/public/stylesheets/spinelz/menubar.css +78 -0
  269. data/examples/al-admin/public/stylesheets/spinelz/modal.css +22 -0
  270. data/examples/al-admin/public/stylesheets/spinelz/navPanel.css +58 -0
  271. data/examples/al-admin/public/stylesheets/spinelz/selectableTable.css +28 -0
  272. data/examples/al-admin/public/stylesheets/spinelz/sideBarBox.css +82 -0
  273. data/examples/al-admin/public/stylesheets/spinelz/sortableTable.css +51 -0
  274. data/examples/al-admin/public/stylesheets/spinelz/switcher.css +23 -0
  275. data/examples/al-admin/public/stylesheets/spinelz/tabBox.css +94 -0
  276. data/examples/al-admin/public/stylesheets/spinelz/timepicker.css +508 -0
  277. data/examples/al-admin/public/stylesheets/spinelz/toolbar.css +82 -0
  278. data/examples/al-admin/public/stylesheets/spinelz/treeview.css +121 -0
  279. data/examples/al-admin/public/stylesheets/spinelz/window.css +140 -0
  280. data/examples/al-admin/public/stylesheets/structure.css +81 -0
  281. data/examples/al-admin/public/stylesheets/syntaxes.css +1 -0
  282. data/examples/al-admin/public/stylesheets/users.css +13 -0
  283. data/examples/al-admin/public/stylesheets/welcome.css +0 -0
  284. data/examples/al-admin/script/about +3 -0
  285. data/examples/al-admin/script/console +3 -0
  286. data/examples/al-admin/script/dbconsole +3 -0
  287. data/examples/al-admin/script/destroy +3 -0
  288. data/examples/al-admin/script/generate +3 -0
  289. data/examples/al-admin/script/performance/benchmarker +3 -0
  290. data/examples/al-admin/script/performance/profiler +3 -0
  291. data/examples/al-admin/script/performance/request +3 -0
  292. data/examples/al-admin/script/plugin +3 -0
  293. data/examples/al-admin/script/process/inspector +3 -0
  294. data/examples/al-admin/script/process/reaper +3 -0
  295. data/examples/al-admin/script/process/spawner +3 -0
  296. data/examples/al-admin/script/runner +3 -0
  297. data/examples/al-admin/script/server +3 -0
  298. data/examples/al-admin/test/fixtures/users.yml +9 -0
  299. data/examples/al-admin/test/functional/account_controller_test.rb +12 -0
  300. data/examples/al-admin/test/functional/attributes_controller_test.rb +8 -0
  301. data/examples/al-admin/test/functional/directory_controller_test.rb +8 -0
  302. data/examples/al-admin/test/functional/object_classes_controller_test.rb +8 -0
  303. data/examples/al-admin/test/functional/syntaxes_controller_test.rb +8 -0
  304. data/examples/al-admin/test/functional/users_controller_test.rb +8 -0
  305. data/examples/al-admin/test/functional/welcome_controller_test.rb +8 -0
  306. data/examples/al-admin/test/integration/sign_up_test.rb +44 -0
  307. data/examples/al-admin/test/run-test.sh +3 -0
  308. data/examples/al-admin/test/test_helper.rb +52 -0
  309. data/examples/al-admin/test/unit/user_test.rb +12 -0
  310. data/examples/al-admin/vendor/plugins/exception_notification/README +111 -0
  311. data/examples/al-admin/vendor/plugins/exception_notification/init.rb +1 -0
  312. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifiable.rb +99 -0
  313. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier.rb +66 -0
  314. data/examples/al-admin/vendor/plugins/exception_notification/lib/exception_notifier_helper.rb +78 -0
  315. data/examples/al-admin/vendor/plugins/exception_notification/test/exception_notifier_helper_test.rb +61 -0
  316. data/examples/al-admin/vendor/plugins/exception_notification/test/test_helper.rb +7 -0
  317. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_backtrace.rhtml +1 -0
  318. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_environment.rhtml +7 -0
  319. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_inspect_model.rhtml +16 -0
  320. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_request.rhtml +4 -0
  321. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_session.rhtml +2 -0
  322. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/_title.rhtml +3 -0
  323. data/examples/al-admin/vendor/plugins/exception_notification/views/exception_notifier/exception_notification.rhtml +6 -0
  324. data/examples/config.yaml.example +5 -0
  325. data/examples/example.der +0 -0
  326. data/examples/example.jpg +0 -0
  327. data/examples/groupadd +41 -0
  328. data/examples/groupdel +35 -0
  329. data/examples/groupls +49 -0
  330. data/examples/groupmod +42 -0
  331. data/examples/lpasswd +55 -0
  332. data/examples/objects/group.rb +13 -0
  333. data/examples/objects/ou.rb +4 -0
  334. data/examples/objects/user.rb +20 -0
  335. data/examples/ouadd +38 -0
  336. data/examples/useradd +45 -0
  337. data/examples/useradd-binary +53 -0
  338. data/examples/userdel +34 -0
  339. data/examples/userls +50 -0
  340. data/examples/usermod +42 -0
  341. data/examples/usermod-binary-add +50 -0
  342. data/examples/usermod-binary-add-time +54 -0
  343. data/examples/usermod-binary-del +48 -0
  344. data/examples/usermod-lang-add +43 -0
  345. data/lib/active_ldap.rb +105 -0
  346. data/lib/active_ldap/action_controller/ldap_benchmarking.rb +55 -0
  347. data/lib/active_ldap/acts/tree.rb +75 -0
  348. data/lib/active_ldap/adapter/base.rb +705 -0
  349. data/lib/active_ldap/adapter/jndi.rb +184 -0
  350. data/lib/active_ldap/adapter/jndi_connection.rb +185 -0
  351. data/lib/active_ldap/adapter/ldap.rb +290 -0
  352. data/lib/active_ldap/adapter/ldap_ext.rb +105 -0
  353. data/lib/active_ldap/adapter/net_ldap.rb +309 -0
  354. data/lib/active_ldap/adapter/net_ldap_ext.rb +23 -0
  355. data/lib/active_ldap/association/belongs_to.rb +47 -0
  356. data/lib/active_ldap/association/belongs_to_many.rb +58 -0
  357. data/lib/active_ldap/association/children.rb +21 -0
  358. data/lib/active_ldap/association/collection.rb +105 -0
  359. data/lib/active_ldap/association/has_many.rb +31 -0
  360. data/lib/active_ldap/association/has_many_utils.rb +44 -0
  361. data/lib/active_ldap/association/has_many_wrap.rb +62 -0
  362. data/lib/active_ldap/association/proxy.rb +107 -0
  363. data/lib/active_ldap/associations.rb +202 -0
  364. data/lib/active_ldap/attributes.rb +184 -0
  365. data/lib/active_ldap/base.rb +1594 -0
  366. data/lib/active_ldap/callbacks.rb +52 -0
  367. data/lib/active_ldap/command.rb +49 -0
  368. data/lib/active_ldap/compatible.rb +44 -0
  369. data/lib/active_ldap/configuration.rb +147 -0
  370. data/lib/active_ldap/connection.rb +294 -0
  371. data/lib/active_ldap/distinguished_name.rb +291 -0
  372. data/lib/active_ldap/entry_attribute.rb +78 -0
  373. data/lib/active_ldap/escape.rb +12 -0
  374. data/lib/active_ldap/get_text.rb +9 -0
  375. data/lib/active_ldap/get_text/parser.rb +161 -0
  376. data/lib/active_ldap/get_text_fallback.rb +60 -0
  377. data/lib/active_ldap/get_text_support.rb +20 -0
  378. data/lib/active_ldap/helper.rb +92 -0
  379. data/lib/active_ldap/human_readable.rb +132 -0
  380. data/lib/active_ldap/ldap_error.rb +74 -0
  381. data/lib/active_ldap/ldif.rb +930 -0
  382. data/lib/active_ldap/object_class.rb +95 -0
  383. data/lib/active_ldap/operations.rb +610 -0
  384. data/lib/active_ldap/populate.rb +53 -0
  385. data/lib/active_ldap/railtie.rb +31 -0
  386. data/lib/active_ldap/schema.rb +699 -0
  387. data/lib/active_ldap/schema/syntaxes.rb +417 -0
  388. data/lib/active_ldap/timeout.rb +75 -0
  389. data/lib/active_ldap/timeout_stub.rb +17 -0
  390. data/lib/active_ldap/user_password.rb +92 -0
  391. data/lib/active_ldap/validations.rb +229 -0
  392. data/lib/active_ldap/xml.rb +122 -0
  393. data/po/en/active-ldap.po +4029 -0
  394. data/po/ja/active-ldap.po +4060 -0
  395. data/rails_generators/model_active_ldap/USAGE +17 -0
  396. data/rails_generators/model_active_ldap/model_active_ldap_generator.rb +69 -0
  397. data/rails_generators/model_active_ldap/templates/model_active_ldap.rb +3 -0
  398. data/rails_generators/model_active_ldap/templates/unit_test.rb +8 -0
  399. data/rails_generators/scaffold_active_ldap/scaffold_active_ldap_generator.rb +7 -0
  400. data/rails_generators/scaffold_active_ldap/templates/ldap.yml +18 -0
  401. data/test/al-test-utils.rb +439 -0
  402. data/test/command.rb +112 -0
  403. data/test/config.yaml.sample +6 -0
  404. data/test/fixtures/lower_case_object_class_schema.rb +802 -0
  405. data/test/run-test.rb +44 -0
  406. data/test/test_acts_as_tree.rb +60 -0
  407. data/test/test_adapter.rb +121 -0
  408. data/test/test_associations.rb +664 -0
  409. data/test/test_attributes.rb +117 -0
  410. data/test/test_base.rb +1177 -0
  411. data/test/test_base_per_instance.rb +61 -0
  412. data/test/test_bind.rb +62 -0
  413. data/test/test_callback.rb +37 -0
  414. data/test/test_configuration.rb +40 -0
  415. data/test/test_connection.rb +82 -0
  416. data/test/test_connection_per_class.rb +112 -0
  417. data/test/test_connection_per_dn.rb +112 -0
  418. data/test/test_dn.rb +172 -0
  419. data/test/test_find.rb +176 -0
  420. data/test/test_groupadd.rb +50 -0
  421. data/test/test_groupdel.rb +46 -0
  422. data/test/test_groupls.rb +107 -0
  423. data/test/test_groupmod.rb +51 -0
  424. data/test/test_ldif.rb +1891 -0
  425. data/test/test_load.rb +133 -0
  426. data/test/test_lpasswd.rb +75 -0
  427. data/test/test_object_class.rb +74 -0
  428. data/test/test_reflection.rb +182 -0
  429. data/test/test_schema.rb +559 -0
  430. data/test/test_syntax.rb +383 -0
  431. data/test/test_user.rb +217 -0
  432. data/test/test_user_password.rb +101 -0
  433. data/test/test_useradd-binary.rb +62 -0
  434. data/test/test_useradd.rb +57 -0
  435. data/test/test_userdel.rb +48 -0
  436. data/test/test_userls.rb +91 -0
  437. data/test/test_usermod-binary-add-time.rb +65 -0
  438. data/test/test_usermod-binary-add.rb +64 -0
  439. data/test/test_usermod-binary-del.rb +66 -0
  440. data/test/test_usermod-lang-add.rb +60 -0
  441. data/test/test_usermod.rb +58 -0
  442. data/test/test_validation.rb +274 -0
  443. metadata +502 -0
@@ -0,0 +1,60 @@
1
+ module ActiveLdap
2
+ module GetTextFallback
3
+ module_function
4
+ def add_text_domain(name, options)
5
+ end
6
+
7
+ module_function
8
+ def default_available_locales=(name)
9
+ end
10
+
11
+ module_function
12
+ def default_text_domain=(name)
13
+ end
14
+
15
+ module Translation
16
+ class << self
17
+ def included(base)
18
+ base.extend(self)
19
+ end
20
+ end
21
+
22
+ def _(msg_id)
23
+ msg_id
24
+ end
25
+
26
+ def n_(arg1, arg2, arg3=nil)
27
+ if arg1.kind_of?(Array)
28
+ msg_id = arg1[0]
29
+ msg_id_plural = arg1[1]
30
+ n = arg2
31
+ else
32
+ msg_id = arg1
33
+ msg_id_plural = arg2
34
+ n = arg3
35
+ end
36
+ n == 1 ? msg_id : msg_id_plural
37
+ end
38
+
39
+ def N_(msg_id)
40
+ msg_id
41
+ end
42
+
43
+ def Nn_(msg_id, msg_id_plural)
44
+ [msg_id, msg_id_plural]
45
+ end
46
+
47
+ def s_(msg_id, div='|')
48
+ index = msg_id.rindex(div)
49
+ if index
50
+ msg_id[(index + 1)..-1]
51
+ else
52
+ msg_id
53
+ end
54
+ end
55
+ end
56
+
57
+ end
58
+
59
+ GetText = GetTextFallback
60
+ end
@@ -0,0 +1,20 @@
1
+ module ActiveLdap
2
+ class << self
3
+ def get_text_supported?
4
+ not const_defined?(:GetTextFallback)
5
+ end
6
+ end
7
+
8
+ module GetTextSupport
9
+ class << self
10
+ def included(base)
11
+ base.class_eval do
12
+ include(GetText::Translation)
13
+ GetText.add_text_domain('active-ldap',:path=>'po', :type=>:po)
14
+ GetText.default_available_locales = ['en', 'jp']
15
+ GetText.default_text_domain = "active-ldap"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,92 @@
1
+ module ActiveLdap
2
+ module Helper
3
+ def ldap_attribute_name_gettext(attribute)
4
+ Base.human_attribute_name(attribute)
5
+ end
6
+ alias_method(:la_, :ldap_attribute_name_gettext)
7
+
8
+ def ldap_attribute_description_gettext(attribute)
9
+ Base.human_attribute_description(attribute)
10
+ end
11
+ alias_method(:lad_, :ldap_attribute_description_gettext)
12
+
13
+ def ldap_object_class_name_gettext(object_class)
14
+ Base.human_object_class_name(object_class)
15
+ end
16
+ alias_method(:loc_, :ldap_object_class_name_gettext)
17
+
18
+ def ldap_object_class_description_gettext(object_class)
19
+ Base.human_object_class_description(object_class)
20
+ end
21
+ alias_method(:locd_, :ldap_object_class_description_gettext)
22
+
23
+ def ldap_syntax_name_gettext(syntax)
24
+ Base.human_syntax_name(syntax)
25
+ end
26
+ alias_method(:ls_, :ldap_syntax_name_gettext)
27
+
28
+ def ldap_syntax_description_gettext(syntax)
29
+ Base.human_syntax_description(syntax)
30
+ end
31
+ alias_method(:lsd_, :ldap_syntax_description_gettext)
32
+
33
+ def ldap_field(type, object_name, method, options={})
34
+ case type
35
+ when "radio_button", "check_box", "text_area"
36
+ form_method = type
37
+ else
38
+ form_method = "#{type}_field"
39
+ end
40
+
41
+ object = options[:object]
42
+ if object.nil?
43
+ normalized_object_name = object_name.to_s.sub(/\[\](\])?$/, "\\1")
44
+ object = instance_variable_get("@#{normalized_object_name}")
45
+ end
46
+ values = object.nil? ? nil : object[method, true]
47
+ values = [nil] if values.blank?
48
+ required_ldap_options = options.delete(:ldap_options) || []
49
+ required_ldap_options.each do |required_ldap_option|
50
+ found = false
51
+ values.each do |value|
52
+ next unless value.is_a?(Hash)
53
+ if Hash.to_a[0].to_s == required_ldap_option.to_s
54
+ found = true
55
+ break
56
+ end
57
+ end
58
+ values << {required_ldap_option => ""} unless found
59
+ end
60
+
61
+ fields = []
62
+ collect_values = Proc.new do |value, ldap_options|
63
+ case value
64
+ when Hash
65
+ value.each do |k, v|
66
+ collect_values.call(v, ldap_options + [k])
67
+ end
68
+ when Array
69
+ value.each do |v|
70
+ collect_values.call(v, ldap_options)
71
+ end
72
+ else
73
+ id = "#{object_name}_#{method}"
74
+ name = "#{object_name}[#{method}][]"
75
+ ldap_options.collect.each do |ldap_option|
76
+ id << "_#{ldap_option}"
77
+ name << "[#{ldap_option}][]"
78
+ end
79
+ ldap_value_options = {:id => id, :name => name, :value => value}
80
+ field = send(form_method, object_name, method,
81
+ ldap_value_options.merge(options))
82
+ if block_given?
83
+ field = yield(field, {:options => ldap_options, :value => value})
84
+ end
85
+ fields << field unless field.blank?
86
+ end
87
+ end
88
+ collect_values.call(values, [])
89
+ fields.join("\n")
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,132 @@
1
+ module ActiveLdap
2
+ module HumanReadable
3
+ def self.included(base)
4
+ super
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def human_attribute_name(attribute_or_name)
10
+ msgid = human_attribute_name_msgid(attribute_or_name)
11
+ msgid ||= human_attribute_name_with_gettext(attribute_or_name)
12
+ s_(msgid)
13
+ end
14
+
15
+ def human_attribute_name_msgid(attribute_or_name)
16
+ if attribute_or_name.is_a?(Schema::Attribute)
17
+ name = attribute_or_name.name
18
+ else
19
+ attribute = schema.attribute(attribute_or_name)
20
+ return nil if attribute.id.nil?
21
+ if attribute.name == attribute_or_name or
22
+ attribute.aliases.include?(attribute_or_name)
23
+ name = attribute_or_name
24
+ else
25
+ return nil
26
+ end
27
+ end
28
+ "LDAP|Attribute|#{name}"
29
+ end
30
+
31
+ def human_attribute_description(attribute_or_name)
32
+ msgid = human_attribute_description_msgid(attribute_or_name)
33
+ return nil if msgid.nil?
34
+ s_(msgid)
35
+ end
36
+
37
+ def human_attribute_description_msgid(attribute_or_name)
38
+ if attribute_or_name.is_a?(Schema::Attribute)
39
+ attribute = attribute_or_name
40
+ else
41
+ attribute = schema.attribute(attribute_or_name)
42
+ return nil if attribute.nil?
43
+ end
44
+ description = attribute.description
45
+ return nil if description.nil?
46
+ "LDAP|Description|Attribute|#{attribute.name}|#{description}"
47
+ end
48
+
49
+ def human_object_class_name(object_class_or_name)
50
+ s_(human_object_class_name_msgid(object_class_or_name))
51
+ end
52
+
53
+ def human_object_class_name_msgid(object_class_or_name)
54
+ if object_class_or_name.is_a?(Schema::ObjectClass)
55
+ name = object_class_or_name.name
56
+ else
57
+ name = object_class_or_name
58
+ end
59
+ "LDAP|ObjectClass|#{name}"
60
+ end
61
+
62
+ def human_object_class_description(object_class_or_name)
63
+ msgid = human_object_class_description_msgid(object_class_or_name)
64
+ return nil if msgid.nil?
65
+ s_(msgid)
66
+ end
67
+
68
+ def human_object_class_description_msgid(object_class_or_name)
69
+ if object_class_or_name.is_a?(Schema::ObjectClass)
70
+ object_class = object_class_or_name
71
+ else
72
+ object_class = schema.object_class(object_class_or_name)
73
+ return nil if object_class.nil?
74
+ end
75
+ description = object_class.description
76
+ return nil if description.nil?
77
+ "LDAP|Description|ObjectClass|#{object_class.name}|#{description}"
78
+ end
79
+
80
+ def human_syntax_name(syntax_or_id)
81
+ s_(human_syntax_name_msgid(syntax_or_id))
82
+ end
83
+
84
+ def human_syntax_name_msgid(syntax_or_id)
85
+ if syntax_or_id.is_a?(Schema::Syntax)
86
+ id = syntax_or_id.id
87
+ else
88
+ id = syntax_or_id
89
+ end
90
+ "LDAP|Syntax|#{id}"
91
+ end
92
+
93
+ def human_syntax_description(syntax_or_id)
94
+ msgid = human_syntax_description_msgid(syntax_or_id)
95
+ return nil if msgid.nil?
96
+ s_(msgid)
97
+ end
98
+
99
+ def human_syntax_description_msgid(syntax_or_id)
100
+ if syntax_or_id.is_a?(Schema::Syntax)
101
+ syntax = syntax_or_id
102
+ else
103
+ syntax = schema.ldap_syntax(syntax_or_id)
104
+ return nil if syntax.nil?
105
+ end
106
+ description = syntax.description
107
+ return nil if description.nil?
108
+ "LDAP|Description|Syntax|#{syntax.id}|#{description}"
109
+ end
110
+
111
+ def human_readable_format(object)
112
+ case object
113
+ when Array
114
+ "[#{object.collect {|value| human_readable_format(value)}.join(', ')}]"
115
+ when Hash
116
+ formatted_values = []
117
+ object.each do |key, value|
118
+ formatted_values << [human_readable_format(key),
119
+ human_readable_format(value)].join("=>")
120
+ end
121
+ "{#{formatted_values.join(', ')}}"
122
+ else
123
+ if object.respond_to?(:to_human_readable_format)
124
+ object.to_human_readable_format
125
+ else
126
+ object.inspect
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,74 @@
1
+ module ActiveLdap
2
+ class LdapError < Error
3
+ class << self
4
+ def define(code, name, target)
5
+ klass_name = name.downcase.camelize
6
+ target.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
7
+ class #{klass_name} < #{self}
8
+ CODE = #{code}
9
+ def code
10
+ CODE
11
+ end
12
+ end
13
+ EOC
14
+ target.const_get(klass_name)
15
+ end
16
+ end
17
+
18
+ ERRORS = {}
19
+ {
20
+ 0x00 => "SUCCESS",
21
+ 0x01 => "OPERATIONS_ERROR",
22
+ 0x02 => "PROTOCOL_ERROR",
23
+ 0x03 => "TIME_LIMIT_EXCEEDED",
24
+ 0x04 => "SIZE_LIMIT_EXCEEDED",
25
+ 0x05 => "COMPARE_FALSE",
26
+ 0x06 => "COMPARE_TRUE",
27
+ 0x07 => "AUTH_METHOD_NOT_SUPPORTED",
28
+ 0x08 => "STRONG_AUTH_REQUIRED",
29
+ 0x09 => "PARTIAL_RESULTS", # LDAPv2+ (not LDAPv3)
30
+
31
+ 0x0a => "REFERRAL",
32
+ 0x0b => "ADMIN_LIMIT_EXCEEDED",
33
+ 0x0c => "UNAVAILABLE_CRITICAL_EXTENSION",
34
+ 0x0d => "CONFIDENTIALITY_REQUIRED",
35
+ 0x0e => "LDAP_SASL_BIND_IN_PROGRESS",
36
+
37
+ 0x10 => "NO_SUCH_ATTRIBUTE",
38
+ 0x11 => "UNDEFINED_TYPE",
39
+ 0x12 => "INAPPROPRIATE_MATCHING",
40
+ 0x13 => "CONSTRAINT_VIOLATION",
41
+ 0x14 => "TYPE_OR_VALUE_EXISTS",
42
+ 0x15 => "INVALID_SYNTAX",
43
+
44
+ 0x20 => "NO_SUCH_OBJECT",
45
+ 0x21 => "ALIAS_PROBLEM",
46
+ 0x22 => "INVALID_DN_SYNTAX",
47
+ 0x23 => "IS_LEAF",
48
+ 0x24 => "ALIAS_DEREF_PROBLEM",
49
+
50
+ 0x2F => "PROXY_AUTHZ_FAILURE",
51
+ 0x30 => "INAPPROPRIATE_AUTH",
52
+ 0x31 => "INVALID_CREDENTIALS",
53
+ 0x32 => "INSUFFICIENT_ACCESS",
54
+
55
+ 0x33 => "BUSY",
56
+ 0x34 => "UNAVAILABLE",
57
+ 0x35 => "UNWILLING_TO_PERFORM",
58
+ 0x36 => "LOOP_DETECT",
59
+
60
+ 0x40 => "NAMING_VIOLATION",
61
+ 0x41 => "OBJECT_CLASS_VIOLATION",
62
+ 0x42 => "NOT_ALLOWED_ON_NONLEAF",
63
+ 0x43 => "NOT_ALLOWED_ON_RDN",
64
+ 0x44 => "ALREADY_EXISTS",
65
+ 0x45 => "NO_OBJECT_CLASS_MODS",
66
+ 0x46 => "RESULTS_TOO_LARGE",
67
+ 0x47 => "AFFECTS_MULTIPLE_DSAS",
68
+
69
+ 0x50 => "OTHER",
70
+ }.each do |code, name|
71
+ ERRORS[code] = LdapError.define(code, name, self)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,930 @@
1
+ require "strscan"
2
+ require "uri"
3
+ require "open-uri"
4
+
5
+ module ActiveLdap
6
+ class Ldif
7
+ module Attributes
8
+ module_function
9
+ def encode(attributes)
10
+ return "" if attributes.empty?
11
+
12
+ result = ""
13
+ normalize(attributes).sort_by {|name,| name}.each do |name, values|
14
+ values.each do |options, value|
15
+ result << Attribute.encode([name, *options].join(";"), value)
16
+ end
17
+ end
18
+ result
19
+ end
20
+
21
+ def normalize(attributes)
22
+ result = {}
23
+ attributes.each do |name, values|
24
+ result[name] = Attribute.normalize_value(values).sort
25
+ end
26
+ result
27
+ end
28
+ end
29
+
30
+ module Attribute
31
+ SIZE = 75
32
+
33
+ module_function
34
+ def binary_value?(value)
35
+ if value.respond_to?(:encoding)
36
+ return true if value.encoding == Encoding.find("ascii-8bit")
37
+ end
38
+ if /\A#{Parser::SAFE_STRING}\z/ =~ value
39
+ false
40
+ else
41
+ true
42
+ end
43
+ end
44
+
45
+ def encode(name, value)
46
+ return "#{name}:\n" if value.blank?
47
+ result = "#{name}:"
48
+
49
+ value = value.to_s unless value.is_a?(String)
50
+ if value[-1, 1] == ' ' or binary_value?(value)
51
+ result << ":"
52
+ value = [value].pack("m").gsub(/\n/, '')
53
+ end
54
+ result << " "
55
+
56
+ first_line_value_size = SIZE - result.size
57
+ if value.size > first_line_value_size
58
+ first_line_value = value[0, first_line_value_size]
59
+ rest_value = value[first_line_value_size..-1]
60
+ else
61
+ first_line_value = value
62
+ rest_value = nil
63
+ end
64
+
65
+ result << "#{first_line_value}\n"
66
+ return result if rest_value.nil?
67
+
68
+ rest_value.scan(/.{1,#{SIZE - 1}}/).each do |line| # FIXME
69
+ result << " #{line}\n"
70
+ end
71
+ result
72
+ end
73
+
74
+ def normalize_value(value, result=[])
75
+ case value
76
+ when Array
77
+ value.each {|val| normalize_value(val, result)}
78
+ when Hash
79
+ value.each do |option, val|
80
+ normalize_value(val).each do |options, v|
81
+ result << [[option] + options, v]
82
+ end
83
+ end
84
+ result
85
+ else
86
+ result << [[], value]
87
+ end
88
+ result
89
+ end
90
+ end
91
+
92
+ class Parser
93
+ include GetTextSupport
94
+
95
+ attr_reader :ldif
96
+ def initialize(source)
97
+ @ldif = nil
98
+ source = source.to_s if source.is_a?(LDIF)
99
+ @source = source
100
+ end
101
+
102
+ ATTRIBUTE_TYPE_CHARS = /[a-zA-Z][a-zA-Z0-9\-]*/
103
+ SAFE_CHAR = /[\x01-\x09\x0B-\x0C\x0E-\x7F]/
104
+ SAFE_INIT_CHAR = /[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B\x3D-\x7F]/
105
+ SAFE_STRING = /#{SAFE_INIT_CHAR}#{SAFE_CHAR}*/
106
+ FILL = / */
107
+ def parse
108
+ return @ldif if @ldif
109
+
110
+ @scanner = Scanner.new(@source)
111
+ raise version_spec_is_missing unless @scanner.scan(/version:/)
112
+ @scanner.scan(FILL)
113
+
114
+ version = @scanner.scan(/\d+/)
115
+ raise version_number_is_missing if version.nil?
116
+
117
+ version = Integer(version)
118
+ raise unsupported_version(version) if version != 1
119
+
120
+ raise separator_is_missing unless @scanner.scan_separators
121
+
122
+ records = parse_records
123
+
124
+ @ldif = LDIF.new(records)
125
+ end
126
+
127
+ private
128
+ def read_base64_value
129
+ value = @scanner.scan(/[a-zA-Z0-9\+\/=]+/)
130
+ return nil if value.nil?
131
+ encoding = value.encoding if value.respond_to?(:encoding)
132
+ value = value.unpack("m")[0].chomp
133
+ if value.respond_to?(:force_encoding)
134
+ value.force_encoding(encoding)
135
+ value.force_encoding("ascii-8bit") unless value.valid_encoding?
136
+ end
137
+ value
138
+ end
139
+
140
+ def read_external_file
141
+ uri_string = @scanner.scan(URI::ABS_URI)
142
+ raise uri_is_missing if uri_string.nil?
143
+ uri = nil
144
+ begin
145
+ uri = URI.parse(uri_string)
146
+ rescue URI::Error
147
+ raise invalid_uri(uri_string, $!.message)
148
+ end
149
+
150
+ if uri.scheme == "file"
151
+ File.open(uri.path, "rb") {|file| file.read}
152
+ else
153
+ uri.read
154
+ end
155
+ end
156
+
157
+ def parse_dn(dn_string)
158
+ DN.parse(dn_string).to_s
159
+ rescue DistinguishedNameInvalid
160
+ raise invalid_dn(dn_string, $!.reason)
161
+ end
162
+
163
+ def parse_attributes(least=0, &block)
164
+ i = 0
165
+ attributes = {}
166
+ block ||= Proc.new {@scanner.check_separator}
167
+ loop do
168
+ i += 1
169
+ if i >= least
170
+ break if block.call or @scanner.eos?
171
+ end
172
+ type, options, value = parse_attribute
173
+ if @scanner.scan_separator.nil? and !@scanner.eos?
174
+ raise separator_is_missing
175
+ end
176
+ attributes[type] ||= []
177
+ container = attributes[type]
178
+ options.each do |option|
179
+ parent = container.find do |val|
180
+ val.is_a?(Hash) and val.has_key?(option)
181
+ end
182
+ if parent.nil?
183
+ parent = {option => []}
184
+ container << parent
185
+ end
186
+ container = parent[option]
187
+ end
188
+ container << value
189
+ end
190
+ raise attribute_spec_is_missing if attributes.size < least
191
+ attributes
192
+ end
193
+
194
+ def parse_attribute_description
195
+ type = @scanner.scan(ATTRIBUTE_TYPE_CHARS)
196
+ raise attribute_type_is_missing if type.nil?
197
+ options = parse_options
198
+ [type, options]
199
+ end
200
+
201
+ def parse_attribute
202
+ type, options = parse_attribute_description
203
+ value = parse_attribute_value
204
+ [type, options, value]
205
+ end
206
+
207
+ def parse_options
208
+ options = []
209
+ while @scanner.scan(/;/)
210
+ option = @scanner.scan(ATTRIBUTE_TYPE_CHARS)
211
+ raise option_is_missing if option.nil?
212
+ options << option
213
+ end
214
+ options
215
+ end
216
+
217
+ def parse_attribute_value(accept_external_file=true)
218
+ raise attribute_value_separator_is_missing if @scanner.scan(/:/).nil?
219
+ if @scanner.scan(/:/)
220
+ @scanner.scan(FILL)
221
+ read_base64_value
222
+ elsif accept_external_file and @scanner.scan(/</)
223
+ @scanner.scan(FILL)
224
+ read_external_file
225
+ else
226
+ @scanner.scan(FILL)
227
+ @scanner.scan(SAFE_STRING)
228
+ end
229
+ end
230
+
231
+ def parse_control
232
+ return nil if @scanner.scan(/control:/).nil?
233
+ @scanner.scan(FILL)
234
+ type = @scanner.scan(/\d+(?:\.\d+)*/)
235
+ raise control_type_is_missing if type.nil?
236
+ criticality = nil
237
+ if @scanner.scan(/ +/)
238
+ criticality = @scanner.scan(/true|false/)
239
+ raise criticality_is_missing if criticality.nil?
240
+ end
241
+ value = parse_attribute_value if @scanner.check(/:/)
242
+ raise separator_is_missing unless @scanner.scan_separator
243
+ ChangeRecord::Control.new(type, criticality, value)
244
+ end
245
+
246
+ def parse_controls
247
+ controls = []
248
+ loop do
249
+ control = parse_control
250
+ break if control.nil?
251
+ controls << control
252
+ end
253
+ controls
254
+ end
255
+
256
+ def parse_change_type
257
+ return nil unless @scanner.scan(/changetype:/)
258
+ @scanner.scan(FILL)
259
+ type = @scanner.check(ATTRIBUTE_TYPE_CHARS)
260
+ raise change_type_value_is_missing if type.nil?
261
+ unless @scanner.scan(/add|delete|modrdn|moddn|modify/)
262
+ raise unknown_change_type(type)
263
+ end
264
+
265
+ raise separator_is_missing unless @scanner.scan_separator
266
+ type
267
+ end
268
+
269
+ def parse_modify_name_record(klass, dn, controls)
270
+ raise new_rdn_mark_is_missing unless @scanner.scan(/newrdn\b/)
271
+ new_rdn = parse_attribute_value(false)
272
+ raise new_rdn_value_is_missing if new_rdn.nil?
273
+ raise separator_is_missing unless @scanner.scan_separator
274
+
275
+ unless @scanner.scan(/deleteoldrdn:/)
276
+ raise delete_old_rdn_mark_is_missing
277
+ end
278
+ @scanner.scan(FILL)
279
+ delete_old_rdn = @scanner.scan(/[01]/)
280
+ raise delete_old_rdn_value_is_missing if delete_old_rdn.nil?
281
+ raise separator_is_missing unless @scanner.scan_separator
282
+
283
+ if @scanner.scan(/newsuperior\b/)
284
+ @scanner.scan(FILL)
285
+ new_superior = parse_attribute_value(false)
286
+ raise new_superior_value_is_missing if new_superior.nil?
287
+ new_superior = parse_dn(new_superior)
288
+ raise separator_is_missing unless @scanner.scan_separator
289
+ end
290
+ klass.new(dn, controls, new_rdn, delete_old_rdn, new_superior)
291
+ end
292
+
293
+ def parse_modify_spec
294
+ return nil unless @scanner.check(/(#{ATTRIBUTE_TYPE_CHARS}):/)
295
+ type = @scanner[1]
296
+ unless @scanner.scan(/(?:add|delete|replace):/)
297
+ raise unknown_modify_type(type)
298
+ end
299
+ @scanner.scan(FILL)
300
+ attribute, options = parse_attribute_description
301
+ raise separator_is_missing unless @scanner.scan_separator
302
+ attributes = parse_attributes {@scanner.check(/-/)}
303
+ raise modify_spec_separator_is_missing unless @scanner.scan(/-/)
304
+ raise separator_is_missing unless @scanner.scan_separator
305
+ [type, attribute, options, attributes]
306
+ end
307
+
308
+ def parse_modify_record(dn, controls)
309
+ operations = []
310
+ loop do
311
+ spec = parse_modify_spec
312
+ break if spec.nil?
313
+ type, attribute, options, attributes = spec
314
+ case type
315
+ when "add"
316
+ klass = ModifyRecord::AddOperation
317
+ when "delete"
318
+ klass = ModifyRecord::DeleteOperation
319
+ when "replace"
320
+ klass = ModifyRecord::ReplaceOperation
321
+ else
322
+ unknown_modify_type(type)
323
+ end
324
+ operations << klass.new(attribute, options, attributes)
325
+ end
326
+ ModifyRecord.new(dn, controls, operations)
327
+ end
328
+
329
+ def parse_change_type_record(dn, controls, change_type)
330
+ case change_type
331
+ when "add"
332
+ attributes = parse_attributes(1)
333
+ AddRecord.new(dn, controls, attributes)
334
+ when "delete"
335
+ DeleteRecord.new(dn, controls)
336
+ when "moddn"
337
+ parse_modify_name_record(ModifyDNRecord, dn, controls)
338
+ when "modrdn"
339
+ parse_modify_name_record(ModifyRDNRecord, dn, controls)
340
+ when "modify"
341
+ parse_modify_record(dn, controls)
342
+ else
343
+ raise unknown_change_type(change_type)
344
+ end
345
+ end
346
+
347
+ def parse_record
348
+ raise dn_mark_is_missing unless @scanner.scan(/dn:/)
349
+ if @scanner.scan(/:/)
350
+ @scanner.scan(FILL)
351
+ dn = read_base64_value
352
+ raise dn_is_missing if dn.nil?
353
+ dn = parse_dn(dn)
354
+ else
355
+ @scanner.scan(FILL)
356
+ dn = @scanner.scan(/#{SAFE_STRING}$/)
357
+ if dn.nil?
358
+ partial_dn = @scanner.scan(SAFE_STRING)
359
+ raise dn_has_invalid_character(@scanner.check(/./)) if partial_dn
360
+ raise dn_is_missing
361
+ end
362
+ dn = parse_dn(dn)
363
+ end
364
+
365
+ raise separator_is_missing unless @scanner.scan_separator
366
+
367
+ controls = parse_controls
368
+ change_type = parse_change_type
369
+ raise change_type_is_missing if change_type.nil? and !controls.empty?
370
+
371
+ if change_type
372
+ parse_change_type_record(dn, controls, change_type)
373
+ else
374
+ attributes = parse_attributes(1)
375
+ ContentRecord.new(dn, attributes)
376
+ end
377
+ end
378
+
379
+ def parse_records
380
+ records = []
381
+ loop do
382
+ records << parse_record
383
+ break if @scanner.eos?
384
+ raise separator_is_missing if @scanner.scan_separator.nil?
385
+
386
+ break if @scanner.eos?
387
+ break if @scanner.scan_separators and @scanner.eos?
388
+ end
389
+ records
390
+ end
391
+
392
+ def invalid_ldif(reason)
393
+ LdifInvalid.new(@source, reason, @scanner.line, @scanner.column)
394
+ end
395
+
396
+ def version_spec_is_missing
397
+ invalid_ldif(_("version spec is missing"))
398
+ end
399
+
400
+ def version_number_is_missing
401
+ invalid_ldif(_("version number is missing"))
402
+ end
403
+
404
+ def unsupported_version(version)
405
+ invalid_ldif(_("unsupported version: %d") % version)
406
+ end
407
+
408
+ def separator_is_missing
409
+ invalid_ldif(_("separator is missing"))
410
+ end
411
+
412
+ def dn_mark_is_missing
413
+ invalid_ldif(_("'dn:' is missing"))
414
+ end
415
+
416
+ def dn_is_missing
417
+ invalid_ldif(_("DN is missing"))
418
+ end
419
+
420
+ def invalid_dn(dn_string, reason)
421
+ invalid_ldif(_("DN is invalid: %s: %s") % [dn_string, reason])
422
+ end
423
+
424
+ def dn_has_invalid_character(character)
425
+ invalid_ldif(_("DN has an invalid character: %s") % character)
426
+ end
427
+
428
+ def attribute_type_is_missing
429
+ invalid_ldif(_("attribute type is missing"))
430
+ end
431
+
432
+ def option_is_missing
433
+ invalid_ldif(_("option is missing"))
434
+ end
435
+
436
+ def attribute_value_separator_is_missing
437
+ invalid_ldif(_("':' is missing"))
438
+ end
439
+
440
+ def invalid_uri(uri_string, message)
441
+ invalid_ldif(_("URI is invalid: %s: %s") % [uri_string, message])
442
+ end
443
+
444
+ def modify_spec_separator_is_missing
445
+ invalid_ldif(_("'-' is missing"))
446
+ end
447
+
448
+ def unknown_change_type(change_type)
449
+ invalid_ldif(_("unknown change type: %s") % change_type)
450
+ end
451
+
452
+ def change_type_is_missing
453
+ invalid_ldif(_("change type is missing"))
454
+ end
455
+
456
+ def control_type_is_missing
457
+ invalid_ldif(_("control type is missing"))
458
+ end
459
+
460
+ def criticality_is_missing
461
+ invalid_ldif(_("criticality is missing"))
462
+ end
463
+
464
+ def change_type_value_is_missing
465
+ invalid_ldif(_("change type value is missing"))
466
+ end
467
+
468
+ def attribute_spec_is_missing
469
+ invalid_ldif(_("attribute spec is missing"))
470
+ end
471
+
472
+ def new_rdn_mark_is_missing
473
+ invalid_ldif(_("'newrdn:' is missing"))
474
+ end
475
+
476
+ def new_rdn_value_is_missing
477
+ invalid_ldif(_("new RDN value is missing"))
478
+ end
479
+
480
+ def delete_old_rdn_mark_is_missing
481
+ invalid_ldif(_("'deleteoldrdn:' is missing"))
482
+ end
483
+
484
+ def delete_old_rdn_value_is_missing
485
+ invalid_ldif(_("delete old RDN value is missing"))
486
+ end
487
+
488
+ def new_superior_value_is_missing
489
+ invalid_ldif(_("new superior value is missing"))
490
+ end
491
+
492
+ def unknown_modify_type(type)
493
+ invalid_ldif(_("unknown modify type: %s") % type)
494
+ end
495
+ end
496
+
497
+ class Scanner
498
+ SEPARATOR = /(?:\r\n|\n)/
499
+ SEPARATORS = /(?:(?:^#.*)?#{SEPARATOR})+/
500
+
501
+ def initialize(source)
502
+ @source = source
503
+ @scanner = StringScanner.new(@source)
504
+ @sub_scanner = nil
505
+ @sub_scanner = next_segment || StringScanner.new("")
506
+ end
507
+
508
+ def scan(regexp)
509
+ @sub_scanner = next_segment if @sub_scanner.eos?
510
+ @sub_scanner.scan(regexp)
511
+ end
512
+
513
+ def check(regexp)
514
+ @sub_scanner = next_segment if @sub_scanner.eos?
515
+ @sub_scanner.check(regexp)
516
+ end
517
+
518
+ def scan_separator
519
+ return @scanner.scan(SEPARATOR) if @sub_scanner.eos?
520
+
521
+ scan(SEPARATOR)
522
+ end
523
+
524
+ def check_separator
525
+ return @scanner.check(SEPARATOR) if @sub_scanner.eos?
526
+
527
+ check(SEPARATOR)
528
+ end
529
+
530
+ def scan_separators
531
+ return @scanner.scan(SEPARATORS) if @sub_scanner.eos?
532
+
533
+ sub_result = scan(SEPARATORS)
534
+ return nil if sub_result.nil?
535
+ return sub_result unless @sub_scanner.eos?
536
+
537
+ result = @scanner.scan(SEPARATORS)
538
+ return sub_result if result.nil?
539
+
540
+ sub_result + result
541
+ end
542
+
543
+ def [](*args)
544
+ @sub_scanner[*args]
545
+ end
546
+
547
+ def eos?
548
+ @sub_scanner = next_segment if @sub_scanner.eos?
549
+ @sub_scanner.eos? and @scanner.eos?
550
+ end
551
+
552
+ def line
553
+ _consumed_source = consumed_source
554
+ return 1 if _consumed_source.empty?
555
+
556
+ n = Compatible.string_to_lines(_consumed_source).size
557
+ n += 1 if _consumed_source[-1, 1] == "\n"
558
+ n
559
+ end
560
+
561
+ def column
562
+ _consumed_source = consumed_source
563
+ return 1 if _consumed_source.empty?
564
+
565
+ position - (_consumed_source.rindex("\n") || -1)
566
+ end
567
+
568
+ def position
569
+ sub_scanner_string = @sub_scanner.string
570
+ if sub_scanner_string.respond_to?(:bytesize)
571
+ sub_scanner_string_size = sub_scanner_string.bytesize
572
+ else
573
+ sub_scanner_string_size = sub_scanner_string.size
574
+ end
575
+ @scanner.pos - (sub_scanner_string_size - @sub_scanner.pos)
576
+ end
577
+
578
+ private
579
+ def next_segment
580
+ loop do
581
+ segment = @scanner.scan(/.+(?:#{SEPARATOR} .*)*#{SEPARATOR}?/)
582
+ return @sub_scanner if segment.nil?
583
+ next if segment[0, 1] == "#"
584
+ return StringScanner.new(segment.gsub(/\r?\n /, ''))
585
+ end
586
+ end
587
+
588
+ def consumed_source
589
+ @source[0, position]
590
+ end
591
+ end
592
+
593
+ class << self
594
+ def parse(ldif)
595
+ Parser.new(ldif).parse
596
+ end
597
+ end
598
+
599
+ include Enumerable
600
+
601
+ attr_reader :version, :records
602
+ def initialize(records=[])
603
+ @version = 1
604
+ @records = records
605
+ end
606
+
607
+ def <<(record)
608
+ @records << record
609
+ end
610
+
611
+ def each(&block)
612
+ @records.each(&block)
613
+ end
614
+
615
+ def to_s
616
+ result = "version: #{@version}\n"
617
+ result << @records.collect do |record|
618
+ record.to_s
619
+ end.join("\n")
620
+ result
621
+ end
622
+
623
+ def ==(other)
624
+ other.is_a?(self.class) and
625
+ @version == other.version and @records == other.records
626
+ end
627
+
628
+ class Record
629
+ include GetTextSupport
630
+
631
+ attr_reader :dn, :attributes
632
+ def initialize(dn, attributes)
633
+ @dn = dn
634
+ @attributes = attributes
635
+ end
636
+
637
+ def to_hash
638
+ attributes.merge({"dn" => dn})
639
+ end
640
+
641
+ def to_s
642
+ result = to_s_prelude
643
+ result << to_s_content
644
+ result
645
+ end
646
+
647
+ def ==(other)
648
+ other.is_a?(self.class) and
649
+ @dn == other.dn and
650
+ Attributes.normalize(@attributes) ==
651
+ Attributes.normalize(other.attributes)
652
+ end
653
+
654
+ private
655
+ def to_s_prelude
656
+ Attribute.encode("dn", dn)
657
+ end
658
+
659
+ def to_s_content
660
+ Attributes.encode(@attributes)
661
+ end
662
+ end
663
+
664
+ class ContentRecord < Record
665
+ end
666
+
667
+ class ChangeRecord < Record
668
+ attr_reader :controls, :change_type
669
+ def initialize(dn, attributes, controls, change_type)
670
+ super(dn, attributes)
671
+ @controls = controls
672
+ @change_type = change_type
673
+ end
674
+
675
+ def add?
676
+ @change_type == "add"
677
+ end
678
+
679
+ def delete?
680
+ @change_type == "delete"
681
+ end
682
+
683
+ def modify?
684
+ @change_type == "modify"
685
+ end
686
+
687
+ def modify_dn?
688
+ @change_type == "moddn"
689
+ end
690
+
691
+ def modify_rdn?
692
+ @change_type == "modrdn"
693
+ end
694
+
695
+ def ==(other)
696
+ super(other) and
697
+ @controls = other.controls and
698
+ @change_type == other.change_type
699
+ end
700
+
701
+ private
702
+ def to_s_prelude
703
+ result = super
704
+ @controls.each do |control|
705
+ result << control.to_s
706
+ end
707
+ result
708
+ end
709
+
710
+ def to_s_content
711
+ result = "changetype: #{@change_type}\n"
712
+ result << super
713
+ result
714
+ end
715
+
716
+ class Control
717
+ attr_reader :type, :value
718
+ def initialize(type, criticality, value)
719
+ @type = type
720
+ @criticality = normalize_criticality(criticality)
721
+ @value = value
722
+ end
723
+
724
+ def criticality?
725
+ @criticality
726
+ end
727
+
728
+ def to_a
729
+ [@type, @criticality, @value]
730
+ end
731
+
732
+ def to_hash
733
+ {
734
+ :type => @type,
735
+ :criticality => @criticality,
736
+ :value => @value,
737
+ }
738
+ end
739
+
740
+ def to_s
741
+ result = "control: #{@type}"
742
+ result << " #{@criticality}" unless @criticality.nil?
743
+ result << @value if @value
744
+ result << "\n"
745
+ result
746
+ end
747
+
748
+ def ==(other)
749
+ other.is_a?(self.class) and
750
+ @type == other.type and
751
+ @criticality = other.criticality and
752
+ @value == other.value
753
+ end
754
+
755
+ private
756
+ def normalize_criticality(criticality)
757
+ case criticality
758
+ when "true", true
759
+ true
760
+ when "false", false
761
+ false
762
+ when nil
763
+ nil
764
+ else
765
+ raise ArgumentError,
766
+ _("invalid criticality value: %s") % criticality.inspect
767
+ end
768
+ end
769
+ end
770
+ end
771
+
772
+ class AddRecord < ChangeRecord
773
+ def initialize(dn, controls=[], attributes={})
774
+ super(dn, attributes, controls, "add")
775
+ end
776
+ end
777
+
778
+ class DeleteRecord < ChangeRecord
779
+ def initialize(dn, controls=[])
780
+ super(dn, {}, controls, "delete")
781
+ end
782
+ end
783
+
784
+ class ModifyNameRecord < ChangeRecord
785
+ attr_reader :new_rdn, :new_superior
786
+ def initialize(dn, controls, change_type,
787
+ new_rdn, delete_old_rdn, new_superior)
788
+ super(dn, {}, controls, change_type)
789
+ @new_rdn = new_rdn
790
+ @delete_old_rdn = normalize_delete_old_rdn(delete_old_rdn)
791
+ @new_superior = new_superior
792
+ end
793
+
794
+ def delete_old_rdn?
795
+ @delete_old_rdn
796
+ end
797
+
798
+ private
799
+ def normalize_delete_old_rdn(delete_old_rdn)
800
+ case delete_old_rdn
801
+ when "1", true
802
+ true
803
+ when "0", false
804
+ false
805
+ when nil
806
+ nil
807
+ else
808
+ raise ArgumentError,
809
+ _("invalid deleteoldrdn value: %s") % delete_old_rdn.inspect
810
+ end
811
+ end
812
+
813
+ def to_s_content
814
+ result = super
815
+ result << "newrdn: #{@new_rdn}\n"
816
+ result << "deleteoldrdn: #{@delete_old_rdn ? 1 : 0}\n"
817
+ result << Attribute.encode("newsuperior", @new_superior) if @new_superior
818
+ result
819
+ end
820
+ end
821
+
822
+ class ModifyDNRecord < ModifyNameRecord
823
+ def initialize(dn, controls, new_rdn, delete_old_rdn, new_superior=nil)
824
+ super(dn, controls, "moddn", new_rdn, delete_old_rdn, new_superior)
825
+ end
826
+ end
827
+
828
+ class ModifyRDNRecord < ModifyNameRecord
829
+ def initialize(dn, controls, new_rdn, delete_old_rdn, new_superior=nil)
830
+ super(dn, controls, "modrdn", new_rdn, delete_old_rdn, new_superior)
831
+ end
832
+ end
833
+
834
+ class ModifyRecord < ChangeRecord
835
+ include Enumerable
836
+
837
+ attr_reader :operations
838
+ def initialize(dn, controls=[], operations=[])
839
+ super(dn, {}, controls, "modify")
840
+ @operations = operations
841
+ end
842
+
843
+ def each(&block)
844
+ @operations.each(&block)
845
+ end
846
+
847
+ def <<(operation)
848
+ @operations << operation
849
+ end
850
+
851
+ def add_operation(type, attribute, options, attributes)
852
+ klass = self.class.const_get("#{type.to_s.capitalize}Operation")
853
+ self << klass.new(attribute, options, attributes)
854
+ end
855
+
856
+ def ==(other)
857
+ super(other) and @operations == other.operations
858
+ end
859
+
860
+ private
861
+ def to_s_content
862
+ result = super
863
+ return result if @operations.empty?
864
+ @operations.collect do |operation|
865
+ result << "#{operation}-\n"
866
+ end
867
+ result
868
+ end
869
+
870
+ class Operation
871
+ attr_reader :type, :attribute, :options, :attributes
872
+ def initialize(type, attribute, options, attributes)
873
+ @type = type
874
+ @attribute = attribute
875
+ @options = options
876
+ @attributes = attributes
877
+ end
878
+
879
+ def full_attribute_name
880
+ [@attribute, *@options].join(";")
881
+ end
882
+
883
+ def add?
884
+ @type == "add"
885
+ end
886
+
887
+ def delete?
888
+ @type == "delete"
889
+ end
890
+
891
+ def replace?
892
+ @type == "replace"
893
+ end
894
+
895
+ def to_s
896
+ Attribute.encode(@type, full_attribute_name) +
897
+ Attributes.encode(@attributes)
898
+ end
899
+
900
+ def ==(other)
901
+ other.is_a?(self.class) and
902
+ @type == other.type and
903
+ full_attribute_name == other.full_attribute_name and
904
+ Attributes.normalize(@attributes) ==
905
+ Attributes.normalize(other.attributes)
906
+ end
907
+ end
908
+
909
+ class AddOperation < Operation
910
+ def initialize(attribute, options, attributes)
911
+ super("add", attribute, options, attributes)
912
+ end
913
+ end
914
+
915
+ class DeleteOperation < Operation
916
+ def initialize(attribute, options, attributes)
917
+ super("delete", attribute, options, attributes)
918
+ end
919
+ end
920
+
921
+ class ReplaceOperation < Operation
922
+ def initialize(attribute, options, attributes)
923
+ super("replace", attribute, options, attributes)
924
+ end
925
+ end
926
+ end
927
+ end
928
+
929
+ LDIF = Ldif
930
+ end