13 static const char hex_table[] =
"0123456789ABCDEF";
14 static char* string_to_hex_alloc(
const char* str,
int len) {
18 memset(tmp, 0, len * 2 + 1);
19 for (l = 0, n = 0; l < len; l++) {
20 tmp[n++] = hex_table[(str[l] & 0xF0) >> 4];
21 tmp[n++] = hex_table[str[l] & 0x0F];
36 if (WSAStartup(WINSOCK_VERSION, &wsaData) != 0)
70 for (n = 0; n < count; n++)
71 salt[n] = (randSeed % 255) + 1;
84 memset(md5tmp, 0,
sizeof(md5tmp));
86 md5_update(&md5ctx, (uint8_t*)password, (uint32_t)strlen(password));
87 md5_update(&md5ctx, (uint8_t*)salt, (uint32_t)strlen(salt));
93 md5digest = string_to_hex_alloc(md5tmp, 16);
103 char* authheader = NULL;
110 salthash = string_to_hex_alloc(salt, 8);
112 authheader = (
char*)
PhAllocateSafe(strlen(keyhash) + strlen(salthash) + 7);
114 sprintf(authheader,
" MD5:%s.%s", keyhash, salthash);
128 int growl_tcp_register(
const char *
const server ,
const char *
const appname ,
const char **
const notifications ,
const int notifications_count ,
129 const char *
const password,
const char*
const icon )
131 SOCKET sock = INVALID_SOCKET;
135 FILE *iconfile = NULL;
137 uint8_t buffer[1024];
142 if (sock == INVALID_SOCKET)
goto leave;
147 iconfile = fopen(icon,
"rb");
149 fseek(iconfile, 0, SEEK_END);
150 iconsize = ftell(iconfile);
151 fseek(iconfile, 0, SEEK_SET);
152 memset(md5tmp, 0,
sizeof(md5tmp));
154 while (!feof(iconfile)) {
155 bytes_read = fread(buffer, 1, 1024, iconfile);
156 if (bytes_read)
md5_update(&md5ctx, buffer, (uint32_t)bytes_read);
158 fseek(iconfile, 0, SEEK_SET);
160 iconid = string_to_hex_alloc(md5tmp, 16);
164 growl_tcp_write(sock,
"GNTP/1.0 REGISTER NONE %s", authheader ? authheader :
"");
168 growl_tcp_write(sock,
"Application-Icon: x-growl-resource://%s", iconid);
177 for(i=0;i<notifications_count;i++)
180 growl_tcp_write(sock,
"Notification-Display-Name: %s", notifications[i]);
184 growl_tcp_write(sock,
"Notification-Icon: x-growl-resource://%s", iconid);
199 while (!feof(iconfile))
201 size_t bytes_read = fread(buffer, 1, 1024, iconfile);
214 sock = INVALID_SOCKET;
219 int len = (int)strlen(line);
221 if (strncmp(line,
"GNTP/1.0 -ERROR", 15) == 0)
223 if (strncmp(line + 15,
" NONE", 5) != 0)
225 fprintf(stderr,
"failed to register notification\n");
238 if (iconfile) fclose(iconfile);
239 if (iconid)
PhFree(iconid);
240 if (authheader)
PhFree(authheader);
242 return (sock == 0) ? 0 : INVALID_SOCKET;
246 int growl_tcp_notify(
const char *
const server,
const char *
const appname,
const char *
const notify,
const char *
const title,
const char *
const message ,
247 const char *
const password,
const char*
const url,
const char*
const icon)
249 SOCKET sock = INVALID_SOCKET;
253 FILE *iconfile = NULL;
255 uint8_t buffer[1024];
260 if (sock == INVALID_SOCKET)
goto leave;
267 iconfile = fopen(icon,
"rb");
270 fseek(iconfile, 0, SEEK_END);
271 iconsize = ftell(iconfile);
272 fseek(iconfile, 0, SEEK_SET);
273 memset(md5tmp, 0,
sizeof(md5tmp));
275 while (!feof(iconfile))
277 bytes_read = fread(buffer, 1, 1024, iconfile);
278 if (bytes_read)
md5_update(&md5ctx, buffer, (uint32_t)bytes_read);
280 fseek(iconfile, 0, SEEK_SET);
282 iconid = string_to_hex_alloc(md5tmp, 16);
286 growl_tcp_write(sock,
"GNTP/1.0 NOTIFY NONE %s", authheader ? authheader :
"");
293 growl_tcp_write(sock,
"Notification-Icon: x-growl-resource://%s", iconid);
299 if (url)
growl_tcp_write(sock,
"Notification-Callback-Target: %s", url );
306 while (!feof(iconfile))
308 size_t bytes_read = fread(buffer, 1, 1024, iconfile);
322 sock = INVALID_SOCKET;
326 int len = (int)strlen(line);
328 if (strncmp(line,
"GNTP/1.0 -ERROR", 15) == 0)
330 if (strncmp(line + 15,
" NONE", 5) != 0)
332 fprintf(stderr,
"failed to post notification\n");
345 if (iconfile) fclose(iconfile);
346 if (iconid)
PhFree(iconid);
347 if (authheader)
PhFree(authheader);
349 return (sock == 0) ? 0 : INVALID_SOCKET;
354 int growl(
const char *
const server,
const char *
const appname,
const char *
const notify,
const char *
const title,
const char *
const message ,
355 const char *
const icon ,
const char *
const password ,
const char *url )
357 int rc =
growl_tcp_register( server , appname , (
const char **
const)¬ify , 1 , password, icon );
360 rc =
growl_tcp_notify( server, appname, notify, title, message , password, url, icon );
366 void growl_append_md5(
unsigned char *
const data ,
const int data_length ,
const char *
const password )
371 memset(md5tmp, 0,
sizeof(md5tmp));
373 md5_update(&md5ctx, (uint8_t*)data, data_length );
376 md5_update(&md5ctx, (uint8_t*)password, (uint32_t)strlen(password));
380 memcpy( data + data_length , md5tmp , 16 );
384 int growl_udp_register(
const char *
const server ,
const char *
const appname ,
const char **
const notifications ,
const int notifications_count ,
const char *
const password )
386 int register_header_length = 22+(int)strlen(appname);
392 uint8_t GROWL_PROTOCOL_VERSION = 1;
393 uint8_t GROWL_TYPE_REGISTRATION = 0;
395 uint16_t appname_length = ntohs((u_short)strlen(appname));
396 uint8_t _notifications_count = notifications_count;
397 uint8_t default_notifications_count = notifications_count;
402 for(i=0;i<notifications_count;i++)
404 register_header_length += 3 + (int)strlen(notifications[i]);
407 if (!data)
return -1;
408 memset( data , 0 , register_header_length );
412 memcpy( data + pointer , &GROWL_PROTOCOL_VERSION , 1 );
414 memcpy( data + pointer , &GROWL_TYPE_REGISTRATION , 1 );
416 memcpy( data + pointer , &appname_length , 2 );
418 memcpy( data + pointer , &_notifications_count , 1 );
420 memcpy( data + pointer, &default_notifications_count , 1 );
422 sprintf( (
char*)data + pointer ,
"%s" , appname );
423 pointer += (int)strlen(appname);
425 for(i=0;i<notifications_count;i++)
427 uint16_t notify_length = ntohs((u_short)strlen(notifications[i]));
428 memcpy( data + pointer, ¬ify_length , 2 );
430 sprintf( (
char*)data + pointer ,
"%s" , notifications[i] );
431 pointer += (int)strlen(notifications[i]);
434 for(j=0;j<notifications_count;j++)
436 memcpy( data + pointer , &j , 1 );
449 int growl_udp_notify(
const char *
const server,
const char *
const appname,
const char *
const notify,
const char *
const title,
const char *
const message ,
450 const char *
const password )
452 int notify_header_length = 28 + (int)(strlen(appname)+strlen(notify)+strlen(message)+strlen(title));
453 unsigned char *data = (
unsigned char*)
PhAllocateSafe(notify_header_length);
457 uint8_t GROWL_PROTOCOL_VERSION = 1;
458 uint8_t GROWL_TYPE_NOTIFICATION = 1;
460 uint16_t flags = ntohs(0);
461 uint16_t appname_length = ntohs((u_short)strlen(appname));
462 uint16_t notify_length = ntohs((u_short)strlen(notify));
463 uint16_t title_length = ntohs((u_short)strlen(title));
464 uint16_t message_length = ntohs((u_short)strlen(message));
466 if (!data)
return -1;
469 memset( data , 0 , notify_header_length );
472 memcpy( data + pointer , &GROWL_PROTOCOL_VERSION , 1 );
474 memcpy( data + pointer , &GROWL_TYPE_NOTIFICATION , 1 );
476 memcpy( data + pointer , &flags , 2 );
478 memcpy( data + pointer , ¬ify_length , 2 );
480 memcpy( data + pointer , &title_length , 2 );
482 memcpy( data + pointer , &message_length , 2 );
484 memcpy( data + pointer , &appname_length , 2 );
486 strcpy( (
char*)data + pointer , notify );
487 pointer += (int)strlen(notify);
488 strcpy( (
char*)data + pointer , title );
489 pointer += (int)strlen(title);
490 strcpy( (
char*)data + pointer , message );
491 pointer += (int)strlen(message);
492 strcpy( (
char*)data + pointer , appname );
493 pointer += (int)strlen(appname);
506 int growl_udp(
const char *
const server,
const char *
const appname,
const char *
const notify,
const char *
const title,
const char *
const message ,
507 const char *
const icon ,
const char *
const password ,
const char *url )
509 int rc =
growl_udp_register( server , appname , (
const char **
const)¬ify , 1 , password );
512 rc =
growl_udp_notify( server, appname, notify, title, message , password );
518 "[The \"BSD licence\"]\r\n"
519 "Copyright (c) 2009-2010 Yasuhiro Matsumoto\r\n"
520 "All rights reserved.\r\n"
522 "Redistribution and use in source and binary forms, with or without\r\n"
523 "modification, are permitted provided that the following conditions\r\n"
526 " 1. Redistributions of source code must retain the above copyright\r\n"
527 " notice, this list of conditions and the following disclaimer.\r\n"
528 " 2. Redistributions in binary form must reproduce the above copyright\r\n"
529 " notice, this list of conditions and the following disclaimer in the\r\n"
530 " documentation and/or other materials provided with the distribution.\r\n"
531 " 3. The name of the author may not be used to endorse or promote products\r\n"
532 " derived from this software without specific prior written permission.\r\n"
534 "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r\n"
535 "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r\n"
536 "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r\n"
537 "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r\n"
538 "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r\n"
539 "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n"
540 "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n"
541 "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n"
542 "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r\n"
543 "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n"