
/*
 *@@sourcefile xwpvcard.c:
 *      This file contains SOM code for the following XWorkplace classes:
 *
 *      --  XWPVCard (WPDataFile subclass)
 *
 *      XWPVCard is a special WPDataFile subclass for vCard files
 *      which is automatically assigned for each file that has the
 *      *.vcf file extension.
 *
 *      Installation of this class is optional.
 *
 *@@added V0.9.16 (2002-01-05) [umoeller]
 *@@somclass XWPVCard xvc_
 *@@somclass M_XWPVCard xvcM_
 */

/*
 *      Copyright (C) 2002-2003 Ulrich M”ller.
 *
 *      This file is part of the XWorkplace source package.
 *      XWorkplace is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published
 *      by the Free Software Foundation, in version 2 as it comes in the
 *      "COPYING" file of the XWorkplace main distribution.
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 */

/*
 *  This file was generated by the SOM Compiler and Emitter Framework.
 *  Generated using:
 *      SOM Emitter emitctm: 2.41
 */

#ifndef SOM_Module_xwpvcard_Source
#define SOM_Module_xwpvcard_Source
#endif
#define XWPVCard_Class_Source
#define M_XWPVCard_Class_Source

#pragma strings(readonly)

/*
 *  Suggested #include order:
 *  1)  os2.h
 *  2)  C library headers
 *  3)  setup.h (code generation and debugging options)
 *  4)  headers in helpers\
 *  5)  at least one SOM implementation header (*.ih)
 *  6)  dlgids.h, headers in shared\ (as needed)
 *  7)  headers in implementation dirs (e.g. filesys\, as needed)
 *  8)  #pragma hdrstop and then more SOM headers which crash with precompiled headers
 */

#define INCL_DOSEXCEPTIONS
#define INCL_DOSPROCESS
#define INCL_DOSSEMAPHORES
#define INCL_DOSERRORS

#define INCL_WINSTATICS
#define INCL_WINBUTTONS
#define INCL_WINENTRYFIELDS
#define INCL_WINLISTBOXES
#define INCL_WINMLE
#define INCL_WINSTDCNR
#include <os2.h>

// C library headers
#include <stdio.h>
#include <setjmp.h>

// generic headers
#include "setup.h"                      // code generation and debugging options

// headers in /helpers
#include "helpers\cnrh.h"               // container helper routines
#include "helpers\dialog.h"             // dialog helpers
#include "helpers\dosh.h"               // Control Program helper routines
#include "helpers\except.h"             // exception handling
#include "helpers\linklist.h"           // linked list helper routines
#include "helpers\nls.h"                // National Language Support helpers
#include "helpers\standards.h"          // some standard macros
#include "helpers\stringh.h"            // string helper routines
#include "helpers\vcard.h"              // vCard parsing
#include "helpers\winh.h"               // PM helper routines
#include "helpers\xstring.h"            // extended string helpers

// SOM headers which don't crash with prec. header files
// #include "xfobj.ih"
#include "xwpvcard.ih"

// XWorkplace implementation headers
#include "dlgids.h"                     // all the IDs that are shared with NLS
#include "shared\common.h"              // the majestic XWorkplace include file
#include "shared\helppanels.h"          // all XWorkplace help panel IDs
#include "shared\kernel.h"              // XWorkplace Kernel
#include "shared\notebook.h"            // generic XWorkplace notebook handling

// other SOM headers
#pragma hdrstop                 // VAC++ keeps crashing otherwise

/* ******************************************************************
 *
 *   Shared stuff
 *
 ********************************************************************/

#define TEXT_WIDTH  60
#define EF_WIDTH    100
#define EF_HEIGHT   -1

#define TEXT_AND_ENTRYFIELD(varname, string, idbase) \
            varname ## Text = CONTROLDEF_TEXT(string, idbase ## _TEXT, TEXT_WIDTH, -1), \
            varname ## EF = CONTROLDEF_ENTRYFIELD_RO(NULL, idbase ## _EF, EF_WIDTH, EF_HEIGHT)

/*
 *@@ SetEFText:
 *
 */

STATIC VOID SetEFText(PNOTEBOOKPAGE pnbp,    // notebook info struct
                      ULONG ulID,
                      PCSZ pcsz)
{
    HWND hwnd;
    if (hwnd = WinWindowFromID(pnbp->hwndDlgPage, ulID))
    {
        winhSetEntryFieldLimit(hwnd, 1000);
        WinSetWindowText(hwnd, (PSZ)pcsz);
    }
}

/* ******************************************************************
 *
 *   "Summary" page
 *
 ********************************************************************/

#define ID_XSDI_VCARD_SUMMARY_NAME_TEXT        32000
#define ID_XSDI_VCARD_SUMMARY_NAME_EF          32001
#define ID_XSDI_VCARD_SUMMARY_TITLE_TEXT       32002
#define ID_XSDI_VCARD_SUMMARY_TITLE_EF         32003
#define ID_XSDI_VCARD_SUMMARY_ADDRESS_TEXT     32004
#define ID_XSDI_VCARD_SUMMARY_ADDRESS_EF       32005
#define ID_XSDI_VCARD_SUMMARY_EMAIL_TEXT       32006
#define ID_XSDI_VCARD_SUMMARY_EMAIL_EF         32007

static const CONTROLDEF
    TEXT_AND_ENTRYFIELD(SummaryName,
                        "~Name:",
                        ID_XSDI_VCARD_SUMMARY_NAME),
    TEXT_AND_ENTRYFIELD(SummaryTitle,
                        "~Title:",
                        ID_XSDI_VCARD_SUMMARY_TITLE),
    SummaryAddressText = CONTROLDEF_TEXT(
                            "~Address:",
                            ID_XSDI_VCARD_SUMMARY_ADDRESS_TEXT,
                            TEXT_WIDTH,
                            -1),
    SummaryAddressEF = CONTROLDEF_MLE(
                            NULL,
                            ID_XSDI_VCARD_SUMMARY_ADDRESS_EF,
                            EF_WIDTH,
                            70),
    TEXT_AND_ENTRYFIELD(SummaryEmail,
                        "~E-Mail:",
                        ID_XSDI_VCARD_SUMMARY_EMAIL);

static const DLGHITEM dlgSummary[] =
    {
        START_TABLE,            // root table, required
            START_ROW(ROW_VALIGN_CENTER),
                CONTROL_DEF(&SummaryNameText),
                CONTROL_DEF(&SummaryNameEF),
            START_ROW(ROW_VALIGN_CENTER),
                CONTROL_DEF(&SummaryTitleText),
                CONTROL_DEF(&SummaryTitleEF),
            START_ROW(ROW_VALIGN_CENTER),
                CONTROL_DEF(&SummaryAddressText),
                CONTROL_DEF(&SummaryAddressEF),
            START_ROW(ROW_VALIGN_CENTER),
                CONTROL_DEF(&SummaryEmailText),
                CONTROL_DEF(&SummaryEmailEF),
            START_ROW(0),
                CONTROL_DEF(&G_UndoButton),         // common.c
                CONTROL_DEF(&G_DefaultButton),      // common.c
                CONTROL_DEF(&G_HelpButton),         // common.c
        END_TABLE
    };

/*
 *@@ SetStringOrArray:
 *
 */

STATIC VOID SetStringOrArray(PNOTEBOOKPAGE pnbp,    // notebook info struct
                             ULONG ulID,
                             PCSZ pcszReal,
                             PCSZ *papcsz,
                             CHAR cSeparator,
                             ULONG c,
                             PULONG paulOrder)
{
    PCSZ pcszTemp = NULL;
    XSTRING strTemp;
    xstrInit(&strTemp, 0);

    if (pcszReal)
        pcszTemp = pcszReal;
    else if (papcsz)
    {
        // if we can't find a formatted name, let's
        // compose one ourselves
        ULONG   ul;

        for (ul = 0;
             ul < c;
             ul++)
        {
            if (papcsz[paulOrder[ul]])
            {
                if (strTemp.ulLength)
                    xstrcatc(&strTemp, cSeparator);
                xstrcat(&strTemp, papcsz[paulOrder[ul]], 0);
            }
        }

        pcszTemp = strTemp.psz;
    }

    SetEFText(pnbp,
              ulID,
              pcszTemp);
    xstrClear(&strTemp);
}

/*
 *@@ vcfSummaryInitPage:
 *      "vCard" page notebook callback function (notebook.c).
 *
 */

STATIC VOID vcfSummaryInitPage(PNOTEBOOKPAGE pnbp,    // notebook info struct
                               ULONG flFlags)                // CBI_* flags (notebook.h)
{
    if (flFlags & CBI_INIT)
    {
        ntbFormatPage(pnbp->hwndDlgPage,
                      dlgSummary,
                      ARRAYITEMCOUNT(dlgSummary));
    }

    if (flFlags & CBI_SET)
    {
        XWPVCardData *somThis = XWPVCardGetData(pnbp->inbp.somSelf);
        PVCARD      pvc;
        APIRET      arc = NO_ERROR;
        CHAR        sz[CCHMAXPATH];

        if (!_pvCard)
            if (_wpQueryFilename(pnbp->inbp.somSelf, sz, TRUE))
                arc = vcfRead(sz, (PVCARD*)&_pvCard);

        if (pvc = (PVCARD)_pvCard)
        {
            ULONG   aulFormattedNameOrder[] =
                {
                    VCF_VALUE_INDEX_N_PREFIX,
                    VCF_VALUE_INDEX_N_GIVEN,
                    VCF_VALUE_INDEX_N_ADDITIONAL,
                    VCF_VALUE_INDEX_N_FAMILY,
                    VCF_VALUE_INDEX_N_SUFFIX
                },
                    aulAddressOrder[] =
                {
                    VCF_VALUE_INDEX_ADR_POSTOFFICE,
                    VCF_VALUE_INDEX_ADR_EXTENDED,
                    VCF_VALUE_INDEX_ADR_STREET,
                    VCF_VALUE_INDEX_ADR_LOCALITY,
                    VCF_VALUE_INDEX_ADR_REGION,
                    VCF_VALUE_INDEX_ADR_POSTALCODE,
                    VCF_VALUE_INDEX_ADR_COUNTRY
                };

            SetStringOrArray(pnbp,
                             ID_XSDI_VCARD_SUMMARY_NAME_EF,
                             pvc->pcszFormattedName,
                             pvc->apcszName,
                             ' ',
                             ARRAYITEMCOUNT(aulFormattedNameOrder),
                             aulFormattedNameOrder);

            SetEFText(pnbp,
                      ID_XSDI_VCARD_SUMMARY_TITLE_EF,
                      pvc->pcszJobTitle);

            SetStringOrArray(pnbp,
                             ID_XSDI_VCARD_SUMMARY_ADDRESS_EF,
                             (pvc->cLabels)
                                ? pvc->paLabels[0].pcszLabel
                                : NULL,
                             (pvc->cDeliveryAddresses)
                                ? pvc->paDeliveryAddresses[0].apcszAddress
                                : NULL,
                             '\n',
                             ARRAYITEMCOUNT(aulAddressOrder),
                             aulAddressOrder);

            SetEFText(pnbp,
                      ID_XSDI_VCARD_SUMMARY_EMAIL_EF,
                      pvc->pcszEmail);
        }
    }
}

/* ******************************************************************
 *
 *   "Name" page
 *
 ********************************************************************/

#define ID_XSDI_VCARD_PERS_NAMEFIELDS_GROUP      30002
#define ID_XSDI_VCARD_PERS_FAMILY_TEXT           30003
#define ID_XSDI_VCARD_PERS_FAMILY_EF             30004
#define ID_XSDI_VCARD_PERS_GIVEN_TEXT            30005
#define ID_XSDI_VCARD_PERS_GIVEN_EF              30006
#define ID_XSDI_VCARD_PERS_ADDITIONAL_TEXT       30007
#define ID_XSDI_VCARD_PERS_ADDITIONAL_EF         30008
#define ID_XSDI_VCARD_PERS_PREFIX_TEXT           30009
#define ID_XSDI_VCARD_PERS_PREFIX_EF             30010
#define ID_XSDI_VCARD_PERS_SUFFIX_TEXT           30011
#define ID_XSDI_VCARD_PERS_SUFFIX_EF             30012

static const CONTROLDEF
    NameFieldsGroup = CONTROLDEF_GROUP(
                            "Name fields",
                            ID_XSDI_VCARD_PERS_NAMEFIELDS_GROUP,
                            -1,
                            -1),
    TEXT_AND_ENTRYFIELD(NameFamily,
                        "~Family name:",
                        ID_XSDI_VCARD_PERS_FAMILY),
    TEXT_AND_ENTRYFIELD(NameGiven,
                        "~Given name:",
                        ID_XSDI_VCARD_PERS_GIVEN),
    TEXT_AND_ENTRYFIELD(NameAdditional,
                        "A~dditional names:",
                        ID_XSDI_VCARD_PERS_ADDITIONAL),
    TEXT_AND_ENTRYFIELD(NamePrefix,
                        "Name ~prefix",
                        ID_XSDI_VCARD_PERS_PREFIX),
    TEXT_AND_ENTRYFIELD(NameSuffix,
                        "Name su~ffix:",
                        ID_XSDI_VCARD_PERS_SUFFIX);

static const DLGHITEM dlgName[] =
    {
        START_TABLE,            // root table, required
            START_ROW(0),
                START_GROUP_TABLE(&NameFieldsGroup),
                    START_ROW(0),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&NamePrefixText),
                           CONTROL_DEF(&NamePrefixEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&NameGivenText),
                           CONTROL_DEF(&NameGivenEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&NameAdditionalText),
                           CONTROL_DEF(&NameAdditionalEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&NameFamilyText),
                           CONTROL_DEF(&NameFamilyEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&NameSuffixText),
                           CONTROL_DEF(&NameSuffixEF),
                END_TABLE,
            START_ROW(0),
                CONTROL_DEF(&G_UndoButton),         // common.c
                CONTROL_DEF(&G_DefaultButton),      // common.c
                CONTROL_DEF(&G_HelpButton),         // common.c
        END_TABLE
    };

/*
 *@@ vcfNameInitPage:
 *      "vCard" page notebook callback function (notebook.c).
 *
 */

STATIC VOID vcfNameInitPage(PNOTEBOOKPAGE pnbp,    // notebook info struct
                            ULONG flFlags)                // CBI_* flags (notebook.h)
{
    if (flFlags & CBI_INIT)
    {
        ntbFormatPage(pnbp->hwndDlgPage,
                      dlgName,
                      ARRAYITEMCOUNT(dlgName));
    }

    if (flFlags & CBI_SET)
    {
        XWPVCardData *somThis = XWPVCardGetData(pnbp->inbp.somSelf);
        PVCARD      pvc;
        APIRET      arc = NO_ERROR;
        CHAR        sz[CCHMAXPATH];

        if (!_pvCard)
            if (_wpQueryFilename(pnbp->inbp.somSelf, sz, TRUE))
                arc = vcfRead(sz, (PVCARD*)&_pvCard);

        if (pvc = (PVCARD)_pvCard)
        {
            ULONG   aulIDs[] =
                {
                     ID_XSDI_VCARD_PERS_FAMILY_EF,
                     ID_XSDI_VCARD_PERS_GIVEN_EF,
                     ID_XSDI_VCARD_PERS_ADDITIONAL_EF,
                     ID_XSDI_VCARD_PERS_PREFIX_EF,
                     ID_XSDI_VCARD_PERS_SUFFIX_EF,
                },
                    ul;

            for (ul = 0;
                 ul < ARRAYITEMCOUNT(aulIDs);
                 ul++)
            {
                SetEFText(pnbp,
                          aulIDs[ul],
                          (PSZ)pvc->apcszName[ul]);
            }
        }
    }
}

/* ******************************************************************
 *
 *   "Phone numbers" page
 *
 ********************************************************************/

#define ID_XSDI_VCARD_PHONE_LISTBOX         33000
#define ID_XSDI_VCARD_PHONE_GROUP           33001
#define ID_XSDI_VCARD_PHONE_NUMBER_TEXT     33002
#define ID_XSDI_VCARD_PHONE_NUMBER_EF       33003
#define ID_XSDI_VCARD_PHONE_PREF            33004
#define ID_XSDI_VCARD_PHONE_WORK            33005
#define ID_XSDI_VCARD_PHONE_HOME            33006
#define ID_XSDI_VCARD_PHONE_VOICE           33007
#define ID_XSDI_VCARD_PHONE_FAX             33008
#define ID_XSDI_VCARD_PHONE_MSG             33009
#define ID_XSDI_VCARD_PHONE_CELL            33010
#define ID_XSDI_VCARD_PHONE_PAGER           33011
#define ID_XSDI_VCARD_PHONE_BBS             33012
#define ID_XSDI_VCARD_PHONE_MODEM           33013
#define ID_XSDI_VCARD_PHONE_CAR             33014
#define ID_XSDI_VCARD_PHONE_ISDN            33015
#define ID_XSDI_VCARD_PHONE_VIDEO           33016


static const CONTROLDEF
    PhoneLB = CONTROLDEF_LISTBOX(
                            ID_XSDI_VCARD_PHONE_LISTBOX,
                            30,
                            100),
    PhoneGroup = CONTROLDEF_GROUP(
                            "Current phone number settings",
                            ID_XSDI_VCARD_PHONE_GROUP,
                            -1,
                            -1),
    TEXT_AND_ENTRYFIELD(PhoneNumber,
                        "~Number:",
                        ID_XSDI_VCARD_PHONE_NUMBER),
    PhoneCB_PREF = CONTROLDEF_AUTOCHECKBOX(
                        "Preferred",
                        ID_XSDI_VCARD_PHONE_PREF, -1, -1), // preferred no.
    PhoneCB_WORK = CONTROLDEF_AUTOCHECKBOX(
                        "Work",
                        ID_XSDI_VCARD_PHONE_WORK, -1, -1), // work no.
    PhoneCB_HOME = CONTROLDEF_AUTOCHECKBOX(
                        "Home",
                        ID_XSDI_VCARD_PHONE_HOME, -1, -1), // home no.
    PhoneCB_VOICE = CONTROLDEF_AUTOCHECKBOX(
                        "Voice",
                        ID_XSDI_VCARD_PHONE_VOICE, -1, -1), // voice no. (default)
    PhoneCB_FAX = CONTROLDEF_AUTOCHECKBOX(
                        "Fax",
                        ID_XSDI_VCARD_PHONE_FAX, -1, -1), // fax no.
    PhoneCB_MSG = CONTROLDEF_AUTOCHECKBOX(
                        "Messaging",
                        ID_XSDI_VCARD_PHONE_MSG, -1, -1), // messaging service
    PhoneCB_CELL = CONTROLDEF_AUTOCHECKBOX(
                        "Cellular",
                        ID_XSDI_VCARD_PHONE_CELL, -1, -1), // cell phone
    PhoneCB_PAGER = CONTROLDEF_AUTOCHECKBOX(
                        "Pager",
                        ID_XSDI_VCARD_PHONE_PAGER, -1, -1), // pager
    PhoneCB_BBS = CONTROLDEF_AUTOCHECKBOX(
                        "BBS",
                        ID_XSDI_VCARD_PHONE_BBS, -1, -1), // bulletin board service
    PhoneCB_MODEM = CONTROLDEF_AUTOCHECKBOX(
                        "Modem",
                        ID_XSDI_VCARD_PHONE_MODEM, -1, -1), // modem
    PhoneCB_CAR = CONTROLDEF_AUTOCHECKBOX(
                        "Car",
                        ID_XSDI_VCARD_PHONE_CAR, -1, -1), // car phone
    PhoneCB_ISDN = CONTROLDEF_AUTOCHECKBOX(
                        "ISDN",
                        ID_XSDI_VCARD_PHONE_ISDN, -1, -1), // isdn
    PhoneCB_VIDEO = CONTROLDEF_AUTOCHECKBOX(
                        "Video",
                        ID_XSDI_VCARD_PHONE_VIDEO, -1, -1); // video phone

static const DLGHITEM dlgPhone[] =
    {
        START_TABLE,            // root table, required
            START_ROW(0),
                CONTROL_DEF(&PhoneLB),
                START_GROUP_TABLE(&PhoneGroup),
                    START_ROW(ROW_VALIGN_CENTER),
                        CONTROL_DEF(&PhoneNumberText),
                        CONTROL_DEF(&PhoneNumberEF),
                    START_ROW(ROW_VALIGN_TOP),
                        START_TABLE,
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_PREF),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_WORK),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_HOME),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_VOICE),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_FAX),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_MSG),
                        END_TABLE,
                        START_TABLE,
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_CELL),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_PAGER),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_BBS),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_MODEM),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_CAR),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_ISDN),
                            START_ROW(0),
                                CONTROL_DEF(&PhoneCB_VIDEO),
                        END_TABLE,
                END_TABLE,
            START_ROW(0),
                CONTROL_DEF(&G_UndoButton),         // common.c
                CONTROL_DEF(&G_DefaultButton),      // common.c
                CONTROL_DEF(&G_HelpButton),         // common.c
        END_TABLE
    };

/*
 *@@ vcfPhoneInitPage:
 *
 */

STATIC VOID vcfPhoneInitPage(PNOTEBOOKPAGE pnbp,    // notebook info struct
                             ULONG flFlags)                // CBI_* flags (notebook.h)
{
    if (flFlags & CBI_INIT)
    {
        ntbFormatPage(pnbp->hwndDlgPage,
                      dlgPhone,
                      ARRAYITEMCOUNT(dlgPhone));
    }

    if (flFlags & CBI_SET)
    {
        XWPVCardData *somThis = XWPVCardGetData(pnbp->inbp.somSelf);
        PVCARD      pvc;
        APIRET      arc = NO_ERROR;
        CHAR        sz[CCHMAXPATH];

        if (!_pvCard)
            if (_wpQueryFilename(pnbp->inbp.somSelf, sz, TRUE))
                arc = vcfRead(sz, (PVCARD*)&_pvCard);

        if (pvc = (PVCARD)_pvCard)
        {
            ULONG ul;
            HWND hwndLB = WinWindowFromID(pnbp->hwndDlgPage,
                                          ID_XSDI_VCARD_PHONE_LISTBOX);
            for (ul = 0;
                 ul < pvc->cPhones;
                 ul++)
            {
                SHORT sIndex;
                sprintf(sz, "%d", ul + 1);
                sIndex = WinInsertLboxItem(hwndLB, LIT_END, sz);
                winhSetLboxItemHandle(hwndLB, sIndex, ul);
            }
        }
    }
}

/*
 *@@ vcfPhoneItemChanged:
 *
 */

STATIC MRESULT XWPENTRY vcfPhoneItemChanged(PNOTEBOOKPAGE pnbp,
                                            ULONG ulItemID, USHORT usNotifyCode,
                                            ULONG ulExtra)
{
    MRESULT mrc = 0;

    switch (ulItemID)
    {
        case ID_XSDI_VCARD_PHONE_LISTBOX:
            if (usNotifyCode == LN_SELECT)
            {
                XWPVCardData *somThis = XWPVCardGetData(pnbp->inbp.somSelf);

                SHORT sIndex = winhQueryLboxSelectedItem(pnbp->hwndControl,
                                                         LIT_FIRST);
                PVCARD      pvc;
                if (    (pvc = (PVCARD)_pvCard)
                     && (sIndex >= 0)
                     && (sIndex < pvc->cPhones)
                   )
                {
                    PVCPHONE pPhone = &pvc->paPhones[sIndex];
                    ULONG aulFlags[] =
                        {
                             VCF_PHONEFL_PREF,
                             VCF_PHONEFL_WORK,
                             VCF_PHONEFL_HOME,
                             VCF_PHONEFL_VOICE       ,
                             VCF_PHONEFL_FAX,
                             VCF_PHONEFL_MSG,
                             VCF_PHONEFL_CELL        ,
                             VCF_PHONEFL_PAGER,
                             VCF_PHONEFL_BBS,
                             VCF_PHONEFL_MODEM,
                             VCF_PHONEFL_CAR,
                             VCF_PHONEFL_ISDN        ,
                             VCF_PHONEFL_VIDEO,
                        };
                    ULONG aulIDs[] =
                        {
                             ID_XSDI_VCARD_PHONE_PREF,
                             ID_XSDI_VCARD_PHONE_WORK,
                             ID_XSDI_VCARD_PHONE_HOME,
                             ID_XSDI_VCARD_PHONE_VOICE       ,
                             ID_XSDI_VCARD_PHONE_FAX,
                             ID_XSDI_VCARD_PHONE_MSG,
                             ID_XSDI_VCARD_PHONE_CELL        ,
                             ID_XSDI_VCARD_PHONE_PAGER,
                             ID_XSDI_VCARD_PHONE_BBS,
                             ID_XSDI_VCARD_PHONE_MODEM,
                             ID_XSDI_VCARD_PHONE_CAR,
                             ID_XSDI_VCARD_PHONE_ISDN        ,
                             ID_XSDI_VCARD_PHONE_VIDEO
                        };
                    ULONG ul;

                    WinSetDlgItemText(pnbp->hwndDlgPage,
                                      ID_XSDI_VCARD_PHONE_NUMBER_EF,
                                      pPhone->pcszNumber);

                    for (ul = 0;
                         ul < ARRAYITEMCOUNT(aulIDs);
                         ul++)
                    {
                        winhSetDlgItemChecked(pnbp->hwndDlgPage,
                                              aulIDs[ul],
                                              ((pPhone->fl & aulFlags[ul]) != 0));
                    }
                }
            }
        break;
    }

    return mrc;
}

/* ******************************************************************
 *
 *   "Addresses" page
 *
 ********************************************************************/

#define ID_XSDI_VCARD_ADDR_NAMEFIELDS_GROUP     31002
#define ID_XSDI_VCARD_ADDR_POBOX_TEXT           31003
#define ID_XSDI_VCARD_ADDR_POBOX_EF             31004
#define ID_XSDI_VCARD_ADDR_EXTENDED_TEXT        31015
#define ID_XSDI_VCARD_ADDR_EXTENDED_EF          31016
#define ID_XSDI_VCARD_ADDR_STREET_TEXT          31017
#define ID_XSDI_VCARD_ADDR_STREET_EF            31018
#define ID_XSDI_VCARD_ADDR_LOCALITY_TEXT        31019
#define ID_XSDI_VCARD_ADDR_LOCALITY_EF          31020
#define ID_XSDI_VCARD_ADDR_STATE_TEXT           31021
#define ID_XSDI_VCARD_ADDR_STATE_EF             31022
#define ID_XSDI_VCARD_ADDR_POSTALCODE_TEXT      31023
#define ID_XSDI_VCARD_ADDR_POSTALCODE_EF        31024
#define ID_XSDI_VCARD_ADDR_COUNTRY_TEXT         31025
#define ID_XSDI_VCARD_ADDR_COUNTRY_EF           31026

static const CONTROLDEF
    AddressFieldsGroup = CONTROLDEF_GROUP(
                            "Address fields",
                            ID_XSDI_VCARD_ADDR_NAMEFIELDS_GROUP,
                            -1,
                            -1),
    TEXT_AND_ENTRYFIELD(AddressesPostOffice,
                        "Post office box:",
                        ID_XSDI_VCARD_ADDR_POBOX),
    TEXT_AND_ENTRYFIELD(AddressesExtended,
                        "Additional:",
                        ID_XSDI_VCARD_ADDR_EXTENDED),
    TEXT_AND_ENTRYFIELD(AddressesStreet,
                        "Street:",
                        ID_XSDI_VCARD_ADDR_STREET),
    TEXT_AND_ENTRYFIELD(AddressesLocality,
                        "Town:",
                        ID_XSDI_VCARD_ADDR_LOCALITY),
    TEXT_AND_ENTRYFIELD(AddressesState,
                        "State:",
                        ID_XSDI_VCARD_ADDR_STATE),
    TEXT_AND_ENTRYFIELD(AddressesPostalCode,
                        "Zip code:",
                        ID_XSDI_VCARD_ADDR_POSTALCODE),
    TEXT_AND_ENTRYFIELD(AddressesCountry,
                        "Country:",
                        ID_XSDI_VCARD_ADDR_COUNTRY);

static const DLGHITEM dlgAddresses[] =
    {
        START_TABLE,            // root table, required
            START_ROW(0),
                START_GROUP_TABLE(&AddressFieldsGroup),
                    START_ROW(0),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&AddressesExtendedText),
                           CONTROL_DEF(&AddressesExtendedEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&AddressesStreetText),
                           CONTROL_DEF(&AddressesStreetEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&AddressesPostOfficeText),
                           CONTROL_DEF(&AddressesPostOfficeEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&AddressesLocalityText),
                           CONTROL_DEF(&AddressesLocalityEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&AddressesStateText),
                           CONTROL_DEF(&AddressesStateEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&AddressesPostalCodeText),
                           CONTROL_DEF(&AddressesPostalCodeEF),
                        START_ROW(ROW_VALIGN_CENTER),
                           CONTROL_DEF(&AddressesCountryText),
                           CONTROL_DEF(&AddressesCountryEF),
                END_TABLE,
            START_ROW(0),
                CONTROL_DEF(&G_UndoButton),         // common.c
                CONTROL_DEF(&G_DefaultButton),      // common.c
                CONTROL_DEF(&G_HelpButton),         // common.c
        END_TABLE
    };

/*
 *@@ vcfAddressesInitPage:
 *
 */

STATIC VOID vcfAddressesInitPage(PNOTEBOOKPAGE pnbp,    // notebook info struct
                                 ULONG flFlags)                // CBI_* flags (notebook.h)
{
    if (flFlags & CBI_INIT)
    {
        ntbFormatPage(pnbp->hwndDlgPage,
                      dlgAddresses,
                      ARRAYITEMCOUNT(dlgAddresses));
    }

    if (flFlags & CBI_SET)
    {
        XWPVCardData *somThis = XWPVCardGetData(pnbp->inbp.somSelf);
        PVCARD      pvc;
        APIRET      arc = NO_ERROR;
        CHAR        sz[CCHMAXPATH];

        if (!_pvCard)
            if (_wpQueryFilename(pnbp->inbp.somSelf, sz, TRUE))
                arc = vcfRead(sz, (PVCARD*)&_pvCard);

        if (pvc = (PVCARD)_pvCard)
        {
            ULONG   aulIDs[] =
                {
                    ID_XSDI_VCARD_ADDR_POBOX_EF,
                    ID_XSDI_VCARD_ADDR_EXTENDED_EF,
                    ID_XSDI_VCARD_ADDR_STREET_EF,
                    ID_XSDI_VCARD_ADDR_LOCALITY_EF,
                    ID_XSDI_VCARD_ADDR_STATE_EF,
                    ID_XSDI_VCARD_ADDR_POSTALCODE_EF,
                    ID_XSDI_VCARD_ADDR_COUNTRY_EF
                },
                    ul;

            if (pvc->cDeliveryAddresses)
            {
                for (ul = 0;
                     ul < ARRAYITEMCOUNT(aulIDs);
                     ul++)
                {
                    SetEFText(pnbp,
                              aulIDs[ul],
                              (PSZ)pvc->paDeliveryAddresses[0].apcszAddress[ul]);
                }
            }
        }
    }
}

/* ******************************************************************
 *
 *   XWPVCard instance methods
 *
 ********************************************************************/

/*
 *@@ wpInitData:
 *
 */

SOM_Scope void  SOMLINK xvc_wpInitData(XWPVCard *somSelf)
{
    XWPVCardData *somThis = XWPVCardGetData(somSelf);
    XWPVCardMethodDebug("XWPVCard","xvc_wpInitData");

    XWPVCard_parent_WPDataFile_wpInitData(somSelf);

    _pvCard = NULL;
}

/*
 *@@ wpUnInitData:
 *      this WPObject instance method is called when the object
 *      is destroyed as a SOM object, either because it's being
 *      made dormant (via wpMakeDormant) or being deleted for
 *      good (via wpFree). All allocated in-memory resources
 *      should be freed here, but to destroy the physical
 *      representation of the object, override wpDestroyObject
 *      instead.
 *
 *      The parent method must always be called last.
 */

SOM_Scope void  SOMLINK xvc_wpUnInitData(XWPVCard *somSelf)
{
    XWPVCardData *somThis = XWPVCardGetData(somSelf);
    XWPVCardMethodDebug("XWPVCard","xvc_wpUnInitData");

    if (_pvCard)
        vcfFree((PVCARD*)&_pvCard);

    XWPVCard_parent_WPDataFile_wpUnInitData(somSelf);
}

/*
 *@@ wpFilterPopupMenu:
 *      this WPObject instance method allows the object to
 *      filter out unwanted menu items from the context menu.
 *      This gets called before wpModifyPopupMenu.
 *
 *      We call the parent (data file) method, which filters
 *      out the standard items according to the "Workplace
 *      Shell" settings, and then also remove print, which
 *      we do not support yet. @@todo
 *
 *@@added V0.9.19 (2002-06-15) [umoeller]
 */

SOM_Scope ULONG  SOMLINK xvc_wpFilterPopupMenu(XWPVCard *somSelf,
                                               ULONG ulFlags,
                                               HWND hwndCnr,
                                               BOOL fMultiSelect)
{
    XWPVCardData *somThis = XWPVCardGetData(somSelf);
    XWPVCardMethodDebug("XWPVCard","xvc_wpFilterPopupMenu");

    return XWPVCard_parent_WPDataFile_wpFilterPopupMenu(somSelf,
                                                        ulFlags,
                                                        hwndCnr,
                                                        fMultiSelect)
            & ~CTXT_PRINT;
}

/*
 *@@ wpAddSettingsPages:
 *      this WPObject instance method gets called by the WPS
 *      when the Settings view is opened to have all the
 *      settings page inserted into hwndNotebook. Override
 *      this method to add new settings pages to either the
 *      top or the bottom of notebooks of a given class.
 */

SOM_Scope BOOL  SOMLINK xvc_wpAddSettingsPages(XWPVCard *somSelf,
                                               HWND hwndNotebook)
{
    BOOL brc = FALSE;

    XWPVCardData *somThis = XWPVCardGetData(somSelf);
    XWPVCardMethodDebug("XWPVCard","xvc_wpAddSettingsPages");

    if (XWPVCard_parent_WPDataFile_wpAddSettingsPages(somSelf,
                                                      hwndNotebook))
    {
        TRY_LOUD(excpt1)
        {
            INSERTNOTEBOOKPAGE inbp;

            memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
            inbp.somSelf = somSelf;
            inbp.hwndNotebook = hwndNotebook;
            inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
            inbp.usPageStyleFlags = BKA_MAJOR;
            inbp.pcszName = "Addresses",    // @@todo
            inbp.ulDlgID = ID_XFD_EMPTYDLG;
            inbp.ulDefaultHelpPanel  = ID_XSH_VCARD_PAGE; // @@todo
            inbp.ulPageID = SP_VCARD_ADDRESSES;
            inbp.pfncbInitPage    = vcfAddressesInitPage;
            ntbInsertPage(&inbp);

            memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
            inbp.somSelf = somSelf;
            inbp.hwndNotebook = hwndNotebook;
            inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
            inbp.usPageStyleFlags = BKA_MAJOR;
            inbp.pcszName = "Phone numbers",    // @@todo
            inbp.ulDlgID = ID_XFD_EMPTYDLG;
            inbp.ulDefaultHelpPanel  = ID_XSH_VCARD_PAGE; // @@todo
            inbp.ulPageID = SP_VCARD_PHONE;
            inbp.pfncbInitPage    = vcfPhoneInitPage;
            inbp.pfncbItemChanged = vcfPhoneItemChanged;
            ntbInsertPage(&inbp);

            memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
            inbp.somSelf = somSelf;
            inbp.hwndNotebook = hwndNotebook;
            inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
            inbp.usPageStyleFlags = BKA_MAJOR;
            inbp.pcszName = "Name"; // @@todo
            inbp.ulDlgID = ID_XFD_EMPTYDLG;
            inbp.ulDefaultHelpPanel  = ID_XSH_VCARD_PAGE; // @@todo
            inbp.ulPageID = SP_VCARD_NAME;
            inbp.pfncbInitPage    = vcfNameInitPage;
            ntbInsertPage(&inbp);

            memset(&inbp, 0, sizeof(INSERTNOTEBOOKPAGE));
            inbp.somSelf = somSelf;
            inbp.hwndNotebook = hwndNotebook;
            inbp.hmod = cmnQueryNLSModuleHandle(FALSE);
            inbp.usPageStyleFlags = BKA_MAJOR;
            inbp.pcszName = "Summary",    // @@todo
            inbp.ulDlgID = ID_XFD_EMPTYDLG;
            inbp.ulDefaultHelpPanel  = ID_XSH_VCARD_PAGE; // @@todo
            inbp.ulPageID = SP_VCARD_SUMMARY;
            inbp.pfncbInitPage    = vcfSummaryInitPage;
            ntbInsertPage(&inbp);

            brc = TRUE;
        }
        CATCH(excpt1)
        {
        } END_CATCH();
    }

    return brc;
}

/*
 *@@ wpCreateFromTemplate:
 *
 */

SOM_Scope WPObject*  SOMLINK xvc_wpCreateFromTemplate(XWPVCard *somSelf,
                                                      WPFolder* folder,
                                                      BOOL fLock)
{
    WPObject *pNew;

    // XWPVCardData *somThis = XWPVCardGetData(somSelf);
    XWPVCardMethodDebug("XWPVCard","xvc_wpCreateFromTemplate");

    if (pNew = XWPVCard_parent_WPDataFile_wpCreateFromTemplate(somSelf,
                                                               folder,
                                                               fLock))
        _wpViewObject(pNew, NULLHANDLE, OPEN_SETTINGS, 0);

    return pNew;
}


/* ******************************************************************
 *
 *   XWPVCard class methods
 *
 ********************************************************************/

/*
 *@@ wpclsInitData:
 *      this M_WPObject class method gets called when a class
 *      is loaded by the WPS (probably from within a
 *      somFindClass call) and allows the class to initialize
 *      itself.
 *
 */

SOM_Scope void  SOMLINK xvcM_wpclsInitData(M_XWPVCard *somSelf)
{
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsInitData");

    M_XWPVCard_parent_M_WPDataFile_wpclsInitData(somSelf);

    krnClassInitialized(G_pcszXWPVCard);
}

/*
 *@@ wpclsCreateDefaultTemplates:
 *
 */

SOM_Scope BOOL  SOMLINK xvcM_wpclsCreateDefaultTemplates(M_XWPVCard *somSelf,
                                                         WPObject* Folder)
{
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsCreateDefaultTemplates");

    return M_XWPVCard_parent_M_WPDataFile_wpclsCreateDefaultTemplates(somSelf,
                                                                      Folder);
}

/*
 *@@ wpclsQueryTitle:
 *
 */

SOM_Scope PSZ  SOMLINK xvcM_wpclsQueryTitle(M_XWPVCard *somSelf)
{
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsQueryTitle");

    return "vCard";
}

/*
 *@@ wpclsQueryDefaultView:
 *      this M_WPObject class method returns the default view for
 *      objects of a class.
 *      The way this works is that WPObject::wpQueryDefaultView
 *      apparently checks for whether an instance default view
 *      has been set by the user. If not, this class method gets
 *      called.
 *
 *      We return OPEN_SETTINGS for the vCard. This will only work
 *      for *.vcf files that have not been previously opened,
 *      unfortunately, because the WPS resets data file default
 *      views to 0x1000 internally and stores that with the
 *      instance data, apparently.
 *
 *@@added V0.9.16 (2002-01-05) [umoeller]
 */

SOM_Scope ULONG  SOMLINK xvcM_wpclsQueryDefaultView(M_XWPVCard *somSelf)
{
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsQueryDefaultView");

    return OPEN_SETTINGS;
}

/*
 *@@ wpclsQueryDefaultHelp:
 *      this M_WPObject class method returns the default help
 *      panel for objects of this class. This gets called
 *      from WPObject::wpQueryDefaultHelp if no instance
 *      help settings (HELPLIBRARY, HELPPANEL) have been
 *      set for an individual object. It is thus recommended
 *      to override this method instead of the instance
 *      method to change the default help panel for a class
 *      in order not to break instance help settings (fixed
 *      with 0.9.20).
 *
 *      We override the default data file help and return
 *      help for vCard objects here.
 *
 *@@added V0.9.20 (2002-07-12) [umoeller]
 */

SOM_Scope BOOL  SOMLINK xvcM_wpclsQueryDefaultHelp(M_XWPVCard *somSelf,
                                                   PULONG pHelpPanelId,
                                                   PSZ pszHelpLibrary)
{
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsQueryDefaultHelp");

    strcpy(pszHelpLibrary, cmnQueryHelpLibrary());
    *pHelpPanelId = ID_XSH_VCARD_MAIN;
    return TRUE;
}

/*
 *@@ wpclsQueryIconData:
 *      this M_WPObject class method must return information
 *      about how to build the default icon for objects
 *      of a class. This gets called from various other
 *      methods whenever a class default icon is needed;
 *      most importantly, M_WPObject::wpclsQueryIcon
 *      calls this to build a class default icon, which
 *      is then cached in the class's instance data.
 *      If a subclass wants to change a class default icon,
 *      it should always override _this_ method instead of
 *      wpclsQueryIcon.
 *
 *      Note that the default WPS implementation does not
 *      allow for specifying the ICON_FILE format here,
 *      which is why we have overridden
 *      M_XFldObject::wpclsQueryIcon too. This allows us
 *      to return icon _files_ for theming too. For details
 *      about the WPS's crappy icon management, refer to
 *      src\filesys\icons.c.
 *
 */

SOM_Scope ULONG  SOMLINK xvcM_wpclsQueryIconData(M_XWPVCard *somSelf,
                                                 PICONINFO pIconInfo)
{
    HMODULE hmod;
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsQueryIconData");

    if (hmod = cmnQueryMainResModuleHandle())
    {
        if (pIconInfo)
        {
            pIconInfo->fFormat = ICON_RESOURCE;
            pIconInfo->hmod = hmod;
            pIconInfo->resid = ID_ICONXWPVCARD;
        }

        return sizeof(ICONINFO);
    }

    return M_XWPVCard_parent_M_WPDataFile_wpclsQueryIconData(somSelf,
                                                             pIconInfo);
}


/*
 *@@ wpclsQueryInstanceFilter:
 *      this M_WPFileSystem class method determines which file-system
 *      objects will be instances of a certain class according
 *      to a file filter.
 *
 *      We assign ourselves to "*.vcf" types here.
 */

SOM_Scope PSZ  SOMLINK xvcM_wpclsQueryInstanceFilter(M_XWPVCard *somSelf)
{
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsQueryInstanceFilter");

    return "*.vcf";
}

/*
 *@@ wpclsQueryInstanceType:
 *      this M_WPDataFile class method determines which file-system
 *      objects will be instances of a certain class according
 *      to a file type.
 *
 *      We assign ourselves to the "vCard" type here.
 *
 *@@added V0.9.16 (2002-01-05) [umoeller]
 */

SOM_Scope PSZ  SOMLINK xvcM_wpclsQueryInstanceType(M_XWPVCard *somSelf)
{
    /* M_XWPVCardData *somThis = M_XWPVCardGetData(somSelf); */
    M_XWPVCardMethodDebug("M_XWPVCard","xvcM_wpclsQueryInstanceType");

    return "vCard";
}

