982 lines
20 KiB
C++
982 lines
20 KiB
C++
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
session.cxx
|
|
|
|
Abstract:
|
|
|
|
Contains functions for maintaining the global session list and SESSION_INFO
|
|
specific functions
|
|
|
|
Contents:
|
|
AcquireSessionLock
|
|
ReleaseSessionLock
|
|
CleanupSessions
|
|
(CleanupViewList)
|
|
FindOrCreateSession
|
|
(CreateSession)
|
|
(DestroySession)
|
|
ReferenceSession
|
|
DereferenceSession
|
|
AcquireViewLock
|
|
ReleaseViewLock
|
|
GopherTransaction
|
|
IsServerGopherPlus
|
|
IsGopherPlusSession
|
|
SearchSessionsForAttribute
|
|
|
|
Author:
|
|
|
|
Richard L Firth (rfirth) 19-Oct-1994
|
|
|
|
Environment:
|
|
|
|
Win32 DLL
|
|
|
|
Revision History:
|
|
|
|
19-Oct-1994 rfirth
|
|
Created
|
|
|
|
--*/
|
|
|
|
#include <wininetp.h>
|
|
#include "gfrapih.h"
|
|
|
|
|
|
// manifests
|
|
|
|
|
|
#define NULL_HANDLE ((HANDLE)0)
|
|
|
|
|
|
// private prototypes
|
|
|
|
|
|
PRIVATE
|
|
VOID
|
|
CleanupViewList(
|
|
IN LPSESSION_INFO SessionInfo,
|
|
IN VIEW_TYPE ViewType
|
|
);
|
|
|
|
PRIVATE
|
|
LPSESSION_INFO
|
|
CreateSession(
|
|
IN LPSTR Host,
|
|
IN DWORD Port,
|
|
OUT LPDWORD Error
|
|
);
|
|
|
|
PRIVATE
|
|
VOID
|
|
DestroySession(
|
|
IN LPSESSION_INFO SessionInfo
|
|
);
|
|
|
|
|
|
// data
|
|
|
|
|
|
PUBLIC SERIALIZED_LIST SessionList;
|
|
|
|
DEBUG_DATA(LONG, NumberOfSessions, 0);
|
|
|
|
|
|
// functions
|
|
|
|
|
|
|
|
VOID
|
|
AcquireSessionLock(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Acquires the SESSION_INFO list lock
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LockSerializedList(&SessionList);
|
|
}
|
|
|
|
|
|
VOID
|
|
ReleaseSessionLock(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Releases the SESSION_INFO list lock
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
UnlockSerializedList(&SessionList);
|
|
}
|
|
|
|
|
|
VOID
|
|
CleanupSessions(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tries to Remove all SESSION_INFOs from the session list, and terminate all
|
|
active operations
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
None,
|
|
"CleanupSessions",
|
|
NULL
|
|
));
|
|
|
|
while (1) {
|
|
|
|
LPSESSION_INFO sessionInfo;
|
|
|
|
//
|
|
// find the next SESSION_INFO to delete. Because we may cause the entry
|
|
// currently at the head of the list to be deleted during this loop, we
|
|
// must walk the list each time. We may also end up with a list of items
|
|
// that are marked for delete, but cannot be deleted until the threads
|
|
// that own them complete their current operations
|
|
//
|
|
|
|
AcquireSessionLock();
|
|
|
|
for (sessionInfo = (LPSESSION_INFO)HeadOfSerializedList(&SessionList);
|
|
(sessionInfo != (LPSESSION_INFO)&SessionList.List.Flink)
|
|
&& !(sessionInfo->Flags & SI_CLEANUP);
|
|
sessionInfo = (LPSESSION_INFO)sessionInfo->List.Flink) {
|
|
|
|
//
|
|
// empty loop
|
|
//
|
|
|
|
}
|
|
if (sessionInfo == (LPSESSION_INFO)&SessionList.List.Flink) {
|
|
|
|
DEBUG_PRINT(SESSION,
|
|
INFO,
|
|
("end of list\n"
|
|
));
|
|
|
|
ReleaseSessionLock();
|
|
break;
|
|
}
|
|
|
|
//
|
|
// mark this SESSION_INFO as being cleaned up, in case it does not get
|
|
// removed from the list (some other thread is accessing it)
|
|
//
|
|
|
|
sessionInfo->Flags |= SI_CLEANUP;
|
|
|
|
//
|
|
// increment the reference count so that we can release the list lock
|
|
//
|
|
|
|
ReferenceSession(sessionInfo);
|
|
ReleaseSessionLock();
|
|
|
|
//
|
|
// now we have a pointer to a SESSION_INFO that cannot be deleted until
|
|
// after we have dereferenced it. Dereference any items in the Find and
|
|
// File lists. Note that had we not referenced the SESSION_INFO above,
|
|
// it might have gotten deleted after cleaning up the Find list, and we
|
|
// would be in danger of passing a bogus pointer to the second cleanup
|
|
// view list call below
|
|
//
|
|
|
|
CleanupViewList(sessionInfo, ViewTypeFind);
|
|
CleanupViewList(sessionInfo, ViewTypeFile);
|
|
|
|
//
|
|
// finally, dereference the session. This may cause it to be deleted,
|
|
// and for the list to be changed
|
|
//
|
|
|
|
DereferenceSession(sessionInfo);
|
|
}
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
PRIVATE
|
|
VOID
|
|
CleanupViewList(
|
|
IN LPSESSION_INFO SessionInfo,
|
|
IN VIEW_TYPE ViewType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans up a VIEW_INFO list on a SESSION_INFO
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO we are cleaning up
|
|
|
|
ViewType - identifies which VIEW_INFO list to clean up
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
None,
|
|
"CleanupViewList",
|
|
"%x, %x",
|
|
SessionInfo,
|
|
ViewType
|
|
));
|
|
|
|
//
|
|
// walk this VIEW_INFO list trying to delete everything by dereferencing
|
|
//
|
|
|
|
while (1) {
|
|
|
|
LPSERIALIZED_LIST viewList;
|
|
LPVIEW_INFO viewInfo;
|
|
HINTERNET handle;
|
|
|
|
AcquireViewLock(SessionInfo, ViewType);
|
|
|
|
viewList = &SessionInfo->FindList;
|
|
for (viewInfo = (LPVIEW_INFO)HeadOfSerializedList(viewList);
|
|
(viewInfo != (LPVIEW_INFO)&viewList->List.Flink)
|
|
&& !(viewInfo->Flags & VI_CLEANUP);
|
|
viewInfo = (LPVIEW_INFO)viewInfo->List.Flink) {
|
|
|
|
//
|
|
// empty loop
|
|
//
|
|
|
|
}
|
|
|
|
if (viewInfo == (LPVIEW_INFO)&viewList->List.Flink) {
|
|
|
|
DEBUG_PRINT(SESSION,
|
|
INFO,
|
|
("end of list\n"
|
|
));
|
|
|
|
ReleaseViewLock(SessionInfo, ViewType);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// mark this VIEW_INFO as being cleaned-up, so we don't hit it again if
|
|
// we don't delete it from the list this time
|
|
//
|
|
|
|
viewInfo->Flags |= VI_CLEANUP;
|
|
|
|
//
|
|
// safe to release the view lock
|
|
//
|
|
|
|
ReleaseViewLock(SessionInfo, ViewType);
|
|
|
|
//
|
|
// now dereference the VIEW_INFO. This may destroy it, but cannot
|
|
// destroy the SESSION_INFO, since we added an extra reference in
|
|
// CleanupSessions()
|
|
//
|
|
|
|
DereferenceView(viewInfo);
|
|
}
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
LPSESSION_INFO
|
|
FindOrCreateSession(
|
|
IN LPSTR Host,
|
|
IN DWORD Port,
|
|
OUT LPDWORD Error
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locates a SESSION_INFO that contains (Host, Port), or creates a new
|
|
SESSION_INFO
|
|
|
|
BUGBUG - need to do the following:
|
|
|
|
resolve the host name
|
|
find host by name/port or address/port
|
|
|
|
Arguments:
|
|
|
|
Host - pointer to host name where gopher server lives
|
|
|
|
Port - port at which gopher server listens
|
|
|
|
Error - place to return error
|
|
|
|
Return Value:
|
|
|
|
LPSESSION_INFO
|
|
Success - pointer to session info. Created contains TRUE if we created
|
|
the SESSION_INFO, else FALSE
|
|
|
|
Failure - NULL
|
|
Error contains reason for failure
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSESSION_INFO sessionInfo;
|
|
BOOL found;
|
|
|
|
AcquireSessionLock();
|
|
|
|
found = FALSE;
|
|
for (sessionInfo = (LPSESSION_INFO)SessionList.List.Flink;
|
|
sessionInfo != (LPSESSION_INFO)&SessionList.List;
|
|
sessionInfo = (LPSESSION_INFO)(sessionInfo->List.Flink)) {
|
|
|
|
if (!stricmp(sessionInfo->Host, Host) && (sessionInfo->Port == Port)) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
sessionInfo = CreateSession(Host, Port, Error);
|
|
if (sessionInfo != NULL) {
|
|
InsertAtHeadOfSerializedList(&SessionList, &sessionInfo->List);
|
|
}
|
|
}
|
|
if (sessionInfo != NULL) {
|
|
|
|
//
|
|
// the reference count will be at least 2
|
|
//
|
|
|
|
ReferenceSession(sessionInfo);
|
|
}
|
|
|
|
ReleaseSessionLock();
|
|
|
|
return sessionInfo;
|
|
}
|
|
|
|
|
|
PRIVATE
|
|
LPSESSION_INFO
|
|
CreateSession(
|
|
IN LPSTR Host,
|
|
IN DWORD Port,
|
|
OUT LPDWORD Error
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates and initializes a SESSION_INFO 'object'
|
|
|
|
Arguments:
|
|
|
|
Host - pointer to host name/ip address
|
|
|
|
Port - host port
|
|
|
|
Error - place to return reason for failure
|
|
|
|
Return Value:
|
|
|
|
LPSESSION_INFO
|
|
Success - pointer to initialized session info
|
|
|
|
Failure - NULL
|
|
Error contains reason for failure
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSESSION_INFO sessionInfo;
|
|
LPSTR hostName = NULL;
|
|
DWORD error;
|
|
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
Pointer,
|
|
"CreateSession",
|
|
"%q, %d, %x",
|
|
Host,
|
|
Port,
|
|
Error
|
|
));
|
|
|
|
sessionInfo = NEW(SESSION_INFO);
|
|
if (sessionInfo != NULL) {
|
|
hostName = NEW_STRING(Host);
|
|
if (hostName != NULL) {
|
|
error = AllocateHandle((LPVOID)sessionInfo, &sessionInfo->Handle);
|
|
if (error == ERROR_SUCCESS) {
|
|
|
|
InitializeListHead(&sessionInfo->List);
|
|
sessionInfo->Host = hostName;
|
|
sessionInfo->Port = Port;
|
|
InitializeSerializedList(&sessionInfo->FindList);
|
|
InitializeSerializedList(&sessionInfo->FileList);
|
|
|
|
SESSION_CREATED();
|
|
|
|
}
|
|
} else {
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
} else {
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
if (error != ERROR_SUCCESS) {
|
|
if (hostName != NULL) {
|
|
DEL_STRING(hostName);
|
|
}
|
|
if (sessionInfo != NULL) {
|
|
DEL(sessionInfo);
|
|
}
|
|
sessionInfo = NULL;
|
|
}
|
|
|
|
DEBUG_ERROR(SESSION, error);
|
|
|
|
*Error = error;
|
|
|
|
DEBUG_LEAVE(sessionInfo);
|
|
|
|
return sessionInfo;
|
|
}
|
|
|
|
|
|
PRIVATE
|
|
VOID
|
|
DestroySession(
|
|
IN LPSESSION_INFO SessionInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opposite of CreateSession - removes a SESSION_INFO from SessionList and
|
|
frees all resources owned by the SESSION_INFO and finally frees the memory
|
|
|
|
Assumes: 1. SessionListLock is held
|
|
2. SessionInfo is not on any lists
|
|
3. The SERIALIZED_LISTs have already been created
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO to delete
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER((DBG_GOPHER,
|
|
None,
|
|
"DestroySession",
|
|
"%x",
|
|
SessionInfo
|
|
));
|
|
|
|
INET_DEBUG_ASSERT(SessionInfo->List.Flink == NULL);
|
|
INET_DEBUG_ASSERT(SessionInfo->List.Blink == NULL);
|
|
INET_ASSERT(SessionInfo->ReferenceCount == 0);
|
|
INET_ASSERT(IsSerializedListEmpty(&SessionInfo->FindList));
|
|
INET_DEBUG_ASSERT(!IsLockHeld(&SessionInfo->FindList));
|
|
INET_ASSERT(IsSerializedListEmpty(&SessionInfo->FileList));
|
|
INET_DEBUG_ASSERT(!IsLockHeld(&SessionInfo->FileList));
|
|
|
|
if (SessionInfo->Handle) {
|
|
FreeHandle(SessionInfo->Handle);
|
|
}
|
|
|
|
if (SessionInfo->Host != NULL) {
|
|
DEL(SessionInfo->Host);
|
|
}
|
|
|
|
TerminateSerializedList(&SessionInfo->FindList);
|
|
TerminateSerializedList(&SessionInfo->FileList);
|
|
|
|
DEL(SessionInfo);
|
|
|
|
SESSION_DESTROYED();
|
|
|
|
DEBUG_LEAVE(0);
|
|
}
|
|
|
|
|
|
VOID
|
|
ReferenceSession(
|
|
IN LPSESSION_INFO SessionInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Increases the reference count of a SESSION_INFO
|
|
|
|
Arguments:
|
|
|
|
Session - pointer to SESSION_INFO to reference
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
INET_ASSERT(SessionInfo != NULL);
|
|
|
|
InterlockedIncrement(&SessionInfo->ReferenceCount);
|
|
}
|
|
|
|
|
|
LPSESSION_INFO
|
|
DereferenceSession(
|
|
IN LPSESSION_INFO SessionInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reduces the reference count of a SESSION_INFO. If it goes to zero, the
|
|
SESSION_INFO is removed from the SessionList and is deallocated
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO to dereference
|
|
|
|
Return Value:
|
|
|
|
LPSESSION_INFO
|
|
NULL - SessionInfo was deleted
|
|
|
|
!NULL - Reference count still >0
|
|
|
|
--*/
|
|
|
|
{
|
|
INET_ASSERT(SessionInfo);
|
|
INET_ASSERT(SessionInfo->ReferenceCount >= 1);
|
|
|
|
//
|
|
// use InterlockedDecrement to dereference the session. If it goes to zero
|
|
// acquire the session lock, check if the reference count is still zero,
|
|
// and if so, remove the session from the session list
|
|
//
|
|
|
|
if (InterlockedDecrement(&SessionInfo->ReferenceCount) == 0) {
|
|
AcquireSessionLock();
|
|
if (SessionInfo->ReferenceCount == 0) {
|
|
RemoveFromSerializedList(&SessionList, (PLIST_ENTRY)SessionInfo);
|
|
DestroySession(SessionInfo);
|
|
SessionInfo = NULL;
|
|
}
|
|
ReleaseSessionLock();
|
|
}
|
|
return SessionInfo;
|
|
}
|
|
|
|
|
|
VOID
|
|
AcquireViewLock(
|
|
IN LPSESSION_INFO SessionInfo,
|
|
IN VIEW_TYPE ViewType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Acquires one of the SessionInfo View locks
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO
|
|
|
|
ViewType - identifies which list to lock
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSERIALIZED_LIST list;
|
|
|
|
INET_ASSERT(SessionInfo != NULL);
|
|
INET_ASSERT((ViewType == ViewTypeFile) || (ViewType == ViewTypeFind));
|
|
|
|
list = (ViewType == ViewTypeFile)
|
|
? &SessionInfo->FileList
|
|
: &SessionInfo->FindList
|
|
;
|
|
LockSerializedList(list);
|
|
}
|
|
|
|
|
|
VOID
|
|
ReleaseViewLock(
|
|
IN LPSESSION_INFO SessionInfo,
|
|
IN VIEW_TYPE ViewType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Releases the SessionInfo View lock
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO
|
|
|
|
ViewType - identifies which list to lock
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSERIALIZED_LIST list;
|
|
|
|
INET_ASSERT(SessionInfo != NULL);
|
|
INET_ASSERT((ViewType == ViewTypeFile) || (ViewType == ViewTypeFind));
|
|
|
|
list = (ViewType == ViewTypeFile)
|
|
? &SessionInfo->FileList
|
|
: &SessionInfo->FindList
|
|
;
|
|
UnlockSerializedList(list);
|
|
}
|
|
|
|
|
|
DWORD
|
|
GopherTransaction(
|
|
IN LPVIEW_INFO ViewInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs an 'atomic' gopher operation. Connects to a server (if it isn't
|
|
already connected (in the future?)), sends a request and receives the
|
|
entire response message. The connection is terminated
|
|
|
|
Arguments:
|
|
|
|
ViewInfo - pointer to VIEW_INFO describing gopher server to talk to,
|
|
request and buffer for response
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure - Winsock error
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD error;
|
|
|
|
INET_ASSERT(ViewInfo != NULL);
|
|
|
|
error = GopherConnect(ViewInfo);
|
|
if (error == ERROR_SUCCESS) {
|
|
error = GopherSendRequest(ViewInfo);
|
|
if (error == ERROR_SUCCESS) {
|
|
|
|
DWORD bytesReceived;
|
|
|
|
//
|
|
// receive the first part of the response. We don't care about the
|
|
// number of bytes received at this point
|
|
//
|
|
// If the response is completed and the connection is not persistent
|
|
// or an error occurs, the connection will be closed
|
|
//
|
|
|
|
ViewInfo->BufferInfo->Flags |= BI_FIRST_RECEIVE;
|
|
error = GopherReceiveResponse(ViewInfo, &bytesReceived);
|
|
}
|
|
}
|
|
return error;
|
|
}
|
|
|
|
|
|
DWORD
|
|
IsServerGopherPlus(
|
|
IN LPSESSION_INFO SessionInfo,
|
|
OUT LPBOOL Answer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tries to determine whether a gopher server identified by Session is gopher+.
|
|
The caller should already have determined that we don't know the type of
|
|
gopher server described by Session and should modify the flags based on a
|
|
successful return from this function
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO describing the (unknown) gopher server
|
|
|
|
Answer - pointer to place to put the answer
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure - WSA error
|
|
|
|
--*/
|
|
|
|
{
|
|
/*
|
|
DWORD error;
|
|
BYTE buffer[GOPHER_PLUS_INFO_TOKEN_LENGTH + 2]; // "+INFO"
|
|
// + 1 for possible ':'
|
|
// + 1 for ' '
|
|
BOOL receiveComplete;
|
|
|
|
//
|
|
// in order to find out the type of gopher server, we send a request for
|
|
// gopher+ info of the root directory. We will get back either the gopher+
|
|
// information or a gopher0 server will return the directory list (or we
|
|
// will get an error). Therefore, if the transaction doesn't result in an
|
|
// error, we can say that if the buffer starts with "+INFO" then the
|
|
// server is gopher+ else plain gopher
|
|
//
|
|
|
|
error = GopherTransaction(SessionInfo,
|
|
GOPHER_PLUS_INFO_REQUEST,
|
|
TRUE,
|
|
sizeof(buffer),
|
|
buffer,
|
|
NULL,
|
|
&receiveComplete
|
|
);
|
|
|
|
//
|
|
// in both gopher+ and gopher server cases, the server should want to
|
|
// return more data than we've supplied buffer for (7 bytes!). In the
|
|
// case of gopher+, it will be trying to return the +INFO block for
|
|
// the directory entry. In the case of gopher, it will be trying to
|
|
// return the entire default directory list. Either way, we don't care
|
|
// to take the data: "+INFO[:] " being present or not at the start of
|
|
// the buffer is good enough for us, so just close the session and
|
|
// examine what we have
|
|
//
|
|
|
|
DisconnectFromServer(SessionInfo, );
|
|
if (error == ERROR_SUCCESS) {
|
|
|
|
register DWORD matchLength;
|
|
|
|
matchLength = IsGopherPlusToken(GOPHER_PLUS_INFO_TOKEN,
|
|
GOPHER_PLUS_INFO_TOKEN_LENGTH,
|
|
buffer,
|
|
sizeof(buffer)
|
|
);
|
|
*Answer = (BOOL)(matchLength != 0);
|
|
|
|
IF_DEBUG(SESSION) {
|
|
DBGPRINT(DBG_INFO,
|
|
"IsServerGopherPlus",
|
|
("Server \"%s\" %s gopher+\n",
|
|
SessionInfo->Host,
|
|
(matchLength == 0) ? "NOT" : "IS"
|
|
));
|
|
}
|
|
} else {
|
|
IF_DEBUG(SESSION) {
|
|
DBGPRINT(DBG_ERROR,
|
|
"IsServerGopherPlus",
|
|
("GopherTransaction() returns %d\n",
|
|
error
|
|
));
|
|
}
|
|
}
|
|
return error;
|
|
*/
|
|
*Answer = FALSE;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsGopherPlusSession(
|
|
IN LPSESSION_INFO SessionInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns TRUE if Session is a session with a gopher+ server
|
|
|
|
Arguments:
|
|
|
|
SessionInfo - pointer to SESSION_INFO describing gopher[+] server
|
|
|
|
Return Value:
|
|
|
|
BOOL
|
|
|
|
--*/
|
|
|
|
{
|
|
return (BOOL)SessionInfo->Flags & SI_GOPHER_PLUS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
SearchSessionsForAttribute(
|
|
IN LPSTR Locator,
|
|
IN LPSTR Attribute,
|
|
IN LPBYTE Buffer,
|
|
IN OUT LPDWORD BufferLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches all VIEW_INFO buffers for a requested Locator and extracts the
|
|
attributes if found
|
|
|
|
Arguments:
|
|
|
|
Locator - pointer to locator describing item to get attributes for
|
|
|
|
Attribute - pointer to string describing attribute(s) to get
|
|
|
|
Buffer - pointer to buffer in which to return attribute strings
|
|
|
|
BufferLength - IN: length of Buffer in bytes
|
|
OUT: length of returned attribute strings in bytes,
|
|
excluding any terminating NUL
|
|
|
|
Return Value:
|
|
|
|
DWORD
|
|
Success - ERROR_SUCCESS
|
|
|
|
Failure - ERROR_GOPHER_ATTRIBUTE_NOT_FOUND
|
|
ERROR_INSUFFICIENT_BUFFER
|
|
|
|
--*/
|
|
|
|
{
|
|
LPSESSION_INFO session;
|
|
BOOL found = FALSE;
|
|
DWORD error = ERROR_SUCCESS;
|
|
|
|
AcquireSessionLock();
|
|
/*
|
|
for (session = (LPSESSION_INFO)SessionList.Flink;
|
|
session != (LPSESSION_INFO)&SessionList.Flink;
|
|
session = (LPSESSION_INFO)session->List.Flink) {
|
|
|
|
LPVIEW_INFO viewInfo;
|
|
|
|
AcquireFindLock(session);
|
|
for (findInfo = (LPVIEW_INFO)session->FindList.Flink;
|
|
findInfo != (LPVIEW_INFO)&session->FindList;
|
|
findInfo = (LPVIEW_INFO)findInfo->List.Flink) {
|
|
|
|
ReferenceFind(findInfo);
|
|
if (findInfo->Handle) {
|
|
found = TRUE;
|
|
break; // out of for()
|
|
}
|
|
}
|
|
if (found) {
|
|
break; // out of while()
|
|
}
|
|
ReleaseFindLock(session);
|
|
}
|
|
if (found) {
|
|
error = ERROR_SUCCESS;
|
|
} else {
|
|
error = ERROR_GOPHER_ATTRIBUTE_NOT_FOUND;
|
|
}
|
|
*/
|
|
ReleaseSessionLock();
|
|
|
|
error = ERROR_GOPHER_ATTRIBUTE_NOT_FOUND;
|
|
|
|
return error;
|
|
}
|