master ohmu/fastfetch-openbsd / src / modules / wifi / wifi.c
ohmu  ·  2026-10-15
  1#include "common/printing.h"
  2#include "common/jsonconfig.h"
  3#include "common/strutil.h"
  4#include "detection/wifi/wifi.h"
  5#include "modules/wifi/wifi.h"
  6
  7bool ffPrintWifi(FFWifiOptions* options) {
  8    FF_LIST_AUTO_DESTROY result = ffListCreate();
  9
 10    const char* error = ffDetectWifi(&result);
 11    if (error) {
 12        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Wifi), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
 13        return false;
 14    }
 15    if (!result.length) {
 16        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Wifi), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No Wifi interfaces found");
 17        return false;
 18    }
 19
 20    FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
 21
 22    for (uint32_t index = 0; index < result.length; ++index) {
 23        FFWifiResult* item = FF_LIST_GET(FFWifiResult, result, index);
 24        uint8_t moduleIndex = result.length == 1 ? 0 : (uint8_t) (index + 1);
 25
 26        // https://en.wikipedia.org/wiki/List_of_WLAN_channels
 27        char bandStr[8];
 28        if (item->conn.frequency > 58000) {
 29            strcpy(bandStr, "60");
 30        } else if (item->conn.frequency > 40000) {
 31            strcpy(bandStr, "45");
 32        } else if (item->conn.frequency > 5900) {
 33            strcpy(bandStr, "6");
 34        } else if (item->conn.frequency > 5100) {
 35            strcpy(bandStr, "5");
 36        } else if (item->conn.frequency > 4900) {
 37            strcpy(bandStr, "4.9");
 38        } else if (item->conn.frequency > 3600) {
 39            strcpy(bandStr, "3.65");
 40        } else if (item->conn.frequency > 2000) {
 41            strcpy(bandStr, "2.4");
 42        } else if (item->conn.frequency > 800) {
 43            strcpy(bandStr, "0.9");
 44        } else {
 45            bandStr[0] = '\0';
 46        }
 47
 48        if (options->moduleArgs.outputFormat.length == 0) {
 49            ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Wifi), moduleIndex, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
 50
 51            FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
 52            if (item->conn.ssid.length) {
 53                if (item->conn.signalQuality != -DBL_MAX) {
 54                    if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 55                        ffPercentAppendBar(&buffer, item->conn.signalQuality, options->percent, &options->moduleArgs);
 56                        ffStrbufAppendC(&buffer, ' ');
 57                    }
 58                }
 59
 60                if (!(percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) {
 61                    ffStrbufAppend(&buffer, &item->conn.ssid);
 62
 63                    if (item->conn.protocol.length) {
 64                        ffStrbufAppendS(&buffer, " - ");
 65                        ffStrbufAppend(&buffer, &item->conn.protocol);
 66                    }
 67                    if (bandStr[0]) {
 68                        ffStrbufAppendF(&buffer, " - %s%sGHz", bandStr, instance.config.display.freqSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ");
 69                    }
 70                    if (item->conn.security.length) {
 71                        ffStrbufAppendS(&buffer, " - ");
 72                        ffStrbufAppend(&buffer, &item->conn.security);
 73                    }
 74                    ffStrbufAppendC(&buffer, ' ');
 75                }
 76
 77                if (item->conn.signalQuality != -DBL_MAX) {
 78                    if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
 79                        ffPercentAppendNum(&buffer, item->conn.signalQuality, options->percent, buffer.length > 0, &options->moduleArgs);
 80                    }
 81                }
 82
 83                ffStrbufTrimRight(&buffer, ' ');
 84            } else {
 85                ffStrbufAppend(&buffer, &item->inf.status);
 86            }
 87            ffStrbufPutTo(&buffer, stdout);
 88        } else {
 89            FF_STRBUF_AUTO_DESTROY percentNum = ffStrbufCreate();
 90            if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
 91                ffPercentAppendNum(&percentNum, item->conn.signalQuality, options->percent, false, &options->moduleArgs);
 92            }
 93            FF_STRBUF_AUTO_DESTROY percentBar = ffStrbufCreate();
 94            if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
 95                ffPercentAppendBar(&percentBar, item->conn.signalQuality, options->percent, &options->moduleArgs);
 96            }
 97
 98            FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Wifi), moduleIndex, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
 99                                                                                                                       FF_ARG(item->inf.description, "inf-desc"),
100                                                                                                                       FF_ARG(item->inf.status, "inf-status"),
101                                                                                                                       FF_ARG(item->conn.status, "status"),
102                                                                                                                       FF_ARG(item->conn.ssid, "ssid"),
103                                                                                                                       FF_ARG(item->conn.bssid, "bssid"),
104                                                                                                                       FF_ARG(item->conn.protocol, "protocol"),
105                                                                                                                       FF_ARG(percentNum, "signal-quality"),
106                                                                                                                       FF_ARG(item->conn.rxRate, "rx-rate"),
107                                                                                                                       FF_ARG(item->conn.txRate, "tx-rate"),
108                                                                                                                       FF_ARG(item->conn.security, "security"),
109                                                                                                                       FF_ARG(percentBar, "signal-quality-bar"),
110                                                                                                                       FF_ARG(item->conn.channel, "channel"),
111                                                                                                                       FF_ARG(item->conn.channelWidth, "channel-width"),
112                                                                                                                       FF_ARG(bandStr, "band"),
113                                                                                                                   }));
114        }
115    }
116
117    FF_LIST_FOR_EACH (FFWifiResult, item, result) {
118        ffStrbufDestroy(&item->inf.description);
119        ffStrbufDestroy(&item->inf.status);
120        ffStrbufDestroy(&item->conn.status);
121        ffStrbufDestroy(&item->conn.ssid);
122        ffStrbufDestroy(&item->conn.bssid);
123        ffStrbufDestroy(&item->conn.protocol);
124        ffStrbufDestroy(&item->conn.security);
125    }
126
127    return true;
128}
129
130void ffParseWifiJsonObject(FFWifiOptions* options, yyjson_val* module) {
131    yyjson_val *key, *val;
132    size_t idx, max;
133    yyjson_obj_foreach (module, idx, max, key, val) {
134        if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
135            continue;
136        }
137
138        if (ffPercentParseJsonObject(key, val, &options->percent)) {
139            continue;
140        }
141
142        ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Wifi), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
143    }
144}
145
146[[gnu::cold]]
147void ffGenerateWifiJsonConfig(FFWifiOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
148    ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
149
150    ffPercentGenerateJsonConfig(doc, module, options->percent);
151}
152
153bool ffGenerateWifiJsonResult([[maybe_unused]] FFWifiOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
154    FF_LIST_AUTO_DESTROY result = ffListCreate();
155    const char* error = ffDetectWifi(&result);
156    if (error) {
157        yyjson_mut_obj_add_str(doc, module, "error", error);
158        return false;
159    }
160
161    yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
162    FF_LIST_FOR_EACH (FFWifiResult, wifi, result) {
163        yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
164
165        yyjson_mut_val* inf = yyjson_mut_obj_add_obj(doc, obj, "inf");
166        yyjson_mut_obj_add_strbuf(doc, inf, "description", &wifi->inf.description);
167        yyjson_mut_obj_add_strbuf(doc, inf, "status", &wifi->inf.status);
168
169        yyjson_mut_val* conn = yyjson_mut_obj_add_obj(doc, obj, "conn");
170        yyjson_mut_obj_add_strbuf(doc, conn, "status", &wifi->conn.status);
171        yyjson_mut_obj_add_strbuf(doc, conn, "ssid", &wifi->conn.ssid);
172        yyjson_mut_obj_add_strbuf(doc, conn, "bssid", &wifi->conn.bssid);
173        yyjson_mut_obj_add_strbuf(doc, conn, "protocol", &wifi->conn.protocol);
174        yyjson_mut_obj_add_strbuf(doc, conn, "security", &wifi->conn.security);
175        if (wifi->conn.signalQuality != -DBL_MAX) {
176            yyjson_mut_obj_add_real(doc, conn, "signalQuality", wifi->conn.signalQuality);
177        } else {
178            yyjson_mut_obj_add_null(doc, conn, "signalQuality");
179        }
180        if (wifi->conn.rxRate != -DBL_MAX) {
181            yyjson_mut_obj_add_real(doc, conn, "rxRate", wifi->conn.rxRate);
182        } else {
183            yyjson_mut_obj_add_null(doc, conn, "rxRate");
184        }
185        if (wifi->conn.txRate != -DBL_MAX) {
186            yyjson_mut_obj_add_real(doc, conn, "txRate", wifi->conn.txRate);
187        } else {
188            yyjson_mut_obj_add_null(doc, conn, "txRate");
189        }
190        yyjson_mut_obj_add_uint(doc, conn, "channel", wifi->conn.channel);
191        yyjson_mut_obj_add_uint(doc, conn, "channelWidth", wifi->conn.channelWidth);
192        yyjson_mut_obj_add_uint(doc, conn, "frequency", wifi->conn.frequency);
193    }
194
195    FF_LIST_FOR_EACH (FFWifiResult, item, result) {
196        ffStrbufDestroy(&item->inf.description);
197        ffStrbufDestroy(&item->inf.status);
198        ffStrbufDestroy(&item->conn.status);
199        ffStrbufDestroy(&item->conn.ssid);
200        ffStrbufDestroy(&item->conn.bssid);
201        ffStrbufDestroy(&item->conn.protocol);
202        ffStrbufDestroy(&item->conn.security);
203    }
204
205    return true;
206}
207
208void ffInitWifiOptions(FFWifiOptions* options) {
209    ffOptionInitModuleArg(&options->moduleArgs, "");
210
211    options->percent = (FFPercentageModuleConfig) { 75, 50, 0 };
212}
213
214void ffDestroyWifiOptions(FFWifiOptions* options) {
215    ffOptionDestroyModuleArg(&options->moduleArgs);
216}
217
218FFModuleBaseInfo ffWifiModuleInfo = {
219    .name = "Wifi",
220    .description = "Print connected Wi-Fi info (SSID, connection and security protocol)",
221    .displayName = {
222        .en = "Wi-Fi",
223        .ar = "واي فاي",
224        .cs = "Wi-Fi",
225        .de = "WLAN",
226        .es = "Wi-Fi",
227        .fi = "Wi-Fi",
228        .fr = "Wi-Fi",
229        .gl = "Wi-Fi",
230        .he = "Wi-Fi",
231        .id = "Wi-Fi",
232        .it = "Wi-Fi",
233        .ja = "Wi-Fi",
234        .ko = "와이파이",
235        .pl = "Wi-Fi",
236        .pt = "Wi-Fi",
237        .ru = "Wi-Fi",
238        .tr = "Wi-Fi",
239        .uk = "Wi-Fi",
240        .vi = "Wi-Fi",
241        .zh_CN = "无线网络",
242        .zh_TW = "無線網路",
243    },
244    .initOptions = (void*) ffInitWifiOptions,
245    .destroyOptions = (void*) ffDestroyWifiOptions,
246    .parseJsonObject = (void*) ffParseWifiJsonObject,
247    .printModule = (void*) ffPrintWifi,
248    .generateJsonResult = (void*) ffGenerateWifiJsonResult,
249    .generateJsonConfig = (void*) ffGenerateWifiJsonConfig,
250    .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
251        { "Interface description", "inf-desc" },
252        { "Interface status", "inf-status" },
253        { "Connection status", "status" },
254        { "Connection SSID", "ssid" },
255        { "Connection BSSID", "bssid" },
256        { "Connection protocol", "protocol" },
257        { "Connection signal quality (percentage num)", "signal-quality" },
258        { "Connection RX rate", "rx-rate" },
259        { "Connection TX rate", "tx-rate" },
260        { "Connection Security algorithm", "security" },
261        { "Connection signal quality (percentage bar)", "signal-quality-bar" },
262        { "Connection channel number", "channel" },
263        { "Connection channel width in MHz", "channel-width" },
264        { "Connection channel band in GHz", "band" },
265    })),
266    .defaultOrder = 52,
267};