1 /*
2  * Copyright (c) 2001 Tommy Bohlin <tommy@gatespace.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 /* iasclt.c
27  */
28 
29 #include <irda.h>
30 #include <ias.h>
31 
32 #include <string.h>
33 
34 /**********************************************************************
35  * Constants
36  **********************************************************************/
37 
38 static const char id_client[]="ias client";
39 static const char id_inbuf[]="ias client inbuf";
40 
41 /**********************************************************************
42  * Data structures
43  **********************************************************************/
44 
45 typedef struct IASClientPrivate {
46   IASClient ias;
47   Connection* con;
48 
49   bool busy;
50   int op;
51 
52   int outOfs;
53   int outLength;
54   u_char outBuf[256];
55 
56   int inOfs;
57   int inLength;
58   int inMax;
59   u_char* inBuf;
60 } IASClientPrivate;
61 
62 /**********************************************************************
63  * Internal functions
64  **********************************************************************/
65 
sendACK(Connection * con,int op)66 static void sendACK(Connection* con, int op)
67 {
68   u_char hdr[1];
69 
70   hdr[0]=op|IAS_ACK|IAS_LAST;
71   connWrite(con,hdr,1);
72 }
73 
status(Connection * con,int event,void * buf,int len)74 static void status(Connection* con, int event, void* buf, int len)
75 {
76   IASClientPrivate* iasp=(IASClientPrivate*)con->handle;
77 
78   if(event==CONN_CLOSED) {
79     if(iasp->ias.debug&IAS_DEBUG_INFO) birda_log("ias connection closed\n");
80     connClose(con);
81     iasp->con=0;
82 
83     if(iasp->busy) {
84       iasp->busy=FALSE;
85       freeMem(iasp->inBuf);
86       iasp->inBuf=0;
87       if(iasp->ias.status) iasp->ias.status(&iasp->ias,IAS_QUERY_FAILED);
88     }
89   }
90 }
91 
sendChunk(IASClientPrivate * iasp)92 static void sendChunk(IASClientPrivate* iasp)
93 {
94   int n=iasp->outLength-iasp->outOfs;
95   int k=connGetSendDataSize(iasp->con)-1;
96   u_char hdr[1];
97   if(k>n) k=n;
98   hdr[0]=iasp->op;
99   if(k==n) hdr[0]|=IAS_LAST;
100   connWrite2(iasp->con,hdr,1,iasp->outBuf,k);
101   iasp->outOfs+=k;
102 }
103 
data(Connection * con,void * buf0,int len)104 static void data(Connection* con, void* buf0, int len)
105 {
106   u_char* buf=(u_char*)buf0;
107   IASClientPrivate* iasp=(IASClientPrivate*)con->handle;
108   u_char op;
109 
110   /* Just ignore null input, OK? */
111   if(len<1) return;
112   op=buf[0]&~(IAS_LAST|IAS_ACK);
113 
114   if(!iasp->busy || op!=iasp->op) {
115     status(con,CONN_CLOSED,0,0);
116     return;
117   }
118 
119   if(iasp->outOfs<iasp->outLength) {
120     if((buf[0]&IAS_ACK) && op==iasp->op) sendChunk(iasp);
121     else {
122       status(con,CONN_CLOSED,0,0);
123     }
124     return;
125   }
126   if(buf[0]&IAS_ACK) return;
127 
128   while(iasp->inMax<iasp->inLength+len-1) {
129     iasp->inMax*=2;
130     iasp->inBuf=growMem(iasp->inBuf,iasp->inMax);
131   }
132 
133   memcpy(iasp->inBuf+iasp->inLength,buf+1,len-1);
134   iasp->inLength+=len-1;
135 
136   if(buf[0]&IAS_LAST) {
137     iasp->busy=FALSE;
138 
139     iasp->inOfs=3;
140     if(iasp->inLength>0 && iasp->inBuf[0]!=IAS_SUCCESS) iasp->inLength=0;
141 
142     if(iasp->ias.status) iasp->ias.status(&iasp->ias,IAS_QUERY_COMPLETE);
143   } else {
144     sendACK(con,op);
145   }
146 }
147 
148 /**********************************************************************
149  * External functions
150  **********************************************************************/
151 
iasCltGetValueByClass(IASClient * ias,const char * class,const char * name)152 bool iasCltGetValueByClass(IASClient* ias, const char* class, const char* name)
153 {
154   IASClientPrivate* iasp=(IASClientPrivate*)ias;
155 
156   if(iasp->con && !iasp->busy) {
157     int clen=strlen(class);
158     int nlen=strlen(name);
159     if(clen>60) clen=60;
160     if(nlen>60) nlen=60;
161     iasp->outBuf[0]=clen;
162     memcpy(iasp->outBuf+1,class,clen);
163     iasp->outBuf[1+clen]=nlen;
164     memcpy(iasp->outBuf+2+clen,name,nlen);
165 
166     iasp->busy=TRUE;
167     iasp->op=OP_GetValueByClass;
168     iasp->outOfs=0;
169     iasp->outLength=2+clen+nlen;
170     iasp->inLength=0;
171 
172     sendChunk(iasp);
173     return TRUE;
174   }
175   return FALSE;
176 }
177 
iasCltClose(IASClient * ias)178 void iasCltClose(IASClient* ias)
179 {
180   IASClientPrivate* iasp=(IASClientPrivate*)ias;
181 
182   if(iasp->con) connClose(iasp->con);
183   if(iasp->inBuf) freeMem(iasp->inBuf);
184   freeMem(iasp);
185 }
186 
iasCltShowResult(IASClient * ias)187 void iasCltShowResult(IASClient* ias)
188 {
189   int type,id;
190 
191   while((type=iasCltResType(ias))!=IAS_NONE) {
192     id=iasCltResId(ias);
193     switch(type) {
194     case IAS_INT:
195       birda_log("  %d. int %d\n",id,iasCltResInt(ias));
196       break;
197     case IAS_OCTETS:
198       birda_log("  %d. octets ",id);
199       showBytes(iasCltResPtr(ias),iasCltResLength(ias));
200       break;
201     case IAS_STRING:
202       birda_log("  %d. string %.*s\n",id,
203 	      iasCltResLength(ias),(char*)iasCltResPtr(ias));
204       break;
205     }
206     iasCltResNext(ias);
207   }
208 }
209 
iasCltResType(IASClient * ias)210 int iasCltResType(IASClient* ias)
211 {
212   IASClientPrivate* iasp=(IASClientPrivate*)ias;
213 
214   if(iasp->busy || !iasp->inBuf) return IAS_NONE;
215   for(;;) {
216     int i=iasp->inOfs;
217     int n=iasp->inLength-i;
218 
219     if(n<3) return IAS_NONE;
220     switch(iasp->inBuf[i+2]) {
221     case IAS_NONE:
222       iasp->inOfs+=3;
223       continue;
224     case IAS_INT:
225       if(n>=7) return IAS_INT;
226       break;
227     case IAS_OCTETS:
228       if(n>=5 && n>=getBEShort(iasp->inBuf+i+3)+5) return IAS_OCTETS;
229       break;
230     case IAS_STRING:
231       if(n>=5 && n>=iasp->inBuf[i+4]+5) return IAS_STRING;
232       break;
233     }
234     iasp->inOfs=iasp->inLength;
235     return IAS_NONE;
236   }
237 }
238 
iasCltResId(IASClient * ias)239 int iasCltResId(IASClient* ias)
240 {
241   IASClientPrivate* iasp=(IASClientPrivate*)ias;
242 
243   return getBEShort(iasp->inBuf+iasp->inOfs);
244 }
245 
iasCltResInt(IASClient * ias)246 int iasCltResInt(IASClient* ias)
247 {
248   IASClientPrivate* iasp=(IASClientPrivate*)ias;
249 
250   return getBELong(iasp->inBuf+iasp->inOfs+3);
251 }
252 
iasCltResCharSet(IASClient * ias)253 int iasCltResCharSet(IASClient* ias)
254 {
255   IASClientPrivate* iasp=(IASClientPrivate*)ias;
256 
257   return iasp->inBuf[iasp->inOfs+3];
258 }
259 
iasCltResLength(IASClient * ias)260 int iasCltResLength(IASClient* ias)
261 {
262   IASClientPrivate* iasp=(IASClientPrivate*)ias;
263 
264   switch(iasp->inBuf[iasp->inOfs+2]) {
265   case IAS_INT:    return 4;
266   case IAS_OCTETS: return getBEShort(iasp->inBuf+iasp->inOfs+3);
267   case IAS_STRING: return iasp->inBuf[iasp->inOfs+4];
268   default:         return 0;
269   }
270 }
271 
iasCltResPtr(IASClient * ias)272 void* iasCltResPtr(IASClient* ias)
273 {
274   IASClientPrivate* iasp=(IASClientPrivate*)ias;
275 
276   return iasp->inBuf+iasp->inOfs+5;
277 }
278 
iasCltResNext(IASClient * ias)279 void iasCltResNext(IASClient* ias)
280 {
281   IASClientPrivate* iasp=(IASClientPrivate*)ias;
282   int i=iasp->inOfs;
283 
284   switch(iasp->inBuf[i+2]) {
285   case IAS_INT:
286     iasp->inOfs+=7;
287     break;
288   case IAS_OCTETS:
289     iasp->inOfs+=5+getBEShort(iasp->inBuf+i+3);
290     break;
291   case IAS_STRING:
292     iasp->inOfs+=5+iasp->inBuf[i+4];
293     break;
294   }
295 }
296 
createIASClient(LAP * lap)297 IASClient* createIASClient(LAP* lap)
298 {
299   IASClientPrivate* iasp;
300   Connection* con=lapNewConnection(lap,IAS_LSAPSEL,0,0,0);
301   if(!con) return 0;
302 
303   iasp=allocMem(id_client,sizeof(IASClientPrivate));
304   iasp->ias.handle=0;
305   iasp->ias.status=0;
306   iasp->con=con;
307   iasp->con->handle=iasp;
308   iasp->con->status=status;
309   iasp->con->data=data;
310   iasp->busy=FALSE;
311   iasp->outOfs=0;
312   iasp->outLength=0;
313   iasp->inLength=0;
314   iasp->inMax=256;
315   iasp->inBuf=allocMem(id_inbuf,iasp->inMax);
316 
317   return &iasp->ias;
318 }
319