/ettercap/src/ec_ui.c

# · C · 352 lines · 170 code · 86 blank · 96 comment · 36 complexity · 6da16f936217321f09bc35680d4c36b9 MD5 · raw file

  1. /*
  2. ettercap -- user interface stuff
  3. Copyright (C) ALoR & NaGA
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. $Id: ec_ui.c,v 1.30 2004/09/28 13:50:37 alor Exp $
  16. */
  17. #include <ec.h>
  18. #include <ec_ui.h>
  19. #include <stdarg.h>
  20. #include <pthread.h>
  21. /* globals */
  22. struct ui_message {
  23. char *message;
  24. STAILQ_ENTRY(ui_message) next;
  25. };
  26. static STAILQ_HEAD(, ui_message) messages_queue = STAILQ_HEAD_INITIALIZER(messages_queue);
  27. /* global mutex on interface */
  28. static pthread_mutex_t ui_msg_mutex = PTHREAD_MUTEX_INITIALIZER;
  29. #define UI_MSG_LOCK do{ pthread_mutex_lock(&ui_msg_mutex); }while(0)
  30. #define UI_MSG_UNLOCK do{ pthread_mutex_unlock(&ui_msg_mutex); }while(0)
  31. /* protos... */
  32. void ui_init(void);
  33. void ui_start(void);
  34. void ui_cleanup(void);
  35. void ui_msg(const char *fmt, ...);
  36. void ui_error(const char *fmt, ...);
  37. void ui_fatal_error(const char *msg);
  38. void ui_input(const char *title, char *input, size_t n, void (*callback)(void));
  39. int ui_progress(char *title, int value, int max);
  40. int ui_msg_flush(int max);
  41. int ui_msg_purge_all(void);
  42. void ui_register(struct ui_ops *ops);
  43. /*******************************************/
  44. /* called to initialize the user interface */
  45. void ui_init(void)
  46. {
  47. DEBUG_MSG("ui_init");
  48. EXECUTE(GBL_UI->init);
  49. GBL_UI->initialized = 1;
  50. }
  51. /* called to run the user interface */
  52. void ui_start(void)
  53. {
  54. DEBUG_MSG("ui_start");
  55. if (GBL_UI->initialized)
  56. EXECUTE(GBL_UI->start);
  57. else
  58. DEBUG_MSG("ui_start called initialized");
  59. }
  60. /* called to end the user interface */
  61. void ui_cleanup(void)
  62. {
  63. if (GBL_UI->initialized) {
  64. DEBUG_MSG("ui_cleanup");
  65. EXECUTE(GBL_UI->cleanup);
  66. GBL_UI->initialized = 0;
  67. }
  68. }
  69. /* implement the progress bar */
  70. int ui_progress(char *title, int value, int max)
  71. {
  72. if (GBL_UI->progress)
  73. return GBL_UI->progress(title, value, max);
  74. return UI_PROGRESS_UPDATED;
  75. }
  76. /*
  77. * the FATAL_MSG error handling function
  78. */
  79. void ui_error(const char *fmt, ...)
  80. {
  81. va_list ap;
  82. int n;
  83. size_t size = 50;
  84. char *msg;
  85. /*
  86. * we hope the message is shorter
  87. * than 'size', else realloc it
  88. */
  89. SAFE_CALLOC(msg, size, sizeof(char));
  90. while (1) {
  91. /* Try to print in the allocated space. */
  92. va_start(ap, fmt);
  93. n = vsnprintf (msg, size, fmt, ap);
  94. va_end(ap);
  95. /* If that worked, we have finished. */
  96. if (n > -1 && (size_t)n < size)
  97. break;
  98. /* Else try again with more space. */
  99. if (n > -1) /* glibc 2.1 */
  100. size = n+1; /* precisely what is needed */
  101. else /* glibc 2.0 */
  102. size *= 2; /* twice the old size */
  103. SAFE_REALLOC(msg, size);
  104. }
  105. /* dump the error in the debug file */
  106. DEBUG_MSG("%s", msg);
  107. /* call the function */
  108. if (GBL_UI->error)
  109. EXECUTE(GBL_UI->error, msg);
  110. /* the interface is not yet initialized */
  111. else
  112. fprintf(stderr, "\n%s\n", msg);
  113. /* free the message */
  114. SAFE_FREE(msg);
  115. }
  116. /*
  117. * the FATAL_ERROR error handling function
  118. */
  119. void ui_fatal_error(const char *msg)
  120. {
  121. /*
  122. * call the function
  123. * make sure that the globals have been alloc'd
  124. */
  125. if (GBLS && GBL_UI && GBL_UI->fatal_error && GBL_UI->initialized)
  126. EXECUTE(GBL_UI->fatal_error, msg);
  127. /* the interface is not yet initialized */
  128. else {
  129. fprintf(stderr, "\n%s\n\n", msg);
  130. exit(-1);
  131. }
  132. }
  133. /*
  134. * this fuction enqueues the messages displayed by
  135. * ui_msg_flush()
  136. */
  137. void ui_msg(const char *fmt, ...)
  138. {
  139. va_list ap;
  140. struct ui_message *msg;
  141. int n;
  142. size_t size = 50;
  143. SAFE_CALLOC(msg, 1, sizeof(struct ui_message));
  144. /*
  145. * we hope the message is shorter
  146. * than 'size', else realloc it
  147. */
  148. SAFE_CALLOC(msg->message, size, sizeof(char));
  149. while (1) {
  150. /* Try to print in the allocated space. */
  151. va_start(ap, fmt);
  152. n = vsnprintf (msg->message, size, fmt, ap);
  153. va_end(ap);
  154. /* If that worked, we have finished. */
  155. if (n > -1 && (size_t)n < size)
  156. break;
  157. /* Else try again with more space. */
  158. if (n > -1) /* glibc 2.1 */
  159. size = n+1; /* precisely what is needed */
  160. else /* glibc 2.0 */
  161. size *= 2; /* twice the old size */
  162. SAFE_REALLOC(msg->message, size);
  163. }
  164. /* log the messages if needed */
  165. if (GBL_OPTIONS->msg_fd) {
  166. fprintf(GBL_OPTIONS->msg_fd, "%s", msg->message);
  167. fflush(GBL_OPTIONS->msg_fd);
  168. }
  169. /*
  170. * MUST use the mutex.
  171. * this MAY be a different thread !!
  172. */
  173. UI_MSG_LOCK;
  174. /* add the message to the queue */
  175. STAILQ_INSERT_TAIL(&messages_queue, msg, next);
  176. UI_MSG_UNLOCK;
  177. }
  178. /*
  179. * get the user input
  180. */
  181. void ui_input(const char *title, char *input, size_t n, void (*callback)(void))
  182. {
  183. DEBUG_MSG("ui_input");
  184. EXECUTE(GBL_UI->input, title, input, n, callback);
  185. }
  186. /*
  187. * this function is used to display up to 'max' messages.
  188. * a user interface MUST use this to empty the message queue.
  189. */
  190. int ui_msg_flush(int max)
  191. {
  192. int i = 0;
  193. struct ui_message *msg;
  194. /* the queue is updated by other threads */
  195. UI_MSG_LOCK;
  196. /* sanity check */
  197. if (!GBL_UI->initialized)
  198. return 0;
  199. while ( (msg = STAILQ_FIRST(&messages_queue)) != NULL) {
  200. /* diplay the message */
  201. GBL_UI->msg(msg->message);
  202. STAILQ_REMOVE_HEAD(&messages_queue, msg, next);
  203. /* free the message */
  204. SAFE_FREE(msg->message);
  205. SAFE_FREE(msg);
  206. /* do not display more then 'max' messages */
  207. if (++i == max)
  208. break;
  209. }
  210. UI_MSG_UNLOCK;
  211. /* returns the number of displayed messages */
  212. return i;
  213. }
  214. /*
  215. * empty all the message queue
  216. */
  217. int ui_msg_purge_all(void)
  218. {
  219. int i = 0;
  220. struct ui_message *msg;
  221. /* the queue is updated by other threads */
  222. UI_MSG_LOCK;
  223. while ( (msg = STAILQ_FIRST(&messages_queue)) != NULL) {
  224. STAILQ_REMOVE_HEAD(&messages_queue, msg, next);
  225. /* free the message */
  226. SAFE_FREE(msg->message);
  227. SAFE_FREE(msg);
  228. }
  229. UI_MSG_UNLOCK;
  230. /* returns the number of purgeded messages */
  231. return i;
  232. }
  233. /*
  234. * register the function pointer for
  235. * the user interface.
  236. * a new user interface MUST implement this
  237. * three function and use this function
  238. * to hook in the right place.
  239. */
  240. void ui_register(struct ui_ops *ops)
  241. {
  242. BUG_IF(ops->init == NULL);
  243. GBL_UI->init = ops->init;
  244. BUG_IF(ops->cleanup == NULL);
  245. GBL_UI->cleanup = ops->cleanup;
  246. BUG_IF(ops->start == NULL);
  247. GBL_UI->start = ops->start;
  248. BUG_IF(ops->msg == NULL);
  249. GBL_UI->msg = ops->msg;
  250. BUG_IF(ops->error == NULL);
  251. GBL_UI->error = ops->error;
  252. BUG_IF(ops->fatal_error == NULL);
  253. GBL_UI->fatal_error = ops->fatal_error;
  254. BUG_IF((ops->input == NULL)&&(ops->type != UI_DAEMONIZE));
  255. GBL_UI->input = ops->input;
  256. BUG_IF(ops->progress == NULL);
  257. GBL_UI->progress = ops->progress;
  258. GBL_UI->type = ops->type;
  259. }
  260. /* EOF */
  261. // vim:ts=3:expandtab