Merged silc_1_0_branch to trunk.
[silc.git] / lib / silcutil / silcprotocol.c
1 /*
2
3   silcprotocol.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2005 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
12   
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.
17
18 */
19 /*
20  * Created: Tue Nov 25 19:25:33 GMT+0200 1997
21  */
22 /* $Id$ */
23
24 #include "silcincludes.h"
25
26 /* Dynamically registered protocols */
27 SilcProtocolObject *silc_protocol_list = NULL;
28
29 /* Dynamically registers new protocol. The protocol is added into protocol
30    list and can be unregistered with silc_protocol_unregister. */
31
32 void silc_protocol_register(SilcProtocolType type,
33                             SilcProtocolCallback callback)
34 {
35   SilcProtocolObject *proto_new;
36
37   proto_new = silc_calloc(1, sizeof(*proto_new));
38   proto_new->type = type;
39   proto_new->callback = callback;
40
41   if (!silc_protocol_list)
42     silc_protocol_list = proto_new;
43   else {
44     proto_new->next = silc_protocol_list;
45     silc_protocol_list = proto_new;
46   }
47 }
48
49 /* Unregisters protocol. The unregistering is done by both protocol type
50    and the protocol callback. */
51
52 void silc_protocol_unregister(SilcProtocolType type,
53                               SilcProtocolCallback callback)
54 {
55   SilcProtocolObject *protocol, *prev;
56
57   protocol = silc_protocol_list;
58   prev = NULL;
59   while (protocol && (protocol->type != type && 
60                       protocol->callback != callback)) {
61     prev = protocol;
62     protocol = protocol->next;
63   }
64
65   if (protocol) {
66     if (prev)
67       prev->next = protocol->next;
68     else
69       silc_protocol_list = protocol->next;
70
71     silc_free(protocol);
72   }
73 }
74
75 /* Allocates a new protocol object. The new allocated and initialized 
76    protocol is returned to the new_protocol argument. The argument context
77    is the context to be sent as argument for the protocol. The callback
78    argument is the function to be called _after_ the protocol has finished. */
79
80 void silc_protocol_alloc(SilcProtocolType type, SilcProtocol *new_protocol,
81                          void *context, SilcProtocolFinalCallback callback)
82 {
83   SilcProtocolObject *protocol;
84
85   SILC_LOG_DEBUG(("Allocating new protocol type %d", type));
86
87   protocol = silc_protocol_list;
88   while (protocol && protocol->type != type)
89     protocol = protocol->next;
90
91   if (!protocol) {
92     SILC_LOG_ERROR(("Requested protocol does not exists"));
93     *new_protocol = NULL;
94     return;
95   }
96
97   *new_protocol = silc_calloc(1, sizeof(**new_protocol));
98   (*new_protocol)->protocol = protocol;
99   (*new_protocol)->state = SILC_PROTOCOL_STATE_UNKNOWN;
100   (*new_protocol)->context = context;
101   (*new_protocol)->final_callback = callback;
102 }
103
104 /* Frees a protocol object. */
105
106 void silc_protocol_free(SilcProtocol protocol)
107 {
108   if (protocol)
109     silc_free(protocol);
110 }
111
112 /* Executes next state of the protocol. The state must be set before
113    calling this function. */
114
115 void silc_protocol_execute(SilcProtocol protocol, SilcSchedule schedule,
116                            long secs, long usecs)
117 {
118   if (secs + usecs) 
119     silc_schedule_task_add(schedule, 0, 
120                            protocol->protocol->callback, (void *)protocol, 
121                            secs, usecs, 
122                            SILC_TASK_TIMEOUT,
123                            SILC_TASK_PRI_NORMAL);
124   else
125     protocol->protocol->callback(schedule, silc_schedule_get_context(schedule),
126                                  0, 0, (void *)protocol);
127 }
128
129 /* Executes the final callback of the protocol. */
130
131 void silc_protocol_execute_final(SilcProtocol protocol, SilcSchedule schedule)
132 {
133   protocol->final_callback(schedule, silc_schedule_get_context(schedule),
134                            0, 0, (void *)protocol);
135 }
136
137 /* Cancels the execution of the next state of the protocol. */
138
139 void silc_protocol_cancel(SilcProtocol protocol, SilcSchedule schedule)
140 {
141   silc_schedule_task_del_by_context(schedule, protocol);
142 }