PageRenderTime 87ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/gyachi-1.2.11/client/webcam.c

#
C | 368 lines | 243 code | 59 blank | 66 comment | 37 complexity | 514823f40a635cbb20c3577e8b074fbb MD5 | raw file
Possible License(s): GPL-2.0
  1. /* Mainly a wrapper for launching the external web cam
  2. viewer gyache-webcam, but handles the necessary
  3. Ymsg negotiations inside Gyach */
  4. /*****************************************************************************
  5. * webcam.c
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
  20. * MA 02111-1307, USA.
  21. *
  22. * Copyright (C) 2003-2005, Erica Andrews
  23. * (Phrozensmoke ['at'] yahoo.com)
  24. * http://phpaint.sourceforge.net/pyvoicechat/
  25. *
  26. * Released under the terms of the GPL.
  27. * *NO WARRANTY*
  28. *
  29. * VERY preliminary code for handling webcams - much of this code is
  30. * borrowed from the Ayttm/libyahoo2 projects
  31. *****************************************************************************/
  32. #include <sys/types.h>
  33. #include <sys/stat.h>
  34. #include <sys/wait.h>
  35. #include <unistd.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <stdio.h>
  39. #include <signal.h>
  40. #include <gtk/gtk.h>
  41. #include "config.h"
  42. #include "webcam.h"
  43. #include "sounds.h"
  44. #include "friends.h"
  45. #include "profname.h"
  46. #include "interface.h"
  47. #include "users.h"
  48. #include "gyachi_notebook.h"
  49. #include "util.h"
  50. #include "gyach.h"
  51. #include "gy_config.h"
  52. #include "gyachi_lib.h"
  53. const char *uploader_name = "gyachi-upload";
  54. const char *webcam_name = "gyachi-webcam";
  55. char *lastcamwho =NULL;
  56. int launch_my_cam=0;
  57. int my_cam_is_on=0;
  58. GList *launchers = NULL;
  59. void yahoo_webcam_get_feed(char *who)
  60. {
  61. if (!who) {return;}
  62. if (lastcamwho) {free(lastcamwho); lastcamwho=NULL; launch_my_cam=0;}
  63. if (!enable_webcam_features) {
  64. show_ok_dialog(_("Sorry, You have the webcam feature disabled."));
  65. return;
  66. }
  67. /* This is REALLY stupid, Yahoo will send us a webcam key with NO name
  68. attached, so all we can do is save the last requested name and hope
  69. they match up! */
  70. lastcamwho=strdup(who);
  71. if (!strcasecmp(lastcamwho, get_default_profile_name())) {
  72. launch_my_cam=1;
  73. ymsg_get_webcam(ymsg_sess, NULL); /* get the webcam-server for broadcasting */
  74. }
  75. else {
  76. ymsg_get_webcam(ymsg_sess, lastcamwho);
  77. }
  78. }
  79. char *make_webcam_friends( ) {
  80. GList *this_friend;
  81. char *frmsg=malloc(10240);
  82. if (!frmsg) {return strdup("");}
  83. sprintf( frmsg, "%s", "");
  84. this_friend = friend_list;
  85. while( this_friend ) {
  86. if (strlen(frmsg)>10155) {break;} /* avoid buffer overflow */
  87. if ( this_friend != friend_list ) { strcat( frmsg, "," );}
  88. strcat( frmsg, this_friend->data );
  89. this_friend = g_list_next( this_friend );
  90. }
  91. return frmsg;
  92. }
  93. void my_sig_child_handler(int sig, siginfo_t *my_siginfo, void *arg)
  94. {
  95. int pid = my_siginfo->si_pid;
  96. int status;
  97. waitpid(pid, &status, 0);
  98. /* remove pid from launcher list.
  99. * If launcher list empties, then reset broadcast flag
  100. */
  101. launchers = g_list_remove(launchers, (void *)pid);
  102. if (g_list_length(launchers) == 0) {
  103. my_cam_is_on = -1;
  104. }
  105. }
  106. void yahoo_process_webcam_key(char *key, char *server)
  107. {
  108. struct stat sbuf;
  109. char *(pieces[4]);
  110. char *launcher=NULL;
  111. static int handler_installed = 0;
  112. struct sigaction my_sigaction;
  113. sigset_t my_blocked_sigs, old_blocked_sigs;
  114. pid_t pid;
  115. if (!enable_webcam_features) {
  116. return;
  117. }
  118. if (!key) {
  119. return;
  120. }
  121. if (!lastcamwho) {
  122. return;
  123. }
  124. if (!handler_installed) {
  125. memset(&my_sigaction, 0, sizeof(my_sigaction));
  126. my_sigaction.sa_sigaction = my_sig_child_handler;
  127. my_sigaction.sa_flags = SA_SIGINFO;
  128. sigaction(SIGCHLD, &my_sigaction, 0);
  129. }
  130. if (launch_my_cam) { /* launch the webcam uploader */
  131. char *myfriends=NULL;
  132. pieces[0]=EXPANDED_LIBEXECDIR;
  133. pieces[1]="/";
  134. pieces[2]=(char *)uploader_name;
  135. pieces[3]=NULL;
  136. launcher=build_string(pieces);
  137. if ( stat( launcher, &sbuf )) {
  138. char *wmsg;
  139. char *msg = _("The GyachI external webcam broadcaster could not be found");
  140. wmsg = malloc(strlen(msg) + strlen(launcher) + 4);
  141. sprintf(wmsg, "%s:\n\n%s", msg, launcher);
  142. show_ok_dialog(wmsg);
  143. free(wmsg);
  144. free(lastcamwho);
  145. lastcamwho=NULL;
  146. launch_my_cam=0;
  147. free(launcher);
  148. launcher=NULL;
  149. return;
  150. }
  151. /* TODO: add friends list as last argument */
  152. if (!webcam_device) {
  153. webcam_device=strdup("/dev/video0");
  154. }
  155. myfriends=make_webcam_friends( );
  156. /* block signals before forking.
  157. * This will prevent a race condition of
  158. * the child starting, and exiting *BEFORE* the
  159. * parent starts up.
  160. */
  161. sigfillset(&my_blocked_sigs);
  162. sigprocmask(SIG_BLOCK, &my_blocked_sigs, &old_blocked_sigs);
  163. pid=fork();
  164. if (pid == 0) {
  165. /* we're the child
  166. * re-enable our signal mask, and then exec the launcher.
  167. */
  168. sigprocmask(SIG_BLOCK, &old_blocked_sigs, 0);
  169. execl(launcher,
  170. launcher,
  171. get_default_profile_name(),
  172. key,
  173. webcam_device,
  174. server,
  175. myfriends,
  176. NULL);
  177. }
  178. /* we're the parent
  179. * Add child PID to glist of launchers. Be sure to
  180. * block signals (in particular SIG CHILD) while we do this
  181. */
  182. my_cam_is_on = 1;
  183. launchers = g_list_append(launchers, (void *)pid);
  184. sigprocmask(SIG_BLOCK, &old_blocked_sigs, 0);
  185. free(launcher);
  186. launcher=NULL;
  187. free(lastcamwho);
  188. lastcamwho=NULL;
  189. free(myfriends);
  190. myfriends=NULL;
  191. if (show_cam_is_on) {
  192. char *launch_status;
  193. launch_status=malloc(strlen(webcamtext)+4);
  194. strcpy(launch_status, "99:");
  195. strcpy(launch_status+3, webcamtext);
  196. ymsg_away(ymsg_sess, launch_status);
  197. free(launch_status);
  198. launch_status=NULL;
  199. }
  200. launch_my_cam=0;
  201. return ;
  202. }
  203. else {
  204. /* run EXTERNAL VIEWER HERE */
  205. if (! webcam_viewer_app) {
  206. webcam_viewer_app=strdup("GyachI Webcam");
  207. }
  208. /* check to see if the external viewer is there */
  209. pieces[0]=EXPANDED_LIBEXECDIR;
  210. pieces[1]="/";
  211. pieces[2]=(char *)webcam_name;
  212. pieces[3]=NULL;
  213. launcher=build_string(pieces);
  214. if ( stat( launcher, &sbuf )) {
  215. char *wmsg;
  216. char *msg = _("The GyachI external webcam viewer could not be found");
  217. wmsg = malloc(strlen(msg) + strlen(launcher) + 4);
  218. sprintf(wmsg, "%s:\n\n%s", msg, launcher);
  219. show_ok_dialog(wmsg);
  220. return;
  221. }
  222. pid=fork();
  223. if (pid == 0) {
  224. /* we're the child
  225. * re-enable our signal mask, and then exec the launcher.
  226. */
  227. execl(launcher,
  228. launcher,
  229. lastcamwho,
  230. get_default_profile_name(),
  231. key,
  232. server,
  233. NULL);
  234. }
  235. free(launcher);
  236. launcher=NULL;
  237. free(lastcamwho);
  238. lastcamwho=NULL;
  239. }
  240. }
  241. void gyache_yahoo_webcam_invite_callback(char *who, int result)
  242. {
  243. if (!enable_webcam_features) {
  244. return;
  245. }
  246. if (result) {
  247. ymsg_webcam_invite_accept( ymsg_sess, who);
  248. yahoo_webcam_get_feed(who);
  249. }
  250. else {
  251. ymsg_webcam_invite_reject( ymsg_sess, who);
  252. }
  253. }
  254. void on_webcam_invite_accept (GtkWidget *button, gpointer user_data)
  255. {
  256. GtkWidget *tmp_widget;
  257. char *who=NULL;
  258. who = g_object_get_data(G_OBJECT(button), "who" );
  259. if (who) {gyache_yahoo_webcam_invite_callback(who,1); free(who);}
  260. tmp_widget=g_object_get_data(G_OBJECT(button), "mywindow");
  261. if (tmp_widget) {gtk_widget_destroy(tmp_widget);}
  262. }
  263. void on_webcam_invite_reject (GtkWidget *button, gpointer user_data)
  264. {
  265. GtkWidget *tmp_widget;
  266. char *who=NULL;
  267. who = g_object_get_data(G_OBJECT(button), "who" );
  268. if (who) {gyache_yahoo_webcam_invite_callback(who,0); free(who);}
  269. tmp_widget=g_object_get_data(G_OBJECT(button), "mywindow");
  270. if (tmp_widget) {gtk_widget_destroy(tmp_widget);}
  271. }
  272. void yahoo_webcam_invite_msg(char *who)
  273. {
  274. char buff[256];
  275. GtkWidget *okbutton=NULL;
  276. GtkWidget *cbutton=NULL;
  277. GtkWidget *parent; /* either pm of "who", or main chat window */
  278. if (!enable_webcam_features) {
  279. /* we aren't allowing webcam, so auto-reject invites */
  280. /* packet_handler should catch this first, but just in case */
  281. ymsg_webcam_invite_reject( ymsg_sess, who);
  282. return;
  283. }
  284. snprintf(buff, 254, _("The yahoo user <b>%s</b> has invited you to view their webcam. Do you want to accept?"), who);
  285. parent = find_pms_window(who);
  286. if (!parent) parent=chat_window;
  287. gtk_window_present(GTK_WINDOW(parent));
  288. okbutton=show_confirm_dialog_config_p(parent, buff, "Yes", "No", 0);
  289. if (!okbutton) {ymsg_webcam_invite_reject( ymsg_sess, who); return;}
  290. g_signal_connect(G_OBJECT(okbutton), "clicked",
  291. G_CALLBACK (on_webcam_invite_accept), NULL);
  292. g_object_set_data(G_OBJECT(okbutton), "who", strdup(who));
  293. cbutton=g_object_get_data(G_OBJECT(okbutton), "cancel" );
  294. if (cbutton) {
  295. g_signal_connect(G_OBJECT(cbutton), "clicked",
  296. G_CALLBACK (on_webcam_invite_reject), NULL);
  297. g_object_set_data(G_OBJECT(cbutton), "who", strdup(who));
  298. }
  299. play_sound_event(SOUND_EVENT_OTHER);
  300. }
  301. /* This should be handled in GyachE, not in the external cam viewer:
  302. A viewer sent a Ymsg packet accepting/rejecting
  303. a cam invite we sent them - this is already handled by packet_handler.c
  304. appropriately */
  305. /*
  306. void yahoo_webcam_invite_reply(char *from, int accept)
  307. {
  308. }
  309. */