982 lines
21 KiB
C++
982 lines
21 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;
|
||
}
|