http://www.bianceng.cn/Programming/cplus/200705/614.htm

高质量C++/C编程指南-第1章-文件结构

第1章 文件结构 每个C++/C程序通常分为两个文件。一个文件用于保存程序的声明( declaration ),称为头文件。另一个文件用于保存程序的实现( implementation ),称为定义( definition )文件。

C++/C 程序的头文件以“ .h ”为后缀, C 程序的定义文件以“ .c ”为后缀, C++ 程序的定义文件通常以“ .cpp ”为后缀(也有一些系统以“ .cc ”或“ .cxx ”为后缀)。

1.1 版权和版本的声明 版权和版本的声明位于头文件和定义文件的开头(参见示例 1-1 ),主要内容有:

( 1 )版权信息。

( 2 )文件名称,标识符,摘要。

( 3 )当前版本号,作者 / 修改者,完成日期。

( 4 )版本历史信息。

/*

* Copyright (c) 2001,上海贝尔有限公司网络应用事业部

* All rights reserved.

*

* 文件名称: filename.h

* 文件标识: 见配置管理计划书

* 摘 要: 简要描述本文件的内容

*

* 当前版本: 1.1

* 作 者: 输入作者(或修改者)名字

* 完成日期: 2001年7月20日

*

* 取代版本 : 1.0

* 原作者 : 输入原作者(或修改者)名字

* 完成日期: 2001年5月10日

*/

示例 1-1 版权和版本的声明

1.2 头文件的结构 头文件由三部分内容组成:

( 1 )头文件开头处的版权和版本声明(参见示例 1-1 )。

( 2 )预处理块。

( 3 )函数和类结构声明等。

假设头文件名称为 graphics.h,头文件的结构参 见示例 1-2 。

l 【规则 1-2-1 】 为了防止头文件被重复引用,应当用 ifndef/define/endif 结构产生预处理块。

l 【规则 1-2-2 】 用 #include < filename.h> 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。

l 【规则 1-2-3 】 用 #include “filename.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。

2 【建议 1-2-1 】 头文件中只存放“声明”而不存放“定义”

在 C++ 语法中,类的成员函数可以在声明的同时被定义,并且自动成为内联函数。这虽然会带来书写上的方便,但却造成了风格不一致,弊大于利。建议将成员函数的定义与声明分开,不论该函数体有多么小。

2 【建议 1-2-2 】 不提倡使用全局变量,尽量不要在头文件中出现象 extern int value 这类声明。

// 版权和版本声明见示例 1-1 ,此处省略。

#ifndef GRAPHICS_H // 防止 graphics.h 被重复引用

#define GRAPHICS_H

#include <math.h> // 引用标准库的头文件

#include “myheader.h” // 引用非标准库的头文件

void Function1(…); // 全局函数声明

class Box // 类结构声明

{

};

#endif

示例 1-2 C++/C头文件的结构

1.3 定义文件的结构 定义文件有三部分内容:

(1) 定义文件开头处的版权和版本声明(参见示例 1-1 )。

(2) 对一些头文件的引用。

(3) 程序的实现体(包括数据和代码)。

假设定义文件的名称为 graphics.cpp, 定义 文件的结构参 见示例 1-3 。

// 版权和版本声明见示例 1-1 ,此处省略。

#include “graphics.h” // 引用头文件

// 全局函数的实现体

void Function1(…)

{

}

// 类成员函数的实现体

void Box::Draw(…)

{

}

示例 1-3 C++/C定义文件的结构

1.4 头文件的作用 早期的编程语言如 Basic 、 Fortran 没有头文件的概念, C++/C 语言的初学者虽然会用使用头文件,但常常不明其理。这里对头文件的作用略作解释:

( 1 )通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。

( 2 )头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。

1.5 目录结构 如果一个软件的头文件数目比较多(如超过十个),通常应将头文件和定义文件分别保存于不同的目录,以便于维护。

例如可将头文件保存于 include 目录,将定义文件保存于 source 目录(可以是多级目录)。

如果某些头文件是私有的,它不会被用户的程序直接引用,则没有必要公开其“声明”。为了加强信息隐藏,这些私有的头文件可以和定义文件存放于同一个目录。

ldapconf.h

/*
**++
**  MODULE:        $RCSfile$
**            $Revision: 83122 $
**            $Date: 2011-07-12 00:58:50 -0700 (Tue, 12 Jul 2011) $
**
**  DESCRIPTION:
**
**  ENVIRONMENT:    Generic Server (NT/Unix)
**
**  COPYRIGHT:        Copyright ?2004 TIBCO Software Inc.
**
**  MODIFICATION HISTORY:
**
**    $Log$
**    Revision 7.5  2006/07/21 14:07:51  cdurrant
**    CR19009_1 – support UTF-8 attribute value translation in LDAP
**
**    Revision 7.4  2004/11/23 14:32:41Z  CharlesD
**    pod_1194_reint – LDAP referrals CRs reintegration
**    Revision 7.3  2004/11/04 17:13:44Z  JohnCA
**    LDAP GENERALI reint
**    Revision 7.2.1.4  2004/10/21 15:49:17Z  JohnCA
**    Revision 7.2.1.3  2004/10/21 09:08:56Z  JohnCA
**    LDAP DN format Enhancements
**    Revision 7.2.1.2  2004/09/28 16:29:20Z  JohnCA
**    LDAP Enhancements for Generali
**    Revision 7.2.1.1  2002/01/09 13:03:46Z  JohnCA
**    Duplicate revision
**    Revision 7.2  2002/01/09 13:03:46Z  SteveC
**    Automatically reintegrated (by autreint.ksh):
**    Reintegration from REINT_630 1.141.1.4
**    Revision 7.1.2.2  2002/01/07 15:01:13  SteveC
**    Revision 7.1.2.1  2001/03/09 18:54:28  SteveC
**    Duplicate revision
**    Revision 1.8  2001/03/09 08:58:03  nick
**    Automated code tidying
**    Revision 1.7  2001/03/08 10:49:41  nick
**    Auto dead code removal
**    Revision 1.6  1998/01/14 17:31:06  ben
**    Revision 1.5  1998/01/05 11:35:07  ben
**    Revision 1.4  1997/12/10 09:59:12  ben
**    UNIX was complaining about weird EOF character.
**    No chg other than resave
**    Revision 1.3  1997/12/09 08:18:06  steve
**    Use message file to hold output messages
**    Revision 1.2  1997/11/25 18:10:37  ben
**–
*/

#include "ldapconf.i"

/* CR6685 SAC 08-12-97 : Definitions for messages */
#define    M_EXISTS        1
#define    M_DELETED        2
#define    M_NOT_FOUND        3
#define    M_E_CFG_READ        4
#define    M_E_LOGIN        5
#define    M_E_PASSWD_MAT        6
#define    M_PASSWD_CONF        7
#define    M_ONLY_SWADMIN        8
#define    M_E_INVALID_ENTRY    9
#define    M_ASK_HOST        10
#define    M_ASK_PORTNUMBER    11
#define    M_E_PORTNO        12
#define    M_ASK_BIND_NAME        13
#define    M_ASK_START_SEARCH    14
#define    M_ASK_FILTER_SEARCH    15
#define    M_E_NO_ENTRIES        16
#define    M_VAL_CHANGE        17
#define    M_VAL_CHG_TO        18
#define    M_E_DUPLICATE        19
#define    M_VAL_DELETE        20
#define    M_VAL_ADD        21
#define    M_ASK_USERNAME        22
#define    M_ASK_ROLE        23
#define    M_ASK_GROUP        24
#define    M_ASK_MENUNAME        25
#define    M_ASK_DESCRIPTION    26
#define    M_ASK_LANGUAGE        27
#define    M_ASK_SORTMAIL        28
#define    M_ASK_ENTER        29
#define    M_CONNECTION        30
#define    M_HOSTNAME        31
#define    M_PORTNO        32
#define    M_CREDENTIALS        33
#define    M_PASSWORD        34
#define    M_SEARCH        35
#define    M_BASE            36
#define    M_FILTER        37
#define    M_USERNAME        38
#define    M_MENUNAME        39
#define    M_LANGUAGE        40
#define    M_DESCRIPTION        41
#define    M_SORTMAIL        42
#define    M_GROUPUSERS        43
#define    M_ROLEUSER        44
#define    M_EXTRA            45
#define    M_DIT            46
#define    M_ASK_ENTER_X        47
#define    M_OVERWRITE        48
#define    M_E_FILENAME        49
#define    M_CONN_TESTING        50
#define    M_CONN_SUCCESS        51
#define    M_ENTRIES_FOUND        52
#define    M_ENTRIES_NONE        53
#define    M_ASK_INFO_FILE        54
#define    M_NO_DATA_CHANGED    55
#define    M_E_DATA_WRITE        56
#define    M_DATA_SAVED        57
#define    M_M_CONN_INFO        58
#define    M_M_SEARCH_INFO        59
#define    M_M_ATTRIB_MAP        60
#define    M_M_VIEW_INFO        61
#define    M_M_CONN_TEST        62
#define    M_M_RETURN_DIT        63
#define    M_M_SAVE        64
#define    M_M_SYNCHRONISE        65
#define    M_M_QUIT        66
#define    M_M_ENTER_OPTION    67
#define    M_E_INVALID_OPTION    68
#define    M_E_UNKNOWN_OPTION    69
#define    M_E_SUBOPTION_REQ    70
#define    M_E_UNKNOWN_SUBOPTION    71
#define    M_E_VALUE_REQ        72
#define    M_DOWNLOAD_USER        73
#define    M_MAPPING        74
#define    M_FILE_SCREEN        75
#define    M_STAFFW_NOT_EXTRA    76
#define    M_X500_NOT_EXTRA    77
#define    M_ASK_CHG_PASSWD    78
#define    M_ASK_PASSWD        79
#define    M_EXTRA_MENU        80
#define    M_MULTIPLE_MAP        81
#define    M_MAPPINGS        82
#define    M_ASK_SAVE        83
#define    M_PLEASE_SAVE        84
#define    M_AMBIGUOUS        85
#define    M_FULL_PARTIAL_QUIT    86
#define M_CONNECT_FAIL    87
#define M_SETINFO_FAIL    88
#define    M_ERROR_PARAM    89

/* CR9574 New messages for additional QSUPERVISOR & userflags parameter */
#define    M_ASK_QSUPERVISORS    90
#define    M_QSUPERVISORS        91
#define    M_ASK_USERFLAGS        92
#define    M_USERFLAGS        93
/* CR9574 End */

/* CR16174 JMC 30-9-2004: New messages for GROUPNAME and ROLENAME parameter */
#define    M_ASK_GROUPNAME        94
#define    M_GROUPNAME        95
#define M_ASK_ROLENAME        96
#define    M_ROLENAME        97
/* CR16174 End */

/* CR16395 JMC 15-9-2004: New message for GRPMEMLDAP */
#define M_M_GRPMEM_LDAP        98
#define    M_GRPUSERS        99
/* CR16395 End */
/* CR14734 CJED 22-NOV-2004 – reintegrated */
#define    M_PARTIAL_FOUND        100
/*
** CR19009 – CJED 21-JUL-2006 – messages for attribute UTF-8 translation
*/
#define M_M_ENABLE_AV_TRANS    101
#define M_M_DISABLE_AV_TRANS    102

/*
** MR 38043 – LingWu 11-Dec-2008 – messages for attribute DN pattern
*/
#define M_ASK_DN_PATTERN    103
#define M_DNPATTERN            104

#define M_ASK_ENABLE_SSL        105
#define M_ASK_DISABLE_SSL        106
#define M_ASK_CERT_PATH        107
#define M_ASK_ACTIVE_DIRECT    108

#define    M_VAL_ADD_X500        109

ldapcon.c

/*
**++
**  MODULE:        $RCSfile$
**            $Revision: 83122 $
**            $Date: 2011-07-12 00:58:50 -0700 (Tue, 12 Jul 2011) $
**
**  DESCRIPTION:
**
**  ENVIRONMENT:    Generic Server (NT/Unix)
**
**  COPYRIGHT:        Copyright ?2004, TIBCO Software Inc.
**
**  MODIFICATION HISTORY:
**
**    $Log$
**    Revision 7.51  2007/02/14 11:13:47  mbanfiel
**    CR19771 Re-order output of mappings to match input order
**
**    Revision 7.50  2007/02/12 16:54:00Z  cdurrant
**    CR19761 – report group membership errors to file as well as screen
**    Revision 7.49  2007/02/01 19:44:50Z  stevec
**    CR19716: If LDAP attribute that determines type of entry comes after membership attribute then members aren't checked
**    Revision 7.48  2007/02/01 12:03:49Z  stevec
**    CR19716: If LDAP attribute that determines type of entry comes after membership attribute then members aren't checked
**    Revision 7.47  2006/12/18 11:28:48Z  cdurrant
**    CR19501 – fail MOVESYSINFO if LDAP sync fails
**    Revision 7.46  2006/12/15 12:21:01Z  cdurrant
**    CR19495 – fix groupusers list handling
**    Revision 7.45  2006/12/08 11:38:22Z  cdurrant
**    CR19493_1 – fix error on Win32 build
**    Revision 7.44  2006/12/07 12:02:26Z  cdurrant
**    CR19493 – show the value of GROUPUSERS attribute in ldapconf
**    Revision 7.42  2006/08/03 14:02:43Z  rhudson
**    CR19048 Itanium Build
**    Revision 7.41  2006/07/21 14:07:50Z  cdurrant
**    CR19009_1 – support UTF-8 attribute value translation in LDAP
**    Revision 7.40  2006/07/14 06:49:35Z  SteveC
**    CR18964: LDAPCONF test treats spaces as valid users in group member lists
**    Revision 7.39  2006/06/21 14:47:05Z  SteveC
**    CR18828: CR18665 was broken by Charles' change to ldapconf.c
**    Revision 7.38  2006/05/19 10:21:24Z  cdurrant
**    CJED_fix_UNIX_build – min macro not available on UNIX build, also used correct size for lustrncpy function.
**    Revision 7.37  2006/05/18 16:15:41Z  SteveC
**    CR18665: Ldapconf outputs error when member of group doesn't exist, even though they may appear later in the LDAP search results
**    Revision 7.36  2006/01/30 15:35:01Z  mbanfiel
**    CR17995: LDAP truncates group membership list at 100 characters
**    Revision 7.35  2006/01/30 11:57:16Z  mbanfiel
**    CR17344 Add ldap_check_all_members_valid function
**    Revision 7.34  2006/01/06 09:38:36Z  rhudson
**    CR17052 Main Trunk Reint
**    Revision 7.33  2005/11/14 17:20:12Z  rhudson
**    Revision 7.32  2005/06/06 09:26:19Z  mbanfiel
**    CR17172 Product name change
**    Revision 7.31  2005/03/14 17:02:54Z  njpatel
**    Reintegration of CR16829
**    CR14758 Corrected overlooked reintegration.
**    Revision 7.30  2005/03/08 16:57:32Z  jcarver
**    Fix for ldap debug trace
**    Revision 7.29  2005/02/21 16:28:44Z  nhaines
**    Changed copyright info
**    Revision 7.28  2005/01/28 14:21:07Z  RobertH
**    CR16881 Fixed startup when server not running
**    Revision 7.27  2005/01/25 15:46:37Z  CharlesD
**    CR16732_1 – First attempt at swldap file upgrade
**    Revision 7.26  2005/01/21 12:49:22Z  JohnCA
**    Fix for ldapconf seg fault
**    Revision 7.25  2005/01/20 17:30:53Z  JohnCA
**    Fixes in line with BG for CR16847
**    Revision 7.24  2005/01/07 11:04:14Z  NickH
**    Modified copyright notice to match spec
**    Revision 7.23  2004/12/22 15:11:57Z  JohnCA
**    Fix for GroupUsers in LDAP
**    Revision 7.22  2004/12/16 15:21:34Z  JohnCA
**    Fix for valid MEMBERLIST in ldap
**    Revision 7.21  2004/12/15 13:32:53Z  JohnCA
**    ldapconf TEST -l fix
**    Revision 7.20  2004/12/10 08:59:05Z  NickH
**    Removed debug printf
**    Revision 7.19  2004/12/10 08:53:55Z  NickH
**    Added new copyright system
**    Revision 7.18  2004/12/02 15:49:56Z  JohnCA
**    Partial Sync to LDAP MSActive
**    Revision 7.17  2004/11/23 14:32:40Z  CharlesD
**    pod_1194_reint – LDAP referrals CRs reintegration
**    Revision 7.16  2004/11/08 17:33:03Z  JohnCA
**    Change X.500 to LDAP
**    Revision 7.15  2004/11/05 10:09:01Z  JohnCA
**    Copyright
**    Revision 7.14  2004/11/04 15:13:22Z  JohnCA
**    LDAP GENERALI reint
**    Revision 7.12.1.6  2004/11/02 16:11:23Z  JohnCA
**    Fix array overrun in ldapconf
**    Revision 7.12.1.5  2004/10/21 16:38:11Z  JohnCA
**    CR16296: Copyright TIBCO 2004
**    Revision 7.12.1.4  2004/10/21 15:49:02Z  JohnCA
**    Revision 7.12.1.3  2004/10/21 09:07:54Z  JohnCA
**    LDAP DN format Enhancements
**    Revision 7.12.1.2  2004/09/28 16:27:49Z  JohnCA
**    LDAP Enhancements for Generali
**    Revision 7.12.1.1  2004/09/13 13:39:41Z  JohnCA
**    Duplicate revision
**    Revision 7.12  2004/09/13 13:39:41Z  CharlesD
**    CR15884_reint_MT – reintegrated back into /batch trunk for POD/1218
**    Revision 7.11  2004/09/10 12:59:02Z  RobertH
**    CR16288 Linux – Remove {} round each field as it is not valid
**    Revision 7.10  2004/02/10 16:34:39Z  KevinG
**    CR14973 copyright changes
**    Revision 7.9  2003/08/14 14:02:11Z  SidA
**    Reintegrations from i9.2-o(1.0.2), i9.2-o(2.2.1), i9.2-o(2.2.2),
**    i9.2-o(3.1) amd i9.2-o(3.3) into main trunk
**    Revision 7.8  2003/04/16 13:19:08  KevinG
**    CR13267 Update copyright
**    Revision 7.7  2002/07/15 15:26:26  SteveC
**    CR11968 : Using extra attributes for ldap X.500 can cause ldapconf and the BG process to crash.
**    Revision 7.6  2002/06/14 09:52:28  SteveC
**    CR11680: copyright version update
**    Revision 7.5.1.2  2003/08/06 11:13:45  JohnCA
**    Reint plus LDAP fixes
**    Revision 7.5.1.1  2002/01/14 14:07:44  JohnCA
**    Duplicate revision
**    Revision 7.5  2002/01/14 14:07:44  SteveC
**    CR10933: NT port integration
**    Revision 7.4  2002/01/09 13:03:44  SteveC
**    Automatically reintegrated (by autreint.ksh):
**    Reintegration from REINT_630 1.141.1.4
**    Revision 7.3.2.3  2002/01/07 15:01:12  SteveC
**    Revision 7.3.2.2  2002/01/03 11:57:17  SteveC
**    Integration from 1.101 –> 1.101.1.27 (PART I)
**    Revision 7.3.2.1  2001/11/16 13:51:39  SteveC
**    Duplicate revision
**    Revision 7.2  2001/07/16 08:51:14  SteveC
**    Reintegration from FILPACKDB branch:
**
**    1.103 –> 1.103.4.4
**    Revision 7.1  2001/03/09 18:54:19  nick
**    Version number update
**    Revision 1.32  2001/03/09 08:57:55  nick
**    Automated code tidying
**    Revision 1.31  2001/03/08 10:49:33  nick
**    Auto dead code removal
**    Revision 1.30  2000/05/25 21:31:44  markb
**    CLEAN_BUILD – Post POD/STR/201 & POD/CUS/146 Integ.
**    Revision 1.29  2000/05/23 00:37:15  markb
**    POD_STR_201_Phase_2_Reint_Main – Reintegrating POD_STR_201 Phase 2 into the main trunk.
**    Revision 1.28  2000/03/23 14:37:42  kevin
**    CR8897 Stop GPF in ldapconf
**    Revision 1.27.1.2  2000/04/11 17:02:43  keith
**    CR8937: Fix compiler warning on AIX
**    Revision 1.27.1.1  2000/03/08 13:15:37  keith
**    Duplicate revision
**    Revision 1.27  2000/03/08 13:15:37  ben
**    CR8892 – oversize attribute values cause coredumping in x500
**    mode reporting.
**    CR8893 – do not destroy swldaplck file if you are not the originator.
**    Revision 1.26  2000/01/10 09:50:17  steve
**    Integration from 1.40.1.11 –> 1.40.1.16 and changes for CR8272
**    Revision 1.25  1999/10/13 16:21:24  markb
**    POD_STR_013 – Added new swprim password checking stuff.
**    Revision 1.24  1999/09/21 15:06:09  markb
**    POD/STR/013 – Changed BOOL to SWBOOL.
**    Revision 1.23  1999/07/01 14:45:26  sid
**    POD/STR/011 – pick up correct prototypes for sw_ref_msg
**    Revision 1.22  1999/05/21 10:09:23  steve
**    Revision 1.21  1999/05/18 07:06:56  steve
**    Revision 1.20  1999/04/21 13:46:06  steve
**    Re-integration from 1.32.1.9
**    Revision 1.19  1999/01/28 17:17:16  steve
**    Automatically reintegrated (by autreint.ksh):
**    Re-integration from I249_NTServer_MultiNode (1.32.1.4)
**    Revision 1.18.1.2  1998/12/22 13:38:24  steve
**    CR7869 : modify search filter the same way the Staffware BG does
**    Revision 1.18.1.1  1998/10/05 06:43:52  steve
**    Duplicate revision
**    Revision 1.17  1998/07/22 10:33:12  ian
**    I265 – Server Integration: compiler warnings
**    Revision 1.16  1998/07/17 15:53:26  keith
**    CR7284: changes for clean compile on UNIX
**    Revision 1.15  1998/06/26 14:07:13  ian
**    CR7036 – FIL Re-integration
**    Revision 1.14.1.2  1998/05/29 10:53:44  ian
**    CR7036 – FIL Integration
**    Revision 1.14.1.1  1998/02/09 10:56:54  ian
**    Duplicate revision
**    Revision 1.13.1.2  1998/01/28 17:09:17  steve
**    CR6733 : Changes made for NT SAL SDK
**    Revision 1.12  1998/01/05 11:35:06  ben
**    Revision 1.11  1997/12/11 10:55:02  ben
**    allow entry of NULL to signify ""
**    Revision 1.10  1997/12/10 12:19:43  steve
**    Revision 1.9  1997/12/10 10:44:25  ben
**    for a clean UNIX build
**    Revision 1.8  1997/12/09 08:18:02  steve
**    Use message file to hold output messages
**    Revision 1.7  1997/12/08 14:38:06  ben
**    Revision 1.6  1997/11/28 19:10:39  ben
**    Safeguard changes
**    Revision 1.5  1997/11/26 18:56:36  ben
**    Revision 1.4  1997/11/25 17:58:00  ben
**    if len  extras too long won't get assigned
**    Revision 1.3  1997/11/25 11:09:53  ben
**    Revision 1.2  1997/11/24 10:03:42  ben
**    Revision 1.1  1997/11/24 09:50:01  ben
**    Initial revision
**–
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef    SW4_UNIX
#include <signal.h>
#include <ctype.h>
#include <pwd.h>
#endif

#include "swvers.h"
#include "swtype.h"
#include "swldap.h"
#include "sallogin.h"
#include "filpost.h"
#include "sallinit.h"
#include "postutil.i"
#include "postwrit.i"
#include "errhand.h"        /* CR6685 SAC */
#include "errhand.i"        /* CR6685 SAC */
#include "wchar.h"
#include "sallogin.i"
#include "filnode.i"
#include "swprim.i"

#include "filuser.i"
#include "swchrset.i"
#include "internal.h"        /* CR6733 SAC */

/* CR10765 SAC 15-11-01 */
#include "psulmain.h"
#include "filpattr.h"
#include "mbset.h"

#ifdef    SW4_WIN32SERVER
#include <conio.h>
#endif
/* CR10647 Fix all compiler warnings cause I'm nice (probably cause more problems though) */
/* Needs an include file at some point (defined in filinit2.c) */
EXTERNAL int    create_filsh (LPCHR swdir, LPCHR debug_log, LPCHR registry_area);

/* SID POD/STR/011 – message funcs now def'd correctly in unimsg.i */
#include "unimsg.i"

#define SIZEOFBIGP 16
#define ER_ENTRY_NOTFOUND   -1
#define LINESONSCR 24

/* CR14758 NJP 14Mar05 – #ifdef left out during reintegration */
#ifdef SW4_UNIX
/* CR14758 JMC 25-2-04 */
extern int ldap_debug;
#endif

NODE my_node;

UCHR msg[256];
UCHR lockfile[256];        /* must be global for sighandler to pick up */

SW_LDAP_info *sw_ldap_info, *sw_ldap_info_copy = NULL;
SW_LDAP *ldap;

SWINT32 ret;
SWINT32 num_entries;
SWINT32 filsh;

/* CR10765 SAC 15-11-01 */
PATTR_SH    hPAT;

/* CR6685 SAC 08-12-97 : message session handle */
int msg_sh;
int lock_fh;
/* CR16288 Linux – Remove {} round each field as it is not valid */
const char *bigentries[] = {
    "ATTRIB",
    "CONNECT",
    "SEARCH",
    "TEST",
    "HELP",
    "VIEW",
    "MOVESYSINFO"
};

typedef struct
{
    UCHR BIGP[SIZEOFBIGP];
    UCHR member[10];
    int set;
} ENTRY;

ENTRY entries[] = {
    {"ATTRIB", "u",},    /* Username      */
    {"ATTRIB", "r",},    /* Role          */
    {"ATTRIB", "g",},    /* Group         */
    {"ATTRIB", "menu",},
    {"ATTRIB", "desc",},    /* Description   */
    {"ATTRIB", "lang",},    /* Language      */
    {"ATTRIB", "sort",},    /* Sortmail      */
    {"ATTRIB", "x",},    /* Extras        */

    {"CONNECT", "h",},    /* Hostname      */
    {"CONNECT", "port",},    /* Username      */
    {"CONNECT", "dn",},    /* DN Entry      */
    {"CONNECT", "pwd",},    /* Password      */

    {"SEARCH", "dn",},
    {"SEARCH", "s",},    /* Search filter */

    {"TEST", "f",},        /* File name     */
    {"TEST", "s",},        /* user/role/group/attribute info to be downloaded from LDAP DIT. */
    {"TEST", "l",},

    {"MOVESYSINFO", "full",},
    {"MOVESYSINFO", "partial"}

};

/* CR9574 Now uses NUM_SW_ELEMENTS in swldap.h instead of */
/* hardcoded sizes */
X500_TO_SWARE_MAP xsmap[NUM_SW_ELEMENTS];

typedef struct ll
{
    UCHR x500[SW_LDAP_ATTRNAME_SIZE];
    UCHR staffware[SW_LDAP_ATTRNAME_SIZE];
    struct ll *next;
}
LL;

#include "ldapconf.h"
LL *head = NULL;

#ifdef    __cplusplus
extern "C"
{
#endif
    int g_UTF8Support = 0;
#ifdef    __cplusplus
}
#endif
/*
**++
** FUNCTIONs LL_xxx perform the required operations for maintaining a linked list of character strings
**–
*/
PRIVATE LL *LL_find (LPUCHR srch)
{
    UCHR usrch[256];
    UCHR ucurr[256];
    LL *p = head;
    LL *ret = NULL;

    lustrcpy (usrch, srch);
    ucase (usrch);

    for (p = head; p != NULL; p = p->next)
    {
        lustrcpy (ucurr, p->staffware);
        ucase (ucurr);
        if (!lustrcmpul (ucurr, usrch))
        {
            ret = p;
            break;
        }
    }
    return ret;
}

/*
**++
**
**–
*/
PRIVATE void LL_add (LPUCHR staffware, LPUCHR x500)
{
    LL *p = NULL;
    LL *next;
    int x;
    p = LL_find (staffware);
    if (p)
    {
        printf (SW_REF_MSG (M_EXISTS), staffware);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        return;
    }

    /* CR9574 Now uses NUM_SW_ELEMENTS in swldap.h instead of */
    /* hardcoded sizes */
    for(x=0;x<NUM_SW_ELEMENTS;x++)
    {
        if (!lustrcmpul (staffware, xsmap[x].staffware))
        {
            printf (SW_REF_MSG (M_STAFFW_NOT_EXTRA));    /* CR6685 SAC */
            printf ("n");    /* CR6685 */
            return;
        }
        if (!lustrcmpul (staffware, xsmap[x].x500))
        {
            printf (SW_REF_MSG (M_X500_NOT_EXTRA));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            return;
        }
    }

    next = (LL *) malloc (sizeof (LL));
    if (head != NULL)
        for (p = head; p->next != NULL; p = p->next);    /* traverse to end of list */
    else
        head = next;    /* anchor the head */
    lustrcpy (next->staffware, staffware);
    lustrcpy (next->x500, x500);
    next->next = NULL;
    if (p)
        p->next = next;
}

/*
**++
**
**–
*/
PRIVATE void LL_del (LPUCHR val)
{
    LL *p = NULL, *prev = NULL;
    for (p = head; p != NULL; prev = p, p = p->next)
    {
        if (!lustrcmpul (p->staffware, val))
        {
            if (prev)
                prev->next = p->next;
            else    /* top of the list, so reset head! */
                head = p->next;
            free (p);
            printf (SW_REF_MSG (M_DELETED), val);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            return;
        }
    }
    printf (SW_REF_MSG (M_NOT_FOUND), val);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */
    return;
}

/*
**++
**
**–
*/
PRIVATE void LL_chg (LPUCHR old, LPUCHR nw)
{
    LL *o;
    LL *n;
    o = LL_find (old);
    if (!o)
    {
        printf (SW_REF_MSG (M_NOT_FOUND), old);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        return;
    }
    n = LL_find (nw);
    if (n)
    {
        printf (SW_REF_MSG (M_EXISTS), nw);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        return;
    }

    /* got here so continue */
    lustrcpy (o->x500, nw);
}

/*
**++
**
**–
*/
PRIVATE void LL_list ()
{
    LL *p;
    int lineno = 0;
    for (p = head; p != NULL; p = p->next)
    {
        printf ("%s -> %sn", p->staffware, p->x500);
        lineno++;
        if (lineno > (LINESONSCR – 2))
        {
            prompt ();
            lineno = 0;
        }
    }
}

/*
**++
**
**–
*/
PRIVATE void LL_freeall ()
{
    LL *p, *next;
    for (p = head; p != NULL; p = next)
    {
        next = p->next;
        free (p);
    }
    head = NULL;
}

/*
**++
** FUNCTION ucase
**
** DESCRIPTION  :
** Converts a given character string to upper case
**–
*/
PRIVATE void ucase (LPUCHR str)
{
    if (!str)
        return;

    while (*str)
    {
        *str = toupper (*str);
        str++;
    }
}

/*
**++
** FUNCTION lcase
**
** DESCRIPTION  :
** Converts a given character string to lower case
**–
*/
PRIVATE void lcase (LPUCHR str)
{
    if (!str)
        return;

    while (*str)
    {
        *str = tolower (*str);
        str++;
    }
}

/*
**++
** REQD?
**–
*/
PRIVATE void initialise (void)
{
    int c;
    int numents;

    numents = sizeof (entries) / sizeof (entries[0]);
    for (c = 0; c < numents; c++)
    {
        entries[c].set = 0;
    }
}

/*
**++
** RENAME
**–
*/
PRIVATE void getbigentry (LPUCHR BIGP, LPUCHR * entry)
/* return an error */
{
    int c;
    int numents = (sizeof (bigentries)) / sizeof (bigentries[0]);

    for (c = 0; (c < numents); c++)
        if (!lustrcmp (bigentries[c], BIGP))
        {
            *entry = (LPUCHR) bigentries[c];
            break;
        }

}

/*
**++
** RENAME
**–
*/
PRIVATE int getentry (LPUCHR BIGP, LPUCHR member)
{
    int c;
    int numents;
    int ret = ER_ENTRY_NOTFOUND;
    numents = sizeof (entries) / sizeof (entries[0]);

    for (c = 0; ((ret == ER_ENTRY_NOTFOUND) && (c < numents)); c++)
    {
        if ((!lustrcmp (entries[c].BIGP, BIGP))
            && (!lustrcmp (entries[c].member, member)))
            ret = c;
    }
    return ret;
}

/*
**++
** FUNCTION GetValidCh
**
** DESCRIPTION  :
** Displays a prompt for an input character; this character is checked to be a valid character for the context
**–
*/
PRIVATE void GetValidCh (char *prompt, char *valid, LPUCHR str)
{
    UCHR buff[80];
    UCHR promptcpy[128];

    lustrcpy (promptcpy, prompt);
    while (TRUE)
    {
        printf ("%s", promptcpy);
        gets ((char *) buff);
        ucase (buff);
        if ((strstr (valid, (char *) buff) == NULL)
            || lustrlen (buff) != 1)
        {
            printf (SW_REF_MSG (M_E_INVALID_ENTRY));    /* CR6685 SAC */
            printf ("nn");    /* CR6685 SAC */
        }
        else
            break;
    }
    lustrcpy (str, buff);
}

/*
**++
** FUNCTION connection
**
** DESCRIPTION  :
** Read connection information
**–
*/
PRIVATE void connection ()
{
    UCHR buff[1024];

    printf (SW_REF_MSG (M_ASK_HOST), sw_ldap_info->hostname);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
    if (strlen (gets ((char *) buff)))
        lustrcpy (sw_ldap_info->hostname, buff);
    */
    my_gets (sw_ldap_info->hostname, sizeof(sw_ldap_info->hostname)-1);

    while (TRUE)
    {
        int i;
        UCHR b[10];

        printf (SW_REF_MSG (M_ASK_PORTNUMBER), sw_ldap_info->hostname, sw_ldap_info->portno);    /* CR6685 SAC */

        if (!strlen (gets ((char *) buff)))
            break;

        i = atoi ((char *) buff);
        sprintf ((char *) b, "%d", i);
        if ((i < 0) || lustrcmp (buff, b))
        {
            printf (SW_REF_MSG (M_E_PORTNO));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
        }
        else
        {
            sw_ldap_info->portno = i;
            break;
        }
    }

    printf (SW_REF_MSG (M_ASK_BIND_NAME), sw_ldap_info->credentials);    /* CR6685 SAC */
    my_gets (sw_ldap_info->credentials, SW_LDAP_CRED_SIZE);

    GetValidCh (SW_REF_MSG (M_ASK_CHG_PASSWD), "YN", buff);    /* CR6685 SAC */

    if (!lustrcmp (buff, "Y"))
    {
        int ret = SW_OK;
        UCHR Msg1[100], Msg2[100];

        lustrcpy (Msg1, SW_REF_MSG (M_ASK_PASSWD));
        lustrcpy (Msg2, SW_REF_MSG (M_PASSWD_CONF));

        /*
           ** Use new swprim function for getting and confirming password entry
         */
        do
        {
            ret =
                sw_get_password_confirm (buff, Msg1, Msg2,
                             sizeof (buff) – 1);
            if (ret != SW_OK)
            {
                printf ("%sn", SW_REF_MSG (M_E_PASSWD_MAT));
            }
        }
        while (ret != SW_OK);
        lustrcpy (sw_ldap_info->password, buff);
    }
    printf (SW_REF_MSG (M_ASK_ACTIVE_DIRECT), sw_ldap_info->isAD ? "Yes" : "No");
    GetValidCh("","YN",buff);
    sw_ldap_info->isAD =!lustrcmp (buff, "Y");
    #ifndef SW4_WIN32SERVER

    if(sw_ldap_info->enableSSL)
    {
        GetValidCh(SW_REF_MSG(M_ASK_DISABLE_SSL),"YN",buff);
        sw_ldap_info->enableSSL =lustrcmp (buff, "Y");
    }
    else
    {
        GetValidCh(SW_REF_MSG(M_ASK_ENABLE_SSL),"YN",buff);
        sw_ldap_info->enableSSL =!lustrcmp (buff, "Y");
    }
    
    if(sw_ldap_info->enableSSL)
    {
        printf (SW_REF_MSG (M_ASK_CERT_PATH), sw_ldap_info->certpath);       /* CR6685 SAC */
        my_gets (sw_ldap_info->certpath, SW_LDAP_BASE_SIZE);
    }
    #endif

    

    
}

/*
**++
** FUNCTION search
**
** DESCRIPTION  :
** Read search information
**–
*/
PRIVATE void search ()
{
    /* MR 41741  UCHR buff[256]; */

    printf (SW_REF_MSG (M_ASK_START_SEARCH), sw_ldap_info->base);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
     * if (strlen (gets ((char *) buff)))
     *    lustrcpy (sw_ldap_info->base, buff);
     */
    my_gets (sw_ldap_info->base, sizeof(sw_ldap_info->base)-1);

    printf (SW_REF_MSG (M_ASK_FILTER_SEARCH), sw_ldap_info->filter);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
     * if (strlen (gets ((char *) buff)))
     *    lustrcpy (sw_ldap_info->filter, buff);
     */
    my_gets (sw_ldap_info->filter, sizeof(sw_ldap_info->filter)-1);

    printf (SW_REF_MSG (M_ASK_DN_PATTERN), sw_ldap_info->dnPattern);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
     * if (strlen (gets ((char *) buff)))
     * {
     *    lustrcpy (sw_ldap_info->dnPattern, buff);
     * }
     */
    my_gets (sw_ldap_info->dnPattern, sizeof(sw_ldap_info->dnPattern)-1);
}

/*
**++
**
**–
*/
PRIVATE void extra_to_LL ()
{
    int x;
    LL_freeall ();        /* to be sure, to be sure */
    for (x = 0; x < sw_ldap_info->num_extras; x++)
        LL_add (sw_ldap_info->extra[x]->staffware, sw_ldap_info->extra[x]->x500);
}

/*
**++
**
**–
*/
PRIVATE void LL_to_extra ()
{
    LL *p;

    SW_LDAP_extra_free (sw_ldap_info);

    for (p = head; p != NULL; p = p->next)
    {
        SW_LDAP_extra_add (sw_ldap_info, p->staffware, p->x500);
    }
}

/*
**++
** FUNCTION extras
**
** DESCRIPTION  :
** Read extra information
**–
*/
PRIVATE void extras ()
{
    UCHR buff[SW_LDAP_ATTRNAME_SIZE];
    extra_to_LL ();
    while (TRUE)
    {
        GetValidCh (SW_REF_MSG (M_EXTRA_MENU), "LCDAQ", buff);    /* CR6685 SAC */

        if ((!head) && strstr ("LCD", (char *) buff))
        {        /*attempted to list/change/delete an empty list */
            printf (SW_REF_MSG (M_E_NO_ENTRIES));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            continue;
        }

        if (!lustrcmp (buff, "L"))
            LL_list ();
        else if (!lustrcmp (buff, "C"))
        {
            LL *o, *n;
            UCHR nw[256];

            printf (SW_REF_MSG (M_VAL_CHANGE));    /* CR6685 SAC */

            gets ((char *) buff);
            if (!*buff)
                continue;
            o = LL_find (buff);
            if (!o)
            {
                printf (SW_REF_MSG (M_NOT_FOUND), buff);    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                continue;
            }

            printf (SW_REF_MSG (M_VAL_CHG_TO), buff);    /* CR6685 SAC */

            gets ((char *) nw);
            /* CR9620 Don't allow values to be changed to NULL or space (cause PAG are bound */
            /* to try a space prefix) or something equally silly */
            if(*nw == 0 || *nw == ' ') {
                /* print out a message that it's invalid */
                printf (SW_REF_MSG (M_E_INVALID_ENTRY));
                printf("n");
            } else {
                n = LL_find (nw);
                if (n)
                {
                    printf (SW_REF_MSG (M_EXISTS), nw);    /* CR6685 SAC */
                    printf ("n");    /* CR6685 SAC */
                    continue;
                }
                LL_chg (buff, nw);
            /* CR9620 End */
            }
        }

        else if (!lustrcmp (buff, "D"))
        {

            printf (SW_REF_MSG (M_VAL_DELETE));    /* CR6685 SAC */

            gets ((char *) buff);
            if (!*buff)
                continue;
            LL_del (buff);
        }
        else if (!lustrcmp (buff, "A"))
        {
            UCHR x500[SW_LDAP_ATTRNAME_SIZE];
            printf (SW_REF_MSG (M_VAL_ADD));    /* CR6685 SAC */

            gets ((char *) buff);
            
            if (!*buff)
                continue;
            printf (SW_REF_MSG (M_VAL_ADD_X500));
            gets ((char *) x500);

            /* CR13995 JMC 31-7-03 Don't allow values to be added to NULL or space */
            if(*buff == 0 || *buff == ' ' || *x500 == 0 || *x500 == ' ') {
                /* print out a message that it's invalid */
                printf (SW_REF_MSG (M_E_INVALID_ENTRY));
                printf("n");
            } else {
                /* add entry to extras */
                LL_add (buff, x500);
            } /* CR13995 end */
        }

        else if (!lustrcmp (buff, "Q"))
        {
            LL_to_extra ();
            return;
        }
    }
}

/*
**++
** FUNCTION chk_dups
**
** DESCRIPTION  :
** Check no duplicates in attribute settings
**–
*/
PRIVATE SWBOOL chk_dups ()
{
    struct DUPCHECK
    {
        UCHR x500[SW_LDAP_ATTRNAME_SIZE + 1];
        int count;
    } dupcheck[7];

    int x, y;
    SWBOOL are_dups = FALSE;

    memset ((LPCHR) & dupcheck, '', sizeof (dupcheck));
    for (x = 0; x < 7; x++)
    {
        for (y = 0; y < 7; y++)
        {
            if (!lustrcmpul (xsmap[x].x500, (LPUCHR) ""))
                break;

            if (!lustrcmpul (xsmap[x].x500, dupcheck[y].x500))
            {    /* match found */
                dupcheck[y].count++;
                break;
            }
        }
        if (y >= 7)
        {        /* not found */
            y = 0;
            while (lustrcmp (dupcheck[y].x500, (LPUCHR) ""))
                y++;
            lustrcpy (dupcheck[y].x500, xsmap[x].x500);
            dupcheck[y].count++;
        }
    }

    for (x = 0; x < 7; x++)
    {
        if (dupcheck[x].count > 1)
        {
            printf (SW_REF_MSG (M_MULTIPLE_MAP),
                dupcheck[x].count, dupcheck[x].x500);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            are_dups = TRUE;
        }
    }
    return are_dups;
}

/*
**++
** FUNCTION my_gets
**
** DESCRIPTION  :
**
**–
*/
PRIVATE void my_gets (LPUCHR entry, int size)
{
    UCHR buff[2048];     /* MR 41741 : Cope with long responses */
    int  len;

    len = strlen(gets((char *)buff));
    if (len)
    {
        /* CR16486 JMC 2-11-2004: fix array overrun */
        lustrncpy (entry, buff, size);
    }

}

/*
**++
** FUNCTION attrib
**
** DESCRIPTION  :
** Read attribute mapping information
**–
*/
PRIVATE void attrib ()
{
    printf (SW_REF_MSG (M_ASK_USERNAME), sw_ldap_info->username);    /* CR6685 SAC */
    my_gets (sw_ldap_info->username, SW_LDAP_ATTRNAME_SIZE);

    /* CR16174 JMC 30-9-2004: Add new mappings for groupname and rolename */
    printf(SW_REF_MSG(M_ASK_GROUPNAME), sw_ldap_info->groupname);
    my_gets(sw_ldap_info->groupname, SW_LDAP_ATTRNAME_SIZE);

    printf(SW_REF_MSG(M_ASK_ROLENAME), sw_ldap_info->rolename);
    my_gets(sw_ldap_info->rolename, SW_LDAP_ATTRNAME_SIZE);
    /* CR16174 End */

    printf (SW_REF_MSG (M_ASK_DESCRIPTION), sw_ldap_info->description);    /* CR6685 SAC */
    my_gets (sw_ldap_info->description, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_LANGUAGE), sw_ldap_info->language);    /* CR6685 SAC */
    my_gets (sw_ldap_info->language, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_MENUNAME), sw_ldap_info->menuname);    /* CR6685 SAC */
    my_gets (sw_ldap_info->menuname, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_SORTMAIL), sw_ldap_info->sortmail);    /* CR6685 SAC */
    my_gets (sw_ldap_info->sortmail, SW_LDAP_SORTMAIL_SIZE);

    printf (SW_REF_MSG (M_ASK_GROUP), sw_ldap_info->groupusers);    /* CR6685 SAC */
    my_gets (sw_ldap_info->groupusers, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_ROLE), sw_ldap_info->roleuser);    /* CR6685 SAC */
    my_gets (sw_ldap_info->roleuser, SW_LDAP_ATTRNAME_SIZE);

    /* CR9574 Added new mapping for qsupervisors and userflags entry */
    printf (SW_REF_MSG (M_ASK_QSUPERVISORS), sw_ldap_info->qsupervisors);
    my_gets(sw_ldap_info->qsupervisors, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_USERFLAGS), sw_ldap_info->userflags);
    my_gets(sw_ldap_info->userflags, SW_LDAP_ATTRNAME_SIZE);
    /* CR9574 End */

    extras ();
    SW_LDAP_set_def_mappings (filsh, (X500_TO_SWARE_MAP *) xsmap,
                  sw_ldap_info);

    if (chk_dups ())
        prompt ();
}

/*
**++
**
**–
*/
PRIVATE void prompt ()
{
    printf (SW_REF_MSG (M_ASK_ENTER));    /* CR6738 ZJS */
    getchar ();
}

/*
**++
**
**–
*/
PRIVATE void view (int interactive)
{

    int x;
    int lineno;
    int len;

    UCHR buff[SW_LDAP_PASSWD_SIZE];

    if (interactive)
        printf ("nnnnnn");

    printf ("n");        /* CR6685 SAC */
    printf (SW_REF_MSG (M_DIT),
        sw_ldap_info->whichdit ? "LDAP" : "Staffware");    /* CR6685 SAC */
    printf("n");

    printf (SW_REF_MSG (M_GRPUSERS),
        sw_ldap_info->grpmemldap ? "LDAP DN" : "MEMBER LIST");    /* CR16395 JMC */
    printf ("nn");    /* CR6685 SAC */

    printf (SW_REF_MSG (M_CONNECTION));    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_HOSTNAME), sw_ldap_info->hostname);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_PORTNO), sw_ldap_info->portno);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_CREDENTIALS), sw_ldap_info->credentials);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    memset (&buff, '', sizeof (buff));
    len = lustrlen (sw_ldap_info->password);
    for (x = 0; x < len; x++)
        buff[x] = '*';

    printf (SW_REF_MSG (M_PASSWORD), buff);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf ("n");        /* CR6685 SAC */
    printf (SW_REF_MSG (M_SEARCH));    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_BASE), sw_ldap_info->base);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_FILTER), sw_ldap_info->filter);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_DNPATTERN), sw_ldap_info->dnPattern);    /* MR 38043 LingWu */
    printf ("n");        /* MR 38043 LingWu */

    printf ("n");        /* CR6685 SAC */
    printf (SW_REF_MSG (M_MAPPINGS));    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_USERNAME), sw_ldap_info->username);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    /* CR16174 JMC 30-9-2004: Add view for groupname and rolename */
    printf(SW_REF_MSG(M_GROUPNAME), sw_ldap_info->groupname);
    printf("n");

    printf(SW_REF_MSG(M_ROLENAME), sw_ldap_info->rolename);
    printf("n");
    /* CR16174 End */

    /* CR19771 MEB 14Feb07 Display in same order as input of mappings */
    printf (SW_REF_MSG (M_DESCRIPTION), sw_ldap_info->description);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    /* CR19771 MEB 14Feb07 Display in same order as input of mappings */
    printf (SW_REF_MSG (M_LANGUAGE), sw_ldap_info->language);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_MENUNAME), sw_ldap_info->menuname);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_SORTMAIL), sw_ldap_info->sortmail);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_GROUPUSERS), sw_ldap_info->groupusers);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_ROLEUSER), sw_ldap_info->roleuser);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    /* CR9574 Added view of qsupervisors and userflags */
    printf (SW_REF_MSG (M_QSUPERVISORS), sw_ldap_info->qsupervisors);
    printf ("n");

    printf (SW_REF_MSG (M_USERFLAGS), sw_ldap_info->userflags);
    printf ("n");
    /* CR9574 End */

    printf ("nnn");

    if (interactive)
    {
        int y;

        prompt ();
        for (y = 0; y < LINESONSCR; y++)
            printf ("n");
    }

    lineno = 0;
    for (x = 0; x < sw_ldap_info->num_extras; x++)
    {

        printf (SW_REF_MSG (M_EXTRA), x + 1, sw_ldap_info->extra[x]->staffware, sw_ldap_info->extra[x]->x500);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */

        lineno++;
        if (interactive && (lineno > (LINESONSCR – 2)))
        {
            int y;

            prompt ();
            lineno = 0;
            for (y = 0; y < LINESONSCR; y++)
                printf ("n");

        }
    }

    if (interactive && sw_ldap_info->num_extras)
    {
        int y;

        for (y = lineno + 1; y < LINESONSCR; y++)
            printf ("n");
        prompt ();
    }
}

/*
**++
**
**–
*/
PRIVATE int lst_prompt ()
{
    int c;
    printf (SW_REF_MSG (M_ASK_ENTER_X));    /* CR6685 SAC */
    c = getchar ();
    return ((c == 'x') || (c == 'X'));
}

/* CR18665 SAC 18-05-06: added SLIST sort function */
PRIVATE int mysort_strcmpul (LPUCHR lp1, LPUCHR lp2)
{
    return (lustrcmpul (lp1, lp2));
}
/*
 * =============================================================
 * FUNCTION: get_swldap_attr_idx ()
 * =============================================================
 */
/**
 * @brief Returns the index of an attribute in the global attribute map
 *
 * @param iStart    – index to start searching at
 * @param iEnd        – last index to search to + 1
 *
 * @return int        – index for attribute found
 *
 * @retval >= 0        – attribute found, index value
 * @retval < 0        – attribute not found
 *
 * @since added for CR19495, CJED 12-DEC-2006
 *
 */

PRIVATE int get_swldap_attr_idx (int iStart, int iEnd, LPUCHR lpAttrName)
{
    int iRet = -1,
        idx;

    for (idx = iStart; idx < iEnd; idx ++)
    {
        if (!lustrcmpul (xsmap[idx].x500, lpAttrName))
        {
            iRet = idx;
            break;
        }
    }

    return (iRet);
}

/*
 * =============================================================
 * FUNCTION: get_LDAP_users
 * =============================================================
 */
/**
 * @brief creates an SLIST of all users found by LDAP search
 *
 * @param ldmp    results of search
 *
 * @return !NULL    Handle to SLIST
 *
 */
/* CR18665 SAC 18-05-06: added function */
SWMEMHDL get_LDAP_users (SW_LDAP_Message **ldmp)
{
    SW_LDAP_Message    *entry;
    char        *attr, **value;
    SWBOOL        bFound, bIsUser;
    SWINT32        x, num, xsmap_elems = (sizeof xsmap) / (sizeof xsmap[0]);
    SWMEMHDL    hSLIST = NULL;
    USRNODNAME    szUser;

    // initialise SLIST
    if ((hSLIST = slist_init (100, (SLIST_CMPFUNC) mysort_strcmpul, sizeof (USRNODNAME))) == NULL)
    {
        fprintf (stderr, "get_LDAP_users (): failed to create SLIST for users.n");
        return (NULL);
    }

    // get first entry
    entry = SW_LDAP_get_entry (ldap, *ldmp, TRUE);

    while (entry != NULL)
    {
        BerElement *BerElement2GetAttrib = NULL;

        // get first attribute
        attr = SW_LDAP_get_attrib (ldap, entry, TRUE, &BerElement2GetAttrib);

        bFound = FALSE;
        bIsUser = FALSE;

        while ((attr != NULL) || (!bFound && !bIsUser))
        {
            value = SW_LDAP_get_attrib_values(ldap, entry, attr, &num);

            if (value)
            {
                // check to see whether this attribute is the username
                //
                x = get_swldap_attr_idx (0, xsmap_elems, (LPUCHR) attr);
                if (x == LDAP_NAME_POS)
                {
                    // copy the name of this user/group
                    // CJED 19-MAY-2006 – replaced min macro, and coped with strNcpy's foibles
                    // CR18828 SAC 21-06-06: move the '- 1' so that it doesn't reduce the length of the actual value, which truncates the user name
                    lustrncpy (szUser, (LPUCHR) *value, sizeof (szUser) – 1);
        
                    bFound = TRUE;
                }
                else if (x == LDAP_MENUNAME_POS)
                {
/*
** CR19495 – CEJD 12-DEC-2006 – make sure that the menuname has a valid value
*/
                    // check this entry has valid entries for a user
                    if ( ! (lustrcmpul ((LPUCHR) *value, (LPUCHR) "USER") &&
                            lustrcmpul ((LPUCHR) *value, (LPUCHR) "MANAGER") &&
                            lustrcmpul ((LPUCHR) *value, (LPUCHR) "PRODEF") &&
                            lustrcmpul ((LPUCHR) *value, (LPUCHR) "ADMIN")))
                    {
                        bIsUser = TRUE;
                    }
                }

                SW_LDAP_value_free (value);
            }

            // next attribute
            attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
        }

        if (bFound && bIsUser)
        {
            // add to the SLIST
            if (slist_find (hSLIST, (LPUCHR) szUser) < 0)
            {
                slist_add (hSLIST, (LPUCHR) szUser);
            }
        }

        // get next entry
        entry = SW_LDAP_get_entry (ldap, entry, FALSE);
    }

    return (hSLIST);
}

/*
**++
**
**–
** CR19495 – CJED – 12-DEC-2006 – number of entries that we should find are
** now passed in so we can check.
*/
PRIVATE void
write_test (LPUCHR fnam, SW_LDAP_Message ** ldmp, LPUCHR errmsg,
        int interactive, int iNumEntries)
{

    int fd;
    SW_LDAP_Message *entry;
    char *attr, **values;
    int to_file;
    UCHR buff[128];
    int lineno;
    int breakrequest = 0;
    int    i;        /* interator */
    SWINT32    num;        /* number of values */

    lustrcpy (buff, "Y");
    to_file = lustrcmp (fnam, "");

    if (to_file)
    {
        if (fil_fsexists (filsh, (LPFILNAME) fnam))
        {
            if (interactive)
            {    /* CR6742 ZJS */
                sprintf ((char *) msg,
                     SW_REF_MSG (M_OVERWRITE), fnam);    /* CR6685 SAC */
                GetValidCh ((char *) msg, "YN", buff);
            }
            else
            {
                printf (SW_REF_MSG (M_EXISTS), fnam);
                printf ("n");
            }
        }

        if (!lustrcmp (buff, "Y"))
        {
            fd = fil_open (filsh, (LPFILNAME) fnam, FIL_WRITE, 0);
            if (fd < 0)
            {
                printf (SW_REF_MSG (M_E_FILENAME));    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                prompt ();
                return;
            }
        }
        else
            return;
    }

    if (lustrcmp (errmsg, ""))
    {
        if (to_file)
        {
            fil_puts (fd, errmsg);
            fil_close (fd);
            return;
        }
        else
            printf ("%sn", errmsg);    /* CR6700  ZJS */
    }

    lineno = 0;
    entry = SW_LDAP_get_entry (ldap, *ldmp, TRUE);

    while ((entry != NULL) && (!breakrequest))
    {
        /* CR17052 RMG 21/06/05 */
        BerElement *BerElement2GetAttrib = NULL;

        /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
        attr = SW_LDAP_get_attrib (ldap, entry, TRUE, &BerElement2GetAttrib);

        while (attr != NULL)
        {
            /* CR16346 JMC 30-9-2004: Enable multi-valued returns */
            /* initialise to zero */
            num = 0;

            values = SW_LDAP_get_attrib_values(ldap, entry, attr, &num);
            sprintf ((char *) buff, "%20st", attr);    /* CR8892 – ZJS 08/03/2000 – do not concatenate value to buff if oversize, will core dump */

            /* CR16346 JMC 30-9-2004: Enable multi-valued returns */
            for (i = 0; i < num; i++)
            {
                /* check whether to write to file */
                if (to_file)
                {
                    /* write to file */
                    fil_putb (fd, buff, lustrlen (buff));
                    fil_puts (fd, (LPUCHR)values[i]);    /* CR8892 */
                }
                else
                {
                    /* print attribute and value */
                    printf ("%s%sn", buff, values[i]);    /* CR8892 */
                    lineno++;

                    /* check for lines on screen */
                    if ((!to_file) && (lineno > (LINESONSCR – 2)))
                    {
                        /* check for exit response */
                        breakrequest = lst_prompt ();

                        /* check if true */
                        if (breakrequest)
                        {
                            break;
                        }

                        lineno = 0;
                    }
                }
            }

            SW_LDAP_value_free (values);

            if (breakrequest)
            {
                break;
            }

            /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
            attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
        }
        if (breakrequest)
        {
            break;
        }

        if (to_file)
        {
            fil_puts (fd, (LPUCHR) "");
        }
        else
        {
            printf ("n");
            lineno++;
        }
        entry = SW_LDAP_get_entry (ldap, entry, FALSE);
    }

    fil_close (fd);
}
/*
 * =============================================================
 * FUNCTION: output_scrfil_line ()
 * =============================================================
 */
/**
 * @brief Outputs a line of text to either a FIL file or the screen
 *
 * @param iFilHdl    FIL file handle or -1 for screen
 * @param lpTextBuff    Pointer to text
 *
 * @since Added for CR19761 by CJED 12-FEB-2007
 *
 */

PRIVATE void    output_scrfil_line (int iFilHdl, LPUCHR lpTextBuff)
{
    if (iFilHdl >= 0)
    {
        fil_puts (iFilHdl, lpTextBuff);
    }
    else
    {
        printf ("%sn", lpTextBuff);
    }
}

/*
 * ==================================================================
 *  FUNCTION:    ldap_check_all_members_valid
 *          This function will check the string of group user
 *          members and ensure that they are all valid users.
 *          Any invalid users will be flagged and not added to
 *          list of users.
 *          Function added for CR17344
**
** CR19761 – CJED 12-FEB-2007 – output warnings/errors to file as well
**
 * ==================================================================
*/
/* CR18665 SAC 18-05-06: added user SLIST handle */
void ldap_check_all_members_valid (SWMEMHDL hUserSLIST, char *userval, int iFilHdl)
{
    LPUCHR        lpstart, lpend;
    char        tmp_buf[512] = "";
    USERNAME    temp;
    USER_SH        user_sh;
    USERID        uid;
    char        checkedusers[LDAP_MAX_ATTR_LEN + 1];
    SWBOOL        first = TRUE;

    /* Obtain a user session */
    user_sh = user_init (filsh, &my_node, USER_UPDATE | USER_EDIT);
    if (user_sh <= 0)
    {
        output_scrfil_line (iFilHdl,
                (LPUCHR) "User_init failed so NO group user member validation");
        return;
    }

    /* Clear array to hold valid user list */
    sw_mem_set (checkedusers, '', sizeof (checkedusers));

    /* Ponter to start of user values to be checked */
    lpstart = (LPUCHR) userval;

    /* Loop through user values string */
    while (lpstart && *lpstart)
    {
        /* Find end of this record. */
        lpend = lustrchr (lpstart, ',');
        if (lpend)
        {
            /* If we have a record, add it to list */
            if (*lpstart)
            {
                /* make a temporary copy and chop the record up */
                sw_mem_set (tmp_buf, '', sizeof (tmp_buf));
                lustrncpy ((LPUCHR) tmp_buf, lpstart, lpend – lpstart);
            }
            lpend++;    /* Start of next record. */
        }
        else
        {
            /* Last user in list */
            if (*lpstart)
            {
                /* make a temporary copy and take rest of the record */
                sw_mem_set (tmp_buf, '', sizeof (tmp_buf));
                lustrncpy ((LPUCHR) tmp_buf, lpstart, sizeof (tmp_buf));
            }
        }

        /*
         * CR18964 SAC 14-07-06: strip out spaces before we re-check the buffer
         */
        if (tmp_buf)
        {
            /* Strip out any leading or trailing spaces as otherwise
             * user will not be found
             */
            my_cvt ((LPUCHR) tmp_buf, 1);
        }

        /* If user value found and have a valid user session */
        /* CR18964 SAC 14-07-06: check length of buffer */
        if (tmp_buf && (lustrlen (tmp_buf) > 0) && (user_sh > 0))
        {
            /*
             * CR18665 SAC 18-05-06: first we check whether the user exists in the given
             * SLIST, which was generated from the LDAP results.  If so, then the user
             * will be added as part of a MOVESYSINFO.  We have built up the SLIST so that
             * if users are referenced in group membership before they appear as users
             * an error won't be generated.
             */
            if ((uid = slist_find (hUserSLIST, (LPUCHR) tmp_buf)) < 0)
            {
                // user doesn't exist in LDAP, check iPE users

                /* Try and find user */
                uid = user_find_user (user_sh, (LPUSERNAME)tmp_buf, (LPUSERNAME)temp);
            }
/*
** check uid, although slist_find returns values in the range 0 – n, and
** user_find_user returns 1 – n, we'll allow 0 as a valid return.
*/
            if (uid >= 0)
            {
                /* match */
                if (first)
                {
                    /* Copy first user to list of valid users */
                    lustrcpy (checkedusers, tmp_buf);
                    first = FALSE;
                }
                else
                {
                    /* Copy next user to list of valid users with a
                    * comma separator
                    */
                    lustrcat ((LPUCHR) checkedusers, (LPUCHR) ", ");
                    lustrcat ((LPUCHR) checkedusers, (LPUCHR) tmp_buf);
                }
            }
            else
            {
                char    tmpBuff [512];
                /* no match */
                sprintf (tmpBuff, "Group contains INVALID user [%s]", tmp_buf);
                output_scrfil_line (iFilHdl, (LPUCHR) tmpBuff);
            }
        }

        /* Point at start of next record. */
        lpstart = lpend;

    }

    /* If valid users list setup that copy over original unchecked list */
    if (checkedusers != '')
    {
        lustrcpy (userval, checkedusers);
    }

    user_term (user_sh); // CR19716 SAC 01-02-07

} /* end ldap_check_all_members_valid */

/*
**++
**
**–
** CR19495 – CJED 12-DEC-2006 – check we get the same number of entries that
** we've been told are available.
*/
PRIVATE void write_map (LPUCHR fnam, SW_LDAP_Message ** ldmp, int iNumEntries)
{

    int fd;
    SW_LDAP_Message *entry;
    char *attr, **value;
    char    *grpusrsval;
    int    grpusrsval_size;
    int to_file;
    UCHR buff[512];
    int lineno;
    int ctr;

    SWARE_MAP_VALS **mapx;
    int xsmap_elems;
    int mapx_elems;

    int x,
        iEntriesRead;
    int breakrequest = 0;
    SWINT32    num;        /* number of values */
    int    i;        /* iterator */
    int    strsize;    /* string size */
    SWBOOL    usermatch;    /* CR16571 JMC 20-12-2004: usermatch boolean */

    // CR19716 SAC 01-02-07: array to hold group membership attribute values
    LPUCHR    szMembership = NULL, pMembership;
    int    nAllocMembership = 0, nNumMembership = 0, nLenMembership = 0;

    /*
     * CR17995 SAC 26-01-06: allocate an initial buffer
     */
    grpusrsval_size = 1024;
    if ((grpusrsval = (char *) sw_calloc (1, grpusrsval_size * sizeof (char))) == NULL)
    {
        fprintf (stderr, "write_map (): Failed to allocate memory for buffern");
        return;
    }

    /* from here to */
    lustrcpy (buff, "Y");
    to_file = lustrcmp (fnam, "");
/*
** CR19761 – CJED 12-FEB-2007 – we will now use 'fd' as a flag to indicate
** if output is going to screen (value < 0) or to file (value >= 0).
*/
    fd = -1;    /* assume screen output */
    if (to_file)
    {
        if (fil_fsexists (filsh, (LPFILNAME) fnam))
        {        /* is this a naughty conversion? */
            sprintf ((char *) msg, SW_REF_MSG (M_OVERWRITE), fnam);    /* CR6685 SAC */
            GetValidCh ((char *) msg, "YN", buff);
        }

        if (!lustrcmp (buff, "Y"))
        {
            fd = fil_open (filsh, (LPFILNAME) fnam, FIL_WRITE, 0);
            if (fd < 0)
            {
                printf (SW_REF_MSG (M_E_FILENAME));    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                prompt ();
                sw_free (grpusrsval); /* CR17995 SAC 26-01-06 */
                return;
            }
        }
        else
        {
            sw_free (grpusrsval); /* CR17995 SAC 26-01-06 */
            return;
        }
    }

    xsmap_elems = (sizeof xsmap) / (sizeof xsmap[0]);
    mapx_elems = xsmap_elems + sw_ldap_info->num_extras;

    mapx = (SWARE_MAP_VALS **) malloc (sizeof (SWARE_MAP_VALS *) * (mapx_elems));

    for (ctr = 0; ctr < xsmap_elems; ctr++)
    {
        mapx[ctr] = (SWARE_MAP_VALS *) malloc (sizeof (SWARE_MAP_VALS));
        lustrncpy (mapx[ctr]->staffware, xsmap[ctr].staffware, SW_LDAP_ATTRNAME_SIZE);
    }

    for (ctr = xsmap_elems, x = 0; ctr < mapx_elems; ctr++, x++)
    {
        mapx[ctr] = (SWARE_MAP_VALS *) malloc (sizeof (SWARE_MAP_VALS));
        lustrncpy (mapx[ctr]->staffware, sw_ldap_info->extra[x]->staffware, SW_LDAP_ATTRNAME_SIZE);
    }
    /*
     * CR18665 SAC 18-05-06: generate an SLIST of the users that have
     * been found by the search.
     */
    SWMEMHDL hUserSLIST = get_LDAP_users (ldmp);

    lineno = 0;
    iEntriesRead = 0;
    entry = SW_LDAP_get_entry (ldap, *ldmp, TRUE);

    while ((entry != NULL) && (!breakrequest))
    {
        int is_iPE_entity = FALSE;
        SWBOOL    bIs_iPE_group = FALSE;
        int x;

        nLenMembership = 0; // CR19716 SAC 01-02-07

        iEntriesRead ++;
        /* CR17052 RMG 21/06/05 */
        BerElement *BerElement2GetAttrib = NULL;

        for (x = 0; x < mapx_elems; x++)
        {
            memset (mapx[x]->value, '', sizeof(mapx[x]->value));
        }

        /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
        attr = SW_LDAP_get_attrib (ldap, entry, TRUE, &BerElement2GetAttrib);

        while (attr != NULL)
        {
            /* CR16346 JMC 30-9-2004: Enable multi-valued returns */
            /* initialise to zero */
            num = 0;

            value = SW_LDAP_get_attrib_values(ldap, entry, attr, &num);

            /* CR16845 JMC 20-01-2005: Fix for NULL value pointer returned */
            if (value == NULL)
            {
                /*
                 * NULL pointer returned due to value of attribute not being
                 * defined on LDAP Server. Get next attribute and continue.
                 */
                /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
                attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
                continue;
            }
            /* End CR16845 */

            x = get_swldap_attr_idx (0, xsmap_elems, (LPUCHR) attr);
            if (x >= 0)
            {
/*
** CR19493 – CJED 06-DEC-2006 – Always keep track of the mapped values
** NOTE: this used to truncate to ATTRVALSIZE (24) characters, but the
** value buffer is MAX_LONG_ATTR_VAL (255) charcters in size so we'll use.
*/
                lustrncpy (mapx[x]->value, (LPUCHR) * value,
                           MAX_LONG_ATTR_VAL);

                // CR19716 SAC 01-02-07: for a group attribute we need to store the values
                // so we can use them once we have been through all the attributes for this
                // entry.  This is because the membership attribute may come before the one
                // that indicates this is a group and the members aren't validated.
                //
                // The values are stored in the buffer seperated by a NULL character.
                //
                if (x == LDAP_GROUPUSERS_POS)
                {
                    nNumMembership = num;
                    pMembership = szMembership;
                    for (i = 0; i < num; i++)
                    {
                        int    len = lustrlen (value[i]);

                        // do we need to allocate/reallocate the array
                        if (nAllocMembership <= 0)
                        {
                            nAllocMembership = (len * 4); // extend buffer, allowing some room
                            szMembership = (LPUCHR) sw_malloc (nAllocMembership * sizeof (LPUCHR));

                            // start at the beginning
                            pMembership = szMembership;
                        }
                        else if (nLenMembership + len >= nAllocMembership)
                        {
                            nAllocMembership += (len * 4); // extend buffer, allowing some room
                            szMembership = (LPUCHR) sw_realloc (szMembership, nAllocMembership * sizeof (LPUCHR));

                            // make sure we are pointing just after the last entry
                            pMembership = szMembership + nLenMembership;
                        }

                        if (!szMembership)
                        {
                            fprintf (stderr, "write_map (): Failed to (re)allocate memory for group membership valuesn");
                            slist_term (hUserSLIST); // CR19716 SAC 01-02-07
                            return;
                        }

                        lustrncpy ((LPUCHR) pMembership, (LPUCHR) value[i], lustrlen (value[i]));

                        // move pointer passed value we have just added
                        pMembership += (len + 1);

                        // increase the length of the value
                        nLenMembership += (len + 1);
                    }
                }

                if (x == LDAP_MENUNAME_POS)
                {
/*
** CR18401 – CJED 06-DEC-2006 – correctly recognise any iPE entities
** This includes GROUP and ROLE entities.
*/
                    if (! (lustrcmpul ((LPUCHR) *value, (LPUCHR) "USER") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "MANAGER") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "PRODEF") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "ADMIN") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "GROUP") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "ROLE")))
                    {
                        is_iPE_entity = TRUE;
                        if (! lustrcmpul ((LPUCHR) *value, (LPUCHR) "GROUP"))
                        {
                            bIs_iPE_group = TRUE;
                        }
                    }
                }
                // CR19716 SAC 01-02-07: moved group membership check after attribute while() loop
            }
            else    /* search the extras */
            {
                for (x = xsmap_elems; x < mapx_elems; x++)
                {
                    if (!lustrncmpul (sw_ldap_info->extra[x – NUM_SW_ELEMENTS]->x500, (LPUCHR) attr, lustrlen (sw_ldap_info->extra[x – NUM_SW_ELEMENTS]->x500)))
                        break;
                }
                if (x < mapx_elems)    /* found */
                {
                    lustrncpy (mapx[x]->value, (LPUCHR) * value, sizeof (mapx[x]->value) – 1);    /* CR11968 SAC 15-07-02 – CR6904 SAC */
                }
            }

            SW_LDAP_value_free (value);

            /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
            attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
        }

        // CR19716 SAC 01-02-07: moved code after attribute while() loop
        if (bIs_iPE_group && (nNumMembership > 0))
        {
/*
** OK, we're looking for multiple values for this attribute … so loop
** round and concatenate them ? The count of values is in the "num" variable
** returned by the call to SW_LDAP_get_attrib_values()
*/
            /* CR16395 JMC 15-10-2004: LDAP DN format enhancement */
            /* initialise i */
            i = 0;
            pMembership = szMembership; // CR19716 SAC 01-02-07: go through members
            while (i < nNumMembership)
            {

                /* CR16847 JMC 20-01-2005: initialise userval */
                *grpusrsval = '';

                /*
                * CR17995 SAC 26-01-06: check whether the allocated buffer is large
                * enough to hold the full value
                */
                if ((int) lustrlen (pMembership) >= grpusrsval_size)
                {
                    /* resize the buffer */
                    grpusrsval_size = lustrlen (pMembership) + 1024;
                    if ((grpusrsval = (char *) sw_realloc (grpusrsval, grpusrsval_size * sizeof (char))) == NULL)
                    {
                        fprintf (stderr, "write_map (): Failed to re-allocate memory for buffern");

                        // CR19716 SAC 01-02-07
                        slist_term (hUserSLIST);
                        sw_free (szMembership);
                        return;
                    }
                }

                /* CR16751 JMC 20-12-2004: GroupUsers fix */
                /* check for LDAPDN group member format */
                if (sw_ldap_info->grpmemldap == TRUE)
                {
                    /* check if ldap attribute matches that used for username */
                    /* CR17995 SAC 26-01-06: pass in the buffer size */
                    usermatch = ldap_user_match(sw_ldap_info, (char *) pMembership, xsmap, grpusrsval, grpusrsval_size);
                }
                else
                {
                    /* set usermatch to FALSE */
                    usermatch = FALSE;
                }

                /* get User that is a member of a Group */
                if (usermatch == FALSE)
                {
                    /* get User that is a member of a Group */
                    /* CR17995 SAC 26-01-06: pass in the buffer size */
                    (void)SW_LDAP_get_user_member(ldap, sw_ldap_info, (char *) pMembership, xsmap,
                                grpusrsval, grpusrsval_size);
                }
                /* End CR16571 */
                /* check for valid grpusrsval */
                if (*grpusrsval != '')
                {
                    /* CR17344 Check for multiple users in one value */
                    /* CR18665 SAC 18-05-06: pass in user SLIST */
/*
** CR19761 – CJED 12-FEB-2007 – pass down the screen/file flag
*/
                    ldap_check_all_members_valid (hUserSLIST, grpusrsval, fd);

                    if (i == 0)
                    {
                        lustrncpy(mapx[LDAP_GROUPUSERS_POS]->value, (LPUCHR)grpusrsval, MAX_LONG_ATTR_VAL);
                    }
                    else
                    {
                        LPUCHR    lpTmp;
                        strsize = lustrlen (mapx[LDAP_GROUPUSERS_POS]->value);
                        lpTmp = mapx[LDAP_GROUPUSERS_POS]->value + strsize;

                        if ((strsize + 2) < MAX_LONG_ATTR_VAL)
                        {
                            if (strsize > 0)
                            {
                                * lpTmp ++ = ',';
                                strsize ++;
                            }

                            lustrncpy (lpTmp, (LPUCHR)grpusrsval, MAX_LONG_ATTR_VAL – strsize);

                            if ((int) lustrlen ((LPUCHR)grpusrsval) > (MAX_LONG_ATTR_VAL – strsize))
                            {
                                printf ("attribute Name="%s" Value="%s" had been truncated as maximum length is %dn",
                                      attr, mapx[LDAP_GROUPUSERS_POS]->value, MAX_LONG_ATTR_VAL);
                            }
                        }
                    }
                }

                /* increment i */
                i++;

                // CR19716 SAC 01-02-07: move to next member
                pMembership += (lustrlen (pMembership) + 1);
            }
        }

/*
** If this is an iPE entity (user, group or role) then dump the info about it
*/
        if (is_iPE_entity)
        {
            for (x = 0; x < mapx_elems; x++)
            {
                sprintf ((char *) buff, "%20st%s", mapx[x]->staffware, mapx[x]->value);

                if (to_file)
                {
                    fil_puts (fd, buff);
                }
                else
                {
                    printf ("%sn", buff);
                    lineno++;
                    if ((!to_file) && (lineno > (LINESONSCR – 2)))
                    {
                        if (breakrequest = lst_prompt ())    /* should be = not == */
                        {
                            break;
                        }
                        lineno = 0;
                    }
                }

            }

            if (breakrequest)
            {
                break;
            }

            if (to_file)
            {
                fil_puts (fd, (LPUCHR) "");
            }
            else
            {
                printf ("n");
                lineno++;
            }
        }
        entry = SW_LDAP_get_entry (ldap, entry, FALSE);
    }

    printf ("nNumber of entries expected = %d, number read = %dn", iNumEntries, iEntriesRead);

    fil_close (fd);

    slist_term (hUserSLIST); /* CR18665 SAC 18-05-06 */

    for (ctr = 0; ctr < mapx_elems; ctr++)
    {
        free (mapx[ctr]);
    }

    free (mapx);
    mapx = NULL;

    sw_free (grpusrsval); /* CR17995 SAC 26-01-06 */
    sw_free (szMembership); // CR19716 SAC 01-02-07
}

/*
**++
**
**–
*/
PRIVATE void
test (int interactive, LPUCHR filename_b, int download_b, int map_b)
{
    SWINT32 ret;
    SW_LDAP_Message *ldmp = NULL;
    UCHR buff[80];
    UCHR dwnload[80];
    UCHR old_search[SW_LDAP_FILTER_SIZE + 1];    /* CR7869 SAC 22-12-98 */
    UCHR filename_i[80];
    int map_i;

    lustrcpy (filename_i, "");

    if (interactive)
    {
        printf ("n");    /* CR6685 SAC */
        printf (SW_REF_MSG (M_CONN_TESTING));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
    }

    ldap = SW_LDAP_connect (sw_ldap_info, ldap, &ret);
    if (ret != SW_LDAP_SUCCESS)
    {
        char msg[100];

        sprintf (msg, SW_REF_MSG (M_CONNECT_FAIL),
             ldap_msg_to_text (ret, buff), ret);    /* CR6738  ZJS */
        strcat (msg, "n");
        if (interactive)
        {
            printf ("%s", msg);
            prompt ();
        }
        else
            write_test (filename_b, &ldmp, (LPUCHR) msg,
                    interactive, 0);
        return;

    }

    /* CR7869 SAC 22-12-98 : store current search string */
    sw_mem_set (old_search, '', sizeof (old_search));
    lustrcpy (old_search, sw_ldap_info->filter);

    /*
     * CR10765 SAC 15-11-01: alter search filter to the same as the BG
     */
    if (SW_LDAP_filter_BG (sw_ldap_info) != SW_SUCCESS)
    {
        printf ("Failed to alter filter to match BGn");
    }

    lustrcpy (dwnload, "N");
    if (interactive)
    {
        printf (SW_REF_MSG (M_CONN_SUCCESS));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        GetValidCh (SW_REF_MSG (M_DOWNLOAD_USER), "YN", dwnload);    /* CR6685 SAC */

        if (!lustrcmp (dwnload, "Y"))
        {
            int num_entries;

            /* CR14734 JMC 15-1-04: Add Referral code */
            ret = 0;    /* initialise return code form ldap libraries */

            num_entries =
                SW_LDAP_search (sw_ldap_info, ldap, &ldmp, &ret);

            if (ret == SW_LDAP_ERR_SEARCH)
            {
                printf (SW_REF_MSG (M_ENTRIES_NONE));    /* CR6685 SAC */
                prompt ();
                SW_LDAP_disconnect (ldap, ldmp);

                /* CR7869 SAC 22-12-98 : revert to original search string */
                lustrcpy (sw_ldap_info->filter, old_search);
                return;
            }

            /* CR14734 JMC 15-1-04: Add referral code */
            /* Check on PARTIAL RESULT for referrals */
            if (ret == SW_LDAP_PARTIAL_RESULTS)
            {
                /* print warning message */
                printf(SW_REF_MSG(M_PARTIAL_FOUND));
                printf("n");
            }
            if (ret == SW_LDAP_SUCCESS)
            {
                printf("Got Full Results..n");
            }

            printf (SW_REF_MSG (M_ENTRIES_FOUND), num_entries);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */

            GetValidCh (SW_REF_MSG (M_MAPPING), "SL", buff);    /* CR6685 SAC */
            map_i = !lustrcmp (buff, "S");

            GetValidCh (SW_REF_MSG (M_FILE_SCREEN), "FS", buff);    /* CR6685 SAC */

            if (!lustrcmp (buff, "F"))
            {
                printf (SW_REF_MSG (M_ASK_INFO_FILE));    /* CR6685 SAC */
                gets ((char *) filename_i);
            }
/*
** CR19495 – CJED 12-DEC-2006 – pass the number of entries returned by the
** search. This allows the lower level to determine if an error has occurred
** while it's getting entries.
*/
            if (map_i)
                write_map (filename_i, &ldmp, num_entries);
            else
                write_test (filename_i, &ldmp, (LPUCHR) "",
                        interactive, num_entries);

        }
    }
    else
    {
        if (lustrcmp (filename_b, "")
            && fil_fsexists (filsh, (LPFILNAME) filename_b))
        {        /* filename was specified and it exists */
            printf (SW_REF_MSG (M_EXISTS), filename_b);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            my_exit (3);
        }

        if (download_b)
        {
            /* CR14734 JMC 15-1-04: Add Referral code */
            ret = 0; /* Initialise return code from LDAP libraries */
            num_entries = SW_LDAP_search (sw_ldap_info, ldap, &ldmp, &ret);
            if (num_entries > 0)
            {
                if (map_b)
                    write_map (filename_b, &ldmp, num_entries);
                else
                    write_test (filename_b, &ldmp,
                            (LPUCHR) "", interactive, num_entries);    /* passthrough */
            }
            else
            {
                write_test (filename_b, &ldmp,
                        (LPUCHR)
                        SW_REF_MSG (M_ENTRIES_NONE), interactive, 0);    /* CR6685 SAC */

            }
        }
        else
        {
            write_test (filename_b, &ldmp,
                    (LPUCHR) SW_REF_MSG (M_CONN_SUCCESS), interactive, 0);    /* CR6685 SAC */
        }

    }
    SW_LDAP_disconnect (ldap, ldmp);

    /* CR7869 SAC 22-12-98 : revert to original search string */
    lustrcpy (sw_ldap_info->filter, old_search);

    if ((interactive) && lustrcmp (dwnload, "N")
        && !lustrcmp (filename_i, ""))
    {
        prompt ();
    }
}

/*
**++
**
**–
*/
PRIVATE int ldapcmp ()
{
    int    ret = 0,
        x;
/*
** CJED 15-DEC-2006 – do the comparison a member at a time, it's not
** sensible to memcmp the entire structure …
*/
    ret |= lustrcmp (sw_ldap_info->hostname, sw_ldap_info_copy->hostname);
    ret |= lustrcmp (sw_ldap_info->credentials, sw_ldap_info_copy->credentials);
    ret |= lustrcmp (sw_ldap_info->password, sw_ldap_info_copy->password);
    ret |= lustrcmp (sw_ldap_info->base, sw_ldap_info_copy->base);
    ret |= lustrcmp (sw_ldap_info->filter, sw_ldap_info_copy->filter);
    ret |= lustrcmp (sw_ldap_info->dnPattern, sw_ldap_info_copy->dnPattern);
    ret |= lustrcmp (sw_ldap_info->username, sw_ldap_info_copy->username);
    ret |= lustrcmp (sw_ldap_info->menuname, sw_ldap_info_copy->menuname);
    ret |= lustrcmp (sw_ldap_info->language, sw_ldap_info_copy->language);
    ret |= lustrcmp (sw_ldap_info->description, sw_ldap_info_copy->description);
    ret |= lustrcmp (sw_ldap_info->sortmail, sw_ldap_info_copy->sortmail);
    ret |= lustrcmp (sw_ldap_info->groupusers, sw_ldap_info_copy->groupusers);
    ret |= lustrcmp (sw_ldap_info->roleuser, sw_ldap_info_copy->roleuser);
    ret |= lustrcmp (sw_ldap_info->lastsync, sw_ldap_info_copy->lastsync);
    ret |= lustrcmp (sw_ldap_info->locallastsync, sw_ldap_info_copy->locallastsync);
    ret |= lustrcmp (sw_ldap_info->qsupervisors, sw_ldap_info_copy->qsupervisors);
    ret |= lustrcmp (sw_ldap_info->userflags, sw_ldap_info_copy->userflags);
    ret |= lustrcmp (sw_ldap_info->groupname, sw_ldap_info_copy->groupname);
    ret |= lustrcmp (sw_ldap_info->rolename, sw_ldap_info_copy->rolename);
    ret |= lustrcmp (sw_ldap_info->certpath, sw_ldap_info_copy->certpath);

    ret |= (sw_ldap_info->bXlateUTF8 != sw_ldap_info_copy->bXlateUTF8);
    ret |= (sw_ldap_info->enableSSL != sw_ldap_info_copy->enableSSL);
    ret |= (sw_ldap_info->isAD != sw_ldap_info_copy->isAD);
    ret |= (sw_ldap_info->grpmemldap != sw_ldap_info_copy->grpmemldap);
    ret |= (sw_ldap_info->whichdit != sw_ldap_info_copy->whichdit);
    ret |= (sw_ldap_info->portno != sw_ldap_info_copy->portno);
    //Fix MR 31729/SR 1-8FH0GZ LDAPCONF utiltity crashing when additin additional LDAP attributes
    ret |= (sw_ldap_info->num_extras != sw_ldap_info_copy->num_extras);
    ret |= (sw_ldap_info->num_allocated_extras != sw_ldap_info_copy->num_allocated_extras);

    for (x = 0; (! ret) && (x < sw_ldap_info->num_extras); x++)
    {
        ret |= lustrcmp (sw_ldap_info_copy->extra[x]->staffware, sw_ldap_info->extra[x]->staffware);
        ret |= lustrcmp (sw_ldap_info_copy->extra[x]->x500, sw_ldap_info->extra[x]->x500);
    }

    return ret;
}

/*
**++
**
**–
*/
PRIVATE void ldapcpy ()
{
    int x;

    if (sw_ldap_info_copy != NULL)
        free (sw_ldap_info_copy);

    /* CR17822 Cast to correct type */
    sw_ldap_info_copy = (SW_LDAP_info *)malloc (sizeof (SW_LDAP_info));
/*
** CJED 15-DEC-2006 – the only thing in the Info structure that we don't
** want to copy is the array of extras pointers and control info at the
** end of the structure – so calcluate the size of the rest of the structure
** and copy that, then handle the extras stuff.
*/
    x = ((char *) & sw_ldap_info->num_extras) – (char *) sw_ldap_info;
    memcpy (sw_ldap_info_copy, sw_ldap_info, x);

    sw_ldap_info_copy->num_extras = 0;
    sw_ldap_info_copy->num_allocated_extras = 0;
    sw_ldap_info_copy->extra = NULL;

    for (x = 0; x < sw_ldap_info->num_extras; x++)
        SW_LDAP_extra_add (sw_ldap_info_copy, sw_ldap_info->extra[x]->staffware, sw_ldap_info->extra[x]->x500);
}

/*
**++
**
**–
*/
PRIVATE int writeinfo (int interactive)
{
    int changed;
    UCHR buff[80];
    int retcode;
    lustrcpy (buff, "");

    /* changed = memcmp(sw_ldap_info_copy, sw_ldap_info, sizeof(SW_LDAP_info)); */
    changed = ldapcmp ();    /* params in def'n even though global? */
    if (!changed)
        return M_NO_DATA_CHANGED;

    if (interactive && changed)
    {
        GetValidCh (SW_REF_MSG (M_ASK_SAVE), "YN", buff);    /* CR6685 SAC */
    }

    if (changed && ((!interactive) || (!lustrcmp (buff, "Y"))))
    {            /* if changed and (batch) or (changed interactively) */
        if ((retcode = SW_LDAP_set_info (filsh, sw_ldap_info, FALSE))
            != SW_SUCCESS)
        {
            char msg[100];
            UCHR buff[100];
            sprintf (msg, SW_REF_MSG (M_SETINFO_FAIL),
                 ldap_msg_to_text (retcode, buff), retcode);    /* CR6738  ZJS */
            strcat (msg, "n");
            printf ("%s", msg);
/* fil_term (filsh); *//* fil term!!! */
            return M_E_DATA_WRITE;
        }
        return M_DATA_SAVED;
    }
    return 3;

}

/*
**++
**
**–
*/
PRIVATE void save (void)
{
    int w = writeinfo (TRUE);
    if (w == M_NO_DATA_CHANGED)
    {
        printf (SW_REF_MSG (M_NO_DATA_CHANGED));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
    }
    else if (w == M_E_DATA_WRITE)
    {
        printf (SW_REF_MSG (M_E_DATA_WRITE));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
    }
    else if (w == M_DATA_SAVED)
    {
        printf (SW_REF_MSG (M_DATA_SAVED));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        ldapcpy ();    /* memcpy(sw_ldap_info_copy, sw_ldap_info, sizeof(SW_LDAP_info)); */
    }

    prompt ();
}

/*
**++
**
**–
*/
PRIVATE int menu (void)
{
    int x;
    UCHR buff[80];
    char build_year[5]="";
    SWBOOL    bCheckChanged = FALSE;

    /* CR19048 Remove unused variable */
    get_build_year((LPUCHR)build_year);

    while (TRUE)
    {
        for (x = 0; x < LINESONSCR; x++)
            printf ("n");
        /* CR16673 NPH Removed version number (which was wrong!) and changed copyright years to new system */
        /* CR16785 NPH Modified copyright notice to match spec */
        /* CR16948 NPH Modified copyright again */
        printf
            ("====================================================================n");
        /* CR16829 NJP 13Jan05 Insert TIBCO into product name */
        printf
            ("    TIBCO iProcess LDAP Connection Administration Utilityn");
        printf
            ("        Copyright (c) %s-%s, TIBCO Software Inc.n",SWVERS_COPYRIGHT_START_IPE,build_year);
        printf
            ("====================================================================n");
        printf ("nn  [1]       %s", SW_REF_MSG (M_M_CONN_INFO));    /* CR6685 SAC */
        printf ("n  [2]       %s", SW_REF_MSG (M_M_SEARCH_INFO));    /* CR6685 SAC */
        printf ("n  [3]       %s", SW_REF_MSG (M_M_ATTRIB_MAP));    /* CR6685 SAC */

        sprintf ((char *) msg, SW_REF_MSG (M_M_GRPMEM_LDAP),
             sw_ldap_info->grpmemldap ? "LDAP DN" : "MEMBER LIST");    /* CR16395 JMC */
        printf ("n  [4]       %s", msg);                /* CR16395 JMC */

        printf ("n  [5]       %s", SW_REF_MSG (M_M_VIEW_INFO));    /* CR6685 SAC */
        printf ("n  [6]       %s", SW_REF_MSG (M_M_CONN_TEST));    /* CR6685 SAC */

        sprintf ((char *) msg, SW_REF_MSG (M_M_RETURN_DIT),
             sw_ldap_info->whichdit ? "iProcess Engine" : "LDAP");    /* CR16509 JMC */
        printf ("n  [7]       %s", msg);    /* CR6685 SAC */
        printf ("n  [8]       %s", SW_REF_MSG (M_M_SAVE));    /* CR6685 SAC */
        printf ("n  [9]       %s", SW_REF_MSG (M_M_SYNCHRONISE));    /* CR6685 SAC */
/*
** CR19009 – CJED 21-JUL-2006 – attribute translation option added
*/
        printf ("n  [10]      %s", SW_REF_MSG (sw_ldap_info->bXlateUTF8 ?
                        M_M_DISABLE_AV_TRANS : M_M_ENABLE_AV_TRANS));
        printf ("n  [11]      %s", SW_REF_MSG (M_M_QUIT));    /* CR6685 SAC */

        printf ("nn  %s", SW_REF_MSG (M_M_ENTER_OPTION));    /* CR6685 SAC */

        gets ((char *) buff);
        if (!lustrcmp (buff, "1"))
        {
            connection ();
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "2"))
        {
            search ();
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "3"))
        {
            attrib ();
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp(buff, "4"))
        {
            /* toggle LDAP DN/MEMBER LIST */
            sw_ldap_info->grpmemldap = !sw_ldap_info->grpmemldap;
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "5"))
        {
            view (1);
        }
        else if (!lustrcmp (buff, "6"))
        {
            test (TRUE, (LPUCHR) "", 0, FALSE);
        }
        else if (!lustrcmp (buff, "7"))
        {
            sw_ldap_info->whichdit = !sw_ldap_info->whichdit;
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "8"))
        {
            save ();
            bCheckChanged = FALSE;
        }
        else if (!lustrcmp (buff, "9"))
        {
            if (ldapcmp ())
            {
                printf (SW_REF_MSG (M_PLEASE_SAVE));    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */

                prompt ();
            }
            else
                ldap_movesysinfo ((LPUCHR) "");
        }
        else if (!lustrcmp (buff, "10"))
        {
            sw_ldap_info->bXlateUTF8 = ! sw_ldap_info->bXlateUTF8;
            bCheckChanged = TRUE;

        }
        else if (!lustrcmp (buff, "11"))
               {
            break;
        }
        else
        {
            printf (SW_REF_MSG (M_E_INVALID_OPTION));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */

            prompt ();
        }
    }

    return ((int) bCheckChanged);
}

/*
**++
**
**–
*/
PRIVATE void batch (int argc, LPUCHR * argv)
{
    int c;
    int e;
    LPUCHR current_entry = NULL;
    UCHR tstfile[100];
    int tstdownload = FALSE;
    int extrascleared = FALSE;

    ret = 0;
    num_entries = 0;
    lustrcpy (tstfile, "");

    /* A bit of exception handling here…
       This rearranges input lines like
       LDAPCONF TEST -s -f fred
       to LDAPCONF TEST -f fred -s
       as the code expects -s/-x as last parameter, and its a lot easier to cheat here rather than recode the whole of batch
     */
    if ((argc == 5) && (!lustrcmp (argv[1], "TEST")))
    {
        /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
        if (!lustrcmp (argv[2], "-s") || !lustrcmp (argv[2], "-l"))
        {
            LPUCHR xx;
            xx = argv[2];
            argv[2] = argv[3];
            argv[3] = argv[4];
            argv[4] = xx;
        }
    }

    ucase (argv[1]);
    getbigentry ((LPUCHR) argv[1], &current_entry);
    if (current_entry == NULL)
    {
        printf (SW_REF_MSG (M_E_UNKNOWN_OPTION), argv[1]);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        my_exit (1);
    }

    if (argc == 2)        /* single parameter specified */
    {
        if (!lustrcmp (current_entry, "VIEW"))
        {
            view (0);
            return;
            /* my_exit (0); */
        }
        else if (!lustrcmp (current_entry, "TEST"))
        {
            test (FALSE, tstfile, tstdownload, FALSE);    /* chg so map */
        }
        else
        {
            printf (SW_REF_MSG (M_E_SUBOPTION_REQ), current_entry);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
        }
    }

    c = 2;
    while (c < argc)
    {
        LPUCHR ptr = argv[c];
        lcase (argv[c]);
        if (!lustrcmp (current_entry, "TEST"))
        {    /* only one of them can be set */
            /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
            if (lustrcmp (ptr, "-s") || lustrcmp (ptr, "-l"))
            {
                e = getentry (current_entry, (LPUCHR) "s");
                if (entries[e].set == 0)
                {
                    /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
                    e = getentry (current_entry, (LPUCHR) "l");
                }

                if (entries[e].set == 1)
                {
                    printf (SW_REF_MSG (M_ERROR_PARAM));    /* CR6738  ZJS */
                    printf ("n");
                    my_exit (3);
                }
            }
        }

        e = getentry (current_entry, (ptr + 1));    /* consume 0'th element as "-" */
        if (e == ER_ENTRY_NOTFOUND)
        {
            printf (SW_REF_MSG (M_E_UNKNOWN_SUBOPTION),
                (LPUCHR) ptr, current_entry);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            my_exit (2);
        }
        if (entries[e].set == 1)
        {        /* already set */
            if (lustrcmp (current_entry, "ATTRIB")
                || lustrcmp (ptr, "-x"))
            {    /* allowed repeats on ATTRIB -x -x etc. */
                printf (SW_REF_MSG (M_AMBIGUOUS),
                    (LPUCHR) ptr, current_entry);    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                my_exit (3);
            }
        }
        else
            entries[e].set = 1;

        /* next parameter to set */
        c++;
        if (
            (
             (lustrcmp (current_entry, "TEST")
            /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
              || (lustrcmp (ptr, "-s") && lustrcmp (ptr, "-l")))
             && (lustrcmp (current_entry, "ATTRIB")
             || lustrcmp (ptr, "-x"))
             && (lustrcmp (current_entry, "MOVESYSINFO")
             || (lustrcmp (ptr, "-full")
                 && lustrcmp (ptr, "-partial")))) && (c >= argc))
        {
            printf (SW_REF_MSG (M_E_VALUE_REQ), (LPUCHR) ptr, current_entry);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            my_exit (4);
        }
        else
        {
            ptr++;    /* consume 0'th element */
            lcase (ptr);    /* already done? */
            if (!lustrcmp (current_entry, "ATTRIB"))
            {
                if (!lustrcmp (ptr, "u"))
                    lustrcpy (sw_ldap_info->username,
                          argv[c]);
                else if (!lustrcmp (ptr, "r"))
                    lustrcpy (sw_ldap_info->roleuser,
                          argv[c]);
                else if (!lustrcmp (ptr, "g"))
                    lustrcpy (sw_ldap_info->groupusers,
                          argv[c]);
                else if (!lustrcmp (ptr, "menu"))
                    lustrcpy (sw_ldap_info->menuname,
                          argv[c]);
                else if (!lustrcmp (ptr, "desc"))
                    lustrcpy (sw_ldap_info->description,
                          argv[c]);
                else if (!lustrcmp (ptr, "lang"))
                    lustrcpy (sw_ldap_info->language,
                          argv[c]);
                else if (!lustrcmp (ptr, "sort"))
                    lustrcpy (sw_ldap_info->sortmail,
                          argv[c]);
                else if (!lustrcmp (ptr, "x"))
                {
                    int x;
                    int found = 0;

                    if (!extrascleared)
                    {
                        SW_LDAP_extra_free
                            (sw_ldap_info);
                        extrascleared = TRUE;
                    }

                    for (x = 0;
                         ((x < sw_ldap_info->num_extras)
                          && (!found)); x++)
                        found =
                            (!lustrcmp
                             (sw_ldap_info->extra
                              [x], argv[c]));
                    if (found)
                    {
                        printf (SW_REF_MSG (M_EXISTS),
                            argv[c]);    /* CR6685 SAC */
                        printf ("n");    /* CR6685 SAC */
                        my_exit (5);
                    }

                    SW_LDAP_extra_add (sw_ldap_info,
                               argv[c], argv[c]);

                    /* FIX!!!
                       sw_ldap_info->extra[extra] = (LPUCHR ) malloc(strlen(argv[c])+1);
                       lustrcpy(sw_ldap_info->extra[extra++], argv[c]);
                     */
                }
            }
            else if (!lustrcmp (current_entry, "CONNECT"))
            {
                if (!lustrcmp (ptr, "h"))
                    lustrcpy (sw_ldap_info->hostname,
                          argv[c]);
                else if (!lustrcmp (ptr, "port"))
                {
                    int i;
                    UCHR b[10];

                    i = atoi ((char *) argv[c]);
                    sprintf ((char *) b, "%d", i);
                    if ((i < 0) || lustrcmp (argv[c], b))
                    {
                        printf (SW_REF_MSG (M_E_PORTNO));    /* CR6685 SAC */
                        printf ("n");    /* CR6685 SAC */
                        my_exit (5);
                    }

                    sw_ldap_info->portno = i;
                }
                else if (!lustrcmp (ptr, "dn"))
                    lustrcpy (sw_ldap_info->credentials,
                          argv[c]);
                else if (!lustrcmp (ptr, "pwd"))
                    lustrcpy (sw_ldap_info->password,
                          argv[c]);
            }
            else if (!lustrcmp (current_entry, "SEARCH"))
            {
                if (!lustrcmp (ptr, "dn"))
                    lustrcpy (sw_ldap_info->base,
                          argv[c]);
                else if (!lustrcmp (ptr, "s"))
                    lustrcpy (sw_ldap_info->filter,
                          argv[c]);
            }
            else if (!lustrcmp (current_entry, "TEST"))
            {
                /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
                if (!lustrcmp (ptr, "f"))
                    lustrcpy (tstfile, argv[c]);
                else if ((!lustrcmp (ptr, "s"))
                     || (!lustrcmp (ptr, "l")))
                    tstdownload = TRUE;
                if ((c >= argc)
                    || ((argc == 4) && (c == 3)
                    && !lustrcmp (argv[2], "-f")))
                    test (FALSE, tstfile, tstdownload,
                          lustrcmp (ptr, "l"));
                if (!lustrcmp (current_entry, "TEST")
                    && (!lustrcmp (ptr, "s")
                    || !lustrcmp (ptr, "l")))
                    continue;
            }
            else if (!lustrcmp (current_entry, "MOVESYSINFO"))
                ldap_movesysinfo (ptr);
        }
        c++;
    }

    if (!lustrcmp (current_entry, "ATTRIB"))
    {            /* CR6743 */

        /* CR6746 SAC : 05-01-98 : Set up added mappings */
        SW_LDAP_set_def_mappings (filsh, (X500_TO_SWARE_MAP *) xsmap,
                      sw_ldap_info);
        chk_dups ();
    }

}

/*
 * ==================================================================
 * FUNCTION: ldap_user_match()
 * ==================================================================
 * This function checks the LDAPDN member to see if the ldap attribute
 * matches that mapped to username.
 *
 * PARAMETERS:
 *        info_ptr    sw_ldap_info structure
 *         val_ptr        input value string containing member or LDAP DN
 *         p_xsmap        x.500 mappings
 *         userval_ptr    output User member string
 *
 * RETURN:     match =     TRUE
 *                 FALSE
 *
 * CR16571 JMC 20-12-2004: Checks ldap attribute match to username,
 *                Adds new function
 * CR17995 SAC 26-01-06: added userval_size parameter
 * ==================================================================
 */
PUBLIC SWBOOL ldap_user_match
(
    SW_LDAP_info        *info_ptr,
    char            *val_ptr,
    X500_TO_SWARE_MAP    *p_xsmap,
    char            *userval_ptr,
    int            userval_size
)
{
    char *comma_ptr;                /* comma pointer */
    char usernameval[LDAP_MAX_ATTR_LEN + 1];    /* username value buffer */
    SWBOOL    result;                    /* boolean result */
    SWBOOL    match = FALSE;                /* match boolean */

    /*
     * get LDAP DN attribute name and value beyond the assignment
     * i.e. attrname=wwww,cl=xxxx,cl=yyyy,og=zzzz
     * where usernameval gets returned with everything after the
     * "=". If attrname is the same as
     * Staffware uses for username then TRUE is returned.
     */
    result = SW_LDAP_check_xattrname(val_ptr, p_xsmap, usernameval);

    /* check for same username attribute match*/
    if (result == TRUE)
    {
        /* CR16350 JMC 15-10-2004: truncate on illegal character */
        /* CR17995 SAC 26-01-06: pass in the buffer size */
        SW_LDAP_user_vtrunc(usernameval, info_ptr->grpmemldap, userval_ptr, userval_size);

        /* identify the user value */
        comma_ptr = (LPCHR)lustrchr(userval_ptr, ',');

        /* found one */
        if (comma_ptr != NULL)
        {
            *comma_ptr = '';
        }

        /* assign match */
        match = TRUE;

    }

    return(match);
}

/*
**++

**入口函数

**–
*/
int main (int argc, LPUCHR argv[])
{
    FILNAME mespath;    /* CR6685 SAC */
    SFILNAME temp_file;    /* CR6685 SAC */
    SWBOOL    bPossiblyChanged = FALSE;

    int interactive = (argc == 1);

    /* CR8897 Should always strcpy getenv returns otherwise they are overwritten */
    LPUCHR getenv_rtn;
    UCHR swdir[MAXFILEPATH],
        szDebug [MAXFILEPATH];

    /* CR10765 SAC 15-11-01 */
    SWINT32        nReturn;
    ENVCTXHDL    EnvCtx;
    /* CR15884 JMC 13-8-04: increase Username to SWUV_MAXUSERNAMELENGTH + 1 */
    char        Username[SWUV_MAXUSERNAMELENGTH + 1];

/* CR14758 NJP 14Mar05 – #ifdef left out during reintegration */
#ifdef SW4_UNIX
    /* CR14758 JMC 15-1-04: turn on ldap-3.3 debug trace */
    if (getenv("LDAPDEBUG"))
    {
        /* set all flags for debug trace */
        ldap_debug = 0xffff;
    }
    else
    {
        /* turn off the flags for debug trace */
        ldap_debug = 0;
    }
#endif
    /* CR8897 Should always strcpy getenv returns otherwise they are overwritten */
    getenv_rtn = (LPUCHR) my_getenv (1, "SWDIR", NULL);
    if (getenv_rtn == NULL)
    {
        printf ("SWDIR is not setn");
        /*
         * CR10647 JMC 31-07-03 Reint: Fix all compiler warnings cause
         * I'm nice (probably cause more problems though)
         */
        return 1;
    }
    /* CR8897 Should always strcpy getenv returns otherwise they are overwritten */
    lustrcpy (swdir, getenv_rtn);
/*
** CR16732 – CJED 24-JAN-2005 – get and copy the DEBUG environment variable
** in the same way. Keep a copy as my_getenv() returns a pointer to an
** internal static buffer!
*/
    getenv_rtn = (LPUCHR) my_getenv (1, "DEBUG", NULL);
    if (getenv_rtn != NULL)
    {
        lustrncpy (szDebug, getenv_rtn, sizeof (szDebug) – 1);
    }
    else
    {
        szDebug [0] = '';
    }

    /* CR10229 KWW 8Aug01 Change if to call get_user_identity instead of getpwuid and getuid */
    /* CR19048 Remove unused variable */
    get_user_identity(swdir , (LPUCHR)Username, SWUV_MAXUSERNAMELENGTH);

    /*
    ** CR10765 SAC 15-11-01: initialise process
    */
    /* CR16881 Add PROCESS_IEL_COUNT_SUBSCRIBERS so we don't try and */
    /* contact the server if it isn't running */
    nReturn = process_util_startup ((LPUCHR) "ldapconf",
                    1,
                    NULL,
                    szDebug,
                    PROCESS_NO_LOGIN | PROCESS_NO_SAL | PROCESS_IEL_COUNT_SUBSCRIBERS,
                    (LPUCHR) Username,
                    FALSE);
    if (nReturn != SW_OK)
    {
        printf ("Failed to initialise process: %ldn", nReturn);
        process_startup_display_last_error (NULL);
        return (nReturn);
    }

    /*
     * Getting environment context.
     * This will get the default environment context
     */
    EnvCtx = envGetContext ();
    if(!EnvCtx)
    {
        printf ("Failed to get environment contextn");
        process_shutdown (FALSE, ER_SYSTEM, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        return (ER_SYSTEM);
    }

    /* get the FIL session */
    nReturn = envAttrGet (EnvCtx, ENV_ATTR_FILSH, (void *) &filsh, sizeof (filsh));
    if (SW_OK != nReturn)
    {
        printf ("Failed to get FILSH from environment context: %ldn", nReturn);
        process_shutdown (FALSE, nReturn, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        return (nReturn);
    }

    /*
     * get the PATTR session from the
     * environment context
     */
    nReturn = envAttrGet (EnvCtx, ENV_ATTR_PATSH, (PATTR_SH *) &hPAT, sizeof(PATTR_SH));
    if (nReturn != SW_OK)
    {
        printf ("Failed to get PATTR from environment context: %ldn", nReturn);
        process_shutdown (FALSE, nReturn, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        return (nReturn);
    }

#if defined (SW4_UNIX)
    sprintf ((char *) lockfile, "%s/tsys/swldaplck", swdir);
#elif defined (SW4_WIN32SERVER)
    sprintf ((char *) lockfile, "%s\tsys\swldaplck", swdir);
#endif
    if (
        (lock_fh =
         fil_open (filsh, (LPFILNAME) lockfile,
               FIL_CREAT | FIL_CEXCLUSIVE | FIL_WRITE, 0)) < 1)
    {
        printf ("Application is already in usen");
        if (interactive)
            prompt ();

        process_shutdown (FALSE, lock_fh, (LPUCHR) "LDAPCONF Exiting");
        return 1;
    }

    if ((msg_sh = init_errhand (filsh, "ldapconf", "english")) <= 0)
    {
        fprintf (stderr, "Error message handler failed to initialise – %dn", msg_sh);
        process_shutdown (FALSE, msg_sh, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        my_exit (1);
    }

    /* CR6685 SAC 08-12-97 : Build path to ldapconf message file */
    bld_staffpath (filsh, (LPFILNAME) & mespath, FILD_TEXT,
               (LPSFILNAME) atofile (&temp_file,
                         (LPCHR) SW_LDAP_MES_FILE));

    /* CR6685 SAC 08-12-97 : Initialise the ldapconf message file */
    if (sw_init_msg (filsh, &mespath, '', msg_sh) <= 0)
    {
        fprintf (stderr, "Access to '%s' failed.n", mespath.filepath);
        process_shutdown (FALSE, ER_SYSTEM, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        my_exit (1);
    }

    node_namefind (filsh, &my_node, (LPUCHR) fil_def (filsh, FILC_NODE));

    initialise ();

    sw_ldap_info = (SW_LDAP_info *) SW_LDAP_alloc_info ();

    if (SW_LDAP_get_info (filsh, (SW_LDAP_info *) sw_ldap_info) != SW_LDAP_SUCCESS)
    {
        printf (SW_REF_MSG (M_E_CFG_READ));    /* CR6685 SAC */
    }

    SW_LDAP_set_def_mappings (filsh, (X500_TO_SWARE_MAP *) xsmap, sw_ldap_info);
    ldapcpy ();

    if (interactive)
    {
        bPossiblyChanged = menu ();
    }
    else
    {
        batch (argc, (LPUCHR *) argv);
        bPossiblyChanged = TRUE;        
        /* chk_dups(); */
    }

    writeinfo (interactive);    /* save */

    SW_LDAP_free_info (sw_ldap_info);

    if (lock_fh > 0)    /* CR8893 ZJS 08/03/2000 ie. this session created the lock file in the first place */
    {
        fil_close (lock_fh);    /* CR6685 SAC */
        fil_fsdelete (filsh, (LPFILNAME) lockfile);
    }

    process_shutdown (FALSE, SW_OK, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07

    return 0;
}

/*
**++
**
**–
*/
PRIVATE void ldap_movesysinfo (LPUCHR ptr)
{
    POSTARG argv;
    UCHR buff[128];

    /* CR10765 SAC 15-11-01 */
    IQLMSGINFO        MsgInfo, *pMsgInfo;
    MBSETMSG_SH        mbsh;
    int            rc = SW_OK;
    UCHR            InsBuf[POSTBUFSIZE];

    int interactive = !lustrcmp (ptr, "");

    lustrcpy (buff, "");

    if (interactive)
        GetValidCh (SW_REF_MSG (M_FULL_PARTIAL_QUIT), "FPQ", buff);    /* CR6685 SAC */

    if (!lustrcmp (buff, "Q"))
        return;

    argv[0] = (LPUCHR) I_MOVINFO;
    if ((!lustrcmp (ptr, "full") || (!lustrcmp (buff, "F"))))
        argv[1] = (LPUCHR) "FULL";
    else            /* if ( (!lustrcmp(ptr, "partial") || (! lustrcmp(buff, "P")) */
        argv[1] = (LPUCHR) "PARTIAL";

    /*
     * CR10765 SAC 15-11-01: post the instruction to the BG
     * using the MBoxset interfaces
     */

    /*
     * begin transaction
     */
    rc = fil_get_conn (filsh);
    if (rc < 0)
    {
        fprintf (stderr, "Failed to begin transaction: %dn", rc);
        return;
}

    /*
    ** initialise a mbox set session
    */
    if ((mbsh = MBSetMsg_Init (filsh, hPAT, MBSET_ACC_WRITE_BG, TRUE)) <= 0)
    {
        printf ("Failed to initialise MBoxSet session: %dn", mbsh);
        return;
    }
    /*
    ** build message info string
    */
    pMsgInfo = Bld_MBoxMsgInfo_v1 (&MsgInfo,
                    fil_def (filsh, FILC_PRO),
                    argv[0],
                    fil_def (filsh, FILC_PRO),
                    my_node.name,
                    (LPUCHR) "",
                    (LPUCHR) "",
                    0,
                    0,
                    (LPUCHR) "");

    /*
    ** build buffer from arguments
    */
    bld_instruction ((LPCHR) InsBuf, 2, argv);

    /*
    ** post the message
    */
    if ((rc = MBSetMsg_Enqueue (mbsh,
                pMsgInfo,
                my_node.name,
                IQL_PTY_NONE,
                IQL_DATA_BIN,
                InsBuf,
                lustrlen (InsBuf),
                TRUE)) != SW_OK)
    {
        printf ("Failed to enqueue %s instruction: %dn", argv[0], rc);
    }

    /*
    ** terminate the session
    */
    MBSetMsg_Term (mbsh);

    fil_commit_conn (filsh, 'T', (LPUCHR) "ldap_movesysinfo", (LPUCHR) argv[0]);
}

void sighandler (int sig)
{
    /* Disallow CTRL+C during handler. */
    my_exit (1);
}

void my_exit (int sig)
{
    if (lock_fh > 0)    /* CR8893 ZJS 08/03/2000 ie. this session created the lock file in the first place */
    {
        fil_close (lock_fh);
        fil_fsdelete (filsh, (LPFILNAME) lockfile);
    }

    exit (sig);
}
/*
**++
**  MODULE:        $RCSfile$
**            $Revision: 83122 $
**            $Date: 2011-07-12 00:58:50 -0700 (Tue, 12 Jul 2011) $
**
**  DESCRIPTION:
**
**  ENVIRONMENT:    Generic Server (NT/Unix)
**
**  COPYRIGHT:        Copyright ?2004, TIBCO Software Inc.
**
**  MODIFICATION HISTORY:
**
**    $Log$
**    Revision 7.51  2007/02/14 11:13:47  mbanfiel
**    CR19771 Re-order output of mappings to match input order
**
**    Revision 7.50  2007/02/12 16:54:00Z  cdurrant
**    CR19761 – report group membership errors to file as well as screen
**    Revision 7.49  2007/02/01 19:44:50Z  stevec
**    CR19716: If LDAP attribute that determines type of entry comes after membership attribute then members aren't checked
**    Revision 7.48  2007/02/01 12:03:49Z  stevec
**    CR19716: If LDAP attribute that determines type of entry comes after membership attribute then members aren't checked
**    Revision 7.47  2006/12/18 11:28:48Z  cdurrant
**    CR19501 – fail MOVESYSINFO if LDAP sync fails
**    Revision 7.46  2006/12/15 12:21:01Z  cdurrant
**    CR19495 – fix groupusers list handling
**    Revision 7.45  2006/12/08 11:38:22Z  cdurrant
**    CR19493_1 – fix error on Win32 build
**    Revision 7.44  2006/12/07 12:02:26Z  cdurrant
**    CR19493 – show the value of GROUPUSERS attribute in ldapconf
**    Revision 7.42  2006/08/03 14:02:43Z  rhudson
**    CR19048 Itanium Build
**    Revision 7.41  2006/07/21 14:07:50Z  cdurrant
**    CR19009_1 – support UTF-8 attribute value translation in LDAP
**    Revision 7.40  2006/07/14 06:49:35Z  SteveC
**    CR18964: LDAPCONF test treats spaces as valid users in group member lists
**    Revision 7.39  2006/06/21 14:47:05Z  SteveC
**    CR18828: CR18665 was broken by Charles' change to ldapconf.c
**    Revision 7.38  2006/05/19 10:21:24Z  cdurrant
**    CJED_fix_UNIX_build – min macro not available on UNIX build, also used correct size for lustrncpy function.
**    Revision 7.37  2006/05/18 16:15:41Z  SteveC
**    CR18665: Ldapconf outputs error when member of group doesn't exist, even though they may appear later in the LDAP search results
**    Revision 7.36  2006/01/30 15:35:01Z  mbanfiel
**    CR17995: LDAP truncates group membership list at 100 characters
**    Revision 7.35  2006/01/30 11:57:16Z  mbanfiel
**    CR17344 Add ldap_check_all_members_valid function
**    Revision 7.34  2006/01/06 09:38:36Z  rhudson
**    CR17052 Main Trunk Reint
**    Revision 7.33  2005/11/14 17:20:12Z  rhudson
**    Revision 7.32  2005/06/06 09:26:19Z  mbanfiel
**    CR17172 Product name change
**    Revision 7.31  2005/03/14 17:02:54Z  njpatel
**    Reintegration of CR16829
**    CR14758 Corrected overlooked reintegration.
**    Revision 7.30  2005/03/08 16:57:32Z  jcarver
**    Fix for ldap debug trace
**    Revision 7.29  2005/02/21 16:28:44Z  nhaines
**    Changed copyright info
**    Revision 7.28  2005/01/28 14:21:07Z  RobertH
**    CR16881 Fixed startup when server not running
**    Revision 7.27  2005/01/25 15:46:37Z  CharlesD
**    CR16732_1 – First attempt at swldap file upgrade
**    Revision 7.26  2005/01/21 12:49:22Z  JohnCA
**    Fix for ldapconf seg fault
**    Revision 7.25  2005/01/20 17:30:53Z  JohnCA
**    Fixes in line with BG for CR16847
**    Revision 7.24  2005/01/07 11:04:14Z  NickH
**    Modified copyright notice to match spec
**    Revision 7.23  2004/12/22 15:11:57Z  JohnCA
**    Fix for GroupUsers in LDAP
**    Revision 7.22  2004/12/16 15:21:34Z  JohnCA
**    Fix for valid MEMBERLIST in ldap
**    Revision 7.21  2004/12/15 13:32:53Z  JohnCA
**    ldapconf TEST -l fix
**    Revision 7.20  2004/12/10 08:59:05Z  NickH
**    Removed debug printf
**    Revision 7.19  2004/12/10 08:53:55Z  NickH
**    Added new copyright system
**    Revision 7.18  2004/12/02 15:49:56Z  JohnCA
**    Partial Sync to LDAP MSActive
**    Revision 7.17  2004/11/23 14:32:40Z  CharlesD
**    pod_1194_reint – LDAP referrals CRs reintegration
**    Revision 7.16  2004/11/08 17:33:03Z  JohnCA
**    Change X.500 to LDAP
**    Revision 7.15  2004/11/05 10:09:01Z  JohnCA
**    Copyright
**    Revision 7.14  2004/11/04 15:13:22Z  JohnCA
**    LDAP GENERALI reint
**    Revision 7.12.1.6  2004/11/02 16:11:23Z  JohnCA
**    Fix array overrun in ldapconf
**    Revision 7.12.1.5  2004/10/21 16:38:11Z  JohnCA
**    CR16296: Copyright TIBCO 2004
**    Revision 7.12.1.4  2004/10/21 15:49:02Z  JohnCA
**    Revision 7.12.1.3  2004/10/21 09:07:54Z  JohnCA
**    LDAP DN format Enhancements
**    Revision 7.12.1.2  2004/09/28 16:27:49Z  JohnCA
**    LDAP Enhancements for Generali
**    Revision 7.12.1.1  2004/09/13 13:39:41Z  JohnCA
**    Duplicate revision
**    Revision 7.12  2004/09/13 13:39:41Z  CharlesD
**    CR15884_reint_MT – reintegrated back into /batch trunk for POD/1218
**    Revision 7.11  2004/09/10 12:59:02Z  RobertH
**    CR16288 Linux – Remove {} round each field as it is not valid
**    Revision 7.10  2004/02/10 16:34:39Z  KevinG
**    CR14973 copyright changes
**    Revision 7.9  2003/08/14 14:02:11Z  SidA
**    Reintegrations from i9.2-o(1.0.2), i9.2-o(2.2.1), i9.2-o(2.2.2),
**    i9.2-o(3.1) amd i9.2-o(3.3) into main trunk
**    Revision 7.8  2003/04/16 13:19:08  KevinG
**    CR13267 Update copyright
**    Revision 7.7  2002/07/15 15:26:26  SteveC
**    CR11968 : Using extra attributes for ldap X.500 can cause ldapconf and the BG process to crash.
**    Revision 7.6  2002/06/14 09:52:28  SteveC
**    CR11680: copyright version update
**    Revision 7.5.1.2  2003/08/06 11:13:45  JohnCA
**    Reint plus LDAP fixes
**    Revision 7.5.1.1  2002/01/14 14:07:44  JohnCA
**    Duplicate revision
**    Revision 7.5  2002/01/14 14:07:44  SteveC
**    CR10933: NT port integration
**    Revision 7.4  2002/01/09 13:03:44  SteveC
**    Automatically reintegrated (by autreint.ksh):
**    Reintegration from REINT_630 1.141.1.4
**    Revision 7.3.2.3  2002/01/07 15:01:12  SteveC
**    Revision 7.3.2.2  2002/01/03 11:57:17  SteveC
**    Integration from 1.101 –> 1.101.1.27 (PART I)
**    Revision 7.3.2.1  2001/11/16 13:51:39  SteveC
**    Duplicate revision
**    Revision 7.2  2001/07/16 08:51:14  SteveC
**    Reintegration from FILPACKDB branch:
**
**    1.103 –> 1.103.4.4
**    Revision 7.1  2001/03/09 18:54:19  nick
**    Version number update
**    Revision 1.32  2001/03/09 08:57:55  nick
**    Automated code tidying
**    Revision 1.31  2001/03/08 10:49:33  nick
**    Auto dead code removal
**    Revision 1.30  2000/05/25 21:31:44  markb
**    CLEAN_BUILD – Post POD/STR/201 & POD/CUS/146 Integ.
**    Revision 1.29  2000/05/23 00:37:15  markb
**    POD_STR_201_Phase_2_Reint_Main – Reintegrating POD_STR_201 Phase 2 into the main trunk.
**    Revision 1.28  2000/03/23 14:37:42  kevin
**    CR8897 Stop GPF in ldapconf
**    Revision 1.27.1.2  2000/04/11 17:02:43  keith
**    CR8937: Fix compiler warning on AIX
**    Revision 1.27.1.1  2000/03/08 13:15:37  keith
**    Duplicate revision
**    Revision 1.27  2000/03/08 13:15:37  ben
**    CR8892 – oversize attribute values cause coredumping in x500
**    mode reporting.
**    CR8893 – do not destroy swldaplck file if you are not the originator.
**    Revision 1.26  2000/01/10 09:50:17  steve
**    Integration from 1.40.1.11 –> 1.40.1.16 and changes for CR8272
**    Revision 1.25  1999/10/13 16:21:24  markb
**    POD_STR_013 – Added new swprim password checking stuff.
**    Revision 1.24  1999/09/21 15:06:09  markb
**    POD/STR/013 – Changed BOOL to SWBOOL.
**    Revision 1.23  1999/07/01 14:45:26  sid
**    POD/STR/011 – pick up correct prototypes for sw_ref_msg
**    Revision 1.22  1999/05/21 10:09:23  steve
**    Revision 1.21  1999/05/18 07:06:56  steve
**    Revision 1.20  1999/04/21 13:46:06  steve
**    Re-integration from 1.32.1.9
**    Revision 1.19  1999/01/28 17:17:16  steve
**    Automatically reintegrated (by autreint.ksh):
**    Re-integration from I249_NTServer_MultiNode (1.32.1.4)
**    Revision 1.18.1.2  1998/12/22 13:38:24  steve
**    CR7869 : modify search filter the same way the Staffware BG does
**    Revision 1.18.1.1  1998/10/05 06:43:52  steve
**    Duplicate revision
**    Revision 1.17  1998/07/22 10:33:12  ian
**    I265 – Server Integration: compiler warnings
**    Revision 1.16  1998/07/17 15:53:26  keith
**    CR7284: changes for clean compile on UNIX
**    Revision 1.15  1998/06/26 14:07:13  ian
**    CR7036 – FIL Re-integration
**    Revision 1.14.1.2  1998/05/29 10:53:44  ian
**    CR7036 – FIL Integration
**    Revision 1.14.1.1  1998/02/09 10:56:54  ian
**    Duplicate revision
**    Revision 1.13.1.2  1998/01/28 17:09:17  steve
**    CR6733 : Changes made for NT SAL SDK
**    Revision 1.12  1998/01/05 11:35:06  ben
**    Revision 1.11  1997/12/11 10:55:02  ben
**    allow entry of NULL to signify ""
**    Revision 1.10  1997/12/10 12:19:43  steve
**    Revision 1.9  1997/12/10 10:44:25  ben
**    for a clean UNIX build
**    Revision 1.8  1997/12/09 08:18:02  steve
**    Use message file to hold output messages
**    Revision 1.7  1997/12/08 14:38:06  ben
**    Revision 1.6  1997/11/28 19:10:39  ben
**    Safeguard changes
**    Revision 1.5  1997/11/26 18:56:36  ben
**    Revision 1.4  1997/11/25 17:58:00  ben
**    if len  extras too long won't get assigned
**    Revision 1.3  1997/11/25 11:09:53  ben
**    Revision 1.2  1997/11/24 10:03:42  ben
**    Revision 1.1  1997/11/24 09:50:01  ben
**    Initial revision
**–
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef    SW4_UNIX
#include <signal.h>
#include <ctype.h>
#include <pwd.h>
#endif

#include "swvers.h"
#include "swtype.h"
#include "swldap.h"
#include "sallogin.h"
#include "filpost.h"
#include "sallinit.h"
#include "postutil.i"
#include "postwrit.i"
#include "errhand.h"        /* CR6685 SAC */
#include "errhand.i"        /* CR6685 SAC */
#include "wchar.h"
#include "sallogin.i"
#include "filnode.i"
#include "swprim.i"

#include "filuser.i"
#include "swchrset.i"
#include "internal.h"        /* CR6733 SAC */

/* CR10765 SAC 15-11-01 */
#include "psulmain.h"
#include "filpattr.h"
#include "mbset.h"

#ifdef    SW4_WIN32SERVER
#include <conio.h>
#endif
/* CR10647 Fix all compiler warnings cause I'm nice (probably cause more problems though) */
/* Needs an include file at some point (defined in filinit2.c) */
EXTERNAL int    create_filsh (LPCHR swdir, LPCHR debug_log, LPCHR registry_area);

/* SID POD/STR/011 – message funcs now def'd correctly in unimsg.i */
#include "unimsg.i"

#define SIZEOFBIGP 16
#define ER_ENTRY_NOTFOUND   -1
#define LINESONSCR 24

/* CR14758 NJP 14Mar05 – #ifdef left out during reintegration */
#ifdef SW4_UNIX
/* CR14758 JMC 25-2-04 */
extern int ldap_debug;
#endif

NODE my_node;

UCHR msg[256];
UCHR lockfile[256];        /* must be global for sighandler to pick up */

SW_LDAP_info *sw_ldap_info, *sw_ldap_info_copy = NULL;
SW_LDAP *ldap;

SWINT32 ret;
SWINT32 num_entries;
SWINT32 filsh;

/* CR10765 SAC 15-11-01 */
PATTR_SH    hPAT;

/* CR6685 SAC 08-12-97 : message session handle */
int msg_sh;
int lock_fh;
/* CR16288 Linux – Remove {} round each field as it is not valid */
const char *bigentries[] = {
    "ATTRIB",
    "CONNECT",
    "SEARCH",
    "TEST",
    "HELP",
    "VIEW",
    "MOVESYSINFO"
};

typedef struct
{
    UCHR BIGP[SIZEOFBIGP];
    UCHR member[10];
    int set;
} ENTRY;

ENTRY entries[] = {
    {"ATTRIB", "u",},    /* Username      */
    {"ATTRIB", "r",},    /* Role          */
    {"ATTRIB", "g",},    /* Group         */
    {"ATTRIB", "menu",},
    {"ATTRIB", "desc",},    /* Description   */
    {"ATTRIB", "lang",},    /* Language      */
    {"ATTRIB", "sort",},    /* Sortmail      */
    {"ATTRIB", "x",},    /* Extras        */

    {"CONNECT", "h",},    /* Hostname      */
    {"CONNECT", "port",},    /* Username      */
    {"CONNECT", "dn",},    /* DN Entry      */
    {"CONNECT", "pwd",},    /* Password      */

    {"SEARCH", "dn",},
    {"SEARCH", "s",},    /* Search filter */

    {"TEST", "f",},        /* File name     */
    {"TEST", "s",},        /* user/role/group/attribute info to be downloaded from LDAP DIT. */
    {"TEST", "l",},

    {"MOVESYSINFO", "full",},
    {"MOVESYSINFO", "partial"}

};

/* CR9574 Now uses NUM_SW_ELEMENTS in swldap.h instead of */
/* hardcoded sizes */
X500_TO_SWARE_MAP xsmap[NUM_SW_ELEMENTS];

typedef struct ll
{
    UCHR x500[SW_LDAP_ATTRNAME_SIZE];
    UCHR staffware[SW_LDAP_ATTRNAME_SIZE];
    struct ll *next;
}
LL;

#include "ldapconf.h"
LL *head = NULL;

#ifdef    __cplusplus
extern "C"
{
#endif
    int g_UTF8Support = 0;
#ifdef    __cplusplus
}
#endif
/*
**++
** FUNCTIONs LL_xxx perform the required operations for maintaining a linked list of character strings
**–
*/
PRIVATE LL *LL_find (LPUCHR srch)
{
    UCHR usrch[256];
    UCHR ucurr[256];
    LL *p = head;
    LL *ret = NULL;

    lustrcpy (usrch, srch);
    ucase (usrch);

    for (p = head; p != NULL; p = p->next)
    {
        lustrcpy (ucurr, p->staffware);
        ucase (ucurr);
        if (!lustrcmpul (ucurr, usrch))
        {
            ret = p;
            break;
        }
    }
    return ret;
}

/*
**++
**
**–
*/
PRIVATE void LL_add (LPUCHR staffware, LPUCHR x500)
{
    LL *p = NULL;
    LL *next;
    int x;
    p = LL_find (staffware);
    if (p)
    {
        printf (SW_REF_MSG (M_EXISTS), staffware);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        return;
    }

    /* CR9574 Now uses NUM_SW_ELEMENTS in swldap.h instead of */
    /* hardcoded sizes */
    for(x=0;x<NUM_SW_ELEMENTS;x++)
    {
        if (!lustrcmpul (staffware, xsmap[x].staffware))
        {
            printf (SW_REF_MSG (M_STAFFW_NOT_EXTRA));    /* CR6685 SAC */
            printf ("n");    /* CR6685 */
            return;
        }
        if (!lustrcmpul (staffware, xsmap[x].x500))
        {
            printf (SW_REF_MSG (M_X500_NOT_EXTRA));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            return;
        }
    }

    next = (LL *) malloc (sizeof (LL));
    if (head != NULL)
        for (p = head; p->next != NULL; p = p->next);    /* traverse to end of list */
    else
        head = next;    /* anchor the head */
    lustrcpy (next->staffware, staffware);
    lustrcpy (next->x500, x500);
    next->next = NULL;
    if (p)
        p->next = next;
}

/*
**++
**
**–
*/
PRIVATE void LL_del (LPUCHR val)
{
    LL *p = NULL, *prev = NULL;
    for (p = head; p != NULL; prev = p, p = p->next)
    {
        if (!lustrcmpul (p->staffware, val))
        {
            if (prev)
                prev->next = p->next;
            else    /* top of the list, so reset head! */
                head = p->next;
            free (p);
            printf (SW_REF_MSG (M_DELETED), val);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            return;
        }
    }
    printf (SW_REF_MSG (M_NOT_FOUND), val);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */
    return;
}

/*
**++
**
**–
*/
PRIVATE void LL_chg (LPUCHR old, LPUCHR nw)
{
    LL *o;
    LL *n;
    o = LL_find (old);
    if (!o)
    {
        printf (SW_REF_MSG (M_NOT_FOUND), old);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        return;
    }
    n = LL_find (nw);
    if (n)
    {
        printf (SW_REF_MSG (M_EXISTS), nw);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        return;
    }

    /* got here so continue */
    lustrcpy (o->x500, nw);
}

/*
**++
**
**–
*/
PRIVATE void LL_list ()
{
    LL *p;
    int lineno = 0;
    for (p = head; p != NULL; p = p->next)
    {
        printf ("%s -> %sn", p->staffware, p->x500);
        lineno++;
        if (lineno > (LINESONSCR – 2))
        {
            prompt ();
            lineno = 0;
        }
    }
}

/*
**++
**
**–
*/
PRIVATE void LL_freeall ()
{
    LL *p, *next;
    for (p = head; p != NULL; p = next)
    {
        next = p->next;
        free (p);
    }
    head = NULL;
}

/*
**++
** FUNCTION ucase
**
** DESCRIPTION  :
** Converts a given character string to upper case
**–
*/
PRIVATE void ucase (LPUCHR str)
{
    if (!str)
        return;

    while (*str)
    {
        *str = toupper (*str);
        str++;
    }
}

/*
**++
** FUNCTION lcase
**
** DESCRIPTION  :
** Converts a given character string to lower case
**–
*/
PRIVATE void lcase (LPUCHR str)
{
    if (!str)
        return;

    while (*str)
    {
        *str = tolower (*str);
        str++;
    }
}

/*
**++
** REQD?
**–
*/
PRIVATE void initialise (void)
{
    int c;
    int numents;

    numents = sizeof (entries) / sizeof (entries[0]);
    for (c = 0; c < numents; c++)
    {
        entries[c].set = 0;
    }
}

/*
**++
** RENAME
**–
*/
PRIVATE void getbigentry (LPUCHR BIGP, LPUCHR * entry)
/* return an error */
{
    int c;
    int numents = (sizeof (bigentries)) / sizeof (bigentries[0]);

    for (c = 0; (c < numents); c++)
        if (!lustrcmp (bigentries[c], BIGP))
        {
            *entry = (LPUCHR) bigentries[c];
            break;
        }

}

/*
**++
** RENAME
**–
*/
PRIVATE int getentry (LPUCHR BIGP, LPUCHR member)
{
    int c;
    int numents;
    int ret = ER_ENTRY_NOTFOUND;
    numents = sizeof (entries) / sizeof (entries[0]);

    for (c = 0; ((ret == ER_ENTRY_NOTFOUND) && (c < numents)); c++)
    {
        if ((!lustrcmp (entries[c].BIGP, BIGP))
            && (!lustrcmp (entries[c].member, member)))
            ret = c;
    }
    return ret;
}

/*
**++
** FUNCTION GetValidCh
**
** DESCRIPTION  :
** Displays a prompt for an input character; this character is checked to be a valid character for the context
**–
*/
PRIVATE void GetValidCh (char *prompt, char *valid, LPUCHR str)
{
    UCHR buff[80];
    UCHR promptcpy[128];

    lustrcpy (promptcpy, prompt);
    while (TRUE)
    {
        printf ("%s", promptcpy);
        gets ((char *) buff);
        ucase (buff);
        if ((strstr (valid, (char *) buff) == NULL)
            || lustrlen (buff) != 1)
        {
            printf (SW_REF_MSG (M_E_INVALID_ENTRY));    /* CR6685 SAC */
            printf ("nn");    /* CR6685 SAC */
        }
        else
            break;
    }
    lustrcpy (str, buff);
}

/*
**++
** FUNCTION connection
**
** DESCRIPTION  :
** Read connection information
**–
*/
PRIVATE void connection ()
{
    UCHR buff[1024];

    printf (SW_REF_MSG (M_ASK_HOST), sw_ldap_info->hostname);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
    if (strlen (gets ((char *) buff)))
        lustrcpy (sw_ldap_info->hostname, buff);
    */
    my_gets (sw_ldap_info->hostname, sizeof(sw_ldap_info->hostname)-1);

    while (TRUE)
    {
        int i;
        UCHR b[10];

        printf (SW_REF_MSG (M_ASK_PORTNUMBER), sw_ldap_info->hostname, sw_ldap_info->portno);    /* CR6685 SAC */

        if (!strlen (gets ((char *) buff)))
            break;

        i = atoi ((char *) buff);
        sprintf ((char *) b, "%d", i);
        if ((i < 0) || lustrcmp (buff, b))
        {
            printf (SW_REF_MSG (M_E_PORTNO));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
        }
        else
        {
            sw_ldap_info->portno = i;
            break;
        }
    }

    printf (SW_REF_MSG (M_ASK_BIND_NAME), sw_ldap_info->credentials);    /* CR6685 SAC */
    my_gets (sw_ldap_info->credentials, SW_LDAP_CRED_SIZE);

    GetValidCh (SW_REF_MSG (M_ASK_CHG_PASSWD), "YN", buff);    /* CR6685 SAC */

    if (!lustrcmp (buff, "Y"))
    {
        int ret = SW_OK;
        UCHR Msg1[100], Msg2[100];

        lustrcpy (Msg1, SW_REF_MSG (M_ASK_PASSWD));
        lustrcpy (Msg2, SW_REF_MSG (M_PASSWD_CONF));

        /*
           ** Use new swprim function for getting and confirming password entry
         */
        do
        {
            ret =
                sw_get_password_confirm (buff, Msg1, Msg2,
                             sizeof (buff) – 1);
            if (ret != SW_OK)
            {
                printf ("%sn", SW_REF_MSG (M_E_PASSWD_MAT));
            }
        }
        while (ret != SW_OK);
        lustrcpy (sw_ldap_info->password, buff);
    }
    printf (SW_REF_MSG (M_ASK_ACTIVE_DIRECT), sw_ldap_info->isAD ? "Yes" : "No");
    GetValidCh("","YN",buff);
    sw_ldap_info->isAD =!lustrcmp (buff, "Y");
    #ifndef SW4_WIN32SERVER

    if(sw_ldap_info->enableSSL)
    {
        GetValidCh(SW_REF_MSG(M_ASK_DISABLE_SSL),"YN",buff);
        sw_ldap_info->enableSSL =lustrcmp (buff, "Y");
    }
    else
    {
        GetValidCh(SW_REF_MSG(M_ASK_ENABLE_SSL),"YN",buff);
        sw_ldap_info->enableSSL =!lustrcmp (buff, "Y");
    }
   
    if(sw_ldap_info->enableSSL)
    {
        printf (SW_REF_MSG (M_ASK_CERT_PATH), sw_ldap_info->certpath);       /* CR6685 SAC */
        my_gets (sw_ldap_info->certpath, SW_LDAP_BASE_SIZE);
    }
    #endif

   

   
}

/*
**++
** FUNCTION search
**
** DESCRIPTION  :
** Read search information
**–
*/
PRIVATE void search ()
{
    /* MR 41741  UCHR buff[256]; */

    printf (SW_REF_MSG (M_ASK_START_SEARCH), sw_ldap_info->base);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
     * if (strlen (gets ((char *) buff)))
     *    lustrcpy (sw_ldap_info->base, buff);
     */
    my_gets (sw_ldap_info->base, sizeof(sw_ldap_info->base)-1);

    printf (SW_REF_MSG (M_ASK_FILTER_SEARCH), sw_ldap_info->filter);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
     * if (strlen (gets ((char *) buff)))
     *    lustrcpy (sw_ldap_info->filter, buff);
     */
    my_gets (sw_ldap_info->filter, sizeof(sw_ldap_info->filter)-1);

    printf (SW_REF_MSG (M_ASK_DN_PATTERN), sw_ldap_info->dnPattern);    /* CR6685 SAC */

    /* MR 41741: Check for buffer overruns
     * if (strlen (gets ((char *) buff)))
     * {
     *    lustrcpy (sw_ldap_info->dnPattern, buff);
     * }
     */
    my_gets (sw_ldap_info->dnPattern, sizeof(sw_ldap_info->dnPattern)-1);
}

/*
**++
**
**–
*/
PRIVATE void extra_to_LL ()
{
    int x;
    LL_freeall ();        /* to be sure, to be sure */
    for (x = 0; x < sw_ldap_info->num_extras; x++)
        LL_add (sw_ldap_info->extra[x]->staffware, sw_ldap_info->extra[x]->x500);
}

/*
**++
**
**–
*/
PRIVATE void LL_to_extra ()
{
    LL *p;

    SW_LDAP_extra_free (sw_ldap_info);

    for (p = head; p != NULL; p = p->next)
    {
        SW_LDAP_extra_add (sw_ldap_info, p->staffware, p->x500);
    }
}

/*
**++
** FUNCTION extras
**
** DESCRIPTION  :
** Read extra information
**–
*/
PRIVATE void extras ()
{
    UCHR buff[SW_LDAP_ATTRNAME_SIZE];
    extra_to_LL ();
    while (TRUE)
    {
        GetValidCh (SW_REF_MSG (M_EXTRA_MENU), "LCDAQ", buff);    /* CR6685 SAC */

        if ((!head) && strstr ("LCD", (char *) buff))
        {        /*attempted to list/change/delete an empty list */
            printf (SW_REF_MSG (M_E_NO_ENTRIES));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            continue;
        }

        if (!lustrcmp (buff, "L"))
            LL_list ();
        else if (!lustrcmp (buff, "C"))
        {
            LL *o, *n;
            UCHR nw[256];

            printf (SW_REF_MSG (M_VAL_CHANGE));    /* CR6685 SAC */

            gets ((char *) buff);
            if (!*buff)
                continue;
            o = LL_find (buff);
            if (!o)
            {
                printf (SW_REF_MSG (M_NOT_FOUND), buff);    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                continue;
            }

            printf (SW_REF_MSG (M_VAL_CHG_TO), buff);    /* CR6685 SAC */

            gets ((char *) nw);
            /* CR9620 Don't allow values to be changed to NULL or space (cause PAG are bound */
            /* to try a space prefix) or something equally silly */
            if(*nw == 0 || *nw == ' ') {
                /* print out a message that it's invalid */
                printf (SW_REF_MSG (M_E_INVALID_ENTRY));
                printf("n");
            } else {
                n = LL_find (nw);
                if (n)
                {
                    printf (SW_REF_MSG (M_EXISTS), nw);    /* CR6685 SAC */
                    printf ("n");    /* CR6685 SAC */
                    continue;
                }
                LL_chg (buff, nw);
            /* CR9620 End */
            }
        }

        else if (!lustrcmp (buff, "D"))
        {

            printf (SW_REF_MSG (M_VAL_DELETE));    /* CR6685 SAC */

            gets ((char *) buff);
            if (!*buff)
                continue;
            LL_del (buff);
        }
        else if (!lustrcmp (buff, "A"))
        {
            UCHR x500[SW_LDAP_ATTRNAME_SIZE];
            printf (SW_REF_MSG (M_VAL_ADD));    /* CR6685 SAC */

            gets ((char *) buff);
           
            if (!*buff)
                continue;
            printf (SW_REF_MSG (M_VAL_ADD_X500));
            gets ((char *) x500);

            /* CR13995 JMC 31-7-03 Don't allow values to be added to NULL or space */
            if(*buff == 0 || *buff == ' ' || *x500 == 0 || *x500 == ' ') {
                /* print out a message that it's invalid */
                printf (SW_REF_MSG (M_E_INVALID_ENTRY));
                printf("n");
            } else {
                /* add entry to extras */
                LL_add (buff, x500);
            } /* CR13995 end */
        }

        else if (!lustrcmp (buff, "Q"))
        {
            LL_to_extra ();
            return;
        }
    }
}

/*
**++
** FUNCTION chk_dups
**
** DESCRIPTION  :
** Check no duplicates in attribute settings
**–
*/
PRIVATE SWBOOL chk_dups ()
{
    struct DUPCHECK
    {
        UCHR x500[SW_LDAP_ATTRNAME_SIZE + 1];
        int count;
    } dupcheck[7];

    int x, y;
    SWBOOL are_dups = FALSE;

    memset ((LPCHR) & dupcheck, '', sizeof (dupcheck));
    for (x = 0; x < 7; x++)
    {
        for (y = 0; y < 7; y++)
        {
            if (!lustrcmpul (xsmap[x].x500, (LPUCHR) ""))
                break;

            if (!lustrcmpul (xsmap[x].x500, dupcheck[y].x500))
            {    /* match found */
                dupcheck[y].count++;
                break;
            }
        }
        if (y >= 7)
        {        /* not found */
            y = 0;
            while (lustrcmp (dupcheck[y].x500, (LPUCHR) ""))
                y++;
            lustrcpy (dupcheck[y].x500, xsmap[x].x500);
            dupcheck[y].count++;
        }
    }

    for (x = 0; x < 7; x++)
    {
        if (dupcheck[x].count > 1)
        {
            printf (SW_REF_MSG (M_MULTIPLE_MAP),
                dupcheck[x].count, dupcheck[x].x500);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            are_dups = TRUE;
        }
    }
    return are_dups;
}

/*
**++
** FUNCTION my_gets
**
** DESCRIPTION  :
**
**–
*/
PRIVATE void my_gets (LPUCHR entry, int size)
{
    UCHR buff[2048];     /* MR 41741 : Cope with long responses */
    int  len;

    len = strlen(gets((char *)buff));
    if (len)
    {
        /* CR16486 JMC 2-11-2004: fix array overrun */
        lustrncpy (entry, buff, size);
    }

}

/*
**++
** FUNCTION attrib
**
** DESCRIPTION  :
** Read attribute mapping information
**–
*/
PRIVATE void attrib ()
{
    printf (SW_REF_MSG (M_ASK_USERNAME), sw_ldap_info->username);    /* CR6685 SAC */
    my_gets (sw_ldap_info->username, SW_LDAP_ATTRNAME_SIZE);

    /* CR16174 JMC 30-9-2004: Add new mappings for groupname and rolename */
    printf(SW_REF_MSG(M_ASK_GROUPNAME), sw_ldap_info->groupname);
    my_gets(sw_ldap_info->groupname, SW_LDAP_ATTRNAME_SIZE);

    printf(SW_REF_MSG(M_ASK_ROLENAME), sw_ldap_info->rolename);
    my_gets(sw_ldap_info->rolename, SW_LDAP_ATTRNAME_SIZE);
    /* CR16174 End */

    printf (SW_REF_MSG (M_ASK_DESCRIPTION), sw_ldap_info->description);    /* CR6685 SAC */
    my_gets (sw_ldap_info->description, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_LANGUAGE), sw_ldap_info->language);    /* CR6685 SAC */
    my_gets (sw_ldap_info->language, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_MENUNAME), sw_ldap_info->menuname);    /* CR6685 SAC */
    my_gets (sw_ldap_info->menuname, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_SORTMAIL), sw_ldap_info->sortmail);    /* CR6685 SAC */
    my_gets (sw_ldap_info->sortmail, SW_LDAP_SORTMAIL_SIZE);

    printf (SW_REF_MSG (M_ASK_GROUP), sw_ldap_info->groupusers);    /* CR6685 SAC */
    my_gets (sw_ldap_info->groupusers, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_ROLE), sw_ldap_info->roleuser);    /* CR6685 SAC */
    my_gets (sw_ldap_info->roleuser, SW_LDAP_ATTRNAME_SIZE);

    /* CR9574 Added new mapping for qsupervisors and userflags entry */
    printf (SW_REF_MSG (M_ASK_QSUPERVISORS), sw_ldap_info->qsupervisors);
    my_gets(sw_ldap_info->qsupervisors, SW_LDAP_ATTRNAME_SIZE);

    printf (SW_REF_MSG (M_ASK_USERFLAGS), sw_ldap_info->userflags);
    my_gets(sw_ldap_info->userflags, SW_LDAP_ATTRNAME_SIZE);
    /* CR9574 End */

    extras ();
    SW_LDAP_set_def_mappings (filsh, (X500_TO_SWARE_MAP *) xsmap,
                  sw_ldap_info);

    if (chk_dups ())
        prompt ();
}

/*
**++
**
**–
*/
PRIVATE void prompt ()
{
    printf (SW_REF_MSG (M_ASK_ENTER));    /* CR6738 ZJS */
    getchar ();
}

/*
**++
**
**–
*/
PRIVATE void view (int interactive)
{

    int x;
    int lineno;
    int len;

    UCHR buff[SW_LDAP_PASSWD_SIZE];

    if (interactive)
        printf ("nnnnnn");

    printf ("n");        /* CR6685 SAC */
    printf (SW_REF_MSG (M_DIT),
        sw_ldap_info->whichdit ? "LDAP" : "Staffware");    /* CR6685 SAC */
    printf("n");

    printf (SW_REF_MSG (M_GRPUSERS),
        sw_ldap_info->grpmemldap ? "LDAP DN" : "MEMBER LIST");    /* CR16395 JMC */
    printf ("nn");    /* CR6685 SAC */

    printf (SW_REF_MSG (M_CONNECTION));    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_HOSTNAME), sw_ldap_info->hostname);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_PORTNO), sw_ldap_info->portno);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_CREDENTIALS), sw_ldap_info->credentials);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    memset (&buff, '', sizeof (buff));
    len = lustrlen (sw_ldap_info->password);
    for (x = 0; x < len; x++)
        buff[x] = '*';

    printf (SW_REF_MSG (M_PASSWORD), buff);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf ("n");        /* CR6685 SAC */
    printf (SW_REF_MSG (M_SEARCH));    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_BASE), sw_ldap_info->base);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_FILTER), sw_ldap_info->filter);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_DNPATTERN), sw_ldap_info->dnPattern);    /* MR 38043 LingWu */
    printf ("n");        /* MR 38043 LingWu */

    printf ("n");        /* CR6685 SAC */
    printf (SW_REF_MSG (M_MAPPINGS));    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_USERNAME), sw_ldap_info->username);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    /* CR16174 JMC 30-9-2004: Add view for groupname and rolename */
    printf(SW_REF_MSG(M_GROUPNAME), sw_ldap_info->groupname);
    printf("n");

    printf(SW_REF_MSG(M_ROLENAME), sw_ldap_info->rolename);
    printf("n");
    /* CR16174 End */

    /* CR19771 MEB 14Feb07 Display in same order as input of mappings */
    printf (SW_REF_MSG (M_DESCRIPTION), sw_ldap_info->description);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    /* CR19771 MEB 14Feb07 Display in same order as input of mappings */
    printf (SW_REF_MSG (M_LANGUAGE), sw_ldap_info->language);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_MENUNAME), sw_ldap_info->menuname);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_SORTMAIL), sw_ldap_info->sortmail);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_GROUPUSERS), sw_ldap_info->groupusers);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    printf (SW_REF_MSG (M_ROLEUSER), sw_ldap_info->roleuser);    /* CR6685 SAC */
    printf ("n");        /* CR6685 SAC */

    /* CR9574 Added view of qsupervisors and userflags */
    printf (SW_REF_MSG (M_QSUPERVISORS), sw_ldap_info->qsupervisors);
    printf ("n");

    printf (SW_REF_MSG (M_USERFLAGS), sw_ldap_info->userflags);
    printf ("n");
    /* CR9574 End */

    printf ("nnn");

    if (interactive)
    {
        int y;

        prompt ();
        for (y = 0; y < LINESONSCR; y++)
            printf ("n");
    }

    lineno = 0;
    for (x = 0; x < sw_ldap_info->num_extras; x++)
    {

        printf (SW_REF_MSG (M_EXTRA), x + 1, sw_ldap_info->extra[x]->staffware, sw_ldap_info->extra[x]->x500);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */

        lineno++;
        if (interactive && (lineno > (LINESONSCR – 2)))
        {
            int y;

            prompt ();
            lineno = 0;
            for (y = 0; y < LINESONSCR; y++)
                printf ("n");

        }
    }

    if (interactive && sw_ldap_info->num_extras)
    {
        int y;

        for (y = lineno + 1; y < LINESONSCR; y++)
            printf ("n");
        prompt ();
    }
}

/*
**++
**
**–
*/
PRIVATE int lst_prompt ()
{
    int c;
    printf (SW_REF_MSG (M_ASK_ENTER_X));    /* CR6685 SAC */
    c = getchar ();
    return ((c == 'x') || (c == 'X'));
}

/* CR18665 SAC 18-05-06: added SLIST sort function */
PRIVATE int mysort_strcmpul (LPUCHR lp1, LPUCHR lp2)
{
    return (lustrcmpul (lp1, lp2));
}
/*
 * =============================================================
 * FUNCTION: get_swldap_attr_idx ()
 * =============================================================
 */
/**
 * @brief Returns the index of an attribute in the global attribute map
 *
 * @param iStart    – index to start searching at
 * @param iEnd        – last index to search to + 1
 *
 * @return int        – index for attribute found
 *
 * @retval >= 0        – attribute found, index value
 * @retval < 0        – attribute not found
 *
 * @since added for CR19495, CJED 12-DEC-2006
 *
 */

PRIVATE int get_swldap_attr_idx (int iStart, int iEnd, LPUCHR lpAttrName)
{
    int iRet = -1,
        idx;

    for (idx = iStart; idx < iEnd; idx ++)
    {
        if (!lustrcmpul (xsmap[idx].x500, lpAttrName))
        {
            iRet = idx;
            break;
        }
    }

    return (iRet);
}

/*
 * =============================================================
 * FUNCTION: get_LDAP_users
 * =============================================================
 */
/**
 * @brief creates an SLIST of all users found by LDAP search
 *
 * @param ldmp    results of search
 *
 * @return !NULL    Handle to SLIST
 *
 */
/* CR18665 SAC 18-05-06: added function */
SWMEMHDL get_LDAP_users (SW_LDAP_Message **ldmp)
{
    SW_LDAP_Message    *entry;
    char        *attr, **value;
    SWBOOL        bFound, bIsUser;
    SWINT32        x, num, xsmap_elems = (sizeof xsmap) / (sizeof xsmap[0]);
    SWMEMHDL    hSLIST = NULL;
    USRNODNAME    szUser;

    // initialise SLIST
    if ((hSLIST = slist_init (100, (SLIST_CMPFUNC) mysort_strcmpul, sizeof (USRNODNAME))) == NULL)
    {
        fprintf (stderr, "get_LDAP_users (): failed to create SLIST for users.n");
        return (NULL);
    }

    // get first entry
    entry = SW_LDAP_get_entry (ldap, *ldmp, TRUE);

    while (entry != NULL)
    {
        BerElement *BerElement2GetAttrib = NULL;

        // get first attribute
        attr = SW_LDAP_get_attrib (ldap, entry, TRUE, &BerElement2GetAttrib);

        bFound = FALSE;
        bIsUser = FALSE;

        while ((attr != NULL) || (!bFound && !bIsUser))
        {
            value = SW_LDAP_get_attrib_values(ldap, entry, attr, &num);

            if (value)
            {
                // check to see whether this attribute is the username
                //
                x = get_swldap_attr_idx (0, xsmap_elems, (LPUCHR) attr);
                if (x == LDAP_NAME_POS)
                {
                    // copy the name of this user/group
                    // CJED 19-MAY-2006 – replaced min macro, and coped with strNcpy's foibles
                    // CR18828 SAC 21-06-06: move the '- 1' so that it doesn't reduce the length of the actual value, which truncates the user name
                    lustrncpy (szUser, (LPUCHR) *value, sizeof (szUser) – 1);
       
                    bFound = TRUE;
                }
                else if (x == LDAP_MENUNAME_POS)
                {
/*
** CR19495 – CEJD 12-DEC-2006 – make sure that the menuname has a valid value
*/
                    // check this entry has valid entries for a user
                    if ( ! (lustrcmpul ((LPUCHR) *value, (LPUCHR) "USER") &&
                            lustrcmpul ((LPUCHR) *value, (LPUCHR) "MANAGER") &&
                            lustrcmpul ((LPUCHR) *value, (LPUCHR) "PRODEF") &&
                            lustrcmpul ((LPUCHR) *value, (LPUCHR) "ADMIN")))
                    {
                        bIsUser = TRUE;
                    }
                }

                SW_LDAP_value_free (value);
            }

            // next attribute
            attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
        }

        if (bFound && bIsUser)
        {
            // add to the SLIST
            if (slist_find (hSLIST, (LPUCHR) szUser) < 0)
            {
                slist_add (hSLIST, (LPUCHR) szUser);
            }
        }

        // get next entry
        entry = SW_LDAP_get_entry (ldap, entry, FALSE);
    }

    return (hSLIST);
}

/*
**++
**
**–
** CR19495 – CJED – 12-DEC-2006 – number of entries that we should find are
** now passed in so we can check.
*/
PRIVATE void
write_test (LPUCHR fnam, SW_LDAP_Message ** ldmp, LPUCHR errmsg,
        int interactive, int iNumEntries)
{

    int fd;
    SW_LDAP_Message *entry;
    char *attr, **values;
    int to_file;
    UCHR buff[128];
    int lineno;
    int breakrequest = 0;
    int    i;        /* interator */
    SWINT32    num;        /* number of values */

    lustrcpy (buff, "Y");
    to_file = lustrcmp (fnam, "");

    if (to_file)
    {
        if (fil_fsexists (filsh, (LPFILNAME) fnam))
        {
            if (interactive)
            {    /* CR6742 ZJS */
                sprintf ((char *) msg,
                     SW_REF_MSG (M_OVERWRITE), fnam);    /* CR6685 SAC */
                GetValidCh ((char *) msg, "YN", buff);
            }
            else
            {
                printf (SW_REF_MSG (M_EXISTS), fnam);
                printf ("n");
            }
        }

        if (!lustrcmp (buff, "Y"))
        {
            fd = fil_open (filsh, (LPFILNAME) fnam, FIL_WRITE, 0);
            if (fd < 0)
            {
                printf (SW_REF_MSG (M_E_FILENAME));    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                prompt ();
                return;
            }
        }
        else
            return;
    }

    if (lustrcmp (errmsg, ""))
    {
        if (to_file)
        {
            fil_puts (fd, errmsg);
            fil_close (fd);
            return;
        }
        else
            printf ("%sn", errmsg);    /* CR6700  ZJS */
    }

    lineno = 0;
    entry = SW_LDAP_get_entry (ldap, *ldmp, TRUE);

    while ((entry != NULL) && (!breakrequest))
    {
        /* CR17052 RMG 21/06/05 */
        BerElement *BerElement2GetAttrib = NULL;

        /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
        attr = SW_LDAP_get_attrib (ldap, entry, TRUE, &BerElement2GetAttrib);

        while (attr != NULL)
        {
            /* CR16346 JMC 30-9-2004: Enable multi-valued returns */
            /* initialise to zero */
            num = 0;

            values = SW_LDAP_get_attrib_values(ldap, entry, attr, &num);
            sprintf ((char *) buff, "%20st", attr);    /* CR8892 – ZJS 08/03/2000 – do not concatenate value to buff if oversize, will core dump */

            /* CR16346 JMC 30-9-2004: Enable multi-valued returns */
            for (i = 0; i < num; i++)
            {
                /* check whether to write to file */
                if (to_file)
                {
                    /* write to file */
                    fil_putb (fd, buff, lustrlen (buff));
                    fil_puts (fd, (LPUCHR)values[i]);    /* CR8892 */
                }
                else
                {
                    /* print attribute and value */
                    printf ("%s%sn", buff, values[i]);    /* CR8892 */
                    lineno++;

                    /* check for lines on screen */
                    if ((!to_file) && (lineno > (LINESONSCR – 2)))
                    {
                        /* check for exit response */
                        breakrequest = lst_prompt ();

                        /* check if true */
                        if (breakrequest)
                        {
                            break;
                        }

                        lineno = 0;
                    }
                }
            }

            SW_LDAP_value_free (values);

            if (breakrequest)
            {
                break;
            }

            /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
            attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
        }
        if (breakrequest)
        {
            break;
        }

        if (to_file)
        {
            fil_puts (fd, (LPUCHR) "");
        }
        else
        {
            printf ("n");
            lineno++;
        }
        entry = SW_LDAP_get_entry (ldap, entry, FALSE);
    }

    fil_close (fd);
}
/*
 * =============================================================
 * FUNCTION: output_scrfil_line ()
 * =============================================================
 */
/**
 * @brief Outputs a line of text to either a FIL file or the screen
 *
 * @param iFilHdl    FIL file handle or -1 for screen
 * @param lpTextBuff    Pointer to text
 *
 * @since Added for CR19761 by CJED 12-FEB-2007
 *
 */

PRIVATE void    output_scrfil_line (int iFilHdl, LPUCHR lpTextBuff)
{
    if (iFilHdl >= 0)
    {
        fil_puts (iFilHdl, lpTextBuff);
    }
    else
    {
        printf ("%sn", lpTextBuff);
    }
}

/*
 * ==================================================================
 *  FUNCTION:    ldap_check_all_members_valid
 *          This function will check the string of group user
 *          members and ensure that they are all valid users.
 *          Any invalid users will be flagged and not added to
 *          list of users.
 *          Function added for CR17344
**
** CR19761 – CJED 12-FEB-2007 – output warnings/errors to file as well
**
 * ==================================================================
*/
/* CR18665 SAC 18-05-06: added user SLIST handle */
void ldap_check_all_members_valid (SWMEMHDL hUserSLIST, char *userval, int iFilHdl)
{
    LPUCHR        lpstart, lpend;
    char        tmp_buf[512] = "";
    USERNAME    temp;
    USER_SH        user_sh;
    USERID        uid;
    char        checkedusers[LDAP_MAX_ATTR_LEN + 1];
    SWBOOL        first = TRUE;

    /* Obtain a user session */
    user_sh = user_init (filsh, &my_node, USER_UPDATE | USER_EDIT);
    if (user_sh <= 0)
    {
        output_scrfil_line (iFilHdl,
                (LPUCHR) "User_init failed so NO group user member validation");
        return;
    }

    /* Clear array to hold valid user list */
    sw_mem_set (checkedusers, '', sizeof (checkedusers));

    /* Ponter to start of user values to be checked */
    lpstart = (LPUCHR) userval;

    /* Loop through user values string */
    while (lpstart && *lpstart)
    {
        /* Find end of this record. */
        lpend = lustrchr (lpstart, ',');
        if (lpend)
        {
            /* If we have a record, add it to list */
            if (*lpstart)
            {
                /* make a temporary copy and chop the record up */
                sw_mem_set (tmp_buf, '', sizeof (tmp_buf));
                lustrncpy ((LPUCHR) tmp_buf, lpstart, lpend – lpstart);
            }
            lpend++;    /* Start of next record. */
        }
        else
        {
            /* Last user in list */
            if (*lpstart)
            {
                /* make a temporary copy and take rest of the record */
                sw_mem_set (tmp_buf, '', sizeof (tmp_buf));
                lustrncpy ((LPUCHR) tmp_buf, lpstart, sizeof (tmp_buf));
            }
        }

        /*
         * CR18964 SAC 14-07-06: strip out spaces before we re-check the buffer
         */
        if (tmp_buf)
        {
            /* Strip out any leading or trailing spaces as otherwise
             * user will not be found
             */
            my_cvt ((LPUCHR) tmp_buf, 1);
        }

        /* If user value found and have a valid user session */
        /* CR18964 SAC 14-07-06: check length of buffer */
        if (tmp_buf && (lustrlen (tmp_buf) > 0) && (user_sh > 0))
        {
            /*
             * CR18665 SAC 18-05-06: first we check whether the user exists in the given
             * SLIST, which was generated from the LDAP results.  If so, then the user
             * will be added as part of a MOVESYSINFO.  We have built up the SLIST so that
             * if users are referenced in group membership before they appear as users
             * an error won't be generated.
             */
            if ((uid = slist_find (hUserSLIST, (LPUCHR) tmp_buf)) < 0)
            {
                // user doesn't exist in LDAP, check iPE users

                /* Try and find user */
                uid = user_find_user (user_sh, (LPUSERNAME)tmp_buf, (LPUSERNAME)temp);
            }
/*
** check uid, although slist_find returns values in the range 0 – n, and
** user_find_user returns 1 – n, we'll allow 0 as a valid return.
*/
            if (uid >= 0)
            {
                /* match */
                if (first)
                {
                    /* Copy first user to list of valid users */
                    lustrcpy (checkedusers, tmp_buf);
                    first = FALSE;
                }
                else
                {
                    /* Copy next user to list of valid users with a
                    * comma separator
                    */
                    lustrcat ((LPUCHR) checkedusers, (LPUCHR) ", ");
                    lustrcat ((LPUCHR) checkedusers, (LPUCHR) tmp_buf);
                }
            }
            else
            {
                char    tmpBuff [512];
                /* no match */
                sprintf (tmpBuff, "Group contains INVALID user [%s]", tmp_buf);
                output_scrfil_line (iFilHdl, (LPUCHR) tmpBuff);
            }
        }

        /* Point at start of next record. */
        lpstart = lpend;

    }

    /* If valid users list setup that copy over original unchecked list */
    if (checkedusers != '')
    {
        lustrcpy (userval, checkedusers);
    }

    user_term (user_sh); // CR19716 SAC 01-02-07

} /* end ldap_check_all_members_valid */

/*
**++
**
**–
** CR19495 – CJED 12-DEC-2006 – check we get the same number of entries that
** we've been told are available.
*/
PRIVATE void write_map (LPUCHR fnam, SW_LDAP_Message ** ldmp, int iNumEntries)
{

    int fd;
    SW_LDAP_Message *entry;
    char *attr, **value;
    char    *grpusrsval;
    int    grpusrsval_size;
    int to_file;
    UCHR buff[512];
    int lineno;
    int ctr;

    SWARE_MAP_VALS **mapx;
    int xsmap_elems;
    int mapx_elems;

    int x,
        iEntriesRead;
    int breakrequest = 0;
    SWINT32    num;        /* number of values */
    int    i;        /* iterator */
    int    strsize;    /* string size */
    SWBOOL    usermatch;    /* CR16571 JMC 20-12-2004: usermatch boolean */

    // CR19716 SAC 01-02-07: array to hold group membership attribute values
    LPUCHR    szMembership = NULL, pMembership;
    int    nAllocMembership = 0, nNumMembership = 0, nLenMembership = 0;

    /*
     * CR17995 SAC 26-01-06: allocate an initial buffer
     */
    grpusrsval_size = 1024;
    if ((grpusrsval = (char *) sw_calloc (1, grpusrsval_size * sizeof (char))) == NULL)
    {
        fprintf (stderr, "write_map (): Failed to allocate memory for buffern");
        return;
    }

    /* from here to */
    lustrcpy (buff, "Y");
    to_file = lustrcmp (fnam, "");
/*
** CR19761 – CJED 12-FEB-2007 – we will now use 'fd' as a flag to indicate
** if output is going to screen (value < 0) or to file (value >= 0).
*/
    fd = -1;    /* assume screen output */
    if (to_file)
    {
        if (fil_fsexists (filsh, (LPFILNAME) fnam))
        {        /* is this a naughty conversion? */
            sprintf ((char *) msg, SW_REF_MSG (M_OVERWRITE), fnam);    /* CR6685 SAC */
            GetValidCh ((char *) msg, "YN", buff);
        }

        if (!lustrcmp (buff, "Y"))
        {
            fd = fil_open (filsh, (LPFILNAME) fnam, FIL_WRITE, 0);
            if (fd < 0)
            {
                printf (SW_REF_MSG (M_E_FILENAME));    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                prompt ();
                sw_free (grpusrsval); /* CR17995 SAC 26-01-06 */
                return;
            }
        }
        else
        {
            sw_free (grpusrsval); /* CR17995 SAC 26-01-06 */
            return;
        }
    }

    xsmap_elems = (sizeof xsmap) / (sizeof xsmap[0]);
    mapx_elems = xsmap_elems + sw_ldap_info->num_extras;

    mapx = (SWARE_MAP_VALS **) malloc (sizeof (SWARE_MAP_VALS *) * (mapx_elems));

    for (ctr = 0; ctr < xsmap_elems; ctr++)
    {
        mapx[ctr] = (SWARE_MAP_VALS *) malloc (sizeof (SWARE_MAP_VALS));
        lustrncpy (mapx[ctr]->staffware, xsmap[ctr].staffware, SW_LDAP_ATTRNAME_SIZE);
    }

    for (ctr = xsmap_elems, x = 0; ctr < mapx_elems; ctr++, x++)
    {
        mapx[ctr] = (SWARE_MAP_VALS *) malloc (sizeof (SWARE_MAP_VALS));
        lustrncpy (mapx[ctr]->staffware, sw_ldap_info->extra[x]->staffware, SW_LDAP_ATTRNAME_SIZE);
    }
    /*
     * CR18665 SAC 18-05-06: generate an SLIST of the users that have
     * been found by the search.
     */
    SWMEMHDL hUserSLIST = get_LDAP_users (ldmp);

    lineno = 0;
    iEntriesRead = 0;
    entry = SW_LDAP_get_entry (ldap, *ldmp, TRUE);

    while ((entry != NULL) && (!breakrequest))
    {
        int is_iPE_entity = FALSE;
        SWBOOL    bIs_iPE_group = FALSE;
        int x;

        nLenMembership = 0; // CR19716 SAC 01-02-07

        iEntriesRead ++;
        /* CR17052 RMG 21/06/05 */
        BerElement *BerElement2GetAttrib = NULL;

        for (x = 0; x < mapx_elems; x++)
        {
            memset (mapx[x]->value, '', sizeof(mapx[x]->value));
        }

        /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
        attr = SW_LDAP_get_attrib (ldap, entry, TRUE, &BerElement2GetAttrib);

        while (attr != NULL)
        {
            /* CR16346 JMC 30-9-2004: Enable multi-valued returns */
            /* initialise to zero */
            num = 0;

            value = SW_LDAP_get_attrib_values(ldap, entry, attr, &num);

            /* CR16845 JMC 20-01-2005: Fix for NULL value pointer returned */
            if (value == NULL)
            {
                /*
                 * NULL pointer returned due to value of attribute not being
                 * defined on LDAP Server. Get next attribute and continue.
                 */
                /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
                attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
                continue;
            }
            /* End CR16845 */

            x = get_swldap_attr_idx (0, xsmap_elems, (LPUCHR) attr);
            if (x >= 0)
            {
/*
** CR19493 – CJED 06-DEC-2006 – Always keep track of the mapped values
** NOTE: this used to truncate to ATTRVALSIZE (24) characters, but the
** value buffer is MAX_LONG_ATTR_VAL (255) charcters in size so we'll use.
*/
                lustrncpy (mapx[x]->value, (LPUCHR) * value,
                           MAX_LONG_ATTR_VAL);

                // CR19716 SAC 01-02-07: for a group attribute we need to store the values
                // so we can use them once we have been through all the attributes for this
                // entry.  This is because the membership attribute may come before the one
                // that indicates this is a group and the members aren't validated.
                //
                // The values are stored in the buffer seperated by a NULL character.
                //
                if (x == LDAP_GROUPUSERS_POS)
                {
                    nNumMembership = num;
                    pMembership = szMembership;
                    for (i = 0; i < num; i++)
                    {
                        int    len = lustrlen (value[i]);

                        // do we need to allocate/reallocate the array
                        if (nAllocMembership <= 0)
                        {
                            nAllocMembership = (len * 4); // extend buffer, allowing some room
                            szMembership = (LPUCHR) sw_malloc (nAllocMembership * sizeof (LPUCHR));

                            // start at the beginning
                            pMembership = szMembership;
                        }
                        else if (nLenMembership + len >= nAllocMembership)
                        {
                            nAllocMembership += (len * 4); // extend buffer, allowing some room
                            szMembership = (LPUCHR) sw_realloc (szMembership, nAllocMembership * sizeof (LPUCHR));

                            // make sure we are pointing just after the last entry
                            pMembership = szMembership + nLenMembership;
                        }

                        if (!szMembership)
                        {
                            fprintf (stderr, "write_map (): Failed to (re)allocate memory for group membership valuesn");
                            slist_term (hUserSLIST); // CR19716 SAC 01-02-07
                            return;
                        }

                        lustrncpy ((LPUCHR) pMembership, (LPUCHR) value[i], lustrlen (value[i]));

                        // move pointer passed value we have just added
                        pMembership += (len + 1);

                        // increase the length of the value
                        nLenMembership += (len + 1);
                    }
                }

                if (x == LDAP_MENUNAME_POS)
                {
/*
** CR18401 – CJED 06-DEC-2006 – correctly recognise any iPE entities
** This includes GROUP and ROLE entities.
*/
                    if (! (lustrcmpul ((LPUCHR) *value, (LPUCHR) "USER") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "MANAGER") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "PRODEF") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "ADMIN") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "GROUP") &&
                        lustrcmpul ((LPUCHR) *value, (LPUCHR) "ROLE")))
                    {
                        is_iPE_entity = TRUE;
                        if (! lustrcmpul ((LPUCHR) *value, (LPUCHR) "GROUP"))
                        {
                            bIs_iPE_group = TRUE;
                        }
                    }
                }
                // CR19716 SAC 01-02-07: moved group membership check after attribute while() loop
            }
            else    /* search the extras */
            {
                for (x = xsmap_elems; x < mapx_elems; x++)
                {
                    if (!lustrncmpul (sw_ldap_info->extra[x – NUM_SW_ELEMENTS]->x500, (LPUCHR) attr, lustrlen (sw_ldap_info->extra[x – NUM_SW_ELEMENTS]->x500)))
                        break;
                }
                if (x < mapx_elems)    /* found */
                {
                    lustrncpy (mapx[x]->value, (LPUCHR) * value, sizeof (mapx[x]->value) – 1);    /* CR11968 SAC 15-07-02 – CR6904 SAC */
                }
            }

            SW_LDAP_value_free (value);

            /* CR17052 RMG 21/06/05: New parameter for SW_LDAP_get_attrib */
            attr = SW_LDAP_get_attrib (ldap, entry, FALSE, &BerElement2GetAttrib);
        }

        // CR19716 SAC 01-02-07: moved code after attribute while() loop
        if (bIs_iPE_group && (nNumMembership > 0))
        {
/*
** OK, we're looking for multiple values for this attribute … so loop
** round and concatenate them ? The count of values is in the "num" variable
** returned by the call to SW_LDAP_get_attrib_values()
*/
            /* CR16395 JMC 15-10-2004: LDAP DN format enhancement */
            /* initialise i */
            i = 0;
            pMembership = szMembership; // CR19716 SAC 01-02-07: go through members
            while (i < nNumMembership)
            {

                /* CR16847 JMC 20-01-2005: initialise userval */
                *grpusrsval = '';

                /*
                * CR17995 SAC 26-01-06: check whether the allocated buffer is large
                * enough to hold the full value
                */
                if ((int) lustrlen (pMembership) >= grpusrsval_size)
                {
                    /* resize the buffer */
                    grpusrsval_size = lustrlen (pMembership) + 1024;
                    if ((grpusrsval = (char *) sw_realloc (grpusrsval, grpusrsval_size * sizeof (char))) == NULL)
                    {
                        fprintf (stderr, "write_map (): Failed to re-allocate memory for buffern");

                        // CR19716 SAC 01-02-07
                        slist_term (hUserSLIST);
                        sw_free (szMembership);
                        return;
                    }
                }

                /* CR16751 JMC 20-12-2004: GroupUsers fix */
                /* check for LDAPDN group member format */
                if (sw_ldap_info->grpmemldap == TRUE)
                {
                    /* check if ldap attribute matches that used for username */
                    /* CR17995 SAC 26-01-06: pass in the buffer size */
                    usermatch = ldap_user_match(sw_ldap_info, (char *) pMembership, xsmap, grpusrsval, grpusrsval_size);
                }
                else
                {
                    /* set usermatch to FALSE */
                    usermatch = FALSE;
                }

                /* get User that is a member of a Group */
                if (usermatch == FALSE)
                {
                    /* get User that is a member of a Group */
                    /* CR17995 SAC 26-01-06: pass in the buffer size */
                    (void)SW_LDAP_get_user_member(ldap, sw_ldap_info, (char *) pMembership, xsmap,
                                grpusrsval, grpusrsval_size);
                }
                /* End CR16571 */
                /* check for valid grpusrsval */
                if (*grpusrsval != '')
                {
                    /* CR17344 Check for multiple users in one value */
                    /* CR18665 SAC 18-05-06: pass in user SLIST */
/*
** CR19761 – CJED 12-FEB-2007 – pass down the screen/file flag
*/
                    ldap_check_all_members_valid (hUserSLIST, grpusrsval, fd);

                    if (i == 0)
                    {
                        lustrncpy(mapx[LDAP_GROUPUSERS_POS]->value, (LPUCHR)grpusrsval, MAX_LONG_ATTR_VAL);
                    }
                    else
                    {
                        LPUCHR    lpTmp;
                        strsize = lustrlen (mapx[LDAP_GROUPUSERS_POS]->value);
                        lpTmp = mapx[LDAP_GROUPUSERS_POS]->value + strsize;

                        if ((strsize + 2) < MAX_LONG_ATTR_VAL)
                        {
                            if (strsize > 0)
                            {
                                * lpTmp ++ = ',';
                                strsize ++;
                            }

                            lustrncpy (lpTmp, (LPUCHR)grpusrsval, MAX_LONG_ATTR_VAL – strsize);

                            if ((int) lustrlen ((LPUCHR)grpusrsval) > (MAX_LONG_ATTR_VAL – strsize))
                            {
                                printf ("attribute Name="%s" Value="%s" had been truncated as maximum length is %dn",
                                      attr, mapx[LDAP_GROUPUSERS_POS]->value, MAX_LONG_ATTR_VAL);
                            }
                        }
                    }
                }

                /* increment i */
                i++;

                // CR19716 SAC 01-02-07: move to next member
                pMembership += (lustrlen (pMembership) + 1);
            }
        }

/*
** If this is an iPE entity (user, group or role) then dump the info about it
*/
        if (is_iPE_entity)
        {
            for (x = 0; x < mapx_elems; x++)
            {
                sprintf ((char *) buff, "%20st%s", mapx[x]->staffware, mapx[x]->value);

                if (to_file)
                {
                    fil_puts (fd, buff);
                }
                else
                {
                    printf ("%sn", buff);
                    lineno++;
                    if ((!to_file) && (lineno > (LINESONSCR – 2)))
                    {
                        if (breakrequest = lst_prompt ())    /* should be = not == */
                        {
                            break;
                        }
                        lineno = 0;
                    }
                }

            }

            if (breakrequest)
            {
                break;
            }

            if (to_file)
            {
                fil_puts (fd, (LPUCHR) "");
            }
            else
            {
                printf ("n");
                lineno++;
            }
        }
        entry = SW_LDAP_get_entry (ldap, entry, FALSE);
    }

    printf ("nNumber of entries expected = %d, number read = %dn", iNumEntries, iEntriesRead);

    fil_close (fd);

    slist_term (hUserSLIST); /* CR18665 SAC 18-05-06 */

    for (ctr = 0; ctr < mapx_elems; ctr++)
    {
        free (mapx[ctr]);
    }

    free (mapx);
    mapx = NULL;

    sw_free (grpusrsval); /* CR17995 SAC 26-01-06 */
    sw_free (szMembership); // CR19716 SAC 01-02-07
}

/*
**++
**
**–
*/
PRIVATE void
test (int interactive, LPUCHR filename_b, int download_b, int map_b)
{
    SWINT32 ret;
    SW_LDAP_Message *ldmp = NULL;
    UCHR buff[80];
    UCHR dwnload[80];
    UCHR old_search[SW_LDAP_FILTER_SIZE + 1];    /* CR7869 SAC 22-12-98 */
    UCHR filename_i[80];
    int map_i;

    lustrcpy (filename_i, "");

    if (interactive)
    {
        printf ("n");    /* CR6685 SAC */
        printf (SW_REF_MSG (M_CONN_TESTING));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
    }

    ldap = SW_LDAP_connect (sw_ldap_info, ldap, &ret);
    if (ret != SW_LDAP_SUCCESS)
    {
        char msg[100];

        sprintf (msg, SW_REF_MSG (M_CONNECT_FAIL),
             ldap_msg_to_text (ret, buff), ret);    /* CR6738  ZJS */
        strcat (msg, "n");
        if (interactive)
        {
            printf ("%s", msg);
            prompt ();
        }
        else
            write_test (filename_b, &ldmp, (LPUCHR) msg,
                    interactive, 0);
        return;

    }

    /* CR7869 SAC 22-12-98 : store current search string */
    sw_mem_set (old_search, '', sizeof (old_search));
    lustrcpy (old_search, sw_ldap_info->filter);

    /*
     * CR10765 SAC 15-11-01: alter search filter to the same as the BG
     */
    if (SW_LDAP_filter_BG (sw_ldap_info) != SW_SUCCESS)
    {
        printf ("Failed to alter filter to match BGn");
    }

    lustrcpy (dwnload, "N");
    if (interactive)
    {
        printf (SW_REF_MSG (M_CONN_SUCCESS));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        GetValidCh (SW_REF_MSG (M_DOWNLOAD_USER), "YN", dwnload);    /* CR6685 SAC */

        if (!lustrcmp (dwnload, "Y"))
        {
            int num_entries;

            /* CR14734 JMC 15-1-04: Add Referral code */
            ret = 0;    /* initialise return code form ldap libraries */

            num_entries =
                SW_LDAP_search (sw_ldap_info, ldap, &ldmp, &ret);

            if (ret == SW_LDAP_ERR_SEARCH)
            {
                printf (SW_REF_MSG (M_ENTRIES_NONE));    /* CR6685 SAC */
                prompt ();
                SW_LDAP_disconnect (ldap, ldmp);

                /* CR7869 SAC 22-12-98 : revert to original search string */
                lustrcpy (sw_ldap_info->filter, old_search);
                return;
            }

            /* CR14734 JMC 15-1-04: Add referral code */
            /* Check on PARTIAL RESULT for referrals */
            if (ret == SW_LDAP_PARTIAL_RESULTS)
            {
                /* print warning message */
                printf(SW_REF_MSG(M_PARTIAL_FOUND));
                printf("n");
            }
            if (ret == SW_LDAP_SUCCESS)
            {
                printf("Got Full Results..n");
            }

            printf (SW_REF_MSG (M_ENTRIES_FOUND), num_entries);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */

            GetValidCh (SW_REF_MSG (M_MAPPING), "SL", buff);    /* CR6685 SAC */
            map_i = !lustrcmp (buff, "S");

            GetValidCh (SW_REF_MSG (M_FILE_SCREEN), "FS", buff);    /* CR6685 SAC */

            if (!lustrcmp (buff, "F"))
            {
                printf (SW_REF_MSG (M_ASK_INFO_FILE));    /* CR6685 SAC */
                gets ((char *) filename_i);
            }
/*
** CR19495 – CJED 12-DEC-2006 – pass the number of entries returned by the
** search. This allows the lower level to determine if an error has occurred
** while it's getting entries.
*/
            if (map_i)
                write_map (filename_i, &ldmp, num_entries);
            else
                write_test (filename_i, &ldmp, (LPUCHR) "",
                        interactive, num_entries);

        }
    }
    else
    {
        if (lustrcmp (filename_b, "")
            && fil_fsexists (filsh, (LPFILNAME) filename_b))
        {        /* filename was specified and it exists */
            printf (SW_REF_MSG (M_EXISTS), filename_b);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            my_exit (3);
        }

        if (download_b)
        {
            /* CR14734 JMC 15-1-04: Add Referral code */
            ret = 0; /* Initialise return code from LDAP libraries */
            num_entries = SW_LDAP_search (sw_ldap_info, ldap, &ldmp, &ret);
            if (num_entries > 0)
            {
                if (map_b)
                    write_map (filename_b, &ldmp, num_entries);
                else
                    write_test (filename_b, &ldmp,
                            (LPUCHR) "", interactive, num_entries);    /* passthrough */
            }
            else
            {
                write_test (filename_b, &ldmp,
                        (LPUCHR)
                        SW_REF_MSG (M_ENTRIES_NONE), interactive, 0);    /* CR6685 SAC */

            }
        }
        else
        {
            write_test (filename_b, &ldmp,
                    (LPUCHR) SW_REF_MSG (M_CONN_SUCCESS), interactive, 0);    /* CR6685 SAC */
        }

    }
    SW_LDAP_disconnect (ldap, ldmp);

    /* CR7869 SAC 22-12-98 : revert to original search string */
    lustrcpy (sw_ldap_info->filter, old_search);

    if ((interactive) && lustrcmp (dwnload, "N")
        && !lustrcmp (filename_i, ""))
    {
        prompt ();
    }
}

/*
**++
**
**–
*/
PRIVATE int ldapcmp ()
{
    int    ret = 0,
        x;
/*
** CJED 15-DEC-2006 – do the comparison a member at a time, it's not
** sensible to memcmp the entire structure …
*/
    ret |= lustrcmp (sw_ldap_info->hostname, sw_ldap_info_copy->hostname);
    ret |= lustrcmp (sw_ldap_info->credentials, sw_ldap_info_copy->credentials);
    ret |= lustrcmp (sw_ldap_info->password, sw_ldap_info_copy->password);
    ret |= lustrcmp (sw_ldap_info->base, sw_ldap_info_copy->base);
    ret |= lustrcmp (sw_ldap_info->filter, sw_ldap_info_copy->filter);
    ret |= lustrcmp (sw_ldap_info->dnPattern, sw_ldap_info_copy->dnPattern);
    ret |= lustrcmp (sw_ldap_info->username, sw_ldap_info_copy->username);
    ret |= lustrcmp (sw_ldap_info->menuname, sw_ldap_info_copy->menuname);
    ret |= lustrcmp (sw_ldap_info->language, sw_ldap_info_copy->language);
    ret |= lustrcmp (sw_ldap_info->description, sw_ldap_info_copy->description);
    ret |= lustrcmp (sw_ldap_info->sortmail, sw_ldap_info_copy->sortmail);
    ret |= lustrcmp (sw_ldap_info->groupusers, sw_ldap_info_copy->groupusers);
    ret |= lustrcmp (sw_ldap_info->roleuser, sw_ldap_info_copy->roleuser);
    ret |= lustrcmp (sw_ldap_info->lastsync, sw_ldap_info_copy->lastsync);
    ret |= lustrcmp (sw_ldap_info->locallastsync, sw_ldap_info_copy->locallastsync);
    ret |= lustrcmp (sw_ldap_info->qsupervisors, sw_ldap_info_copy->qsupervisors);
    ret |= lustrcmp (sw_ldap_info->userflags, sw_ldap_info_copy->userflags);
    ret |= lustrcmp (sw_ldap_info->groupname, sw_ldap_info_copy->groupname);
    ret |= lustrcmp (sw_ldap_info->rolename, sw_ldap_info_copy->rolename);
    ret |= lustrcmp (sw_ldap_info->certpath, sw_ldap_info_copy->certpath);

    ret |= (sw_ldap_info->bXlateUTF8 != sw_ldap_info_copy->bXlateUTF8);
    ret |= (sw_ldap_info->enableSSL != sw_ldap_info_copy->enableSSL);
    ret |= (sw_ldap_info->isAD != sw_ldap_info_copy->isAD);
    ret |= (sw_ldap_info->grpmemldap != sw_ldap_info_copy->grpmemldap);
    ret |= (sw_ldap_info->whichdit != sw_ldap_info_copy->whichdit);
    ret |= (sw_ldap_info->portno != sw_ldap_info_copy->portno);
    //Fix MR 31729/SR 1-8FH0GZ LDAPCONF utiltity crashing when additin additional LDAP attributes
    ret |= (sw_ldap_info->num_extras != sw_ldap_info_copy->num_extras);
    ret |= (sw_ldap_info->num_allocated_extras != sw_ldap_info_copy->num_allocated_extras);

    for (x = 0; (! ret) && (x < sw_ldap_info->num_extras); x++)
    {
        ret |= lustrcmp (sw_ldap_info_copy->extra[x]->staffware, sw_ldap_info->extra[x]->staffware);
        ret |= lustrcmp (sw_ldap_info_copy->extra[x]->x500, sw_ldap_info->extra[x]->x500);
    }

    return ret;
}

/*
**++
**
**–
*/
PRIVATE void ldapcpy ()
{
    int x;

    if (sw_ldap_info_copy != NULL)
        free (sw_ldap_info_copy);

    /* CR17822 Cast to correct type */
    sw_ldap_info_copy = (SW_LDAP_info *)malloc (sizeof (SW_LDAP_info));
/*
** CJED 15-DEC-2006 – the only thing in the Info structure that we don't
** want to copy is the array of extras pointers and control info at the
** end of the structure – so calcluate the size of the rest of the structure
** and copy that, then handle the extras stuff.
*/
    x = ((char *) & sw_ldap_info->num_extras) – (char *) sw_ldap_info;
    memcpy (sw_ldap_info_copy, sw_ldap_info, x);

    sw_ldap_info_copy->num_extras = 0;
    sw_ldap_info_copy->num_allocated_extras = 0;
    sw_ldap_info_copy->extra = NULL;

    for (x = 0; x < sw_ldap_info->num_extras; x++)
        SW_LDAP_extra_add (sw_ldap_info_copy, sw_ldap_info->extra[x]->staffware, sw_ldap_info->extra[x]->x500);
}

/*
**++
**
**–
*/
PRIVATE int writeinfo (int interactive)
{
    int changed;
    UCHR buff[80];
    int retcode;
    lustrcpy (buff, "");

    /* changed = memcmp(sw_ldap_info_copy, sw_ldap_info, sizeof(SW_LDAP_info)); */
    changed = ldapcmp ();    /* params in def'n even though global? */
    if (!changed)
        return M_NO_DATA_CHANGED;

    if (interactive && changed)
    {
        GetValidCh (SW_REF_MSG (M_ASK_SAVE), "YN", buff);    /* CR6685 SAC */
    }

    if (changed && ((!interactive) || (!lustrcmp (buff, "Y"))))
    {            /* if changed and (batch) or (changed interactively) */
        if ((retcode = SW_LDAP_set_info (filsh, sw_ldap_info, FALSE))
            != SW_SUCCESS)
        {
            char msg[100];
            UCHR buff[100];
            sprintf (msg, SW_REF_MSG (M_SETINFO_FAIL),
                 ldap_msg_to_text (retcode, buff), retcode);    /* CR6738  ZJS */
            strcat (msg, "n");
            printf ("%s", msg);
/* fil_term (filsh); *//* fil term!!! */
            return M_E_DATA_WRITE;
        }
        return M_DATA_SAVED;
    }
    return 3;

}

/*
**++
**
**–
*/
PRIVATE void save (void)
{
    int w = writeinfo (TRUE);
    if (w == M_NO_DATA_CHANGED)
    {
        printf (SW_REF_MSG (M_NO_DATA_CHANGED));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
    }
    else if (w == M_E_DATA_WRITE)
    {
        printf (SW_REF_MSG (M_E_DATA_WRITE));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
    }
    else if (w == M_DATA_SAVED)
    {
        printf (SW_REF_MSG (M_DATA_SAVED));    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        ldapcpy ();    /* memcpy(sw_ldap_info_copy, sw_ldap_info, sizeof(SW_LDAP_info)); */
    }

    prompt ();
}

/*
**++
**
**–
*/
PRIVATE int menu (void)
{
    int x;
    UCHR buff[80];
    char build_year[5]="";
    SWBOOL    bCheckChanged = FALSE;

    /* CR19048 Remove unused variable */
    get_build_year((LPUCHR)build_year);

    while (TRUE)
    {
        for (x = 0; x < LINESONSCR; x++)
            printf ("n");
        /* CR16673 NPH Removed version number (which was wrong!) and changed copyright years to new system */
        /* CR16785 NPH Modified copyright notice to match spec */
        /* CR16948 NPH Modified copyright again */
        printf
            ("====================================================================n");
        /* CR16829 NJP 13Jan05 Insert TIBCO into product name */
        printf
            ("    TIBCO iProcess LDAP Connection Administration Utilityn");
        printf
            ("        Copyright (c) %s-%s, TIBCO Software Inc.n",SWVERS_COPYRIGHT_START_IPE,build_year);
        printf
            ("====================================================================n");
        printf ("nn  [1]       %s", SW_REF_MSG (M_M_CONN_INFO));    /* CR6685 SAC */
        printf ("n  [2]       %s", SW_REF_MSG (M_M_SEARCH_INFO));    /* CR6685 SAC */
        printf ("n  [3]       %s", SW_REF_MSG (M_M_ATTRIB_MAP));    /* CR6685 SAC */

        sprintf ((char *) msg, SW_REF_MSG (M_M_GRPMEM_LDAP),
             sw_ldap_info->grpmemldap ? "LDAP DN" : "MEMBER LIST");    /* CR16395 JMC */
        printf ("n  [4]       %s", msg);                /* CR16395 JMC */

        printf ("n  [5]       %s", SW_REF_MSG (M_M_VIEW_INFO));    /* CR6685 SAC */
        printf ("n  [6]       %s", SW_REF_MSG (M_M_CONN_TEST));    /* CR6685 SAC */

        sprintf ((char *) msg, SW_REF_MSG (M_M_RETURN_DIT),
             sw_ldap_info->whichdit ? "iProcess Engine" : "LDAP");    /* CR16509 JMC */
        printf ("n  [7]       %s", msg);    /* CR6685 SAC */
        printf ("n  [8]       %s", SW_REF_MSG (M_M_SAVE));    /* CR6685 SAC */
        printf ("n  [9]       %s", SW_REF_MSG (M_M_SYNCHRONISE));    /* CR6685 SAC */
/*
** CR19009 – CJED 21-JUL-2006 – attribute translation option added
*/
        printf ("n  [10]      %s", SW_REF_MSG (sw_ldap_info->bXlateUTF8 ?
                        M_M_DISABLE_AV_TRANS : M_M_ENABLE_AV_TRANS));
        printf ("n  [11]      %s", SW_REF_MSG (M_M_QUIT));    /* CR6685 SAC */

        printf ("nn  %s", SW_REF_MSG (M_M_ENTER_OPTION));    /* CR6685 SAC */

        gets ((char *) buff);
        if (!lustrcmp (buff, "1"))
        {
            connection ();
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "2"))
        {
            search ();
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "3"))
        {
            attrib ();
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp(buff, "4"))
        {
            /* toggle LDAP DN/MEMBER LIST */
            sw_ldap_info->grpmemldap = !sw_ldap_info->grpmemldap;
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "5"))
        {
            view (1);
        }
        else if (!lustrcmp (buff, "6"))
        {
            test (TRUE, (LPUCHR) "", 0, FALSE);
        }
        else if (!lustrcmp (buff, "7"))
        {
            sw_ldap_info->whichdit = !sw_ldap_info->whichdit;
            bCheckChanged = TRUE;
        }
        else if (!lustrcmp (buff, "8"))
        {
            save ();
            bCheckChanged = FALSE;
        }
        else if (!lustrcmp (buff, "9"))
        {
            if (ldapcmp ())
            {
                printf (SW_REF_MSG (M_PLEASE_SAVE));    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */

                prompt ();
            }
            else
                ldap_movesysinfo ((LPUCHR) "");
        }
        else if (!lustrcmp (buff, "10"))
        {
            sw_ldap_info->bXlateUTF8 = ! sw_ldap_info->bXlateUTF8;
            bCheckChanged = TRUE;

        }
        else if (!lustrcmp (buff, "11"))
               {
            break;
        }
        else
        {
            printf (SW_REF_MSG (M_E_INVALID_OPTION));    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */

            prompt ();
        }
    }

    return ((int) bCheckChanged);
}

/*
**++
**
**–
*/
PRIVATE void batch (int argc, LPUCHR * argv)
{
    int c;
    int e;
    LPUCHR current_entry = NULL;
    UCHR tstfile[100];
    int tstdownload = FALSE;
    int extrascleared = FALSE;

    ret = 0;
    num_entries = 0;
    lustrcpy (tstfile, "");

    /* A bit of exception handling here…
       This rearranges input lines like
       LDAPCONF TEST -s -f fred
       to LDAPCONF TEST -f fred -s
       as the code expects -s/-x as last parameter, and its a lot easier to cheat here rather than recode the whole of batch
     */
    if ((argc == 5) && (!lustrcmp (argv[1], "TEST")))
    {
        /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
        if (!lustrcmp (argv[2], "-s") || !lustrcmp (argv[2], "-l"))
        {
            LPUCHR xx;
            xx = argv[2];
            argv[2] = argv[3];
            argv[3] = argv[4];
            argv[4] = xx;
        }
    }

    ucase (argv[1]);
    getbigentry ((LPUCHR) argv[1], &current_entry);
    if (current_entry == NULL)
    {
        printf (SW_REF_MSG (M_E_UNKNOWN_OPTION), argv[1]);    /* CR6685 SAC */
        printf ("n");    /* CR6685 SAC */
        my_exit (1);
    }

    if (argc == 2)        /* single parameter specified */
    {
        if (!lustrcmp (current_entry, "VIEW"))
        {
            view (0);
            return;
            /* my_exit (0); */
        }
        else if (!lustrcmp (current_entry, "TEST"))
        {
            test (FALSE, tstfile, tstdownload, FALSE);    /* chg so map */
        }
        else
        {
            printf (SW_REF_MSG (M_E_SUBOPTION_REQ), current_entry);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
        }
    }

    c = 2;
    while (c < argc)
    {
        LPUCHR ptr = argv[c];
        lcase (argv[c]);
        if (!lustrcmp (current_entry, "TEST"))
        {    /* only one of them can be set */
            /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
            if (lustrcmp (ptr, "-s") || lustrcmp (ptr, "-l"))
            {
                e = getentry (current_entry, (LPUCHR) "s");
                if (entries[e].set == 0)
                {
                    /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
                    e = getentry (current_entry, (LPUCHR) "l");
                }

                if (entries[e].set == 1)
                {
                    printf (SW_REF_MSG (M_ERROR_PARAM));    /* CR6738  ZJS */
                    printf ("n");
                    my_exit (3);
                }
            }
        }

        e = getentry (current_entry, (ptr + 1));    /* consume 0'th element as "-" */
        if (e == ER_ENTRY_NOTFOUND)
        {
            printf (SW_REF_MSG (M_E_UNKNOWN_SUBOPTION),
                (LPUCHR) ptr, current_entry);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            my_exit (2);
        }
        if (entries[e].set == 1)
        {        /* already set */
            if (lustrcmp (current_entry, "ATTRIB")
                || lustrcmp (ptr, "-x"))
            {    /* allowed repeats on ATTRIB -x -x etc. */
                printf (SW_REF_MSG (M_AMBIGUOUS),
                    (LPUCHR) ptr, current_entry);    /* CR6685 SAC */
                printf ("n");    /* CR6685 SAC */
                my_exit (3);
            }
        }
        else
            entries[e].set = 1;

        /* next parameter to set */
        c++;
        if (
            (
             (lustrcmp (current_entry, "TEST")
            /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
              || (lustrcmp (ptr, "-s") && lustrcmp (ptr, "-l")))
             && (lustrcmp (current_entry, "ATTRIB")
             || lustrcmp (ptr, "-x"))
             && (lustrcmp (current_entry, "MOVESYSINFO")
             || (lustrcmp (ptr, "-full")
                 && lustrcmp (ptr, "-partial")))) && (c >= argc))
        {
            printf (SW_REF_MSG (M_E_VALUE_REQ), (LPUCHR) ptr, current_entry);    /* CR6685 SAC */
            printf ("n");    /* CR6685 SAC */
            my_exit (4);
        }
        else
        {
            ptr++;    /* consume 0'th element */
            lcase (ptr);    /* already done? */
            if (!lustrcmp (current_entry, "ATTRIB"))
            {
                if (!lustrcmp (ptr, "u"))
                    lustrcpy (sw_ldap_info->username,
                          argv[c]);
                else if (!lustrcmp (ptr, "r"))
                    lustrcpy (sw_ldap_info->roleuser,
                          argv[c]);
                else if (!lustrcmp (ptr, "g"))
                    lustrcpy (sw_ldap_info->groupusers,
                          argv[c]);
                else if (!lustrcmp (ptr, "menu"))
                    lustrcpy (sw_ldap_info->menuname,
                          argv[c]);
                else if (!lustrcmp (ptr, "desc"))
                    lustrcpy (sw_ldap_info->description,
                          argv[c]);
                else if (!lustrcmp (ptr, "lang"))
                    lustrcpy (sw_ldap_info->language,
                          argv[c]);
                else if (!lustrcmp (ptr, "sort"))
                    lustrcpy (sw_ldap_info->sortmail,
                          argv[c]);
                else if (!lustrcmp (ptr, "x"))
                {
                    int x;
                    int found = 0;

                    if (!extrascleared)
                    {
                        SW_LDAP_extra_free
                            (sw_ldap_info);
                        extrascleared = TRUE;
                    }

                    for (x = 0;
                         ((x < sw_ldap_info->num_extras)
                          && (!found)); x++)
                        found =
                            (!lustrcmp
                             (sw_ldap_info->extra
                              [x], argv[c]));
                    if (found)
                    {
                        printf (SW_REF_MSG (M_EXISTS),
                            argv[c]);    /* CR6685 SAC */
                        printf ("n");    /* CR6685 SAC */
                        my_exit (5);
                    }

                    SW_LDAP_extra_add (sw_ldap_info,
                               argv[c], argv[c]);

                    /* FIX!!!
                       sw_ldap_info->extra[extra] = (LPUCHR ) malloc(strlen(argv[c])+1);
                       lustrcpy(sw_ldap_info->extra[extra++], argv[c]);
                     */
                }
            }
            else if (!lustrcmp (current_entry, "CONNECT"))
            {
                if (!lustrcmp (ptr, "h"))
                    lustrcpy (sw_ldap_info->hostname,
                          argv[c]);
                else if (!lustrcmp (ptr, "port"))
                {
                    int i;
                    UCHR b[10];

                    i = atoi ((char *) argv[c]);
                    sprintf ((char *) b, "%d", i);
                    if ((i < 0) || lustrcmp (argv[c], b))
                    {
                        printf (SW_REF_MSG (M_E_PORTNO));    /* CR6685 SAC */
                        printf ("n");    /* CR6685 SAC */
                        my_exit (5);
                    }

                    sw_ldap_info->portno = i;
                }
                else if (!lustrcmp (ptr, "dn"))
                    lustrcpy (sw_ldap_info->credentials,
                          argv[c]);
                else if (!lustrcmp (ptr, "pwd"))
                    lustrcpy (sw_ldap_info->password,
                          argv[c]);
            }
            else if (!lustrcmp (current_entry, "SEARCH"))
            {
                if (!lustrcmp (ptr, "dn"))
                    lustrcpy (sw_ldap_info->base,
                          argv[c]);
                else if (!lustrcmp (ptr, "s"))
                    lustrcpy (sw_ldap_info->filter,
                          argv[c]);
            }
            else if (!lustrcmp (current_entry, "TEST"))
            {
                /* CR16708 JMC 14-12-2004: Fix to change TEST -x to TEST -l */
                if (!lustrcmp (ptr, "f"))
                    lustrcpy (tstfile, argv[c]);
                else if ((!lustrcmp (ptr, "s"))
                     || (!lustrcmp (ptr, "l")))
                    tstdownload = TRUE;
                if ((c >= argc)
                    || ((argc == 4) && (c == 3)
                    && !lustrcmp (argv[2], "-f")))
                    test (FALSE, tstfile, tstdownload,
                          lustrcmp (ptr, "l"));
                if (!lustrcmp (current_entry, "TEST")
                    && (!lustrcmp (ptr, "s")
                    || !lustrcmp (ptr, "l")))
                    continue;
            }
            else if (!lustrcmp (current_entry, "MOVESYSINFO"))
                ldap_movesysinfo (ptr);
        }
        c++;
    }

    if (!lustrcmp (current_entry, "ATTRIB"))
    {            /* CR6743 */

        /* CR6746 SAC : 05-01-98 : Set up added mappings */
        SW_LDAP_set_def_mappings (filsh, (X500_TO_SWARE_MAP *) xsmap,
                      sw_ldap_info);
        chk_dups ();
    }

}

/*
 * ==================================================================
 * FUNCTION: ldap_user_match()
 * ==================================================================
 * This function checks the LDAPDN member to see if the ldap attribute
 * matches that mapped to username.
 *
 * PARAMETERS:
 *        info_ptr    sw_ldap_info structure
 *         val_ptr        input value string containing member or LDAP DN
 *         p_xsmap        x.500 mappings
 *         userval_ptr    output User member string
 *
 * RETURN:     match =     TRUE
 *                 FALSE
 *
 * CR16571 JMC 20-12-2004: Checks ldap attribute match to username,
 *                Adds new function
 * CR17995 SAC 26-01-06: added userval_size parameter
 * ==================================================================
 */
PUBLIC SWBOOL ldap_user_match
(
    SW_LDAP_info        *info_ptr,
    char            *val_ptr,
    X500_TO_SWARE_MAP    *p_xsmap,
    char            *userval_ptr,
    int            userval_size
)
{
    char *comma_ptr;                /* comma pointer */
    char usernameval[LDAP_MAX_ATTR_LEN + 1];    /* username value buffer */
    SWBOOL    result;                    /* boolean result */
    SWBOOL    match = FALSE;                /* match boolean */

    /*
     * get LDAP DN attribute name and value beyond the assignment
     * i.e. attrname=wwww,cl=xxxx,cl=yyyy,og=zzzz
     * where usernameval gets returned with everything after the
     * "=". If attrname is the same as
     * Staffware uses for username then TRUE is returned.
     */
    result = SW_LDAP_check_xattrname(val_ptr, p_xsmap, usernameval);

    /* check for same username attribute match*/
    if (result == TRUE)
    {
        /* CR16350 JMC 15-10-2004: truncate on illegal character */
        /* CR17995 SAC 26-01-06: pass in the buffer size */
        SW_LDAP_user_vtrunc(usernameval, info_ptr->grpmemldap, userval_ptr, userval_size);

        /* identify the user value */
        comma_ptr = (LPCHR)lustrchr(userval_ptr, ',');

        /* found one */
        if (comma_ptr != NULL)
        {
            *comma_ptr = '';
        }

        /* assign match */
        match = TRUE;

    }

    return(match);
}

/*
**++
**
**–
*/
int main (int argc, LPUCHR argv[])
{
    FILNAME mespath;    /* CR6685 SAC */
    SFILNAME temp_file;    /* CR6685 SAC */
    SWBOOL    bPossiblyChanged = FALSE;

    int interactive = (argc == 1);

    /* CR8897 Should always strcpy getenv returns otherwise they are overwritten */
    LPUCHR getenv_rtn;
    UCHR swdir[MAXFILEPATH],
        szDebug [MAXFILEPATH];

    /* CR10765 SAC 15-11-01 */
    SWINT32        nReturn;
    ENVCTXHDL    EnvCtx;
    /* CR15884 JMC 13-8-04: increase Username to SWUV_MAXUSERNAMELENGTH + 1 */
    char        Username[SWUV_MAXUSERNAMELENGTH + 1];

/* CR14758 NJP 14Mar05 – #ifdef left out during reintegration */
#ifdef SW4_UNIX
    /* CR14758 JMC 15-1-04: turn on ldap-3.3 debug trace */
    if (getenv("LDAPDEBUG"))
    {
        /* set all flags for debug trace */
        ldap_debug = 0xffff;
    }
    else
    {
        /* turn off the flags for debug trace */
        ldap_debug = 0;
    }
#endif
    /* CR8897 Should always strcpy getenv returns otherwise they are overwritten */
    getenv_rtn = (LPUCHR) my_getenv (1, "SWDIR", NULL);
    if (getenv_rtn == NULL)
    {
        printf ("SWDIR is not setn");
        /*
         * CR10647 JMC 31-07-03 Reint: Fix all compiler warnings cause
         * I'm nice (probably cause more problems though)
         */
        return 1;
    }
    /* CR8897 Should always strcpy getenv returns otherwise they are overwritten */
    lustrcpy (swdir, getenv_rtn);
/*
** CR16732 – CJED 24-JAN-2005 – get and copy the DEBUG environment variable
** in the same way. Keep a copy as my_getenv() returns a pointer to an
** internal static buffer!
*/
    getenv_rtn = (LPUCHR) my_getenv (1, "DEBUG", NULL);
    if (getenv_rtn != NULL)
    {
        lustrncpy (szDebug, getenv_rtn, sizeof (szDebug) – 1);
    }
    else
    {
        szDebug [0] = '';
    }

    /* CR10229 KWW 8Aug01 Change if to call get_user_identity instead of getpwuid and getuid */
    /* CR19048 Remove unused variable */
    get_user_identity(swdir , (LPUCHR)Username, SWUV_MAXUSERNAMELENGTH);

    /*
    ** CR10765 SAC 15-11-01: initialise process
    */
    /* CR16881 Add PROCESS_IEL_COUNT_SUBSCRIBERS so we don't try and */
    /* contact the server if it isn't running */
    nReturn = process_util_startup ((LPUCHR) "ldapconf",
                    1,
                    NULL,
                    szDebug,
                    PROCESS_NO_LOGIN | PROCESS_NO_SAL | PROCESS_IEL_COUNT_SUBSCRIBERS,
                    (LPUCHR) Username,
                    FALSE);
    if (nReturn != SW_OK)
    {
        printf ("Failed to initialise process: %ldn", nReturn);
        process_startup_display_last_error (NULL);
        return (nReturn);
    }

    /*
     * Getting environment context.
     * This will get the default environment context
     */
    EnvCtx = envGetContext ();
    if(!EnvCtx)
    {
        printf ("Failed to get environment contextn");
        process_shutdown (FALSE, ER_SYSTEM, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        return (ER_SYSTEM);
    }

    /* get the FIL session */
    nReturn = envAttrGet (EnvCtx, ENV_ATTR_FILSH, (void *) &filsh, sizeof (filsh));
    if (SW_OK != nReturn)
    {
        printf ("Failed to get FILSH from environment context: %ldn", nReturn);
        process_shutdown (FALSE, nReturn, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        return (nReturn);
    }

    /*
     * get the PATTR session from the
     * environment context
     */
    nReturn = envAttrGet (EnvCtx, ENV_ATTR_PATSH, (PATTR_SH *) &hPAT, sizeof(PATTR_SH));
    if (nReturn != SW_OK)
    {
        printf ("Failed to get PATTR from environment context: %ldn", nReturn);
        process_shutdown (FALSE, nReturn, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        return (nReturn);
    }

#if defined (SW4_UNIX)
    sprintf ((char *) lockfile, "%s/tsys/swldaplck", swdir);
#elif defined (SW4_WIN32SERVER)
    sprintf ((char *) lockfile, "%s\tsys\swldaplck", swdir);
#endif
    if (
        (lock_fh =
         fil_open (filsh, (LPFILNAME) lockfile,
               FIL_CREAT | FIL_CEXCLUSIVE | FIL_WRITE, 0)) < 1)
    {
        printf ("Application is already in usen");
        if (interactive)
            prompt ();

        process_shutdown (FALSE, lock_fh, (LPUCHR) "LDAPCONF Exiting");
        return 1;
    }

    if ((msg_sh = init_errhand (filsh, "ldapconf", "english")) <= 0)
    {
        fprintf (stderr, "Error message handler failed to initialise – %dn", msg_sh);
        process_shutdown (FALSE, msg_sh, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        my_exit (1);
    }

    /* CR6685 SAC 08-12-97 : Build path to ldapconf message file */
    bld_staffpath (filsh, (LPFILNAME) & mespath, FILD_TEXT,
               (LPSFILNAME) atofile (&temp_file,
                         (LPCHR) SW_LDAP_MES_FILE));

    /* CR6685 SAC 08-12-97 : Initialise the ldapconf message file */
    if (sw_init_msg (filsh, &mespath, '', msg_sh) <= 0)
    {
        fprintf (stderr, "Access to '%s' failed.n", mespath.filepath);
        process_shutdown (FALSE, ER_SYSTEM, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07
        my_exit (1);
    }

    node_namefind (filsh, &my_node, (LPUCHR) fil_def (filsh, FILC_NODE));

    initialise ();

    sw_ldap_info = (SW_LDAP_info *) SW_LDAP_alloc_info ();

    if (SW_LDAP_get_info (filsh, (SW_LDAP_info *) sw_ldap_info) != SW_LDAP_SUCCESS)
    {
        printf (SW_REF_MSG (M_E_CFG_READ));    /* CR6685 SAC */
    }

    SW_LDAP_set_def_mappings (filsh, (X500_TO_SWARE_MAP *) xsmap, sw_ldap_info);
    ldapcpy ();

    if (interactive)
    {
        bPossiblyChanged = menu ();
    }
    else
    {
        batch (argc, (LPUCHR *) argv);
        bPossiblyChanged = TRUE;       
        /* chk_dups(); */
    }

    writeinfo (interactive);    /* save */

    SW_LDAP_free_info (sw_ldap_info);

    if (lock_fh > 0)    /* CR8893 ZJS 08/03/2000 ie. this session created the lock file in the first place */
    {
        fil_close (lock_fh);    /* CR6685 SAC */
        fil_fsdelete (filsh, (LPFILNAME) lockfile);
    }

    process_shutdown (FALSE, SW_OK, (LPUCHR) "LDAPCONF Exiting"); // CR19716 SAC 01-02-07

    return 0;
}

/*
**++
**
**–
*/
PRIVATE void ldap_movesysinfo (LPUCHR ptr)
{
    POSTARG argv;
    UCHR buff[128];

    /* CR10765 SAC 15-11-01 */
    IQLMSGINFO        MsgInfo, *pMsgInfo;
    MBSETMSG_SH        mbsh;
    int            rc = SW_OK;
    UCHR            InsBuf[POSTBUFSIZE];

    int interactive = !lustrcmp (ptr, "");

    lustrcpy (buff, "");

    if (interactive)
        GetValidCh (SW_REF_MSG (M_FULL_PARTIAL_QUIT), "FPQ", buff);    /* CR6685 SAC */

    if (!lustrcmp (buff, "Q"))
        return;

    argv[0] = (LPUCHR) I_MOVINFO;
    if ((!lustrcmp (ptr, "full") || (!lustrcmp (buff, "F"))))
        argv[1] = (LPUCHR) "FULL";
    else            /* if ( (!lustrcmp(ptr, "partial") || (! lustrcmp(buff, "P")) */
        argv[1] = (LPUCHR) "PARTIAL";

    /*
     * CR10765 SAC 15-11-01: post the instruction to the BG
     * using the MBoxset interfaces
     */

    /*
     * begin transaction
     */
    rc = fil_get_conn (filsh);
    if (rc < 0)
    {
        fprintf (stderr, "Failed to begin transaction: %dn", rc);
        return;
}

    /*
    ** initialise a mbox set session
    */
    if ((mbsh = MBSetMsg_Init (filsh, hPAT, MBSET_ACC_WRITE_BG, TRUE)) <= 0)
    {
        printf ("Failed to initialise MBoxSet session: %dn", mbsh);
        return;
    }
    /*
    ** build message info string
    */
    pMsgInfo = Bld_MBoxMsgInfo_v1 (&MsgInfo,
                    fil_def (filsh, FILC_PRO),
                    argv[0],
                    fil_def (filsh, FILC_PRO),
                    my_node.name,
                    (LPUCHR) "",
                    (LPUCHR) "",
                    0,
                    0,
                    (LPUCHR) "");

    /*
    ** build buffer from arguments
    */
    bld_instruction ((LPCHR) InsBuf, 2, argv);

    /*
    ** post the message
    */
    if ((rc = MBSetMsg_Enqueue (mbsh,
                pMsgInfo,
                my_node.name,
                IQL_PTY_NONE,
                IQL_DATA_BIN,
                InsBuf,
                lustrlen (InsBuf),
                TRUE)) != SW_OK)
    {
        printf ("Failed to enqueue %s instruction: %dn", argv[0], rc);
    }

    /*
    ** terminate the session
    */
    MBSetMsg_Term (mbsh);

    fil_commit_conn (filsh, 'T', (LPUCHR) "ldap_movesysinfo", (LPUCHR) argv[0]);
}

void sighandler (int sig)
{
    /* Disallow CTRL+C during handler. */
    my_exit (1);
}

void my_exit (int sig)
{
    if (lock_fh > 0)    /* CR8893 ZJS 08/03/2000 ie. this session created the lock file in the first place */
    {
        fil_close (lock_fh);
        fil_fsdelete (filsh, (LPFILNAME) lockfile);
    }

    exit (sig);
}