mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 20:47:44 +00:00
492 lines
19 KiB
C
492 lines
19 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/* msgnet.h --- prototypes for API's between libmsg and libnet.
|
|
*/
|
|
|
|
#ifndef _MSGNET_H_
|
|
#define _MSGNET_H_
|
|
#include "msgcom.h"
|
|
|
|
XP_BEGIN_PROTOS
|
|
|
|
/* so libnet can mark expired articles as read. */
|
|
extern int MSG_MarkMessageKeyRead (MSG_Pane *pane, MessageKey key, const char *xref);
|
|
|
|
/* record imap message flags in the db of the current pane (message or thread panes) */
|
|
extern void MSG_RecordImapMessageFlags(MSG_Pane* pane,
|
|
MessageKey msgKey,
|
|
imapMessageFlagsType flags);
|
|
|
|
/* notify libmsg of deleted messages */
|
|
extern void MSG_ImapMsgsDeleted(MSG_Pane *urlPane,
|
|
const char *onlineMailboxName,
|
|
XP_Bool deleteAllMsgs,
|
|
const char *doomedKeyString);
|
|
|
|
/* called to setup state before a copy download */
|
|
extern void MSG_StartImapMessageToOfflineFolderDownload(MWContext* context);
|
|
|
|
/* notify libmsg that inbox filtering is complete */
|
|
extern void MSG_ImapInboxFilteringComplete(MSG_Pane *urlPane);
|
|
|
|
/* notify libmsg that the online/offline synch is complete */
|
|
extern void MSG_ImapOnOffLineSynchComplete(MSG_Pane *urlPane);
|
|
|
|
/* notify libmsg that an imap folder load was interrupted */
|
|
extern void MSG_InterruptImapFolderLoad(MSG_Pane *urlPane, const char *hostName, const char *onlineFolderPath);
|
|
|
|
/* find a reference or NULL to the specified imap folder */
|
|
extern MSG_FolderInfo* MSG_FindImapFolder(MSG_Pane *urlPane, const char *hostName, const char *onlineFolderPath);
|
|
|
|
/* If there is a cached connection, for this folder, uncache it and return it */
|
|
extern TNavigatorImapConnection* MSG_UnCacheImapConnection(MSG_Master* master, const char *host, const char *folderName);
|
|
|
|
/* Cache this connection and return TRUE if there is not one there already, else false */
|
|
extern XP_Bool MSG_TryToCacheImapConnection(MSG_Master* master, const char *host, const char *folderName, TNavigatorImapConnection *connection);
|
|
|
|
extern void MSG_SetIMAPMessageUID (MessageKey key,
|
|
void *state);
|
|
|
|
|
|
extern const char *MSG_GetMessageIdFromState (void *state);
|
|
extern XP_Bool MSG_IsSaveDraftDeliveryState (void *state);
|
|
|
|
extern void MSG_SetUserAuthenticated (MSG_Master* master, XP_Bool bAuthenticated);
|
|
|
|
extern XP_Bool MSG_IsUserAuthenticated (MSG_Master* master);
|
|
|
|
extern void MSG_SetMailAccountURL(MSG_Master* master, const char *urlString);
|
|
|
|
extern const char *MSG_GetMailAccountURL(MSG_Master* master);
|
|
|
|
extern void MSG_SetNewsgroupUsername(MSG_Pane* pane, const char *username);
|
|
extern const char *MSG_GetNewsgroupUsername(MSG_Pane *pane);
|
|
|
|
extern void MSG_SetNewsgroupPassword(MSG_Pane* pane, const char *password);
|
|
extern const char *MSG_GetNewsgroupPassword(MSG_Pane *pane);
|
|
|
|
extern const char* MSG_GetPopHost(MSG_Prefs* prefs);
|
|
|
|
extern XP_Bool MSG_GetUseSSLForIMAP4(MSG_Pane *pane);
|
|
extern int32 MSG_GetIMAPSSLPort(MSG_Pane *pane);
|
|
|
|
/* called from libnet to clean up state from mailbox:copymessages */
|
|
extern void MSG_MessageCopyIsCompleted (struct MessageCopyInfo**);
|
|
|
|
/* called from libnet to determine if the current copy is finished */
|
|
extern XP_Bool MSG_IsMessageCopyFinished(struct MessageCopyInfo*);
|
|
|
|
/* called from mailbox and url libnet modules */
|
|
extern
|
|
int MSG_BeginCopyingMessages(MWContext *context);
|
|
|
|
extern
|
|
int MSG_FinishCopyingMessages(MWContext *context);
|
|
|
|
extern const char *MSG_GetIMAPHostUsername(MSG_Master *master, const char *hostName);
|
|
extern const char *MSG_GetIMAPHostPassword(MSG_Master *master, const char *hostName);
|
|
extern void MSG_SetIMAPHostPassword(MSG_Master *master, const char *hostName, const char *password);
|
|
extern int MSG_GetIMAPHostIsUsingSubscription(MSG_Master *master, const char *hostName, XP_Bool *usingSubscription);
|
|
extern XP_Bool MSG_GetIMAPHostDeleteIsMoveToTrash(MSG_Master *master, const char *hostName);
|
|
extern int IMAP_AddIMAPHost(const char *hostName, XP_Bool usingSubscription, XP_Bool overrideNamespaces,
|
|
const char *personalNamespacePrefix, const char *publicNamespacePrefixes, const char *otherUsersNamespacePrefixes);
|
|
|
|
typedef enum
|
|
{ MSG_NotRunning = 0x00000000
|
|
, MSG_RunningOnline = 0x00000001
|
|
, MSG_RunningOffline = 0x00000002
|
|
} MSG_RunningState;
|
|
|
|
extern MSG_FolderInfo *MSG_SetFolderRunningIMAPUrl(MSG_Pane *urlPane, const char *hostName, const char *onlineFolderPath, MSG_RunningState runningState);
|
|
extern void MSG_IMAPUrlFinished(MSG_FolderInfo *folder, URL_Struct *URL_s);
|
|
|
|
/* ===========================================================================
|
|
OFFLINE IMAP
|
|
===========================================================================
|
|
*/
|
|
|
|
extern uint32 MSG_GetImapMessageFlags(MSG_Pane *urlPane,
|
|
const char *hostName,
|
|
const char *onlineBoxName,
|
|
uint32 key);
|
|
|
|
extern void MSG_StartOfflineImapRetrieval(MSG_Pane *urlPane,
|
|
const char *hostName,
|
|
const char *onlineBoxName,
|
|
uint32 key,
|
|
void **offLineRetrievalData);
|
|
|
|
extern uint32 MSG_GetOfflineMessageSize(void *offLineRetrievalData);
|
|
|
|
extern int MSG_ProcessOfflineImap(void *offLineRetrievalData, char *socketBuffer, uint32 read_size);
|
|
|
|
extern int MSG_InterruptOfflineImap(void *offLineRetrievalData);
|
|
|
|
extern void MSG_GetNextURL(MSG_Pane *pane);
|
|
|
|
/* Returns the original pane that a progress pane was associated with. If
|
|
the given pane is not a progresspane, returns NULL. */
|
|
extern MSG_Pane* MSG_GetParentPane(MSG_Pane* progresspane);
|
|
|
|
/* do an imap biff of the imap inbox */
|
|
extern void MSG_ImapBiff(MWContext* context, MSG_Prefs* prefs);
|
|
|
|
/* The NNTP module of netlib calls these to feed XOVER data to the message
|
|
library, in response to a news:group.name URL having been opened.
|
|
If MSG_FinishXOVER() returns a message ID, that message will be loaded
|
|
next (used for selecting the first unread message in a group after
|
|
listing that group.)
|
|
|
|
The "out" arguments are (if non-NULL) a file descriptor to write the XOVER
|
|
line to, followed by a "\n". This is used by the XOVER-caching code.
|
|
*/
|
|
extern int MSG_InitXOVER (MSG_Pane* pane,
|
|
MSG_NewsHost* host,
|
|
const char* group_name,
|
|
uint32 first_msg, uint32 last_msg,
|
|
uint32 oldest_msg, uint32 youngest_msg,
|
|
void **data);
|
|
extern int MSG_ProcessXOVER (MSG_Pane* pane, char *line, void **data);
|
|
extern int MSG_ProcessNonXOVER (MSG_Pane* pane, char *line, void **data);
|
|
extern int MSG_FinishXOVER (MSG_Pane* pane, void **data, int status);
|
|
|
|
/* In case of XOVER failed due to the authentication process, we need to
|
|
do some clean up. So that we could have a fresh start once we pass the
|
|
authentication check.
|
|
*/
|
|
extern int MSG_ResetXOVER (MSG_Pane* pane, void **data);
|
|
|
|
|
|
/* These calls are used by libnet to determine which articles it ought to
|
|
get in a big newsgroup. */
|
|
|
|
extern int
|
|
MSG_GetRangeOfArtsToDownload(MSG_Pane* pane, void** data, MSG_NewsHost* host,
|
|
const char* group_name,
|
|
int32 first_possible, /* Oldest article available
|
|
from newsserver*/
|
|
int32 last_possible, /* Newest article available
|
|
from newsserver*/
|
|
int32 maxextra,
|
|
int32* first,
|
|
int32* last);
|
|
|
|
|
|
extern int
|
|
MSG_AddToKnownArticles(MSG_Pane *pane, MSG_NewsHost* host,
|
|
const char* groupname, int32 first, int32 last);
|
|
|
|
extern int MSG_InitAddArticleKeyToGroup(MSG_Pane *pane, MSG_NewsHost* host,
|
|
const char* groupName, void **parseState);
|
|
|
|
extern int MSG_AddArticleKeyToGroup(void *parse_state, int32 first);
|
|
|
|
extern int MSG_FinishAddArticleKeyToGroup(MSG_Pane *pane, void **parse_state);
|
|
|
|
/* After displaying a list of newsgroups, we need the NNTP module to go and
|
|
run "GROUP" commands for the ones for which we don't know the unread
|
|
article count. This function returns a count of how many groups we think
|
|
we're going to need this for (so we can display progress in a reasonable
|
|
way).
|
|
*/
|
|
extern int32 MSG_GetNewsRCCount(MSG_Pane* pane, MSG_NewsHost* host);
|
|
|
|
/* Gets the name of the next group that we want to get article counts for.
|
|
The caller must free the given name using XP_FREE().
|
|
MSG_DisplaySubscribedGroup() should get called with this group before
|
|
this call happens again. */
|
|
|
|
extern char* MSG_GetNewsRCGroup(MSG_Pane* pane, MSG_NewsHost* host);
|
|
|
|
|
|
|
|
/* In response to a "news://host/" URL; this is called once for each group
|
|
that was returned by MSG_GetNewsRCGroup(), after the NNTP GROUP command has
|
|
been run. It's also called whenever we actually visit the group (the user
|
|
clicks on the newsgroup line), in case the data has changed since the
|
|
initial passthrough. The "nowvisiting" parameter is TRUE in the latter
|
|
case, FALSE otherwise. */
|
|
extern int MSG_DisplaySubscribedGroup(MSG_Pane* pane,
|
|
MSG_NewsHost* host,
|
|
const char *group,
|
|
int32 oldest_message,
|
|
int32 youngest_message,
|
|
int32 total_messages,
|
|
XP_Bool nowvisiting);
|
|
|
|
/* In response to an NNTP GROUP command, the server said the group doesn't exist */
|
|
extern int MSG_GroupNotFound(MSG_Pane* pane,
|
|
MSG_NewsHost* host,
|
|
const char *group,
|
|
XP_Bool opening);
|
|
|
|
/* In response to a "news://host/?newgroups" URL, to ask the server for a
|
|
list of recently-added newsgroups. Similar to MSG_DisplaySubscribedGroup,
|
|
except that in this case, the group is not already in the list. */
|
|
extern int MSG_DisplayNewNewsGroup (MWContext *context,
|
|
MSG_NewsHost* host, const char *group_name,
|
|
int32 oldest_message,
|
|
int32 youngest_message);
|
|
|
|
|
|
/* News servers work better if you ask for message numbers instead of IDs.
|
|
So, the NNTP module asks us what the group and number of an ID is with
|
|
this. If we don't know, we return 0 for both. If the pane is not a
|
|
thead or message pane, this routine will fail.
|
|
*/
|
|
extern void MSG_NewsGroupAndNumberOfID (MSG_Pane *pane,
|
|
const char *message_id,
|
|
const char **group_return,
|
|
uint32 *message_number_return);
|
|
|
|
/* This routine is used by netlib to see if we have this article off-line
|
|
It might be combined with the above routine, but I'm not sure if this
|
|
is the way we're ultimately going to do this.
|
|
*/
|
|
extern XP_Bool MSG_IsOfflineArticle (MSG_Pane *pane,
|
|
const char *message_id,
|
|
const char **group_return,
|
|
uint32 *message_number_return);
|
|
|
|
extern int MSG_StartOfflineRetrieval(MSG_Pane *pane,
|
|
const char *group,
|
|
uint32 message_number,
|
|
void **offlineState);
|
|
|
|
extern int MSG_ProcessOfflineNews(void *offlineState, char *outputBuffer, int outputBufSize);
|
|
|
|
extern int MSG_InterruptOfflineNews(void *offlineState);
|
|
|
|
/* libnet callbacks for Dredd NNTP extensions */
|
|
|
|
extern void MSG_SupportsNewsExtensions (MSG_NewsHost *host, XP_Bool supports);
|
|
extern void MSG_AddNewsExtension (MSG_NewsHost *host, const char *ext);
|
|
extern XP_Bool MSG_QueryNewsExtension (MSG_NewsHost *host, const char *ext);
|
|
extern XP_Bool MSG_NeedsNewsExtension (MSG_NewsHost *host, const char *ext);
|
|
|
|
extern void MSG_AddSearchableGroup (MSG_NewsHost *host, const char *group);
|
|
extern void MSG_AddSearchableHeader (MSG_NewsHost *host, const char *header);
|
|
extern int MSG_AddProfileGroup (MSG_Pane *pane,
|
|
MSG_NewsHost* host,
|
|
const char *groupName);
|
|
|
|
extern int MSG_AddPrettyName(MSG_NewsHost* host,
|
|
const char *groupName, const char *prettyName);
|
|
|
|
extern int MSG_SetXActiveFlags(MSG_Pane *pane, char *groupName,
|
|
int32 firstPossibleArt,
|
|
int32 lastPossibleArt,
|
|
char *flags);
|
|
|
|
extern int MSG_AddSubscribedGroup (MSG_Pane *pane, const char *groupUrl);
|
|
|
|
extern void MSG_AddPropertyForGet (MSG_NewsHost *host, const char *property,
|
|
const char *value);
|
|
|
|
/* libnet calls this if it got an error 441 back from the newsserver. That
|
|
error almost certainly means that the newsserver already has a message
|
|
with the same message id. If this routine returns TRUE, then we were
|
|
pretty much expecting that error code, because we know we tried twice to
|
|
post the same message, and we can just ignore it. */
|
|
extern XP_Bool MSG_IsDuplicatePost(MSG_Pane* comppane);
|
|
|
|
|
|
/* libnet uses this on an error condition to tell libmsg to generate a new
|
|
message-id for the given composition. */
|
|
extern void MSG_ClearCompositionMessageID(MSG_Pane* comppane);
|
|
|
|
|
|
/* libnet uses this to determine the message-id for the given composition (so
|
|
it can test if this message was already posted.) */
|
|
extern const char* MSG_GetCompositionMessageID(MSG_Pane* comppane);
|
|
|
|
/* The "news:" and "mailbox:" protocol handlers call this when a message is
|
|
displayed, so that we can use the contents of the headers when composing
|
|
replies.
|
|
*/
|
|
extern void
|
|
MSG_ActivateReplyOptions(MSG_Pane* messagepane, MimeHeaders *headers);
|
|
|
|
/* Tell the subscribe pane about a new newsgroup we noticed. */
|
|
|
|
extern int
|
|
MSG_AddNewNewsGroup(MSG_Pane* pane, MSG_NewsHost* host,
|
|
const char* groupname, int32 oldest, int32 youngest,
|
|
const char *flag, XP_Bool bXactiveFlags);
|
|
|
|
/* tell the host info database that we're going to need to get the extra info
|
|
for this new newsgroup
|
|
*/
|
|
extern int MSG_SetGroupNeedsExtraInfo(MSG_NewsHost *host,
|
|
const char* groupname, XP_Bool needsExtra);
|
|
|
|
/* returns the name of the first group which needs extra info */
|
|
extern char *MSG_GetFirstGroupNeedingExtraInfo(MSG_NewsHost *host);
|
|
|
|
/* Find out from libmsg when we last checked for new newsgroups (so we know
|
|
what date to give the "newgroups" command.) */
|
|
|
|
extern time_t
|
|
MSG_NewsgroupsLastUpdatedTime(MSG_NewsHost* host);
|
|
|
|
|
|
|
|
/* The "mailbox:" protocol module uses these routines to invoke the mailbox
|
|
parser in libmsg.
|
|
*/
|
|
extern int MSG_BeginOpenFolderSock (MSG_Pane* pane,
|
|
const char *folder_name,
|
|
const char *message_id, int32 msgnum,
|
|
void **folder_ptr);
|
|
extern int MSG_FinishOpenFolderSock (MSG_Pane* pane,
|
|
const char *folder_name,
|
|
const char *message_id, int32 msgnum,
|
|
void **folder_ptr);
|
|
extern void MSG_CloseFolderSock (MSG_Pane* pane, const char *folder_name,
|
|
const char *message_id, int32 msgnum,
|
|
void *folder_ptr);
|
|
extern int MSG_OpenMessageSock (MSG_Pane* messagepane, const char *folder_name,
|
|
const char *msg_id, int32 msgnum,
|
|
void *folder_ptr, void **message_ptr,
|
|
int32 *content_length);
|
|
extern int MSG_ReadMessageSock (MSG_Pane* messagepane, const char *folder_name,
|
|
void *message_ptr, const char *message_id,
|
|
int32 msgnum, char *buffer, int32 buffer_size);
|
|
extern void MSG_CloseMessageSock (MSG_Pane* messagepane,
|
|
const char *folder_name,
|
|
const char *message_id, int32 msgnum,
|
|
void *message_ptr);
|
|
extern void MSG_PrepareToIncUIDL(MSG_Pane* messagepane, URL_Struct* url,
|
|
const char* uidl);
|
|
|
|
/* This is how "mailbox:?empty-trash" works
|
|
*/
|
|
extern int MSG_BeginEmptyTrash(MSG_Pane* folderpane, URL_Struct* url,
|
|
void** closure);
|
|
extern int MSG_FinishEmptyTrash(MSG_Pane* folderpane, URL_Struct* url,
|
|
void* closure);
|
|
extern int MSG_CloseEmptyTrashSock(MSG_Pane* folderpane, URL_Struct* url,
|
|
void* closure);
|
|
|
|
/* This is how "mailbox:?compress-folder" and
|
|
"mailbox:/foo/baz/nsmail/inbox?compress-folder" works. */
|
|
|
|
extern int MSG_BeginCompressFolder(MSG_Pane* pane, URL_Struct* url,
|
|
const char* foldername, void** closure);
|
|
extern int MSG_FinishCompressFolder(MSG_Pane* pane, URL_Struct* url,
|
|
const char* foldername, void* closure);
|
|
extern int MSG_CloseCompressFolderSock(MSG_Pane* pane, URL_Struct* url,
|
|
void* closure);
|
|
/* This is how "mailbox:?deliver-queued" works
|
|
*/
|
|
extern int MSG_BeginDeliverQueued(MSG_Pane* pane, URL_Struct* url,
|
|
void** closure);
|
|
extern int MSG_FinishDeliverQueued(MSG_Pane* pane, URL_Struct* url,
|
|
void* closure);
|
|
extern int MSG_CloseDeliverQueuedSock(MSG_Pane* pane, URL_Struct* url,
|
|
void* closure);
|
|
|
|
/* This is how "mailbox:?background" works */
|
|
extern int MSG_ProcessBackground(URL_Struct* urlstruct);
|
|
|
|
/* libnet --> libmsg glue for newsgroup searching */
|
|
extern void MSG_AddNewsXpatHit (MWContext *context, uint32 artNum);
|
|
extern void MSG_AddNewsSearchHit (MWContext *context, const char *resultLine);
|
|
|
|
/* libnet --> libmsg glue for imap mail folder searching */
|
|
extern void MSG_AddImapSearchHit (MWContext *context, const char *resultLine);
|
|
/* The POP3 protocol module uses these routines to hand us new messages.
|
|
*/
|
|
extern XP_Bool MSG_BeginMailDelivery (MSG_Pane* folderpane);
|
|
extern void MSG_AbortMailDelivery (MSG_Pane* folderpane);
|
|
extern void MSG_EndMailDelivery (MSG_Pane* folderpane);
|
|
extern void *MSG_IncorporateBegin (MSG_Pane* folderpane,
|
|
FO_Present_Types format_out,
|
|
char *pop3_uidl,
|
|
URL_Struct *url,
|
|
uint32 flags);
|
|
extern int MSG_IncorporateWrite (MSG_Pane* folderpane, void *closure,
|
|
const char *block, int32 length);
|
|
extern int MSG_IncorporateComplete(MSG_Pane* folderpane, void *closure);
|
|
extern int MSG_IncorporateAbort (MSG_Pane* folderpane, void *closure,
|
|
int status);
|
|
extern void MSG_ClearSenderAuthedFlag(MSG_Pane* folderpane, void *closure);
|
|
|
|
|
|
|
|
|
|
/* This is how the netlib registers the converters relevant to MIME message
|
|
display and composition.
|
|
*/
|
|
void MSG_RegisterConverters (void);
|
|
|
|
extern void
|
|
MSG_StartMessageDelivery (MSG_Pane *pane,
|
|
void *fe_data,
|
|
MSG_CompositionFields *fields,
|
|
XP_Bool digest_p,
|
|
XP_Bool dont_deliver_p,
|
|
const char *attachment1_type,
|
|
const char *attachment1_body,
|
|
uint32 attachment1_body_length,
|
|
const struct MSG_AttachmentData *attachments,
|
|
void *mimeRelatedPart, /* only used in compose pane */
|
|
void (*message_delivery_done_callback)
|
|
(MWContext *context,
|
|
void *fe_data,
|
|
int status,
|
|
const char *error_message));
|
|
|
|
/* When a message which has the `partial' bit set, meaning we only downloaded
|
|
the first 20 lines because it was huge, this function will be called to
|
|
return some HTML to tack onto the end of the message to explain that it
|
|
is truncated, and provide a clickable link which will download the whole
|
|
message.
|
|
*/
|
|
extern char *MSG_GeneratePartialMessageBlurb (MSG_Pane* messagepane,
|
|
URL_Struct *url, void *closure,
|
|
MimeHeaders *headers);
|
|
|
|
|
|
extern int MSG_GetUrlQueueSize (const char *url, MWContext *context);
|
|
|
|
extern XP_Bool MSG_RequestForReturnReceipt(MSG_Pane* pane);
|
|
extern XP_Bool MSG_SendingMDNInProgress(MSG_Pane* pane);
|
|
|
|
extern uint32 MSG_GetIMAPMessageSizeFromDB(MSG_Pane *masterPane, const char *hostName, char *folderName, char *id, XP_Bool idIsUid);
|
|
|
|
extern void MSG_RefreshFoldersForUpdatedIMAPHosts(MWContext *context);
|
|
|
|
extern XP_Bool MSG_MailCheck(MWContext *context, MSG_Prefs *prefs);
|
|
|
|
extern void MSG_Pop3MailCheck(MWContext *context);
|
|
|
|
extern int NET_parse_news_url (const char *url,
|
|
char **host_and_portP,
|
|
XP_Bool *securepP,
|
|
char **groupP,
|
|
char **message_idP,
|
|
char **command_specific_dataP);
|
|
|
|
extern char *MSG_GetArbitraryHeadersForHost(MSG_Master *master, const char *hostName);
|
|
|
|
XP_END_PROTOS
|
|
|
|
|
|
#endif
|