]> git.sur5r.net Git - i3/i3/commitdiff
i3-msg: read replies, implement get_workspaces command
authorMichael Stapelberg <michael@stapelberg.de>
Fri, 12 Mar 2010 14:30:09 +0000 (15:30 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Fri, 12 Mar 2010 14:30:09 +0000 (15:30 +0100)
i3-msg/Makefile
i3-msg/main.c

index a5e15b6e49d0aad96826f4a2397398b1de4c3d55..ec4ba6e63c90842536d211bbf4ae3401420edd87 100644 (file)
@@ -3,6 +3,8 @@ TOPDIR=..
 
 include $(TOPDIR)/common.mk
 
+CFLAGS += -I$(TOPDIR)/include
+
 # Depend on the object files of all source-files in src/*.c and on all header files
 FILES=$(patsubst %.c,%.o,$(wildcard *.c))
 HEADERS=$(wildcard *.h)
index 197cceb6816bcf4622810383440e298ec7245919..4c0efbaa86ef55d100b60dc7642c18c3705a9d7d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * i3 - an improved dynamic tiling window manager
  *
- * © 2009 Michael Stapelberg and contributors
+ * © 2009-2010 Michael Stapelberg and contributors
  *
  * See file LICENSE for license information.
  *
@@ -16,6 +16,7 @@
  */
 #include <ev.h>
 #include <stdio.h>
+#include <stdbool.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -27,6 +28,8 @@
 #include <stdint.h>
 #include <getopt.h>
 
+#include <i3/ipc.h>
+
 /*
  * Formats a message (payload) of the given size and type and sends it to i3 via
  * the given socket file descriptor.
  */
 static void ipc_send_message(int sockfd, uint32_t message_size,
                              uint32_t message_type, uint8_t *payload) {
-        int buffer_size = strlen("i3-ipc") + sizeof(uint32_t) + sizeof(uint32_t) + message_size;
+        int buffer_size = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t) + message_size;
         char msg[buffer_size];
         char *walk = msg;
 
-        strcpy(walk, "i3-ipc");
-        walk += strlen("i3-ipc");
+        strcpy(walk, I3_IPC_MAGIC);
+        walk += strlen(I3_IPC_MAGIC);
         memcpy(walk, &message_size, sizeof(uint32_t));
         walk += sizeof(uint32_t);
         memcpy(walk, &message_type, sizeof(uint32_t));
@@ -58,26 +61,83 @@ static void ipc_send_message(int sockfd, uint32_t message_size,
         }
 }
 
+static void ipc_recv_message(int sockfd, uint32_t message_type,
+                             uint32_t *reply_length, uint8_t **reply) {
+        /* Read the message header first */
+        uint32_t to_read = strlen(I3_IPC_MAGIC) + sizeof(uint32_t) + sizeof(uint32_t);
+        char msg[to_read];
+        char *walk = msg;
+
+        uint32_t read_bytes = 0;
+        while (read_bytes < to_read) {
+                int n = read(sockfd, msg + read_bytes, to_read);
+                if (n == -1)
+                        err(EXIT_FAILURE, "read() failed");
+
+                read_bytes += n;
+                to_read -= n;
+        }
+
+        if (memcmp(walk, I3_IPC_MAGIC, strlen(I3_IPC_MAGIC)) != 0)
+                errx(EXIT_FAILURE, "invalid magic in reply");
+
+        walk += strlen(I3_IPC_MAGIC);
+        *reply_length = *((uint32_t*)walk);
+        walk += sizeof(uint32_t);
+        if (*((uint32_t*)walk) != message_type)
+                errx(EXIT_FAILURE, "unexpected reply type (got %d, expected %d)", *((uint32_t*)walk), message_type);
+        walk += sizeof(uint32_t);
+
+        *reply = malloc(*reply_length);
+        if ((*reply) == NULL)
+                err(EXIT_FAILURE, "malloc() failed");
+
+        to_read = *reply_length;
+        read_bytes = 0;
+        while (read_bytes < to_read) {
+                int n = read(sockfd, *reply + read_bytes, to_read);
+                if (n == -1)
+                        err(EXIT_FAILURE, "read() failed");
+
+                read_bytes += n;
+                to_read -= n;
+        }
+}
+
 int main(int argc, char *argv[]) {
         char *socket_path = "/tmp/i3-ipc.sock";
         int o, option_index = 0;
+        int message_type;
+        char *payload = "";
+        bool quiet = false;
 
         static struct option long_options[] = {
                 {"socket", required_argument, 0, 's'},
                 {"type", required_argument, 0, 't'},
                 {"version", no_argument, 0, 'v'},
+                {"quiet", no_argument, 0, 'q'},
                 {"help", no_argument, 0, 'h'},
                 {0, 0, 0, 0}
         };
 
-        char *options_string = "s:t:vh";
+        char *options_string = "s:t:vhq";
 
         while ((o = getopt_long(argc, argv, options_string, long_options, &option_index)) != -1) {
                 if (o == 's') {
                         socket_path = strdup(optarg);
                         break;
                 } else if (o == 't') {
-                        printf("currently only commands are implemented\n");
+                        if (strcasecmp(optarg, "command") == 0)
+                                message_type = I3_IPC_MESSAGE_TYPE_COMMAND;
+                        else if (strcasecmp(optarg, "get_workspaces") == 0)
+                                message_type = I3_IPC_MESSAGE_TYPE_GET_WORKSPACES;
+                        else {
+                                printf("Unknown message type\n");
+                                printf("Known types: command, get_workspaces\n");
+                                exit(EXIT_FAILURE);
+                        }
+                } else if (o == 'q') {
+                        quiet = true;
                 } else if (o == 'v') {
                         printf("i3-msg " I3_VERSION);
                         return 0;
@@ -88,11 +148,8 @@ int main(int argc, char *argv[]) {
                 }
         }
 
-        if (optind >= argc) {
-                fprintf(stderr, "Error: missing message\n");
-                fprintf(stderr, "i3-msg [-s <socket>] [-t <type>] <message>\n");
-                return 1;
-        }
+        if (optind < argc)
+                payload = argv[optind];
 
         int sockfd = socket(AF_LOCAL, SOCK_STREAM, 0);
         if (sockfd == -1)
@@ -105,7 +162,16 @@ int main(int argc, char *argv[]) {
         if (connect(sockfd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un)) < 0)
                 err(EXIT_FAILURE, "Could not connect to i3");
 
-        ipc_send_message(sockfd, strlen(argv[optind]), 0, (uint8_t*)argv[optind]);
+        ipc_send_message(sockfd, strlen(payload), message_type, (uint8_t*)payload);
+
+        if (quiet)
+                return 0;
+
+        uint32_t reply_length;
+        uint8_t *reply;
+        ipc_recv_message(sockfd, message_type, &reply_length, &reply);
+        printf("%.*s", reply_length, reply);
+        free(reply);
 
         close(sockfd);