purple: make it compile against 3.0.x API
[siplcs.git] / src / miranda / miranda-input.c
blob468b5158ee2d7bdbe720b228347a31130fa01f2d
1 /**
2 * @file miranda-input.c
4 * pidgin-sipe
6 * Copyright (C) 2010-11 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <windows.h>
23 #include <stdio.h>
25 #include <glib.h>
27 #include "sipe-backend.h"
29 #include "newpluginapi.h"
30 #include "m_protosvc.h"
31 #include "m_protoint.h"
32 #include "m_netlib.h"
33 #include "miranda-private.h"
35 #define ENTRY_SIG 0x88442211
37 static NETLIBSELECTEX m_select = {0};
38 static GHashTable *m_readhash = NULL;
39 static GHashTable *m_writehash = NULL;
40 static GList *m_entries = NULL;
42 typedef struct sipe_miranda_sel_entry
44 int sig;
45 HANDLE fd;
46 sipe_miranda_input_function func;
47 gpointer user_data;
49 /* Private. For locking only */
50 HANDLE hDoneEvent;
51 gint source;
52 sipe_miranda_input_condition cond;
55 static void __stdcall
56 input_cb_async(void *data)
58 struct sipe_miranda_sel_entry *entry = (struct sipe_miranda_sel_entry*)data;
59 if (entry->fd == NULL)
61 SIPE_DEBUG_INFO("Entry <%08x> already removed. Not calling read/write function", entry);
62 } else {
63 SIPE_DEBUG_INFO("Calling real read/write function for entry <%08x>", entry);
64 entry->func(entry->user_data, entry->source, entry->cond);
66 SetEvent(entry->hDoneEvent);
69 static unsigned __stdcall
70 inputloop(void* data)
72 int cnt;
73 struct sipe_miranda_sel_entry *entry;
74 INT_PTR lstRes;
76 m_select.cbSize = sizeof(m_select);
77 m_select.dwTimeout = 6000;
79 while( m_select.hReadConns[0] || m_select.hWriteConns[0])
82 SIPE_DEBUG_INFO_NOFORMAT("About to run select");
83 lstRes = CallService(MS_NETLIB_SELECTEX, 0, (LPARAM)&m_select);
84 if (lstRes < 0)
86 SIPE_DEBUG_INFO_NOFORMAT("Connection failed while waiting.");
87 break;
89 else if (lstRes == 0)
91 SIPE_DEBUG_INFO_NOFORMAT("Select Timeout.");
93 else
95 SIPE_DEBUG_INFO_NOFORMAT("Back from select");
97 for ( cnt=0 ; m_select.hReadConns[cnt] ; cnt++ )
99 if (!m_select.hReadStatus[cnt]) continue;
100 SIPE_DEBUG_INFO("FD at position <%d> ready to read.", cnt);
101 entry = (struct sipe_miranda_sel_entry*)g_hash_table_lookup(m_readhash, (gconstpointer)m_select.hReadConns[cnt]);
102 if (!entry)
104 SIPE_DEBUG_INFO_NOFORMAT("ERROR: no read handler found.");
105 continue;
107 SIPE_DEBUG_INFO_NOFORMAT("About to call read function.");
108 entry->source = (gint)m_select.hReadConns[cnt];
109 entry->cond = SIPE_MIRANDA_INPUT_READ;
110 entry->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
111 CallFunctionAsync(input_cb_async, entry);
112 WaitForSingleObject(entry->hDoneEvent, INFINITE);
113 CloseHandle(entry->hDoneEvent);
114 SIPE_DEBUG_INFO_NOFORMAT("read function returned.");
117 for ( cnt=0 ; m_select.hWriteConns[cnt] ; cnt++ )
119 if (!m_select.hWriteStatus[cnt]) continue;
120 SIPE_DEBUG_INFO("FD at position <%d> ready to write.", cnt);
121 entry = (struct sipe_miranda_sel_entry*)g_hash_table_lookup(m_writehash, (gconstpointer)m_select.hWriteConns[cnt]);
122 if (!entry)
124 SIPE_DEBUG_INFO_NOFORMAT("ERROR: no write handler found.");
125 continue;
127 SIPE_DEBUG_INFO_NOFORMAT("About to call write function.");
128 entry->source = (gint)m_select.hWriteConns[cnt];
129 entry->cond = SIPE_MIRANDA_INPUT_WRITE;
130 entry->hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
131 CallFunctionAsync(input_cb_async, entry);
132 WaitForSingleObject(entry->hDoneEvent, INFINITE);
133 CloseHandle(entry->hDoneEvent);
134 SIPE_DEBUG_INFO_NOFORMAT("write function returned.");
138 /* Free all removed entries */
139 while (m_entries) g_list_delete_link(m_entries, g_list_last(m_entries));
142 return 0;
145 struct sipe_miranda_sel_entry*
146 sipe_miranda_input_add(HANDLE fd, sipe_miranda_input_condition cond, sipe_miranda_input_function func, gpointer user_data)
148 int rcnt = 0;
149 int wcnt = 0;
150 struct sipe_miranda_sel_entry *entry;
152 if (!m_readhash)
153 m_readhash = g_hash_table_new(NULL, NULL);
155 if (!m_writehash)
156 m_writehash = g_hash_table_new(NULL, NULL);
158 if ((cond != SIPE_MIRANDA_INPUT_READ) && (cond != SIPE_MIRANDA_INPUT_WRITE))
160 SIPE_DEBUG_INFO("Invalid input condition <%d> cond.", cond);
161 return 0;
164 entry = g_new0(struct sipe_miranda_sel_entry,1);
165 entry->sig = ENTRY_SIG;
166 entry->func = func;
167 entry->user_data = user_data;
168 entry->fd = fd;
170 if (cond == SIPE_MIRANDA_INPUT_READ)
172 for ( rcnt=0 ; m_select.hReadConns[rcnt] && m_select.hReadConns[rcnt]!=(HANDLE)fd ; rcnt++ );
173 m_select.hReadConns[rcnt] = (HANDLE)fd;
174 g_hash_table_replace( m_readhash, (gpointer)fd, entry );
176 else if (cond == SIPE_MIRANDA_INPUT_WRITE)
178 for ( wcnt=0 ; m_select.hWriteConns[wcnt] && m_select.hWriteConns[wcnt]!=(HANDLE)fd ; wcnt++ );
179 m_select.hWriteConns[rcnt] = (HANDLE)fd;
180 g_hash_table_replace( m_writehash, (gpointer)fd, entry );
183 if (!(rcnt+wcnt))
184 CloseHandle((HANDLE) mir_forkthreadex( inputloop, NULL, 8192, NULL ));
186 SIPE_DEBUG_INFO_NOFORMAT("Added input handler.");
187 return entry;
190 gboolean
191 sipe_miranda_input_remove(struct sipe_miranda_sel_entry *entry)
193 int cnt;
195 if (!entry)
197 SIPE_DEBUG_INFO_NOFORMAT("Not a valid entry. NULL.");
198 return FALSE;
201 if (entry->sig != ENTRY_SIG)
203 SIPE_DEBUG_INFO("Not a valid entry. Sig is <%08x>.", entry->sig);
204 return FALSE;
207 if (g_hash_table_lookup(m_readhash, (gconstpointer)entry->fd) == entry)
209 for ( cnt=0 ; m_select.hReadConns[cnt] && m_select.hReadConns[cnt]!=(HANDLE)entry->fd ; cnt++ );
210 for ( ; m_select.hReadConns[cnt] ; cnt++ ) m_select.hReadConns[cnt] = m_select.hReadConns[cnt+1];
211 g_hash_table_remove(m_readhash, (gconstpointer)entry->fd);
214 if (g_hash_table_lookup(m_writehash, (gconstpointer)entry->fd) == entry)
216 for ( cnt=0 ; m_select.hWriteConns[cnt] && m_select.hWriteConns[cnt]!=(HANDLE)entry->fd ; cnt++ );
217 for ( ; m_select.hWriteConns[cnt] ; cnt++ ) m_select.hWriteConns[cnt] = m_select.hWriteConns[cnt+1];
218 g_hash_table_remove(m_writehash, (gconstpointer)entry->fd);
221 /* Set fd to NULL so we won't try to call the callback if we're
222 currently waiting to get back to the main thread */
223 entry->fd = NULL;
225 /* Add it to the list of entries that can be freed after the next select
226 * loop in the thread that's handling the actual select
228 g_list_append( m_entries, entry );
230 return TRUE;
236 Local Variables:
237 mode: c
238 c-file-style: "bsd"
239 indent-tabs-mode: t
240 tab-width: 8
241 End: