Index: openacs-4/packages/contacts/catalog/contacts.en_US.ISO-8859-1.xml
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/catalog/contacts.en_US.ISO-8859-1.xml,v
diff -u -r1.95 -r1.96
--- openacs-4/packages/contacts/catalog/contacts.en_US.ISO-8859-1.xml	2 Feb 2007 11:24:57 -0000	1.95
+++ openacs-4/packages/contacts/catalog/contacts.en_US.ISO-8859-1.xml	21 Jun 2007 20:06:41 -0000	1.96
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="ISO-8859-1"?>
-<message_catalog package_key="contacts" package_version="1.2b27" locale="en_US" charset="ISO-8859-1">
+<message_catalog package_key="contacts" package_version="1.2b28" locale="en_US" charset="ISO-8859-1">
 
   <msg key="--_select_a_group_--">-- select a group --</msg>
   <msg key="--add_column--">-- add column --</msg>
@@ -173,6 +173,7 @@
   <msg key="does_not_contain_-">does not contain -&gt;</msg>
   <msg key="does_not_exists">does not exist</msg>
   <msg key="Done">Done</msg>
+  <msg key="dotLRN_Managed">.LRN Managed</msg>
   <msg key="Edit">Edit</msg>
   <msg key="Edit_a_Signature">Edit a Signature</msg>
   <msg key="Edit_complaint">Edit complaint</msg>
@@ -512,6 +513,7 @@
   <msg key="lt_zippostal_does_not_st">zip/postal does not start with -&gt;</msg>
   <msg key="lt_zippostal_starts_with">zip/postal starts with -&gt;</msg>
   <msg key="Mail">Mail</msg>
+  <msg key="Mail_group">Mail %group%</msg>
   <msg key="Mail_Merge">Mail Merge</msg>
   <msg key="Mail_Merge_Results">Mail Merge Results</msg>
   <msg key="Mail_through_p">Mail Through</msg>
Index: openacs-4/packages/contacts/tcl/contact-search-condition-type-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contact-search-condition-type-procs.tcl,v
diff -u -r1.39 -r1.40
--- openacs-4/packages/contacts/tcl/contact-search-condition-type-procs.tcl	29 Jun 2006 08:18:45 -0000	1.39
+++ openacs-4/packages/contacts/tcl/contact-search-condition-type-procs.tcl	21 Jun 2007 20:06:42 -0000	1.40
@@ -873,7 +873,7 @@
                                      [list "[_ contacts.contact_is_not_in_-]" "not_in"] \
                                     ]
 
-            set group_options_old [contact::groups -expand "all" -privilege_required "read" -package_id $package_id]
+            set group_options_old [contact::groups -expand "all" -privilege_required "read" -package_id $package_id -include_dotlrn_p "1"]
 	    set group_options [list]
 	    foreach group $group_options_old {
 		set group_name [lang::util::localize [lindex $group 0]]
Index: openacs-4/packages/contacts/tcl/contact-search-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contact-search-procs.tcl,v
diff -u -r1.37 -r1.38
--- openacs-4/packages/contacts/tcl/contact-search-procs.tcl	8 Sep 2006 12:10:19 -0000	1.37
+++ openacs-4/packages/contacts/tcl/contact-search-procs.tcl	21 Jun 2007 20:06:42 -0000	1.38
@@ -628,15 +628,23 @@
 
     if { $results eq {} } {
 	# we allow for the special case that somebody supplied a
-	# list_id instead of a search_id, if this was the case and
-	# they have permission to read this list
+	# list_id or group_id instead of a search_id
 	if { [contact::list::exists_p -list_id $search_id] } {
 	    if { [contact::owner_read_p -object_id $search_id -owner_id [ad_conn user_id]] } {
+		# they can search for this list
 		if { $and_p } {
 		    append results " and "
 		}
 		append results " $party_id in ( select party_id from contact_list_members where list_id = $search_id ) "
 	    }
+	} elseif { [contact::group::mapped_p -group_id $search_id] } {
+	    if { [permission::permission_p -object_id $search_id -party_id [ad_conn user_id] -privilege "read"] } {
+		  # they can search for this group
+		if { $and_p } {
+		    append results " and "
+		}
+		append results " $party_id in ( select gamm${search_id}.member_id from group_approved_member_map gamm${search_id} where gamm${search_id}.group_id = $search_id ) "
+	    }
 	}
     }
     return $results
Index: openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl,v
diff -u -r1.60 -r1.61
--- openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl	18 Jun 2007 03:20:45 -0000	1.60
+++ openacs-4/packages/contacts/tcl/contacts-callback-procs.tcl	21 Jun 2007 20:06:42 -0000	1.61
@@ -1387,3 +1387,15 @@
 	    -send_immediately
     }
 }    
+
+ad_proc -public -callback group::add_member -impl contacts {
+    {-group_id:required}
+    {-user_id:required}
+    {-rel_type:required}
+    {-member_state:required}
+} {
+    
+} {
+    ns_log Notice "callback group::add_member -group_id $group_id -user_id $user_id -rel_type $rel_type -member_state $member_state"
+
+}
\ No newline at end of file
Index: openacs-4/packages/contacts/tcl/contacts-procs-postgresql.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contacts-procs-postgresql.xql,v
diff -u -r1.25 -r1.26
--- openacs-4/packages/contacts/tcl/contacts-procs-postgresql.xql	12 Jun 2007 13:12:47 -0000	1.25
+++ openacs-4/packages/contacts/tcl/contacts-procs-postgresql.xql	21 Jun 2007 20:06:42 -0000	1.26
@@ -153,21 +153,23 @@
 <fullquery name="contact::groups_list_not_cached.get_groups">
   <querytext>
     select groups2.group_id,
-           acs_objects.title as group_name,
+           $name_field as group_name,
            ( select count(distinct gamm.member_id) from group_approved_member_map gamm where gamm.group_id = groups2.group_id ) as member_count,
            ( select count(distinct gcm.component_id) from group_component_map gcm where gcm.group_id = groups2.group_id) as component_count,
            CASE WHEN contact_groups.package_id is not null THEN '1' ELSE '0' END as mapped_p,
            CASE WHEN default_p THEN '1' ELSE '0' END as default_p,
-           CASE WHEN user_change_p THEN '1' ELSE '0' END as user_change_p
+           CASE WHEN user_change_p THEN '1' ELSE '0' END as user_change_p,
+           $dotlrn_community_p as dotlrn_community_p
       from (select g.* from groups g left join application_groups ag on (ag.group_id = g.group_id) 
 		where (package_id is null or g.group_id = 1231) and group_name not like 'forumgroup_%') groups2 
 		left join ( select * from contact_groups where package_id = :package_id ) as contact_groups on ( groups2.group_id = contact_groups.group_id ), 
 		acs_objects
+      $additional_from
      where groups2.group_id not in ('-1','[contacts::default_group -package_id $package_id]')
 	and groups2.group_id = acs_objects.object_id
        and groups2.group_id not in ( select gcm.component_id from group_component_map gcm where gcm.group_id != -1 )
-       $filter_clause
-     order by mapped_p desc, CASE WHEN contact_groups.default_p THEN '000000000' ELSE upper(groups2.group_name) END
+      $additional_where
+     order by mapped_p desc, CASE WHEN contact_groups.default_p THEN '000000000' ELSE upper( $name_field ) END
   </querytext>
 </fullquery>
 
@@ -220,6 +222,14 @@
   </querytext>
 </fullquery>
 
+<fullquery name="contact::group::mapped_p.select_mapped_p">
+  <querytext>
+	select 1 from contact_groups
+         where group_id = :group_id
+           and package_id = :package_id
+  </querytext>
+</fullquery>
+
 <fullquery name="contact::revision::new.insert_item">
   <querytext>
          insert into cr_items
Index: openacs-4/packages/contacts/tcl/contacts-procs.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/tcl/contacts-procs.tcl,v
diff -u -r1.110 -r1.111
--- openacs-4/packages/contacts/tcl/contacts-procs.tcl	12 Jun 2007 13:12:47 -0000	1.110
+++ openacs-4/packages/contacts/tcl/contacts-procs.tcl	21 Jun 2007 20:06:42 -0000	1.111
@@ -909,6 +909,31 @@
     db_dml map_group {}
 }
 
+ad_proc -public contact::group::mapped_p {
+    -group_id:required
+    {-package_id ""}
+} {
+    this creates a new group for use with contacts (and the permissions system)
+} {
+    if {[empty_string_p $package_id]} {
+	set package_id [ad_conn package_id]
+    }
+    return [db_0or1row select_mapped_p {}]
+}
+
+ad_proc -public contact::group::name {
+    -group_id:required
+} {
+    Get the group name for contacts (this might be a dotlrn community name or a group title)
+} {
+    set dotlrn_community_name [dotlrn_community::get_community_name $group_id]
+    if { $dotlrn_community_name ne "" } {
+	return $dotlrn_community_name
+    } else {
+	return [lang::util::localize [lang::util::localize [group::title -group_id $group_id]]]
+    }
+}
+
 ad_proc -public contact::group::parent {
     -group_id:required
 } {
@@ -919,27 +944,36 @@
 
 ad_proc -public contact::groups_list {
     {-package_id ""}
+    {-include_dotlrn_p "0"}
 } {
     Retrieve a list of all groups currently in the system
 } {
     if { $package_id eq "" } {
 	set package_id [ad_conn package_id]
     }
-    return [util_memoize [list contact::groups_list_not_cached -package_id $package_id]]
+    return [util_memoize [list contact::groups_list_not_cached -package_id $package_id -include_dotlrn_p $include_dotlrn_p]]
 }
 
 ad_proc -public contact::groups_list_not_cached {
     -package_id:required
+    -include_dotlrn_p:required
 } {
     Retrieve a list of all groups currently in the system
 } {
-    # Filter clause
-    # set filter_clause ""
-    set dotlrn_installed_p [apm_package_installed_p dotlrn]
-    if { $dotlrn_installed_p } {
-        set filter_clause "and groups2.group_id not in (select community_id from dotlrn_communities_all)"
-    } else {
-        set filter_clause ""
+    set name_field "acs_objects.title"
+    set dotlrn_community_p " '0'::boolean "
+    set additional_from ""
+    set additional_where ""
+    if { [apm_package_installed_p dotlrn] } {
+	set name_field " CASE WHEN dotlrn_communities_all.community_id is not null THEN dotlrn_communities_all.pretty_name ELSE acs_objects.title END "
+        set dotlrn_community_p " CASE WHEN dotlrn_communities_all.community_id is not null THEN '1'::boolean ELSE '0'::boolean END " 
+	set additional_from " left join dotlrn_communities_all on ( acs_objects.object_id = dotlrn_communities_all.community_id )"
+	if { [string is true $include_dotlrn_p] } {
+	    # we hid archived, but not active communities
+	    set additional_where "and CASE WHEN dotlrn_communities_all.archived_p = 'f' OR dotlrn_communities_all.community_id is null THEN '1'::boolean ELSE 'f'::boolean END"
+	} else {
+	    set additional_where  "and dotlrn_communities_all.community_id is null"
+	}
     }
     return [db_list_of_lists get_groups {}]
 }
@@ -953,6 +987,7 @@
     {-no_member_count:boolean}
     {-package_id ""}
     {-party_id ""}
+    {-include_dotlrn_p "0"}
 } {
     Return the groups that are mapped in contacts
     @param indent_with What should we indent the group name with
@@ -966,8 +1001,8 @@
 
     set user_id [ad_conn user_id]
     set group_list [list]
-    foreach one_group [contact::groups_list -package_id $package_id] {
-	util_unlist $one_group group_id group_name member_count component_count mapped_p default_p user_change_p
+    foreach one_group [contact::groups_list -package_id $package_id -include_dotlrn_p $include_dotlrn_p] {
+	util_unlist $one_group group_id group_name member_count component_count mapped_p default_p user_change_p dotlrn_community_p
 	if {$user_change_p eq ""} {
 	    set user_change_p 0
 	}
@@ -985,11 +1020,12 @@
 	    }
 	}
         if { $mapped_p || $all_p} {
-            lappend group_list [list [lang::util::localize $group_name] $group_id $member_count "1" $mapped_p $default_p $user_change_p]
+	    # we localize twice because for some reason some localized keys references another localized key
+            lappend group_list [list [lang::util::localize [lang::util::localize $group_name]] $group_id $member_count "1" $mapped_p $default_p $user_change_p $dotlrn_community_p]
             if { $component_count > 0 && ( $expand == "all" || $expand == $group_id ) } {
                 db_foreach get_components {} {
 		    if { $mapped_p || $all_p} {
-			lappend group_list [list "$indent_with$group_name" $group_id $member_count "2" $mapped_p $default_p $user_change_p]
+			lappend group_list [list "$indent_with[lang::util::localize [lang::util::localize $group_name]]" $group_id $member_count "2" $mapped_p $default_p $user_change_p $dotlrn_community_p]
 		    }
 		}
             }
@@ -998,6 +1034,7 @@
 
     switch $output {
         list {
+	    ns_log notice "last $group_list"
             set list_output [list]
             foreach group $group_list {
 		if {$no_member_count_p} {
Index: openacs-4/packages/contacts/www/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/index.tcl,v
diff -u -r1.26 -r1.27
--- openacs-4/packages/contacts/www/index.tcl	18 Jun 2007 03:20:45 -0000	1.26
+++ openacs-4/packages/contacts/www/index.tcl	21 Jun 2007 20:06:42 -0000	1.27
@@ -72,6 +72,10 @@
 set public_searches [lang::util::localize_list_of_lists -list [db_list_of_lists public_searches {}]]
 set search_options [concat [list [list [_ contacts.All_Contacts] ""]] $public_searches]
 
+foreach group [contact::groups -expand "all" -privilege_required "read" -include_dotlrn_p "1"] {
+    lappend search_options [list [lindex $group 0] [lindex $group 1] [_ contacts.Groups]]
+}
+
 db_foreach my_searches {} {
     lappend search_options [list "${my_searches_title}" ${my_searches_search_id} [_ contacts.My_Searches]]
 }
@@ -119,12 +123,22 @@
 	}
     }
 }
-
+if { [contact::group::mapped_p -group_id $search_id] && $contacts_total_count > 0 } {
+    set group [contact::group::name -group_id $search_id]
+    set label [_ contacts.Mail_group]
+    append form_elements {
+	{mail_merge_group:text(submit) {label $label} {value "1"}}
+    }
+}
 ad_form -name "search" -method "GET" -export {orderby page_size format extended_columns return_url} -form $form_elements \
     -on_request {
     } -edit_request {
     } -on_refresh {
     } -on_submit {
+	if { ![empty_string_p $mail_merge_group] } {
+	    ad_returnredirect [export_vars -base "message" -url {{group_id $search_id}}]
+	    ad_script_abort
+	}
     } -after_submit {
     }
 
Index: openacs-4/packages/contacts/www/index.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/index.xql,v
diff -u -r1.10 -r1.11
--- openacs-4/packages/contacts/www/index.xql	26 Jun 2006 06:36:52 -0000	1.10
+++ openacs-4/packages/contacts/www/index.xql	21 Jun 2007 20:06:42 -0000	1.11
@@ -29,6 +29,18 @@
       </querytext>
 </fullquery>
 
+<fullquery name="mapped_groups">
+      <querytext>
+    select ao.title as my_lists_title,
+           cl.list_id as my_lists_list_id
+      from contact_lists cl,
+           acs_objects ao
+     where cl.list_id = ao.object_id
+       and ao.object_id in ( select object_id from contact_owners where owner_id in ( :user_id , :package_id ))
+     order by upper(ao.title)
+      </querytext>
+</fullquery>
+
 <fullquery name="my_lists">
       <querytext>
     select ao.title as my_lists_title,
Index: openacs-4/packages/contacts/www/message.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/message.tcl,v
diff -u -r1.36 -r1.37
--- openacs-4/packages/contacts/www/message.tcl	5 Dec 2006 04:16:50 -0000	1.36
+++ openacs-4/packages/contacts/www/message.tcl	21 Jun 2007 20:06:42 -0000	1.37
@@ -8,6 +8,7 @@
     {object_id:integer,multiple,optional}
     {party_id:multiple,optional}
     {party_ids ""}
+    {group_id:integer ""}
     {message_type ""}
     {message:optional}
     {header_id:integer ""}
@@ -42,6 +43,12 @@
     set party_ids [list]
 }
 
+if { ![empty_string_p $group_id] } {
+    if { [contact::group::mapped_p -group_id $group_id] } {
+	set party_ids [group::get_members -group_id $group_id]
+    }
+}
+
 if { [exists_and_not_null party_id] } {
     foreach p_id $party_id {
 	if {[lsearch $party_ids $party_id] < 0} {
Index: openacs-4/packages/contacts/www/admin/group-ae.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/admin/group-ae.tcl,v
diff -u -r1.4 -r1.5
--- openacs-4/packages/contacts/www/admin/group-ae.tcl	16 Dec 2005 15:39:53 -0000	1.4
+++ openacs-4/packages/contacts/www/admin/group-ae.tcl	21 Jun 2007 20:06:42 -0000	1.5
@@ -102,7 +102,7 @@
 } -after_submit {
 
     # First flush our cache for the contact::groups as we change something here
-    util_memoize_flush contact::groups_list_not_cached
+    util_memoize_flush_regexp contact::groups_list_not_cached*
     
     ad_returnredirect -message ${message} ${return_url}
     ad_script_abort
Index: openacs-4/packages/contacts/www/admin/group-map.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/admin/group-map.tcl,v
diff -u -r1.4 -r1.5
--- openacs-4/packages/contacts/www/admin/group-map.tcl	16 Dec 2005 15:39:53 -0000	1.4
+++ openacs-4/packages/contacts/www/admin/group-map.tcl	21 Jun 2007 20:06:42 -0000	1.5
@@ -48,7 +48,7 @@
 }
 
 # First flush our cache for the contact::groups as we change something here
-util_memoize_flush contact::groups_list_not_cached
+util_memoize_flush_regexp contact::groups_list_not_cached*
 
 set package_id [ad_conn package_id]
 
Index: openacs-4/packages/contacts/www/admin/index.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/contacts/www/admin/index.tcl,v
diff -u -r1.14 -r1.15
--- openacs-4/packages/contacts/www/admin/index.tcl	14 Jan 2007 11:35:24 -0000	1.14
+++ openacs-4/packages/contacts/www/admin/index.tcl	21 Jun 2007 20:06:42 -0000	1.15
@@ -23,7 +23,7 @@
         edit {
 	    label {}
 	    display_template {
-		<a href="@groups.edit_url@"><img src="/resources/acs-subsite/Edit16.gif" height="16" width="16" border= "0" alt="[_ acs-kernel.common_Edit]"></a>
+		<if @groups.dotlrn_community_p@ false><a href="@groups.edit_url@"><img src="/resources/acs-subsite/Edit16.gif" height="16" width="16" border= "0" alt="[_ acs-kernel.common_Edit]"></a></if>
 	    }
 	}
         group_name {
@@ -48,6 +48,7 @@
         default {
             label {Default}
             display_template {
+                <if @groups.dotlrn_community_p@ false>
                 <if @groups.default_p@>
                   <img src="/resources/acs-subsite/checkboxchecked.gif" border="0" height="13" width="13" alt="[_ contacts.True]">
                 </if>
@@ -58,55 +59,70 @@
                   <else>
                   </else>
                 </else>
+                </if>
             }
         }
         user_change {
             label {User Change}
             display_template {
+                <if @groups.dotlrn_community_p@ false>
                 <if @groups.user_change_p@>
                   <a href="group-user-change?action=disallow&group_id=@groups.group_id@"><img src="/resources/acs-subsite/checkboxchecked.gif" border="0" height="13" width="13" alt="[_ contacts.True]"></a>
                 </if>
                 <else>
                   <a href="group-user-change?action=allow&group_id=@groups.group_id@"><img src="/resources/acs-subsite/checkbox.gif" border="0" height="13" width="13" alt="[_ contacts.False]"></a>
                 </else>
+                </if>
             }
         }
         person_form {
             display_template {
+                <if @groups.dotlrn_community_p@ false>
                 <a href="@groups.ams_person_url@" class="button">[_ contacts.Person_Form]</a>
+                </if>
             }
         }
         org_form {
             display_template {
+                <if @groups.dotlrn_community_p@ false>
                 <a href="@groups.ams_org_url@" class="button">[_ contacts.Organization_Form]</a>
+                </if>
             }
         }
 	categories {
 	    display_template {
+                <if @groups.dotlrn_community_p@ false>
 		<a href="@groups.categories_url@" class="button">[_ contacts.Manage_group_categories]</a>
+                </if>
 	    }
 	}
 	actions {
 	    display_template {
+                <if @groups.dotlrn_community_p@ false>
 		<if @groups.level@ eq 1><a href="permissions?group_id=@groups.group_id@" class="button">[_ contacts.Permissions]</a></if>
+                </if>
+                <else>
+                #contacts.dotLRN_Managed#
+                </else>
 	    }
         }
     } -filters {
     } -orderby {
     }
 
 
-multirow create groups group_id group_name group_url ams_person_url ams_org_url member_count level mapped_p default_p categories_url edit_url user_change_p
+multirow create groups group_id group_name group_url ams_person_url ams_org_url member_count level mapped_p default_p categories_url edit_url user_change_p dotlrn_community_p
 
 set return_url [ad_conn url]
-foreach group [contact::groups -indent_with "..." -expand "all" -output "all" -privilege_required "admin" -all] {
+foreach group [contact::groups -indent_with "..." -expand "all" -output "all" -privilege_required "admin" -all -include_dotlrn_p "1"] {
     set group_id [lindex $group 1]
     set group_name [lindex $group 0]
     set member_count [lindex $group 2]
     set level [lindex $group 3]
     set mapped_p [lindex $group 4]
     set default_p [lindex $group 5]
     set user_change_p [lindex $group 6]
+    set dotlrn_community_p [lindex $group 7]
     set ams_person_url [ams::list::url \
                           -package_key "contacts" \
                           -object_type "person" \
@@ -126,7 +142,7 @@
     set edit_url [export_vars -base "/acs-lang/admin/edit-localized-message" {{package_key acs-translations} {locale "[ad_conn locale]"} {message_key "group_title_${group_id}"} {return_url [ad_return_url]}}]
 
     set categories_url [export_vars -base "/categories/cadmin/object-map" -url {{object_id $group_id}}]
-    multirow append groups [lindex $group 1] [lindex $group 0] "../?group_id=${group_id}" $ams_person_url $ams_org_url $member_count $level $mapped_p $default_p $categories_url $edit_url $user_change_p
+    multirow append groups [lindex $group 1] [lindex $group 0] "../?group_id=${group_id}" $ams_person_url $ams_org_url $member_count $level $mapped_p $default_p $categories_url $edit_url $user_change_p $dotlrn_community_p
 
 
 }