[gaim-migrate @ 3063]
[pidgin-git.git] / src / protocols / icq / udp.c
blobf268b42c470676bc297c83263a371cfe5bbf35b1
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
3 /*
4 * $Id: udp.c 2487 2001-10-10 19:58:11Z warmenhoven $
6 * Copyright (C) 1998-2001, Denis V. Dmitrienko <denis@null.net> and
7 * Bill Soudan <soudan@kde.org>
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; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #ifdef _WIN32
26 #include <winsock.h>
27 #endif
29 #include <stdlib.h>
31 #include "icqlib.h"
32 #include "udp.h"
33 #include "queue.h"
35 #include "stdpackets.h"
36 #include "icqbyteorder.h"
38 #include "contacts.h"
40 static const BYTE icq_UDPTable[] = {
41 0x59, 0x60, 0x37, 0x6B, 0x65, 0x62, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x60, 0x57, 0x5B, 0x3D,
42 0x5E, 0x34, 0x6D, 0x36, 0x50, 0x3F, 0x6F, 0x67, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x47, 0x63, 0x39,
43 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x43, 0x69, 0x48, 0x33, 0x31, 0x64, 0x35, 0x5A, 0x4A, 0x42,
44 0x56, 0x40, 0x67, 0x53, 0x41, 0x07, 0x6C, 0x49, 0x58, 0x3B, 0x4D, 0x46, 0x68, 0x43, 0x69, 0x48,
45 0x33, 0x31, 0x44, 0x65, 0x62, 0x46, 0x48, 0x53, 0x41, 0x07, 0x6C, 0x69, 0x48, 0x33, 0x51, 0x54,
46 0x5D, 0x4E, 0x6C, 0x49, 0x38, 0x4B, 0x55, 0x4A, 0x62, 0x46, 0x48, 0x33, 0x51, 0x34, 0x6D, 0x36,
47 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F, 0x47, 0x63, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64, 0x35, 0x5A,
48 0x6A, 0x52, 0x6E, 0x3C, 0x51, 0x34, 0x6D, 0x36, 0x50, 0x5F, 0x5F, 0x3F, 0x4F, 0x37, 0x4B, 0x35,
49 0x5A, 0x4A, 0x62, 0x66, 0x58, 0x3B, 0x4D, 0x66, 0x58, 0x5B, 0x5D, 0x4E, 0x6C, 0x49, 0x58, 0x3B,
50 0x4D, 0x66, 0x58, 0x3B, 0x4D, 0x46, 0x48, 0x53, 0x61, 0x4C, 0x59, 0x40, 0x67, 0x33, 0x31, 0x64,
51 0x55, 0x6A, 0x32, 0x3E, 0x44, 0x45, 0x52, 0x6E, 0x3C, 0x31, 0x64, 0x55, 0x6A, 0x52, 0x4E, 0x6C,
52 0x69, 0x48, 0x53, 0x61, 0x4C, 0x39, 0x30, 0x6F, 0x47, 0x63, 0x59, 0x60, 0x57, 0x5B, 0x3D, 0x3E,
53 0x64, 0x35, 0x3A, 0x3A, 0x5A, 0x6A, 0x52, 0x4E, 0x6C, 0x69, 0x48, 0x53, 0x61, 0x6C, 0x49, 0x58,
54 0x3B, 0x4D, 0x46, 0x68, 0x63, 0x39, 0x50, 0x5F, 0x5F, 0x3F, 0x6F, 0x67, 0x53, 0x41, 0x25, 0x41,
55 0x3C, 0x51, 0x54, 0x3D, 0x5E, 0x54, 0x5D, 0x4E, 0x4C, 0x39, 0x50, 0x5F, 0x5F, 0x5F, 0x3F, 0x6F,
56 0x47, 0x43, 0x69, 0x48, 0x33, 0x51, 0x54, 0x5D, 0x6E, 0x3C, 0x31, 0x64, 0x35, 0x5A, 0x00, 0x00,
59 DWORD icq_UDPCalculateCheckCode(icq_Packet *p)
61 DWORD num1, num2;
62 DWORD r1,r2;
64 num1 = p->data[8];
65 num1 <<= 8;
66 num1 += p->data[4];
67 num1 <<= 8;
68 num1 += p->data[2];
69 num1 <<= 8;
70 num1 += p->data[6];
72 r1 = 0x18 + (rand() % (p->length - 0x18));
73 r2 = rand() & 0xff;
75 num2 = r1;
76 num2 <<= 8;
77 num2 += p->data[r1];
78 num2 <<= 8;
79 num2 += r2;
80 num2 <<= 8;
81 num2 += icq_UDPTable[r2];
82 num2 ^= 0xFF00FF;
84 return num1 ^ num2;
87 DWORD icq_UDPScramble(DWORD cc)
89 DWORD a[5];
91 a[0] = cc & 0x0000001F;
92 a[1] = cc & 0x03E003E0;
93 a[2] = cc & 0xF8000400;
94 a[3] = cc & 0x0000F800;
95 a[4] = cc & 0x041F0000;
97 a[0] <<= 0x0C;
98 a[1] <<= 0x01;
99 a[2] >>= 0x0A;
100 a[3] <<= 0x10;
101 a[4] >>= 0x0F;
103 return a[0] + a[1] + a[2] + a[3] + a[4];
106 void icq_UDPEncode(icq_Packet *p, char *buffer)
108 DWORD checkcode = icq_UDPCalculateCheckCode(p);
109 DWORD code1, code2, code3;
110 DWORD pos;
111 DWORD tmp;
113 memcpy(buffer, p->data, p->length);
115 tmp = htoicql(checkcode);
116 memcpy((buffer+0x14),&tmp,sizeof(DWORD));
117 code1 = p->length * 0x68656c6cL;
118 code2 = code1 + checkcode;
119 pos = 0x0A;
121 for(; pos < p->length; pos+=4)
123 DWORD data;
124 memcpy(&data, (p->data)+pos, sizeof(DWORD));
125 data = icqtohl(data);
126 code3 = code2 + icq_UDPTable[pos & 0xFF];
127 data ^= code3;
128 data = htoicql(data);
129 memcpy((buffer+pos),&data,sizeof(DWORD));
131 checkcode = icq_UDPScramble(checkcode);
132 tmp = htoicql(checkcode);
133 memcpy((buffer+0x14),&tmp,sizeof(DWORD));
136 /*********************************************************
137 icq_UDPSockWrite and icq_UDPSockRead are for _UDP_ packets
138 proxy support for TCP sockets is different!
139 *********************************************************/
140 int icq_UDPSockWriteDirect(icq_Link *icqlink, icq_Packet *p)
142 char tmpbuf[ICQ_PACKET_DATA_SIZE+10];
144 if(icqlink->icq_UDPSok <= 3)
146 icq_FmtLog(icqlink, ICQ_LOG_ERROR, "Bad socket!\n");
147 return -1;
150 icq_UDPEncode(p, tmpbuf+10);
152 if(!icqlink->icq_UseProxy)
154 #ifdef _WIN32
155 return send(icqlink->icq_UDPSok, tmpbuf+10, p->length, 0);
156 #else
157 return write(icqlink->icq_UDPSok, tmpbuf+10, p->length);
158 #endif
160 else
162 tmpbuf[0] = 0; /* reserved */
163 tmpbuf[1] = 0; /* reserved */
164 tmpbuf[2] = 0; /* standalone packet */
165 tmpbuf[3] = 1; /* address type IP v4 */
166 *(unsigned long*)&tmpbuf[4] = htonl(icqlink->icq_ProxyDestIP);
167 *(unsigned short*)&tmpbuf[8] = htons(icqlink->icq_ProxyDestPort);
168 #ifdef _WIN32
169 return send(icqlink->icq_UDPSok, tmpbuf, p->length+10, 0)-10;
170 #else
171 return write(icqlink->icq_UDPSok, tmpbuf, p->length+10)-10;
172 #endif
176 int icq_UDPSockWrite(icq_Link *icqlink, icq_Packet *p)
178 icq_UDPQueuePut(icqlink, p);
180 return icq_UDPSockWriteDirect(icqlink, p);
183 int icq_UDPSockRead(icq_Link *icqlink, icq_Packet *p)
185 int res;
186 char tmpbuf[ICQ_PACKET_DATA_SIZE];
188 if(!icqlink->icq_UseProxy)
190 #ifdef _WIN32
191 res = recv(icqlink->icq_UDPSok, p->data, ICQ_PACKET_DATA_SIZE, 0);
192 #else
193 res = read(icqlink->icq_UDPSok, p->data, ICQ_PACKET_DATA_SIZE);
194 #endif
195 p->length = res;
196 return res;
198 else
200 #ifdef _WIN32
201 res = recv(icqlink->icq_UDPSok, tmpbuf, ICQ_PACKET_DATA_SIZE, 0);
202 #else
203 res = read(icqlink->icq_UDPSok, tmpbuf, ICQ_PACKET_DATA_SIZE);
204 #endif
205 if(res<0)
206 return res;
207 memcpy(p->data, &tmpbuf[10], res-10);
208 p->length = res-10;
209 return res-10;
213 /****************************************
214 This must be called every 2 min.
215 so the server knows we're still alive.
216 JAVA client sends two different commands
217 so we do also :)
218 *****************************************/
219 WORD icq_KeepAlive(icq_Link *icqlink) /* V5 */
221 icq_Packet *p = icq_UDPCreateStdSeqPacket(icqlink, UDP_CMD_KEEP_ALIVE, icqlink->d->icq_UDPSeqNum1++);
222 icq_PacketAppend32(p, rand());
223 icq_UDPSockWriteDirect(icqlink, p); /* don't queue keep alive packets! */
224 icq_PacketDelete(p);
226 icq_FmtLog(icqlink, ICQ_LOG_MESSAGE, "Send Keep Alive packet to the server\n");
228 return icqlink->d->icq_UDPSeqNum1-1;
231 /**********************************
232 This must be called to remove
233 messages from the server
234 ***********************************/
235 void icq_SendGotMessages(icq_Link *icqlink) /* V5 */
237 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_ACK_MESSAGES);
238 icq_PacketAppend32(p, rand());
239 icq_UDPSockWrite(icqlink, p);
242 /*************************************
243 this sends over the contact list
244 *************************************/
245 void icq_SendContactList(icq_Link *icqlink) /* V5 */
247 char num_used;
248 icq_ContactItem *ptr = icq_ContactGetFirst(icqlink);
250 while(ptr)
252 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_CONT_LIST);
254 num_used = 0;
255 icq_PacketAdvance(p,1);
256 while(ptr && num_used<64)
258 icq_PacketAppend32(p, ptr->uin);
259 num_used++;
260 ptr = icq_ContactGetNext(ptr);
262 icq_PacketGotoUDPOutData(p, 0);
263 icq_PacketAppend8(p, num_used);
264 icq_UDPSockWrite(icqlink, p);
268 void icq_SendNewUser(icq_Link *icqlink, unsigned long uin) /* V5 */
270 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_ADD_TO_LIST);
271 icq_PacketAppend32(p, uin);
272 icq_UDPSockWrite(icqlink, p);
275 /*************************************
276 this sends over the visible list
277 that allows certain users to see you
278 if you're invisible.
279 *************************************/
280 void icq_SendVisibleList(icq_Link *icqlink) /* V5 */
282 char num_used;
283 icq_ContactItem *ptr = icq_ContactGetFirst(icqlink);
284 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_VIS_LIST);
286 num_used = 0;
287 icq_PacketAdvance(p,1);
288 while(ptr)
290 if(ptr->vis_list)
292 icq_PacketAppend32(p, ptr->uin);
293 num_used++;
295 ptr = icq_ContactGetNext(ptr);
297 if(num_used != 0)
299 icq_PacketGotoUDPOutData(p, 0);
300 icq_PacketAppend8(p, num_used);
301 icq_UDPSockWrite(icqlink, p);
303 else
304 icq_PacketDelete(p);
307 void icq_SendInvisibleList(icq_Link *icqlink) /* V5 */
309 char num_used;
310 icq_ContactItem *ptr = icq_ContactGetFirst(icqlink);
311 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_INVIS_LIST);
313 num_used = 0;
314 icq_PacketAdvance(p,1);
315 while(ptr)
317 if(ptr->invis_list)
319 icq_PacketAppend32(p, ptr->uin);
320 num_used++;
322 ptr = icq_ContactGetNext(ptr);
324 if(num_used != 0)
326 icq_PacketGotoUDPOutData(p, 0);
327 icq_PacketAppend8(p, num_used);
328 icq_UDPSockWrite(icqlink, p);
330 else
331 icq_PacketDelete(p);
334 /**************************************
335 This sends the second login command
336 this is necessary to finish logging in.
337 ***************************************/
338 void icq_SendLogin1(icq_Link *icqlink) /* V5 */
340 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_LOGIN_1);
341 icq_PacketAppend32(p, rand());
342 icq_UDPSockWrite(icqlink, p);
345 /************************************
346 This procedure logins into the server with icq_Uin and pass
347 on the socket icq_Sok and gives our ip and port.
348 It does NOT wait for any kind of a response.
349 *************************************/
350 void icq_Login(icq_Link *icqlink, DWORD status) /* V5 */
352 icq_Packet *p;
354 memset(icqlink->d->icq_UDPServMess, FALSE, sizeof(icqlink->d->icq_UDPServMess));
355 icqlink->d->icq_UDPSession = rand() & 0x3FFFFFFF;
356 icqlink->d->icq_UDPSeqNum1 = rand() & 0x7FFF;
357 icqlink->d->icq_UDPSeqNum2 = 1;
359 p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_LOGIN);
360 icq_PacketAppend32(p, time(0L));
361 icq_PacketAppend32n(p, icqlink->icq_TCPSrvPort);
362 /*icq_PacketAppend16(p, 0);
363 icq_PacketAppend16n(p, htons(icqlink->icq_OurPort));*/
364 icq_PacketAppendString(p, icqlink->icq_Password);
365 icq_PacketAppend32(p, LOGIN_X1_DEF);
366 if(icqlink->icq_UseTCP)
368 if(icqlink->icq_UseProxy)
370 icq_PacketAppend32n(p, htonl(icqlink->icq_ProxyIP));
371 icq_PacketAppend8(p, LOGIN_SNDONLY_TCP);
373 else
375 icq_PacketAppend32n(p, htonl(icqlink->icq_OurIP));
376 icq_PacketAppend8(p, LOGIN_SNDRCV_TCP);
379 else
381 icq_PacketAppend32n(p, htonl(icqlink->icq_ProxyIP));
382 icq_PacketAppend8(p, LOGIN_NO_TCP);
384 icq_PacketAppend32(p, status);
385 icq_PacketAppend32(p, LOGIN_X3_DEF);
386 icq_PacketAppend32(p, LOGIN_X4_DEF);
387 icq_PacketAppend32(p, LOGIN_X5_DEF);
389 icq_UDPSockWrite(icqlink, p);
392 /**********************
393 Logs off ICQ
394 ***********************/
395 void icq_Logout(icq_Link *icqlink) /* V5 */
397 icq_Packet *p = icq_UDPCreateStdSeqPacket(icqlink, UDP_CMD_SEND_TEXT_CODE, icqlink->d->icq_UDPSeqNum1++);
398 icq_PacketAppendString(p, "B_USER_DISCONNECTED");
399 icq_PacketAppend8(p, 5);
400 icq_PacketAppend8(p, 0);
401 icq_UDPSockWriteDirect(icqlink, p); /* don't queue */
402 icq_PacketDelete(p);
405 /*******************************
406 This routine sends the aknowlegement cmd to the
407 server it appears that this must be done after
408 everything the server sends us
409 *******************************/
410 void icq_UDPAck(icq_Link *icqlink, int seq) /* V5 */
412 icq_Packet *p = icq_UDPCreateStdSeqPacket(icqlink, UDP_CMD_ACK, seq);
413 icq_PacketAppend32(p, rand());
415 icq_FmtLog(icqlink, ICQ_LOG_MESSAGE, "Acking\n");
416 icq_UDPSockWriteDirect(icqlink, p);
417 icq_PacketDelete(p);
420 /***************************************************
421 Sends a message thru the server to uin. Text is the
422 message to send.
423 ***************************************************/
424 WORD icq_UDPSendMessage(icq_Link *icqlink, DWORD uin, const char *text) /* V5 */
426 char buf[ICQ_MAX_UDP_MESSAGE_SIZE];
427 icq_Packet *p;
429 strncpy(buf, text, sizeof(buf));
430 buf[sizeof(buf)-1] = 0;
431 icq_RusConv("kw", buf);
433 p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_SEND_THRU_SRV);
434 icq_PacketAppend32(p, uin);
435 icq_PacketAppend16(p, TYPE_MSG);
436 icq_PacketAppendString(p, buf);
438 icq_UDPSockWrite(icqlink, p);
439 return icqlink->d->icq_UDPSeqNum1-1;
442 WORD icq_UDPSendURL(icq_Link *icqlink, DWORD uin, const char *url, const char *descr) /* V5 */
444 char buf1[ICQ_MAX_UDP_MESSAGE_SIZE], buf2[ICQ_MAX_UDP_MESSAGE_SIZE];
445 icq_Packet *p;
447 strncpy(buf1, descr, sizeof(buf1));
448 buf1[sizeof(buf1)-1] = 0;
449 icq_RusConv("kw", buf1);
450 strncpy(buf2, url, sizeof(buf2));
451 buf2[sizeof(buf2)-1] = 0;
453 p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_SEND_THRU_SRV);
454 icq_PacketAppend32(p, uin);
455 icq_PacketAppend16(p, TYPE_URL);
456 icq_PacketAppend16(p, strlen(buf1)+strlen(buf2)+2); /* length + the NULL + 0xFE delimiter */
457 icq_PacketAppendStringFE(p, buf1);
458 icq_PacketAppendString0(p, buf2);
460 icq_UDPSockWrite(icqlink, p);
461 return icqlink->d->icq_UDPSeqNum1-1;
464 /**************************************************
465 Sends a authorization to the server so the Mirabilis
466 client can add the user.
467 ***************************************************/
468 WORD icq_SendAuthMsg(icq_Link *icqlink, DWORD uin) /* V5 */
470 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_SEND_THRU_SRV);
471 icq_PacketAppend32(p, uin);
472 icq_PacketAppend32(p, TYPE_AUTH);
473 icq_PacketAppend16(p, 0);
474 icq_UDPSockWrite(icqlink, p);
476 return icqlink->d->icq_UDPSeqNum1-1;
479 /**************************************************
480 Changes the users status on the server
481 ***************************************************/
482 void icq_ChangeStatus(icq_Link *icqlink, DWORD status) /* V5 */
484 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_STATUS_CHANGE);
485 icq_PacketAppend32(p, status);
486 icqlink->icq_Status = status;
487 icq_UDPSockWrite(icqlink, p);
490 /********************************************************
491 Sends a request to the server for info on a specific user
492 *********************************************************/
493 WORD icq_SendInfoReq(icq_Link *icqlink, DWORD uin) /* V5 */
495 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_INFO_REQ);
496 icq_PacketAppend32(p, uin);
497 icq_UDPSockWrite(icqlink, p);
498 return icqlink->d->icq_UDPSeqNum1-1;
501 /********************************************************
502 Sends a request to the server for info on a specific user
503 *********************************************************/
504 WORD icq_SendExtInfoReq(icq_Link *icqlink, DWORD uin) /* V5 */
506 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_EXT_INFO_REQ);
507 icq_PacketAppend32(p, uin);
508 icq_UDPSockWrite(icqlink, p);
509 return icqlink->d->icq_UDPSeqNum1-1;
512 /**************************************************************
513 Initializes a server search for the information specified
514 ***************************************************************/
515 void icq_SendSearchReq(icq_Link *icqlink, const char *email, const char *nick, const char *first,
516 const char *last) /* V5 */
518 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_SEARCH_USER);
519 icq_PacketAppendString(p, nick);
520 icq_PacketAppendString(p, first);
521 icq_PacketAppendString(p, last);
522 icq_PacketAppendString(p, email);
523 icq_UDPSockWrite(icqlink, p);
526 /**************************************************************
527 Initializes a server search for the information specified
528 ***************************************************************/
529 void icq_SendSearchUINReq(icq_Link *icqlink, DWORD uin) /* V5 */
531 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_SEARCH_UIN);
532 icq_PacketAppend32(p, uin);
533 icq_UDPSockWrite(icqlink, p);
536 /**************************************************
537 Registers a new uin in the ICQ network
538 ***************************************************/
539 void icq_RegNewUser(icq_Link *icqlink, const char *pass) /* V5 */
541 char pass8[9];
542 icq_Packet *p = icq_UDPCreateStdSeqPacket(icqlink, UDP_CMD_REG_NEW_USER, icqlink->d->icq_UDPSeqNum1++);
543 strncpy(pass8, pass, 8);
544 icq_PacketAppendString(p, pass8);
545 icq_PacketAppend32(p, 0xA0);
546 icq_PacketAppend32(p, 0x2461);
547 icq_PacketAppend32(p, 0xA00000);
548 icq_PacketAppend32(p, 0x00);
549 icq_PacketGoto(p, 6);
550 icq_PacketAppend32(p, 0);
551 icq_PacketAppend32(p, rand());
552 icq_UDPSockWrite(icqlink, p);
553 icq_FmtLog(icqlink, ICQ_LOG_MESSAGE, "Send RegNewUser packet to the server\n");
556 WORD icq_UpdateUserInfo(icq_Link *icqlink, const char *nick, const char *first, const char *last,
557 const char *email) /* V5 */
559 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_UPDATE_INFO);
560 icq_PacketAppendString(p, nick);
561 icq_PacketAppendString(p, first);
562 icq_PacketAppendString(p, last);
563 icq_PacketAppendString(p, email);
564 /* auth (byte)? */
565 icq_UDPSockWrite(icqlink, p);
566 return icqlink->d->icq_UDPSeqNum1-1;
569 WORD icq_UpdateAuthInfo(icq_Link *icqlink, DWORD auth) /* V5 */
571 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_UPDATE_AUTH);
572 icq_PacketAppend32(p, auth); /* NOT auth? */
573 icq_UDPSockWrite(icqlink, p);
574 return icqlink->d->icq_UDPSeqNum1-1;
577 WORD icq_UpdateMetaInfoSet(icq_Link *icqlink, const char *nick, const char *first, const char *last,
578 const char *email, const char *email2, const char *email3,
579 const char *city, const char *state, const char *phone, const char *fax,
580 const char *street, const char *cellular, unsigned long zip,
581 unsigned short cnt_code, unsigned char cnt_stat, unsigned char emailhide)
583 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_META_USER);
584 icq_PacketAppend16(p, META_CMD_SET_INFO);
585 icq_PacketAppendString(p, nick);
586 icq_PacketAppendString(p, first);
587 icq_PacketAppendString(p, last);
588 icq_PacketAppendString(p, email);
589 icq_PacketAppendString(p, email2);
590 icq_PacketAppendString(p, email3);
591 icq_PacketAppendString(p, city);
592 icq_PacketAppendString(p, state);
593 icq_PacketAppendString(p, phone);
594 icq_PacketAppendString(p, fax);
595 icq_PacketAppendString(p, street);
596 icq_PacketAppendString(p, cellular);
597 icq_PacketAppend32(p, zip);
598 icq_PacketAppend16(p, cnt_code);
599 icq_PacketAppend8(p, cnt_stat);
600 icq_PacketAppend8(p, emailhide);
601 icq_UDPSockWrite(icqlink, p);
602 return icqlink->d->icq_UDPSeqNum2-1;
605 WORD icq_UpdateMetaInfoHomepage(icq_Link *icqlink, unsigned char age, const char *homepage,
606 unsigned char year, unsigned char month, unsigned char day,
607 unsigned char lang1, unsigned char lang2, unsigned char lang3)
609 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_META_USER);
610 (void)lang1;
611 (void)lang2;
612 (void)lang3;
613 icq_PacketAppend16(p, META_CMD_SET_HOMEPAGE);
614 icq_PacketAppend8(p, age);
615 icq_PacketAppend16(p, 0x0200);
616 icq_PacketAppendString(p, homepage);
617 icq_PacketAppend8(p, year);
618 icq_PacketAppend8(p, month);
619 icq_PacketAppend8(p, day);
620 icq_PacketAppend8(p, 0xFF /* lang1 */);
621 icq_PacketAppend8(p, 0xFF /* lang2 */);
622 icq_PacketAppend8(p, 0xFF /* lang3 */);
623 icq_UDPSockWrite(icqlink, p);
624 return icqlink->d->icq_UDPSeqNum2-1;
627 WORD icq_UpdateMetaInfoAbout(icq_Link *icqlink, const char *about)
629 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_META_USER);
630 icq_PacketAppend16(p, META_CMD_SET_ABOUT);
631 icq_PacketAppendString(p, about);
632 icq_UDPSockWrite(icqlink, p);
633 return icqlink->d->icq_UDPSeqNum2-1;
636 WORD icq_UpdateMetaInfoSecurity(icq_Link *icqlink, unsigned char reqauth, unsigned char webpresence,
637 unsigned char pubip)
639 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_META_USER);
640 icq_PacketAppend16(p, META_CMD_SET_SECURE);
641 icq_PacketAppend8(p, !reqauth);
642 icq_PacketAppend8(p, webpresence);
643 icq_PacketAppend8(p, pubip);
644 icq_UDPSockWrite(icqlink, p);
645 return icqlink->d->icq_UDPSeqNum2-1;
648 WORD icq_UpdateNewUserInfo(icq_Link *icqlink, const char *nick, const char *first, const char *last,
649 const char *email) /* V5 */
651 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_NEW_USER_INFO);
652 icq_PacketAppendString(p, nick);
653 icq_PacketAppendString(p, first);
654 icq_PacketAppendString(p, last);
655 icq_PacketAppendString(p, email);
656 icq_PacketAppend8(p, 1);
657 icq_PacketAppend8(p, 1);
658 icq_PacketAppend8(p, 1);
659 icq_UDPSockWrite(icqlink, p);
660 return icqlink->d->icq_UDPSeqNum1-1;
663 WORD icq_SendMetaInfoReq(icq_Link *icqlink, unsigned long uin)
665 icq_Packet *p = icq_UDPCreateStdPacket(icqlink, UDP_CMD_META_USER);
666 icq_PacketAppend16(p, META_CMD_REQ_INFO);
667 icq_PacketAppend32(p, uin);
668 icq_UDPSockWrite(icqlink, p);
669 return icqlink->d->icq_UDPSeqNum2-1;